Skip to content

Commit 7f61e90

Browse files
authored
Merge pull request #4 from loro-dev/docs-version
docs: refine docs about version and syncing
2 parents 1152cf5 + 9797fee commit 7f61e90

File tree

6 files changed

+115
-5
lines changed

6 files changed

+115
-5
lines changed

pages/docs/advanced/doc_state_and_oplog.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,41 @@ state, the version of DocState and the latest version recorded in OpLog may not
3636
always match. When they align, it is in an _attached_ state; otherwise, it's in
3737
a _detached_ state.
3838

39+
```ts
40+
const doc = new LoroDoc();
41+
doc.setPeerId(1);
42+
doc.getText("text").insert(0, "Hello");
43+
const doc2 = doc.fork(); // create a fork of the doc
44+
console.log(doc.version().toJSON());
45+
// Map(1) { "1" => 5 }
46+
console.log(doc.oplogVersion().toJSON());
47+
// Map(1) { "1" => 5 }
48+
49+
doc.checkout([{ peer: "1", counter: 1 }]);
50+
console.log(doc.version().toJSON());
51+
// Map(1) { "1" => 2 }
52+
console.log(doc.oplogVersion().toJSON());
53+
// Map(1) { "1" => 5 }
54+
55+
doc2.setPeerId(2);
56+
doc2.getText("text").insert(5, "!");
57+
doc.import(doc2.export({ mode: "update" }));
58+
console.log(doc.version().toJSON());
59+
// Map(1) { "1" => 2 }
60+
console.log(doc.oplogVersion().toJSON());
61+
// Map(2) { "1" => 5, "2" => 1 }
62+
63+
console.log(doc.isDetached()); // true
64+
doc.attach();
65+
console.log(doc.version().toJSON());
66+
// Map(2) { "1" => 5, "2" => 1 }
67+
console.log(doc.oplogVersion().toJSON());
68+
// Map(2) { "1" => 5, "2" => 1 }
69+
70+
```
71+
72+
![DocState and OpLog Detached Example](./images/version-4.png)
73+
3974
The doc cannot be edited in the detached mode. Users must use `attach()` to
4075
return to the latest version to continue editing.
4176

228 KB
Loading

pages/docs/tutorial/_meta.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"get_started": "Getting Started",
33
"loro_doc": "Loro Document",
4+
"sync": "Sync",
45
"text": "Text",
56
"composition": "Composing CRDTs",
67
"list": "List and Movable List",

pages/docs/tutorial/get_started.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ listB.delete(1, 1);
304304
// `version` is the version vector of another document
305305
const missingOps = docB.export({
306306
mode: "update",
307-
from: docA.version(),
307+
from: docA.oplogVersion(),
308308
});
309309
docA.import(missingOps);
310310

pages/docs/tutorial/sync.md

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
## Sync
2+
3+
Two documents with concurrent edits can be synchronized by just two message
4+
exchanges.
5+
6+
Below is an example of synchronization between two documents:
7+
8+
```ts
9+
const docA = new LoroDoc();
10+
const docB = new LoroDoc();
11+
const listA: LoroList = docA.getList("list");
12+
listA.insert(0, "A");
13+
listA.insert(1, "B");
14+
listA.insert(2, "C");
15+
// B import the ops from A
16+
const data: Uint8Array = docA.export({ mode: "update" });
17+
// The data can be sent to B through the network
18+
docB.import(data);
19+
expect(docB.toJSON()).toStrictEqual({
20+
list: ["A", "B", "C"],
21+
});
22+
23+
const listB: LoroList = docB.getList("list");
24+
listB.delete(1, 1);
25+
26+
// `doc.export({mode: "update", from: version})` can encode all the ops from the version to the latest version
27+
// `version` is the version vector of another document
28+
const missingOps = docB.export({
29+
mode: "update",
30+
from: docA.oplogVersion(),
31+
});
32+
docA.import(missingOps);
33+
34+
expect(docA.toJSON()).toStrictEqual({
35+
list: ["A", "C"],
36+
});
37+
expect(docA.toJSON()).toStrictEqual(docB.toJSON());
38+
```
39+
40+
## Real-time Collaboration
41+
42+
Due to CRDT properties, document consistency is guaranteed when peers receive the same updates, regardless of order or duplicates.
43+
44+
- First Sync: Initial synchronization between peers (done in the example above)
45+
- Real-time Sync (shown in the example below):
46+
- Subscribe to local updates
47+
- Broadcast updates directly to all the other peers
48+
- No need for version comparison
49+
- As long as updates reach all peers, consistency is maintained
50+
51+
Example:
52+
53+
```ts
54+
const docA = new LoroDoc();
55+
const docB = new LoroDoc();
56+
// Assume docA and docB finished the first sync
57+
58+
docA.subscribeLocalUpdates((update) => {
59+
// simulate sending update to docB
60+
docB.import(update);
61+
});
62+
63+
docB.subscribeLocalUpdates((update) => {
64+
// simulate sending update to docA
65+
docA.import(update);
66+
});
67+
68+
docA.getText("text").insert(0, "Hello");
69+
docA.commit();
70+
await Promise.resolve(); // await the event to be emitted
71+
console.log(docB.toJSON());
72+
// { text: "Hello" }
73+
```

pages/docs/tutorial/time_travel.mdx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ over time.
2727
Before this example will work, it is important that the edits made to the document
2828
have had [timestamp storage](/docs/advanced/timestamp) enabled:
2929

30-
```ts
30+
```ts no_run
3131
doc.setRecordTimestamp(true);
3232
```
3333

@@ -40,7 +40,8 @@ intuition.
4040
The first step is to load our document. Here we assume that you have a snapshot from your database
4141
or API.
4242

43-
```ts
43+
```ts no_run
44+
4445
// Get the snapshot for your doc from your database / API
4546
let snapshot = fetchSnapshot();
4647

@@ -52,7 +53,7 @@ doc.import(snapshot);
5253
Next we must collect and sort the timestamps for every change in the document. We want uesrs to be
5354
able to drag a slider to select a timestamp out of this list.
5455

55-
```ts
56+
```ts no_run
5657
// Collect all changes from the document
5758
const changes = doc.getAllChanges();
5859

@@ -113,7 +114,7 @@ const getFrontiersForTimestamp = (
113114
Finally, all we can get the index from our slider, get the timestamp from our list, and then
114115
checkout the calculated frontiers.
115116

116-
```ts
117+
```ts no_run
117118
let sliderIdx = 3;
118119
const timestamp = timestamps[sliderIdx - 1];
119120
const frontiers = getFrontiersForTimestamp(changes, timestamp);

0 commit comments

Comments
 (0)