Merge branch 'main' into issue90

This commit is contained in:
Dustin J. Mitchell 2021-12-26 19:04:10 -05:00 committed by GitHub
commit 829f67ee02
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 1348 additions and 476 deletions

View file

@ -10,6 +10,7 @@
* [Dates and Durations](./time.md)
* [Configuration](./config-file.md)
* [Environment](./environment.md)
* [Undo](./undo.md)
* [Synchronization](./task-sync.md)
* [Running the Sync Server](./running-sync-server.md)
- [Internal Details](./internals.md)

View file

@ -21,21 +21,63 @@ See [Tasks](./tasks.md) for details on the content of that map.
Every change to the task database is captured as an operation.
In other words, operations act as deltas between database states.
Operations are crucial to synchronization of replicas, using a technique known as Operational Transforms.
Operations are crucial to synchronization of replicas, described in [Synchronization Model](./sync-model.md).
Operations are entirely managed by the replica, and some combinations of operations are described as "invalid" here.
A replica must not create invalid operations, but should be resilient to receiving invalid operations during a synchronization operation.
Each operation has one of the forms
* `Create(uuid)`
* `Delete(uuid)`
* `Update(uuid, property, value, timestamp)`
* `Delete(uuid, oldTask)`
* `Update(uuid, property, oldValue, newValue, timestamp)`
* `UndoPoint()`
The Create form creates a new task.
It is invalid to create a task that already exists.
Similarly, the Delete form deletes an existing task.
It is invalid to delete a task that does not exist.
The `oldTask` property contains the task data from before it was deleted.
The Update form updates the given property of the given task, where property and value are both strings.
Value can also be `None` to indicate deletion of a property.
The Update form updates the given property of the given task, where the property and values are strings.
The `oldValue` gives the old value of the property (or None to create a new property), while `newValue` gives the new value (or None to delete a property).
It is invalid to update a task that does not exist.
The timestamp on updates serves as additional metadata and is used to resolve conflicts.
### Application
Each operation can be "applied" to a task database in a natural way:
* Applying `Create` creates a new, empty task in the task database.
* Applying `Delete` deletes a task, including all of its properties, from the task database.
* Applying `Update` modifies the properties of a task.
* Applying `UndoPoint` does nothing.
### Undo
Each operation also contains enough information to reverse its application:
* Undoing `Create` deletes a task.
* Undoing `Delete` creates a task, including all of the properties in `oldTask`.
* Undoing `Update` modifies the properties of a task, reverting to `oldValue`.
* Undoing `UndoPoint` does nothing.
The `UndoPoint` operation serves as a marker of points in the operation sequence to which the user might wish to undo.
For example, creation of a new task with several properities involves several operations, but is a single step from the user's perspective.
An "undo" command reverses operations, removing them from the operations sequence, until it reaches an `UndoPoint` operation.
### Synchronizing Operations
After operations are synchronized to the server, they can no longer be undone.
As such, the [synchronization model](./sync-model.md) uses simpler operations.
Replica operations are converted to sync operations as follows:
* `Create(uuid)` -> `Create(uuid)` (no change)
* `Delete(uuid, oldTask)` -> `Delete(uuid)`
* `Update(uuid, property, oldValue, newValue, timestamp)` -> `Update(uuid, property, newValue, timestamp)`
* `UndoPoint()` -> Ø (dropped from operation sequence)
Once a sequence of operations has been synchronized, there is no need to store those operations on the replica.
The current implementation deletes operations at that time.
An alternative approach is to keep operations for existing tasks, and provide access to those operations as a "history" of modifications to the task.

View file

@ -34,6 +34,16 @@ Since the replicas are not connected, each may have additional operations that h
The synchronization process uses operational transformation to "linearize" those operations.
This process is analogous (vaguely) to rebasing a sequence of Git commits.
### Sync Operations
The [Replica Storage](./storage.md) model contains additional information in its operations that is not included in operations synchronized to other replicas.
In this document, we will be discussing "sync operations" of the form
* `Create(uuid)`
* `Delete(uuid)`
* `Update(uuid, property, value, timestamp)`
### Versions
Occasionally, database states are given a name (that takes the form of a UUID).

7
docs/src/undo.md Normal file
View file

@ -0,0 +1,7 @@
# Undo
It's easy to make a mistake: mark the wrong task as done, or hit enter before noticing a typo in a tag name.
The `ta undo` command makes it just as easy to fix the mistake, by effectively reversing the most recent change.
Multiple invocations of `ta undo` can be used to undo multiple changes.
The limit of this functionality is that changes which have been synchronized to the server (via `ta sync`) cannot be undone.