It's currently impossible to wait until all SQLite write finish to disk.
This is not guaranteed when closing the ent DB client.
The existing code to move the cache handles the case where the
new location is on a new drive. However, due to the above issue this can
now lead to database corruption.
To avoid database corruption we now use the `os.Rename` function and
prevent moving the cache between drives until a better solution can be
implemented.
Deleting the file isn't enough because it's still held in memory
and is written back to disk on the next write (SetLastVersion during
bridge teardown).
This change implements safe.Mutex and safe.RWMutex, which wrap the
sync.Mutex and sync.RWMutex types and are assigned a globally unique
integer ID. The safe.Lock and safe.RLock methods sort the mutexes
by this integer ID before locking to ensure that locks for a given
set of mutexes are always performed in the same order, avoiding
deadlocks.
Depending on the timing of bridge closure, it was possible for the
IMAP/SMTP servers to not have started serving yet. By grouping this in
a cancelable goroutine group (*xsync.Group), we mitigate this issue.
Further, depending on internet disconnection timing during user login,
it was possible for a user to be improperly logged in. This change
fixes this and adds test coverage for it.
Lastly, depending on timing, certain background tasks (updates check,
connectivity ping) could be improperly started or closed. This change
groups them in the *xsync.Group as well to be closed properly.