Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

DB/Device Supervision

docs/supervision.livemd

DB/Device Supervision

DB Supervisor

DB Supervisor wraps every DB in Queue, Writer, Dry Status Relay, Decider and Compactor.

Queue and Writer are described in DB Prioritization.

Dry Status Relay is Agent that holds read-only state of DB. It is updated by Decider. And read by UI to show red indication.

Decider checks space left on device and starts writing or read-only configuration under WriteSupervisor. For write it starts Writer and Compactor. For read-only - DryWriter, which does no writes in DB or filesystem.

Compactor awaits for period of inactivity (7 minutes) and starts DB compaction. When Writer has something to write, it lets Compactor know, so compaction will get canceled if unfinished.

The supervision strategy is rest for one. Which means that all peers to the right will get restated if children failed. I.e. if CubDB fails, Dry Status Relay, WriteSupervisor and Decider get restarted as well. Queue continues to work, aggregating all the changes User generated. This provides seamless switching into Read Only mode when there is no room to write data.

graph TD;
  s(DB Supervisor)

  s --> Queue
  s --> db[(CubDB)]
  s --> ds[Dry Status Relay]
  s --> ws{{WriteSupervisor}}
  s --> Decider

  ws --> Compactor
  ws --> Writer
  ws -.-> DryWriter

This approach used in all DB Supervisors. Each handles its own DB, otherwise they are identical

  • Chat.Db.InternalDbSupervisor
  • Chat.Db.MainDbSupervisor
  • Chat.Db.MediaDbSupervisor

Device Supervision

Device managing happens in Platform project. (It incorporates Chat as dependency)

Here is a simplified supervision tree.

graph LR;
  subgraph Chat
    ids(InternalDbSupervisor)
    mds(MainDbSupervisor)
    meds(MediaDbSupervisor)
    ca(Application)

    ca -.-> ids
  end

  pa(Application)
  ds(DeviceSupervisor)
  cb[ChatBridge]
  di[DriveIndication]
  drive_sup{{Drives}}
  dr[Drives.Registry]
  udd[UsbDrives.Detector]

  pa --> cb
  pa --> di
  pa --> ds

  ds --> drive_sup
  ds --> dr
  ds --> udd

  drive_sup -..-> mds
  drive_sup -..-> meds

DriveIndication handles extra LED indication hardware

ChatBridge lets Chat to talk to Platform. Wifi setting and drives interaction are possible here.

UsbDrives.Detector polls filesystem for USB devices plug/unplug.

Drives.Registry registers processes used in drive dedicated subtrees.

Drives - supervises detected drives. We need Dynamic Supervisors to start or shutdown supervision subtrees, since devices are not always present. Each drive gets its own subtree.

Drive subtree consists of 2 parts.

  • Booting - heals filesystem, mounts it and decideces which scenario to run
  • Scenario - supervises given scenario behavior

Depending on scenario, subtree will include MainDbSupervisor or MediaSupervisor to supervise DB.

graph TD;
  ds{{Drives}}
  bs(Boot)
  dis[DriveIndicationStarter]
  h[[Healer]]
  healed{{Healed}}
  m[[Mounter]]
  mounted{{Mounted}}
  sc{{Scenario}}
  d[Decider]

  ds -.-> bs
  bs --> dis
  bs --> healed
  bs --> h

  healed --> m
  healed --> mounted

  mounted --> sc
  mounted --> d

DriveIndicationStarter starts indication on custom hardware and ands it when drive ejected (i.e. this process terminated)

Healer detects FS used on drive and checks FS w/ coresponding tool (FAT, exFAT or F2FS)

Mounter mounts device into device dedicated folder

Decider checks device content and starts according scenario under Scenario supervisor.

Main drive supervision

graph TD;
  pmds(Platform MainDbSupervisor)
  mts(Task.Supervisor)
  mm[[Mounter]]
  mdt[DirTask]
  mds(Chat MainDbSupervisor)
  mb[[Bouncer]]
  ms[[Starter]]
  mc[[Copier]]
  mr[[Replicator]]
  msw[[Switcher]]

  pmds --> mts
  pmds --> mm
  pmds --> mdt
  pmds --> mds
  pmds --> mb
  pmds --> ms
  pmds --> mc
  pmds --> mr
  pmds --> msw

