braid-text 0.0.28 → 0.0.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +67 -25
- package/package.json +1 -1
- package/test.js +37 -21
package/index.js
CHANGED
|
@@ -4,7 +4,9 @@ let braidify = require("braid-http").http_server
|
|
|
4
4
|
let fs = require("fs")
|
|
5
5
|
|
|
6
6
|
let braid_text = {
|
|
7
|
+
verbose: false,
|
|
7
8
|
db_folder: './braid-text-db',
|
|
9
|
+
length_cache_size: 10,
|
|
8
10
|
cache: {}
|
|
9
11
|
}
|
|
10
12
|
|
|
@@ -126,7 +128,7 @@ braid_text.serve = async (req, res, options = {}) => {
|
|
|
126
128
|
}
|
|
127
129
|
|
|
128
130
|
waiting_puts++
|
|
129
|
-
console.log(`waiting_puts(after++) = ${waiting_puts}`)
|
|
131
|
+
if (braid_text.verbose) console.log(`waiting_puts(after++) = ${waiting_puts}`)
|
|
130
132
|
|
|
131
133
|
let my_prev_put_p = prev_put_p
|
|
132
134
|
let done_my_turn = null
|
|
@@ -134,7 +136,7 @@ braid_text.serve = async (req, res, options = {}) => {
|
|
|
134
136
|
(done) =>
|
|
135
137
|
(done_my_turn = (statusCode, x) => {
|
|
136
138
|
waiting_puts--
|
|
137
|
-
console.log(`waiting_puts(after--) = ${waiting_puts}`)
|
|
139
|
+
if (braid_text.verbose) console.log(`waiting_puts(after--) = ${waiting_puts}`)
|
|
138
140
|
my_end(statusCode, x)
|
|
139
141
|
done()
|
|
140
142
|
})
|
|
@@ -240,7 +242,7 @@ braid_text.get = async (key, options) => {
|
|
|
240
242
|
let updates = null
|
|
241
243
|
|
|
242
244
|
if (resource.need_defrag) {
|
|
243
|
-
console.log(`doing defrag..`)
|
|
245
|
+
if (braid_text.verbose) console.log(`doing defrag..`)
|
|
244
246
|
resource.need_defrag = false
|
|
245
247
|
resource.doc = defrag_dt(resource.doc)
|
|
246
248
|
}
|
|
@@ -301,10 +303,10 @@ braid_text.put = async (key, options) => {
|
|
|
301
303
|
let parents = resource.doc.getRemoteVersion().map((x) => x.join("-")).sort()
|
|
302
304
|
let og_parents = options_parents || parents
|
|
303
305
|
|
|
304
|
-
let max_pos =
|
|
305
|
-
resource.doc.
|
|
306
|
-
|
|
307
|
-
|
|
306
|
+
let max_pos = resource.length_cache.get('' + og_parents) ??
|
|
307
|
+
(v_eq(parents, og_parents) ? resource.doc.len() :
|
|
308
|
+
dt_get(resource.doc, og_parents).len())
|
|
309
|
+
|
|
308
310
|
if (body != null) {
|
|
309
311
|
patches = [{
|
|
310
312
|
unit: 'text',
|
|
@@ -400,6 +402,10 @@ braid_text.put = async (key, options) => {
|
|
|
400
402
|
}
|
|
401
403
|
resource.actor_seqs[v[0]] = v[1]
|
|
402
404
|
|
|
405
|
+
resource.length_cache.put(`${v[0]}-${v[1]}`, patches.reduce((a, b) =>
|
|
406
|
+
a + (b.content.length ? b.content.length : -(b.range[1] - b.range[0])),
|
|
407
|
+
max_pos))
|
|
408
|
+
|
|
403
409
|
v = `${v[0]}-${v[1] + 1 - change_count}`
|
|
404
410
|
|
|
405
411
|
let ps = og_parents
|
|
@@ -435,7 +441,7 @@ braid_text.put = async (key, options) => {
|
|
|
435
441
|
|
|
436
442
|
if (options.merge_type != "dt") {
|
|
437
443
|
patches = get_xf_patches(resource.doc, v_before)
|
|
438
|
-
console.log(JSON.stringify({ patches }))
|
|
444
|
+
if (braid_text.verbose) console.log(JSON.stringify({ patches }))
|
|
439
445
|
|
|
440
446
|
let version = resource.doc.getRemoteVersion().map((x) => x.join("-")).sort()
|
|
441
447
|
|
|
@@ -451,11 +457,11 @@ braid_text.put = async (key, options) => {
|
|
|
451
457
|
let x = { version }
|
|
452
458
|
x.parents = client.my_last_seen_version
|
|
453
459
|
|
|
454
|
-
console.log("rebasing after timeout.. ")
|
|
455
|
-
console.log(" client.my_unused_version_count = " + client.my_unused_version_count)
|
|
460
|
+
if (braid_text.verbose) console.log("rebasing after timeout.. ")
|
|
461
|
+
if (braid_text.verbose) console.log(" client.my_unused_version_count = " + client.my_unused_version_count)
|
|
456
462
|
x.patches = get_xf_patches(resource.doc, OpLog_remote_to_local(resource.doc, client.my_last_seen_version))
|
|
457
463
|
|
|
458
|
-
console.log(`sending from rebase: ${JSON.stringify(x)}`)
|
|
464
|
+
if (braid_text.verbose) console.log(`sending from rebase: ${JSON.stringify(x)}`)
|
|
459
465
|
client.subscribe(x)
|
|
460
466
|
client.my_last_sent_version = x.version
|
|
461
467
|
|
|
@@ -491,12 +497,12 @@ braid_text.put = async (key, options) => {
|
|
|
491
497
|
|
|
492
498
|
x.parents = options.version
|
|
493
499
|
if (!v_eq(version, options.version)) {
|
|
494
|
-
console.log("rebasing..")
|
|
500
|
+
if (braid_text.verbose) console.log("rebasing..")
|
|
495
501
|
x.patches = get_xf_patches(resource.doc, OpLog_remote_to_local(resource.doc, [og_v]))
|
|
496
502
|
} else {
|
|
497
503
|
// this client already has this version,
|
|
498
504
|
// so let's pretend to send it back, but not
|
|
499
|
-
console.log(`not reflecting back to simpleton`)
|
|
505
|
+
if (braid_text.verbose) console.log(`not reflecting back to simpleton`)
|
|
500
506
|
client.my_last_sent_version = x.version
|
|
501
507
|
continue
|
|
502
508
|
}
|
|
@@ -504,7 +510,7 @@ braid_text.put = async (key, options) => {
|
|
|
504
510
|
x.parents = parents
|
|
505
511
|
x.patches = patches
|
|
506
512
|
}
|
|
507
|
-
console.log(`sending: ${JSON.stringify(x)}`)
|
|
513
|
+
if (braid_text.verbose) console.log(`sending: ${JSON.stringify(x)}`)
|
|
508
514
|
client.subscribe(x)
|
|
509
515
|
client.my_last_sent_version = x.version
|
|
510
516
|
}
|
|
@@ -513,7 +519,7 @@ braid_text.put = async (key, options) => {
|
|
|
513
519
|
let version = resource.doc.getRemoteVersion().map((x) => x.join("-")).sort()
|
|
514
520
|
patches = get_xf_patches(resource.doc, v_before)
|
|
515
521
|
let x = { version, parents, patches }
|
|
516
|
-
console.log(`sending: ${JSON.stringify(x)}`)
|
|
522
|
+
if (braid_text.verbose) console.log(`sending: ${JSON.stringify(x)}`)
|
|
517
523
|
for (let client of resource.simpleton_clients) {
|
|
518
524
|
if (client.my_timeout) continue
|
|
519
525
|
client.subscribe(x)
|
|
@@ -581,13 +587,15 @@ async function get_resource(key) {
|
|
|
581
587
|
|
|
582
588
|
resource.val = resource.doc.get()
|
|
583
589
|
|
|
590
|
+
resource.length_cache = createSimpleCache(braid_text.length_cache_size)
|
|
591
|
+
|
|
584
592
|
done(resource)
|
|
585
593
|
})
|
|
586
594
|
return await cache[key]
|
|
587
595
|
}
|
|
588
596
|
|
|
589
597
|
async function db_folder_init() {
|
|
590
|
-
console.log('__!')
|
|
598
|
+
if (braid_text.verbose) console.log('__!')
|
|
591
599
|
if (!db_folder_init.p) db_folder_init.p = new Promise(async done => {
|
|
592
600
|
await fs.promises.mkdir(braid_text.db_folder, { recursive: true });
|
|
593
601
|
|
|
@@ -614,7 +622,7 @@ async function db_folder_init() {
|
|
|
614
622
|
console.log(`trying to convert file to new format, but the key is too big: ${braid_text.db_folder}/${x}`)
|
|
615
623
|
process.exit()
|
|
616
624
|
}
|
|
617
|
-
console.log(`deleting: ${braid_text.db_folder}/${x}`)
|
|
625
|
+
if (braid_text.verbose) console.log(`deleting: ${braid_text.db_folder}/${x}`)
|
|
618
626
|
await fs.promises.unlink(`${braid_text.db_folder}/${x}`)
|
|
619
627
|
}
|
|
620
628
|
}
|
|
@@ -622,7 +630,7 @@ async function db_folder_init() {
|
|
|
622
630
|
for (let x of await fs.promises.readdir(braid_text.db_folder)) {
|
|
623
631
|
let [_, k, num] = x.match(/^(.*)\.(\d+)$/s)
|
|
624
632
|
if (!convert_us[k]) continue
|
|
625
|
-
console.log(`renaming: ${braid_text.db_folder}/${x} -> ${braid_text.db_folder}/${convert_us[k]}.${num}`)
|
|
633
|
+
if (braid_text.verbose) console.log(`renaming: ${braid_text.db_folder}/${x} -> ${braid_text.db_folder}/${convert_us[k]}.${num}`)
|
|
626
634
|
if (convert_us[k]) await fs.promises.rename(`${braid_text.db_folder}/${x}`, `${braid_text.db_folder}/${convert_us[k]}.${num}`)
|
|
627
635
|
}
|
|
628
636
|
}
|
|
@@ -665,7 +673,7 @@ async function file_sync(key, process_delta, get_init) {
|
|
|
665
673
|
}
|
|
666
674
|
try {
|
|
667
675
|
const filename = files[i]
|
|
668
|
-
console.log(`trying to process file: ${filename}`)
|
|
676
|
+
if (braid_text.verbose) console.log(`trying to process file: ${filename}`)
|
|
669
677
|
const data = await fs.promises.readFile(filename)
|
|
670
678
|
|
|
671
679
|
let cursor = 0
|
|
@@ -699,17 +707,17 @@ async function file_sync(key, process_delta, get_init) {
|
|
|
699
707
|
currentSize += bytes.length + 4 // we account for the extra 4 bytes for uint32
|
|
700
708
|
const filename = `${braid_text.db_folder}/${encoded}.${currentNumber}`
|
|
701
709
|
if (currentSize < threshold) {
|
|
702
|
-
console.log(`appending to db..`)
|
|
710
|
+
if (braid_text.verbose) console.log(`appending to db..`)
|
|
703
711
|
|
|
704
712
|
let buffer = Buffer.allocUnsafe(4)
|
|
705
713
|
buffer.writeUInt32LE(bytes.length, 0)
|
|
706
714
|
await fs.promises.appendFile(filename, buffer)
|
|
707
715
|
await fs.promises.appendFile(filename, bytes)
|
|
708
716
|
|
|
709
|
-
console.log("wrote to : " + filename)
|
|
717
|
+
if (braid_text.verbose) console.log("wrote to : " + filename)
|
|
710
718
|
} else {
|
|
711
719
|
try {
|
|
712
|
-
console.log(`starting new db..`)
|
|
720
|
+
if (braid_text.verbose) console.log(`starting new db..`)
|
|
713
721
|
|
|
714
722
|
currentNumber++
|
|
715
723
|
const init = get_init()
|
|
@@ -720,7 +728,7 @@ async function file_sync(key, process_delta, get_init) {
|
|
|
720
728
|
await fs.promises.writeFile(newFilename, buffer)
|
|
721
729
|
await fs.promises.appendFile(newFilename, init)
|
|
722
730
|
|
|
723
|
-
console.log("wrote to : " + newFilename)
|
|
731
|
+
if (braid_text.verbose) console.log("wrote to : " + newFilename)
|
|
724
732
|
|
|
725
733
|
currentSize = 4 + init.length
|
|
726
734
|
threshold = currentSize * 10
|
|
@@ -728,7 +736,7 @@ async function file_sync(key, process_delta, get_init) {
|
|
|
728
736
|
await fs.promises.unlink(filename)
|
|
729
737
|
} catch (e) { }
|
|
730
738
|
} catch (e) {
|
|
731
|
-
console.log(`e = ${e.stack}`)
|
|
739
|
+
if (braid_text.verbose) console.log(`e = ${e.stack}`)
|
|
732
740
|
}
|
|
733
741
|
}
|
|
734
742
|
}))
|
|
@@ -745,7 +753,7 @@ async function file_sync(key, process_delta, get_init) {
|
|
|
745
753
|
console.error(`Error deleting file: ${file}`)
|
|
746
754
|
reject(err)
|
|
747
755
|
} else {
|
|
748
|
-
console.log(`Deleted file: ${file}`)
|
|
756
|
+
if (braid_text.verbose) console.log(`Deleted file: ${file}`)
|
|
749
757
|
resolve()
|
|
750
758
|
}
|
|
751
759
|
})
|
|
@@ -1513,6 +1521,40 @@ function validate_patch(x) {
|
|
|
1513
1521
|
if (typeof x.content !== 'string') throw new Error(`invalid patch content: must be a string`)
|
|
1514
1522
|
}
|
|
1515
1523
|
|
|
1524
|
+
function createSimpleCache(size) {
|
|
1525
|
+
const maxSize = size
|
|
1526
|
+
const cache = new Map()
|
|
1527
|
+
|
|
1528
|
+
return {
|
|
1529
|
+
put(key, value) {
|
|
1530
|
+
if (cache.has(key)) {
|
|
1531
|
+
// If the key already exists, update its value and move it to the end
|
|
1532
|
+
cache.delete(key)
|
|
1533
|
+
cache.set(key, value)
|
|
1534
|
+
} else {
|
|
1535
|
+
// If the cache is full, remove the oldest entry
|
|
1536
|
+
if (cache.size >= maxSize) {
|
|
1537
|
+
const oldestKey = cache.keys().next().value
|
|
1538
|
+
cache.delete(oldestKey)
|
|
1539
|
+
}
|
|
1540
|
+
// Add the new key-value pair
|
|
1541
|
+
cache.set(key, value)
|
|
1542
|
+
}
|
|
1543
|
+
},
|
|
1544
|
+
|
|
1545
|
+
get(key) {
|
|
1546
|
+
if (!cache.has(key)) {
|
|
1547
|
+
return null
|
|
1548
|
+
}
|
|
1549
|
+
// Move the accessed item to the end (most recently used)
|
|
1550
|
+
const value = cache.get(key)
|
|
1551
|
+
cache.delete(key)
|
|
1552
|
+
cache.set(key, value)
|
|
1553
|
+
return value
|
|
1554
|
+
},
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1557
|
+
|
|
1516
1558
|
braid_text.encode_filename = encode_filename
|
|
1517
1559
|
braid_text.decode_filename = decode_filename
|
|
1518
1560
|
|
package/package.json
CHANGED
package/test.js
CHANGED
|
@@ -9,10 +9,10 @@ async function main() {
|
|
|
9
9
|
|
|
10
10
|
let og_log = console.log
|
|
11
11
|
console.log = () => {}
|
|
12
|
-
for (let t = 0; t <
|
|
12
|
+
for (let t = 0; t < 10000; t++) {
|
|
13
13
|
let seed = base + t
|
|
14
|
-
// for (let t = 0; t <
|
|
15
|
-
// let seed =
|
|
14
|
+
// for (let t = 0; t < 10; t++) {
|
|
15
|
+
// let seed = 1188661 + t
|
|
16
16
|
|
|
17
17
|
og_log(`t = ${t}, seed = ${seed}, best_n = ${best_n} @ ${best_seed}`)
|
|
18
18
|
Math.randomSeed(seed)
|
|
@@ -24,9 +24,19 @@ async function main() {
|
|
|
24
24
|
// 1. create a bunch of edits to a dt
|
|
25
25
|
let doc = new Doc('server')
|
|
26
26
|
|
|
27
|
+
let middle_doc = null
|
|
28
|
+
|
|
29
|
+
if (!middle_doc && (Math.random() < 1/n || n == 0)) {
|
|
30
|
+
middle_doc = Doc.fromBytes(doc.toBytes())
|
|
31
|
+
}
|
|
27
32
|
for (let i = 0; i < n; i++) {
|
|
28
33
|
make_random_edit(doc)
|
|
34
|
+
|
|
35
|
+
if (!middle_doc && (Math.random() < 1/n || i == n - 1)) {
|
|
36
|
+
middle_doc = Doc.fromBytes(doc.toBytes())
|
|
37
|
+
}
|
|
29
38
|
}
|
|
39
|
+
if (!middle_doc) throw 'bad'
|
|
30
40
|
|
|
31
41
|
// 2. let x = the resulting string
|
|
32
42
|
let x = doc.get()
|
|
@@ -49,37 +59,43 @@ async function main() {
|
|
|
49
59
|
}
|
|
50
60
|
|
|
51
61
|
// 5. test dt_get
|
|
52
|
-
let
|
|
53
|
-
|
|
54
|
-
console.log(
|
|
55
|
-
if (
|
|
62
|
+
let middle_v = middle_doc.getRemoteVersion().map(x => x.join('-'))
|
|
63
|
+
let new_middle_doc = dt_get(doc, middle_v)
|
|
64
|
+
console.log('new_middle_doc = ' + new_middle_doc.get())
|
|
65
|
+
if (middle_doc.get() != new_middle_doc.get() && n < best_n) {
|
|
56
66
|
best_n = n
|
|
57
67
|
best_seed = seed
|
|
58
68
|
}
|
|
59
69
|
|
|
60
70
|
// 6. test dt_get_patches(doc, version)
|
|
61
71
|
if (true) {
|
|
62
|
-
let
|
|
63
|
-
let v = []
|
|
64
|
-
for (let i = 0; i < versions.length; i++)
|
|
65
|
-
if (Math.random() > 0.5) v.push(versions[i].join('-'))
|
|
66
|
-
|
|
67
|
-
console.log(`v:${v}`)
|
|
68
|
-
|
|
69
|
-
let temp_doc = dt_get(doc, v)
|
|
70
|
-
console.log(`temp_doc1:${temp_doc.get()}`)
|
|
71
|
-
|
|
72
|
-
let updates = dt_get_patches(doc, v)
|
|
72
|
+
let updates = dt_get_patches(doc, middle_v)
|
|
73
73
|
console.log(`updates:`, updates)
|
|
74
74
|
|
|
75
|
-
apply_updates(
|
|
76
|
-
console.log(`
|
|
77
|
-
if (
|
|
75
|
+
apply_updates(middle_doc, updates)
|
|
76
|
+
console.log(`middle_doc2:${middle_doc.get()}`)
|
|
77
|
+
if (middle_doc.get() != doc.get() && n < best_n) {
|
|
78
78
|
best_n = n
|
|
79
79
|
best_seed = seed
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
|
+
|
|
83
|
+
// 7. try applying a patch that's out of range..
|
|
84
|
+
// if (true) {
|
|
85
|
+
// let agent = Math.random().toString(36).slice(2)
|
|
86
|
+
// let parents = doc.getRemoteVersion().map(x => x.join('-'))
|
|
87
|
+
// let len = doc.len()
|
|
88
|
+
// let args = [`${agent}-0`, parents, len + 1, 'c']
|
|
89
|
+
// console.log('ARGS:', args)
|
|
90
|
+
// try {
|
|
91
|
+
// doc.mergeBytes(dt_create_bytes(...args))
|
|
92
|
+
// } catch (e) {
|
|
93
|
+
// console.log(`EEEE = ${e}`)
|
|
94
|
+
// }
|
|
95
|
+
// console.log('did that..')
|
|
96
|
+
// }
|
|
82
97
|
} catch (e) {
|
|
98
|
+
if (console.log == og_log) throw e
|
|
83
99
|
if (n < best_n) {
|
|
84
100
|
best_n = n
|
|
85
101
|
best_seed = seed
|