title | target-version |
---|---|
document-editing |
0.3.0 |
This document covers document editing executed in the SDK.
Document Editing is a mechanism to modify the document. It consists of two parts, Local and Remote. We will provide a simple document editing example in the SDK to show how it works.
The purpose of this document is to help new SDK contributors to understand the SDK's editing behavior.
This document does not describe algorithms such as CRDTs or logical clocks.
First, we briefly describe Client
and Document
and then explain what happens inside the Client and Document when editing a document.
A high-level overview of Yorkie is as follows:
A description of the main components is as follows:
SDK
consists ofClient
andDocument
.Client
: AClient
is a normal client that can communicate withServer
. Changes on aDocument
can be synchronized by using aClient
.Document
: A Document is a CRDT-based data type through which the model of the application is represented.Server
: AServer
receives changes fromClient
s, stores them in the DB, and propagates them toClient
s who subscribe toDocument
s.
Next, we will look at how Client
and Document
described in Overview work when editing a Document
.
Editing in Yorkie can be divided into Local Editing and Remote Editing.
Local Editing occurs on the machine where it is running. Conversely, Remote Editing occurs on another machine that is editing the Document
.
Local Editing is started by calling the Document.Update
. Document.Update
is usually called whenever edit occurs in the external editor.
The figure above explains Document in more detail. Three internal components are in the Document.
Root
represents the real document (SOT, source of truth). It keeps consistency for both synchronous and asynchronous changes.Clone
represents a JSON proxy object of the document. It createsChange
when the document is edited through the external editor.LocalChanges
is a buffer for localChange
. It keeps all the changes until the client sends them to the server.
Local Editing consists of three logic parts.
- Calling
Document.Update
. - Pushing Changes to Server.
- Propagating Changes to Peers.
Let's take a closer look at the logics.
This logic is executed with 3 sub-logics.
- 1-1. When
Document.Update
is called, the proxy applies the user's edits to theClone
and creates aChange
for it. - 1-2. Changes are applied to
Root
. TheRoot
can be only updated by changes.- To implement transaction processing, user's edits are first applied to the
Clone
instead of theRoot
. If applying to the clone fails, the changes won't be reflected in the root.
- To implement transaction processing, user's edits are first applied to the
- 1-3. Those changes are added to
LocalChanges
. It is used later to send local changes to the server.- Changes are first applied locally and then later reflected on the remote. Refer to the local-first software for more information.
Here's a real code example:
// Go SDK
doc.Update(func(root *json.Object) {
root.SetString("foo", "bar")
})
fmt.Println(doc.Marshal()) // {"foo": "bar"}
The updater function, the first argument of Document.Update
, provides the root
as the first argument. The external editor can use methods in root
to edit the Document. Whenever editing occurs, clone
, acting as a proxy, creates changes and push them to LocalChanges
. These logics work synchronously.
This logic is executed with 2 sub-logics.
- 2-1.
Client
checksLocalChanges
ofDocument
at specific intervals. - 2-2. If there are changes in
LocalChanges
,Client
sends them to theServer
.
If LocalChanges
has changes that need to be synchronized with other peers, it collects them and sends them to the server. These logics work asynchronously.
The Server
receives the changes from the Client
and then stores the changes and propagates them to other Client
s that are subscribing the Document
.
Remote Editing starts when the server responds the changes to the client at the last part of Local Editing.
The Client
who received the changes applies them to the Root
inside the Document
. Externally subscribed handlers through Document.Subscribe
are called if exists, receiving ChangeEvents
as an argument. These logics work synchronously.
// JS SDK
doc.subscribe((event) => {
console.log(event.type);
});
For more details: Subscribing to Document events
Proxy can vary by language or environment. For example, in JS SDK, the Proxy is implemented as JavaScript Proxy, but in the Go SDK, it is just a struct. This is to provide users with an interface that suits the characteristics of the language or environment. If we find a better way later, Proxy component is likely to be changed to other interfaces.