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.
Files changed (3) hide show
  1. package/index.js +67 -25
  2. package/package.json +1 -1
  3. 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 = count_code_points(v_eq(parents, og_parents) ?
305
- resource.doc.get() :
306
- dt_get(resource.doc, og_parents).get())
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "braid-text",
3
- "version": "0.0.28",
3
+ "version": "0.0.30",
4
4
  "description": "Library for collaborative text over http using braid.",
5
5
  "author": "Braid Working Group",
6
6
  "repository": "braid-org/braidjs",
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 < 50000; t++) {
12
+ for (let t = 0; t < 10000; t++) {
13
13
  let seed = base + t
14
- // for (let t = 0; t < 1; t++) {
15
- // let seed = 7271846
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 z = dt_get(doc, doc.getRemoteVersion().map(x => x.join('-'))).get()
53
- console.log('z = ' + z)
54
- console.log(x == z)
55
- if (x != z && n < best_n) {
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 [_agents, versions, _parentss] = dt_parse([...doc.toBytes()])
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(temp_doc, updates)
76
- console.log(`temp_doc2:${temp_doc.get()}`)
77
- if (temp_doc.get() != doc.get() && n < best_n) {
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