Make snapped references to Lazy(Array|Object) in the tree be stored as the Lazy(Array...
authorNick Downing <nick@ndcode.org>
Fri, 7 Jan 2022 00:07:54 +0000 (11:07 +1100)
committerNick Downing <nick@ndcode.org>
Fri, 7 Jan 2022 00:07:54 +0000 (11:07 +1100)
logjson.mjs

index 08793b5..63d3195 100644 (file)
@@ -130,7 +130,9 @@ class Database {
     this.mutex.release()
   }
 
-  async read(ptr, len) {
+  async read(ptr_len) {
+    let [ptr, len] = ptr_len
+
     let buffer = Buffer.alloc(len)
     assert(
       (await this.log.read(buffer, 0, len, ptr)).bytesRead === len
@@ -184,56 +186,50 @@ class Transaction {
     this.value = value
   }
 
+  async read(ptr_len) {
+    let value = await this.database.read(ptr_len)
+    if (typeof value === 'object' && value !== null)
+      value =
+        value instanceof Array ?
+          new LazyArray(this, ptr_len, value) :
+          new LazyObject(this, ptr_len, value)
+    return value
+  }
+
   async get(default_value) {
     if (this.value === undefined) {
       if (default_value === undefined)
         return undefined
       set(default_value)
     }
-    let value = this.value
 
-    if (value instanceof Array) {
-      let [ptr, len, new_value] = value
-      if (new_value === undefined) {
-        new_value = await this.database.read(ptr, len)
-        if (typeof new_value === 'object' && new_value !== null)
-          new_value =
-            new_value instanceof Array ?
-              new LazyArray(this, [ptr, len], new_value) :
-              new LazyObject(this, [ptr, len], new_value)
-        value[2] = new_value
-      }
-      value = new_value
-    }
-    return value
+    if (this.value instanceof Array)
+      this.value = this.read(this.value)
+    return this.value
   }
 
   set(value) {
     this.dirty = true
-    if (typeof value === 'object' && value !== null) {
-      assert(value instanceof Lazy && value.transaction === this)
-      let [ptr, len] = value.ptr_len || [-1, 0]
-      value = [ptr, len, value]
-    }
+    assert(
+      typeof value !== 'object' ||
+      value === null ||
+      (value instanceof Lazy && value.transaction === this)
+    )
     this.value = value
   }
 
   async commit() {
     assert(this.value !== undefined)
 
-    if (this.value instanceof Array) {
-      let [ptr, len, value] = this.value
-      if (value !== undefined) {
-        assert(value instanceof Lazy)
-        if (await value.commit())
-          this.dirty = true
-        this.value = value.ptr_len
-      }
+    if (this.value instanceof Lazy) {
+      if (await this.value.commit())
+        this.dirty = true
+      this.value = this.value.ptr_len
     }
 
     if (this.dirty) {
       await this.database.write_root(this.value)
-      this.database.value = value
+      this.database.value = this.value
     }
 
     this.database.mutex.release()
@@ -318,32 +314,23 @@ class LazyArray extends Lazy {
         return undefined
       set(key, default_value)
     }
-    let value = this.array[key]
 
+    let value = this.array[key]
     if (value instanceof Array) {
-      let [ptr, len, new_value] = value
-      if (new_value === undefined) {
-        new_value = await this.transaction.database.read(ptr, len)
-        if (typeof new_value === 'object' && new_value !== null)
-          new_value =
-            new_value instanceof Array ?
-              new LazyArray(this.transaction, [ptr, len], new_value) :
-              new LazyObject(this.transaction, [ptr, len], new_value)
-        value[2] = new_value
-      }
-      value = new_value
+      value = this.transaction.read(value)
+      this.array[key] = value
     }
     return value
   }
 
   set(key, value) {
     assert(typeof key === 'number')
+    assert(
+      typeof value !== 'object' ||
+      value === null ||
+      (value instanceof Lazy && value.transaction === this.transaction)
+    )
     this.ptr_len = null // mark dirty
-    if (typeof value === 'object' && value !== null) {
-      assert(value instanceof Lazy && value.transaction === this.transaction)
-      let [ptr, len] = value.ptr_len || [-1, 0]
-      value = [ptr, len, value]
-    }
     this.array[key] = value
     this.length = this.array.length
   }
@@ -366,20 +353,16 @@ class LazyArray extends Lazy {
 
   async commit() {
     for (let i = 0; i < this.length; ++i) {
-      let item = this.array[i]
-      if (item instanceof Array) {
-        let [ptr, len, value] = item
-        if (value !== undefined) {
-          assert(value instanceof Lazy)
-          if (await value.commit())
-            this.ptr_len = null // mark dirty
-          this.array[i] = value.ptr_len
-        }
+      let value = this.array[i]
+      if (value instanceof Lazy) {
+        if (await value.commit())
+          this.ptr_len = null // mark dirty
+        this.array[i] = value.ptr_len
       }
     }
 
     if (this.ptr_len === null) {
-      this.ptr_len = await this.transaction.database.write(value)
+      this.ptr_len = await this.transaction.database.write(this.array)
       return true
     }
     return false
@@ -404,32 +387,23 @@ class LazyObject extends Lazy {
         return undefined
       set(key, default_value)
     }
-    let value = this.object[key]
 
+    let value = this.object[key]
     if (value instanceof Array) {
-      let [ptr, len, new_value] = value
-      if (new_value === undefined) {
-        new_value = await this.transaction.database.read(ptr, len)
-        if (typeof new_value === 'object' && new_value !== null)
-          new_value =
-            new_value instanceof Array ?
-              new LazyArray(this.transaction, [ptr, len], new_value) :
-              new LazyObject(this.transaction, [ptr, len], new_value)
-        value[2] = new_value
-      }
-      value = new_value
+      value = this.transaction.read(value)
+      this.object[key] = value
     }
     return value
   }
 
   set(key, value) {
     assert(typeof key === 'string')
+    assert(
+      typeof value !== 'object' ||
+      value === null ||
+      (value instanceof Lazy && value.transaction === this.transaction)
+    )
     this.ptr_len = null // mark dirty
-    if (typeof value === 'object' && value !== null) {
-      assert(value instanceof Lazy && value.transaction === this.transaction)
-      let [ptr, len] = value.ptr_len || [-1, 0]
-      value = [ptr, len, value]
-    }
     this.object[key] = value
   }
 
@@ -446,20 +420,16 @@ class LazyObject extends Lazy {
 
   async commit() {
     for (let i in this.object) {
-      let item = this.object[i]
-      if (item instanceof Array) {
-        let [ptr, len, value] = item
-        if (value !== undefined) {
-          assert(value instanceof Lazy)
-          if (await value.commit())
-            this.ptr_len = null // mark dirty
-          this.object[i] = value.ptr_len
-        }
+      let value = this.object[i]
+      if (value instanceof Lazy) {
+        if (await value.commit())
+          this.ptr_len = null // mark dirty
+        this.object[i] = value.ptr_len
       }
     }
 
     if (this.ptr_len === null) {
-      this.ptr_len = await this.transaction.database.write(value)
+      this.ptr_len = await this.transaction.database.write(this.object)
       return true
     }
     return false