Rationalize how root is stored to make it more like an item of an array or object...
authorNick Downing <nick@ndcode.org>
Thu, 6 Jan 2022 22:50:51 +0000 (09:50 +1100)
committerNick Downing <nick@ndcode.org>
Thu, 6 Jan 2022 22:50:51 +0000 (09:50 +1100)
logjson.mjs

index bc5c971..6efe4d2 100644 (file)
@@ -34,8 +34,67 @@ class Database {
     }
 
     this.eof = (await this.log.stat()).size
+
+    let eof_buffer
     try {
-      this.value = await this.find_root()
+      eof_buffer = await (
+        async () => {
+          let ptr = this.eof & ~0xfff
+          let count = this.eof & 0xfff
+          let buffer = Buffer.alloc(0x1001)
+          assert(
+            (await this.log.read(buffer, 0, count, ptr)).bytesRead === count
+          )
+          while (true) {
+            let i = count
+            if (i && (i = buffer.lastIndexOf(close_angle, i - 2)) != -1) {
+              let eof = ptr + i + 2
+              let blocks = [buffer.slice(0, i)]
+              while (true) {
+                if (i && (i = buffer.lastIndexOf(open_angle, i - 2)) != -1) {
+                  blocks[blocks.length - 1] = blocks[blocks.length - 1].slice(i)
+                  return {eof, buffer: Buffer.concat(blocks.reverse()).slice(2)}
+                }
+
+                if (ptr === 0)
+                  break
+                ptr -= 0x1000
+                if (count) {
+                  buffer[0x1000] = buffer[0]
+                  count = 0x1001
+                }
+                else
+                  count = 0x1000
+                assert(
+                  (await this.log.read(buffer, 0, 0x1000, ptr)).bytesRead === 0x1000
+                )
+                blocks.push(buffer.slice(0, 0x1000))
+              }
+
+              // special case for < at start of database
+              if (count && buffer[0] === 0x3c)
+                return {eof, buffer: Buffer.concat(blocks.reverse()).slice(1)}
+
+              throw new Error('can\'t find logjson start marker')
+            }
+
+            if (ptr === 0)
+              break
+            ptr -= 0x1000
+            if (count) {
+              buffer[0x1000] = buffer[0]
+              count = 0x1001
+            }
+            else
+              count = 0x1000
+            assert(
+              (await this.log.read(buffer, 0, 0x1000, ptr)).bytesRead === 0x1000
+            )
+          }
+
+          throw new Error('can\'t find logjson end marker')
+        }
+      )()
     }
     catch (error) {
       console.log('warning: can\'t find root, truncating database file')
@@ -47,10 +106,10 @@ class Database {
       this.mutex.release()
       return
     }
+    let {eof, buffer} = eof_buffer
+    this.value = JSON.parse(buffer.toString('utf-8'))
 
     // optional: trim any garbage off the end of the database file
-    let [ptr, len] = this.value
-    let eof = ptr + len + 2
     if (eof < this.eof) {
       console.log('warning: garbage after root, truncating database file')
 
@@ -71,63 +130,6 @@ class Database {
     this.mutex.release()
   }
 
-  async find_root() {
-    let ptr = this.eof & ~0xfff
-    let count = this.eof & 0xfff
-    let buffer = Buffer.alloc(0x1001)
-    assert(
-      (await this.log.read(buffer, 0, count, ptr)).bytesRead === count
-    )
-    while (true) {
-      let i = count
-      if (i && (i = buffer.lastIndexOf(close_angle, i - 2)) != -1) {
-        let end = i + ptr
-        while (true) {
-          if (i && (i = buffer.lastIndexOf(open_angle, i - 2)) != -1) {
-            let start = i + ptr + 2
-            return [start, end - start] // ptr, len
-          }
-
-          if (ptr === 0)
-            break
-          ptr -= 0x1000
-          if (count) {
-            buffer[0x1000] = buffer[0]
-            count = 0x1001
-          }
-          else
-            count = 0x1000
-          assert(
-            (await this.log.read(buffer, 0, 0x1000, ptr)).bytesRead === 0x1000
-          )
-        }
-
-        // special case for < at start of database
-        if (count && buffer[0] === 0x3c) {
-          let start = 1
-          return [start, end - start] // ptr, len
-        }
-
-        throw new Error('can\'t find logjson start marker')
-      }
-
-      if (ptr === 0)
-        break
-      ptr -= 0x1000
-      if (count) {
-        buffer[0x1000] = buffer[0]
-        count = 0x1001
-      }
-      else
-        count = 0x1000
-      assert(
-        (await this.log.read(buffer, 0, 0x1000, ptr)).bytesRead === 0x1000
-      )
-    }
-
-    throw new Error('can\'t find logjson end marker')
-  }
-
   async read(ptr, len) {
     let buffer = Buffer.alloc(len)
     assert(
@@ -228,12 +230,20 @@ class Transaction {
       if ((value instanceof Lazy && await value.flush()) || ptr === -1) {
         if (value instanceof Lazy)
           value = value.pack()
-        this.database.value = await this.database.write_root(value)
+        let [ptr, len] = await this.database.write(value)
+
+        this.value[0] = ptr
+        this.value[1] = len
+        this.dirty = true
       }
     }
-    else if (this.dirty) {
+
+    if (this.dirty) {
+      let value = this.value
+      if (value instanceof Array)
+        value = value.slice(0, 2)
       await this.database.write_root(value)
-      this.database.value = this.value
+      this.database.value = value
     }
 
     this.database.mutex.release()