Mounter mounts device into folder specified. And unmounts when terminated.

DirTask ensures that device filesystem has the folder to hold DB.

Chat MainDbSupervisor is DB Supervisor from Chat application described above.

Bouncer prevents DB directory from being renamed.

Starter changes global DB status (in application config). And reverts it back when terminated.

Copier starts blinking leds and copies data. And finishing blinking when terminated.

Replicator starts sync to internal DB every 5 mins. And stops when terminated.

Switcher switches Current DB to main. And reverts Current DB back to internal when terminated.

Media drive supervision

graph TD;
  pms(MediaSupervisor)

  mets(Task.Supervisor)
  mem[[Mounter]]
  fds[FunctionalityDynamicSupervisor]
  d[MediaDecider]

  pms --> mets
  pms --> mem
  pms --> fds
  pms --> d

  pbds(Platform BackupDbSupervisor)
  pcss(Platform CargoSyncSupervisor)
  poss(Platform OnlinersSyncSupervisor)

  fds ---> pbds
  fds ---> pcss
  fds ---> poss

  bdt[DirTask]
  bmds(Chat MediaDbSupervisor)
  bb[[Bouncer]]
  bs[[Starter]]
  bc[[Copier]]
  bst[[Stopper]]

  pbds --> bdt
  pbds --> bmds
  pbds --> bb
  pbds --> bs
  pbds --> bc
  pbds --> bst

  csdt[DirTask]
  csmds(Chat MediaDbSupervisor)
  csb[[Bouncer]]
  css[[Starter]]
  cscds[[CargoDynamicSupervisor]]
  csl[[Logic]]
  csc[[Copier]]
  csst[[Stopper]]

  pcss --> csdt
  pcss --> csmds
  pcss --> csb
  pcss --> css
  pcss --> cscds
  pcss --> csl

  cscds --> csc
  cscds --> csst

  osdt[DirTask]
  osmds(Chat MediaDbSupervisor)
  osb[[Bouncer]]
  oss[[Starter]]
  osods[[OnlinersDynamicSupervisor]]
  osl[[Logic]]
  osc[[Copier]]
  osst[[Stopper]]

  poss --> osdt
  poss --> osmds
  poss --> osb
  poss --> oss
  poss --> osods
  poss --> osl

  osods --> osc
  osods --> osst

Mounter mounts device into folder specified. And unmounts when terminated.

Decider figures out which functionality to start under FunctionalityDynamicSupervisor. It does it by checking whether device contains appropriate directory (backup_db for backup, cargo_db for cargo, or onliners_db for onliners sync). If not, it checks the media settings in the Chat Admin room. If it’s not set yet, the default functionality is used (backup).

Some of the modules are reused between the functionalities. We’ll describe them here while the unique aspects of the functionalities will be described in the below sections.

DirTask ensures that device filesystem has the folder to hold DB.

Chat MediaDbSupervisor is DB Supervisor from Chat application described above.

Bouncer prevents DB directory from being renamed.

Starter changes global DB status (in application config). And reverts it back when terminated.

Copier starts blinking leds and copies data. And finishing blinking when terminated.

Stopper starts extra LED blinking and makes Platform MediaSupervisor to stop. On termination stops LED blinking.

Platform BackupDbSupervisor

Synchronizes MainDb and BackupDb by copying the data that’s available on the device, but not in the MainDb and vice versa.

Platform CargoDbSupervisor

Copies data from the Cargo room. If there’s some data on the device, it copies it to the main drive. Otherwise, it copies data from the only room on main drive. If the room doesn’t exist yet, or if there are multiple rooms, it skips copying data.

Logic is responsible for deciding which room is for Cargo, then starts Copier and Stopper under CargoDynamicSupervisor.

Platform OnlinersSyncSupervisor

Backs data up for the online users. If there’s some data data on the device, it restores it, but again only for the online users. Accomplishes this by sending a request for the keys to each online users’ LiveView process. After receiving keys for all online users and their rooms, it gathers the content on the device belonging to them and copies it from the device, then gathers the content in the MainDb and copies it to the device.

Logic is responsible for sending and receiving PubSub requests, getting the keys for the content that needs to be copied both from and to BackupDb, and starting Copier and Stopper under OnlinersDynamicSupervisor.