Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
4a7fb5c
feat(json-crdt-patch): 🎸 change JSON CRDT Patch ID encoding semantics
streamich Nov 3, 2023
e0b0570
refactor(json-crdt): 💡 rename /const to /con folder
streamich Nov 5, 2023
ca00441
refactor(json-crdt): 💡 rename Const to ConNode
streamich Nov 5, 2023
e0bc392
chore(json-crdt): 🤖 remove "con" from .toString() output
streamich Nov 5, 2023
823ee4a
refactor(json-crdt): 💡 renmae Const.ts to ConNode.ts
streamich Nov 5, 2023
bdd6d3d
style: 💄 run Prettier
streamich Nov 5, 2023
3e36d7e
refactor(json-crdt): 💡 rename ConstApi to ConApi
streamich Nov 5, 2023
7256b0f
refactor(json-crdt): 💡 rename /types folder to /nodes
streamich Nov 5, 2023
caf2051
refactor(json-crdt): 💡 rename /lww-value to /val
streamich Nov 5, 2023
4609c53
refactor(json-crdt): 💡 rename ValueLww class to ValNode
streamich Nov 5, 2023
56636c8
refactor(json-crdt): 💡 rename ValueLww.ts to ValNode.ts
streamich Nov 5, 2023
b088c3b
style: 💄 run Prettier
streamich Nov 5, 2023
8da26cc
refactor(json-crdt): 💡 rename ValueApi class to ValApi
streamich Nov 5, 2023
93278ee
refactor(json-crdt): 💡 rename /lww-array folder to /vec
streamich Nov 5, 2023
ad893ee
refactor(json-crdt): 💡 rename ValueLww to VecNode
streamich Nov 5, 2023
06c56b8
refactor(json-crdt): 💡 rename VectorApi class to VecApi
streamich Nov 5, 2023
a76f373
refactor(json-crdt): 💡 rename /lww-object folder to /obj
streamich Nov 5, 2023
a40126f
refactor(json-crdt): 💡 rename ObjectLww to ObjNode
streamich Nov 5, 2023
da71284
refactor(json-crdt): 💡 rename ObjectApi to ObjApi
streamich Nov 5, 2023
2186b01
refactor(json-crdt): 💡 rename /rga-string folder to /str
streamich Nov 5, 2023
302dfa2
refactor(json-crdt): 💡 rename StringRga class to StrNode
streamich Nov 5, 2023
81c2502
refactor(json-crdt): 💡 rename StringApi class to StrApi
streamich Nov 5, 2023
a9f5f96
chore(json-crdt): 🤖 rename StringApi to StrApi in comments
streamich Nov 5, 2023
42efb57
refactor(json-crdt): 💡 rename BinaryRga class to BinNode
streamich Nov 5, 2023
1a33af8
refactor(json-crdt): 💡 rename BinaryApi class to BinApi
streamich Nov 5, 2023
a8e1a4f
refactor(json-crdt): 💡 rename ArrayRga class to ArrNode
streamich Nov 5, 2023
c1862f1
refactor(json-crdt): 💡 rename ArrayApi class to ArrApi
streamich Nov 5, 2023
35b5ede
refactor(json-crdt): 💡 rename RootLww class to RootNode
streamich Nov 5, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/json-crdt-patch/codec/binary/Decoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ export class Decoder extends CborDecoder<CrdtReader> {

protected decodeId(): ITimestampStruct {
const reader = this.reader;
const [isRelativeTime, x] = reader.b1vu56();
return isRelativeTime ? new Timestamp(this.patchSid!, x) : new Timestamp(x, reader.vu57());
const [isSessionDifferent, x] = reader.b1vu56();
return isSessionDifferent ? new Timestamp(reader.vu57(), x) : new Timestamp(this.patchSid!, x);
}

protected decodeTss(): ITimespanStruct {
Expand Down
6 changes: 3 additions & 3 deletions src/json-crdt-patch/codec/binary/Encoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,10 @@ export class Encoder extends CborEncoder<CrdtWriter> {
const time = id.time;
const writer = this.writer;
if (sessionId === this.patchSid) {
writer.b1vu56(1, time);
writer.b1vu56(0, time);
} else {
writer.b1vu56(0, sessionId);
writer.vu57(time);
writer.b1vu56(1, time);
writer.vu57(sessionId);
}
}

Expand Down
24 changes: 12 additions & 12 deletions src/json-crdt/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,35 +13,35 @@ and random positions of a 10,000-character newly created string.

```
node benchmarks/json-crdt/strings-short.js
json-crdt StringRga type x 228,880 ops/sec ±0.07% (99 runs sampled)
json-crdt StrNode type x 228,880 ops/sec ±0.07% (99 runs sampled)
json-crdt x 187,700 ops/sec ±0.17% (98 runs sampled)
Y.js x 18,288 ops/sec ±0.19% (100 runs sampled)
Automerge x 23.64 ops/sec ±1.54% (44 runs sampled)
Fastest is json-crdt StringRga type
Fastest is json-crdt StrNode type
```

Inserting one 10-char string and deleting one 10-char string range at random
positions from a 10,000-char string, which was beforehand already edited 5,000 times.

```
node benchmarks/json-crdt/strings-long.js
json-crdt StringRga type x 54,250 ops/sec ±20.68% (23 runs sampled)
json-crdt StrNode type x 54,250 ops/sec ±20.68% (23 runs sampled)
json-crdt x 59,628 ops/sec ±14.39% (32 runs sampled)
Y.js x 16,358 ops/sec ±10.79% (45 runs sampled)
Automerge x 1,777 ops/sec ±5.97% (76 runs sampled)
Fastest is json-crdt,json-crdt StringRga type
Fastest is json-crdt,json-crdt StrNode type
```

Editing a string at 10 repeating positions with +/- 6 characters random variance
from those positions.

```
node benchmarks/json-crdt/strings-repeat-insert-positions.js
json-crdt StringRga type x 8,313 ops/sec ±1.52% (93 runs sampled)
json-crdt StrNode type x 8,313 ops/sec ±1.52% (93 runs sampled)
json-crdt x 6,292 ops/sec ±2.22% (77 runs sampled)
Y.js x 3,104 ops/sec ±1.40% (78 runs sampled)
Automerge x 246 ops/sec ±1.04% (85 runs sampled)
Fastest is json-crdt StringRga type
Fastest is json-crdt StrNode type
```

### Real-world comparisons
Expand Down Expand Up @@ -114,22 +114,22 @@ String length: 104852 , Chunk count: 12487
JSON CRDT: 134.596ms
String length: 104852 , Chunk count: 12487
---------------------------------------------
JSON CRDT StringRga: 85.254ms
JSON CRDT StrNode: 85.254ms
String length: 104852 , Chunk count: 12387
---------------------------------------------
JSON CRDT StringRga: 86.487ms
JSON CRDT StrNode: 86.487ms
String length: 104852 , Chunk count: 12387
---------------------------------------------
JSON CRDT StringRga: 73.346ms
JSON CRDT StrNode: 73.346ms
String length: 104852 , Chunk count: 12387
---------------------------------------------
JSON CRDT StringRga: 74.109ms
JSON CRDT StrNode: 74.109ms
String length: 104852 , Chunk count: 12387
---------------------------------------------
JSON CRDT StringRga: 73.593ms
JSON CRDT StrNode: 73.593ms
String length: 104852 , Chunk count: 12387
---------------------------------------------
JSON CRDT StringRga: 74.138ms
JSON CRDT StrNode: 74.138ms
String length: 104852 , Chunk count: 12387
---------------------------------------------
diamond-types-node: 58.114ms
Expand Down
2 changes: 1 addition & 1 deletion src/json-crdt/__bench__/bench.traces.crdt-libs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ runTraceMatrix({
'automerge-paper',
],
editors: [
'StringRga (json-joy)',
'StrNode (json-joy)',
'json-joy',
// 'Y.js',
// 'Y.rs',
Expand Down
2 changes: 1 addition & 1 deletion src/json-crdt/__bench__/bench.traces.non-crdt-libs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ runTraceMatrix({
'automerge-paper',
],
editors: [
'StringRga (json-joy)',
'StrNode (json-joy)',
'diamond-types-node',
'rope.js',
'V8 strings',
Expand Down
22 changes: 11 additions & 11 deletions src/json-crdt/__bench__/profiler/automerge-paper.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@
*/

const {traces} = require('../../data/editing-traces');
const {StringRga} = require('../../../es2020/json-crdt/types/rga-string/StringRga');
const {StrNode} = require('../../../es2020/json-crdt/types/str/StrNode');
const {ts} = require('../../../es2020/json-crdt-patch/clock/logical');

const patches = traces.get('automerge-paper').txns.map((txn) => txn.patches[0]);
const length = patches.length;
console.log('Document operations:', length, patches);

const runStringRga = () => {
const runStrNode = () => {
console.log('---------------------------------------------');
console.time('JSON CRDT StringRga');
console.time('JSON CRDT StrNode');
let time = 0;
const rga = new StringRga(ts(1, time++));
const rga = new StrNode(ts(1, time++));
for (let i = 0; i < length; i++) {
const [pos, del, c] = patches[i];
if (del) {
Expand All @@ -27,14 +27,14 @@ const runStringRga = () => {
}
rga.view();
// console.log(rga.view());
console.timeEnd('JSON CRDT StringRga');
console.timeEnd('JSON CRDT StrNode');
console.log('String length:', rga.length(), ', Chunk count:', rga.size());
// console.log(rga.toString());
};

runStringRga();
runStringRga();
runStringRga();
runStringRga();
runStringRga();
runStringRga();
runStrNode();
runStrNode();
runStrNode();
runStrNode();
runStrNode();
runStrNode();
12 changes: 6 additions & 6 deletions src/json-crdt/__bench__/strings-long.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const Benchmark = require('benchmark');
const {Model} = require('../../es2020/json-crdt');
const {StringRga} = require('../../es2020/json-crdt/types/rga-string/StringRga');
const {StrNode} = require('../../es2020/json-crdt/types/str/StrNode');
const Y = require('yjs');
const Automerge = require('automerge');
const {randomU32} = require('hyperdyperid/lib/randomU32');
Expand All @@ -14,10 +14,10 @@ const len2 = str2.length;

const operations = 1;

const type = new StringRga(ts(1, 1));
const type = new StrNode(ts(1, 1));
type.ins(ts(1, 1), ts(1, 2), str1);
let time = str1.length + 100;
const editStringRga = () => {
const editStrNode = () => {
for (let i = 0; i < operations; i++) {
const pos1 = randomU32(0, len1 - len2);
const pos2 = randomU32(0, len1 - len2);
Expand Down Expand Up @@ -70,7 +70,7 @@ const editAutomerge = () => {
};

for (let i = 0; i < 5000; i++) {
editStringRga();
editStrNode();
editJsonCrdt();
editYjs();
editAutomerge();
Expand All @@ -79,8 +79,8 @@ for (let i = 0; i < 5000; i++) {
const suite = new Benchmark.Suite();

suite
.add('json-crdt StringRga type', function () {
editStringRga();
.add('json-crdt StrNode type', function () {
editStrNode();
})
.add('json-crdt', function () {
editJsonCrdt();
Expand Down
12 changes: 6 additions & 6 deletions src/json-crdt/__bench__/strings-repeat-insert-positions.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const Benchmark = require('benchmark');
const {Model} = require('../../es2020/json-crdt');
const {StringRga} = require('../../es2020/json-crdt/types/rga-string/StringRga');
const {StrNode} = require('../../es2020/json-crdt/types/str/StrNode');
const Y = require('yjs');
const Automerge = require('automerge');
const {randomU32} = require('hyperdyperid/lib/randomU32');
Expand All @@ -15,10 +15,10 @@ const str2 = '1234567890';
const len1 = str1.length;
const len2 = str2.length;

const type = new StringRga(ts(1, 1));
const type = new StrNode(ts(1, 1));
type.ins(ts(1, 1), ts(1, 2), str1);
let time = str1.length + 100;
const editStringRga = () => {
const editStrNode = () => {
for (let i = 0; i < insertPositions.length; i++) {
const pos1 = insertPositions[i] + randomU32(0, variance);
const pos2 = randomU32(0, len1 - len2);
Expand Down Expand Up @@ -71,7 +71,7 @@ const editAutomerge = () => {
};

for (let i = 0; i < 1000; i++) {
editStringRga();
editStrNode();
editJsonCrdt();
editYjs();
editAutomerge();
Expand All @@ -80,8 +80,8 @@ for (let i = 0; i < 1000; i++) {
const suite = new Benchmark.Suite();

suite
.add('json-crdt StringRga type', function () {
editStringRga();
.add('json-crdt StrNode type', function () {
editStrNode();
})
.add('json-crdt', function () {
editJsonCrdt();
Expand Down
12 changes: 6 additions & 6 deletions src/json-crdt/__bench__/strings-short.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const Benchmark = require('benchmark');
const {Model} = require('../../es2020/json-crdt');
const {StringRga} = require('../../es2020/json-crdt/types/rga-string/StringRga');
const {StrNode} = require('../../es2020/json-crdt/types/str/StrNode');
const Y = require('yjs');
const Automerge = require('automerge');
const {randomU32} = require('hyperdyperid/lib/randomU32');
Expand All @@ -14,8 +14,8 @@ const str2 = '1234567890';
const len1 = str1.length;
const len2 = str2.length;

const editStringRga = () => {
const type = new StringRga(ts(1, 1));
const editStrNode = () => {
const type = new StrNode(ts(1, 1));
type.ins(ts(1, 1), ts(1, 2), str1);
let time = str1.length + 100;
for (let i = 0; i < 10; i++) {
Expand Down Expand Up @@ -71,7 +71,7 @@ const editAutomerge = () => {
};

for (let i = 0; i < 10; i++) {
editStringRga();
editStrNode();
editJsonCrdt();
editYjs();
editAutomerge();
Expand All @@ -86,8 +86,8 @@ suite
// arr.splice(pos1, {i: null, r: null, p: null, content: {}, deleted: false, id: [1 ,2]}, {i: null, r: null, p: null, content: {}, deleted: false, id: [1 ,2]});
// arr.splice(pos2, 2);
// })
.add('json-crdt StringRga type', function () {
editStringRga();
.add('json-crdt StrNode type', function () {
editStrNode();
})
.add('json-crdt', function () {
editJsonCrdt();
Expand Down
8 changes: 4 additions & 4 deletions src/json-crdt/__bench__/util/editors.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Timestamp} from '../../../json-crdt-patch/clock';
import {StringRga} from '../../types/rga-string/StringRga';
import {StrNode} from '../../nodes';
import {Model} from '../../model';
import {Doc} from 'diamond-types-node';
import * as Y from 'yjs';
Expand All @@ -11,11 +11,11 @@ const AutomergeUnstable = require('@automerge/automerge/dist/cjs/unstable');
const Rope = require('rope.js');

export const editors = {
'StringRga (json-joy)': {
name: 'StringRga (json-joy)',
'StrNode (json-joy)': {
name: 'StrNode (json-joy)',
factory: () => {
let time = 0;
const rga = new StringRga(new Timestamp(1, time++));
const rga = new StrNode(new Timestamp(1, time++));
return {
ins: (pos: number, insert: string) => {
rga.insAt(pos, new Timestamp(1, time), insert);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@
/**
* Run this demo with:
*
* npx nodemon -q -x ts-node src/json-crdt/__demos__/StringRga-hello-world.ts
* npx nodemon -q -x ts-node src/json-crdt/__demos__/StrNode-hello-world.ts
*/

import {ts} from '../../json-crdt-patch/clock';
import {StringRga} from '../types/rga-string/StringRga';
import {StrNode} from '../nodes';

const sid = 123; // Site ID
let time = 0; // "time"

const id = ts(sid, time++);
const str = new StringRga(id);
const str = new StrNode(id);

console.log(str.view());
console.log(str + '');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
/**
* Run this demo with:
*
* npx nodemon -q -x ts-node src/json-crdt/__demos__/StringRga-json-joy.ts
* npx nodemon -q -x ts-node src/json-crdt/__demos__/StrNode-json-joy.ts
*/

import {ts} from '../../json-crdt-patch/clock';
import {StringRga} from '../types/rga-string/StringRga';
import {StrNode} from '../nodes';

const user1 = 123;
const user2 = 345;
Expand All @@ -16,31 +16,31 @@ const user3 = 789;
console.log();

// User 1 creates a new string
const str1 = new StringRga(ts(user1, 0));
const str1 = new StrNode(ts(user1, 0));
str1.insAt(0, ts(user1, 1), 'js');

// User 2 and 3 insert their changes at the same time "ts(user1, 2)"
str1.ins(ts(user1, 2), ts(user2, 3), ' joy');
str1.ins(ts(user1, 2), ts(user3, 3), 'on');

console.log(str1 + '');
// StringRga 123.0 { "json joy" }
// └─ StringChunk 789.3!2 len:8 { "on" }
// ← StringChunk 123.1!2 len:2 { "js" }
// → StringChunk 345.3!4 len:4 { " joy" }
// StrNode 123.0 { "json joy" }
// └─ StrChunk 789.3!2 len:8 { "on" }
// ← StrChunk 123.1!2 len:2 { "js" }
// → StrChunk 345.3!4 len:4 { " joy" }

console.log();

// User 1 creates a new string "js"
const str2 = new StringRga(ts(user1, 0));
const str2 = new StrNode(ts(user1, 0));
str2.insAt(0, ts(user1, 1), 'js');

// User 2 and 3 insert their changes at the same time "ts(user1, 2)"
str2.ins(ts(user1, 2), ts(user3, 3), 'on');
str2.ins(ts(user1, 2), ts(user2, 3), ' joy');

console.log(str2 + '');
// StringRga 123.0 { "json joy" }
// └─ StringChunk 345.3!4 len:8 { " joy" }
// ← StringChunk 789.3!2 len:4 { "on" }
// ← StringChunk 123.1!2 len:2 { "js" }
// StrNode 123.0 { "json joy" }
// └─ StrChunk 345.3!4 len:8 { " joy" }
// ← StrChunk 789.3!2 len:4 { "on" }
// ← StrChunk 123.1!2 len:2 { "js" }
Loading