Temporarily remove optimization of writing primitive JSON values directly, so that...
authorNick Downing <nick@ndcode.org>
Wed, 5 Jan 2022 00:24:32 +0000 (11:24 +1100)
committerNick Downing <nick@ndcode.org>
Wed, 5 Jan 2022 00:24:32 +0000 (11:24 +1100)
logjson.mjs

index e2010c6..e4800f3 100644 (file)
@@ -9,9 +9,7 @@ class File {
     this.mutex = new Mutex()
     this.log = null
     this.eof = 0
-    this.ptr = 0
-    this.len = 0
-    this.value = undefined
+    this.value = [-1, 0]
   }
 
   async open(path, default_value) {
@@ -28,22 +26,16 @@ class File {
       this.log = await fsPromises.open(path, 'w+')
       this.eof = 0
 
-      let {ptr, len} = await this.write(default_value, true)
-      this.ptr = ptr
-      this.len = len
-
-      // not yet, as it's JSON rather than logjson at the moment:
-      //this.value = default_value
+      this.value = await this.write(default_value, true)
       return
     }
 
     this.eof = (await this.log.stat()).size
-    let {ptr, len} = await this.find_root()
-    this.ptr = ptr
-    this.len = len
+    this.value = await this.find_root()
 
     // optional: trim any garbage off the end of the file
-    this.eof = this.ptr + this.len + 2
+    let [ptr, len] = this.value
+    this.eof = ptr + len + 2
     await this.log.truncate(this.eof)
 
     this.mutex.release()
@@ -73,7 +65,7 @@ class File {
         while (true) {
           if (i && (i = buffer.lastIndexOf(open_angle, i - 2)) != -1) {
             let start = i + ptr + 2
-            return {ptr: start, len: end - start}
+            return [start, end - start] // ptr, len
           }
 
           if (ptr === 0)
@@ -93,7 +85,7 @@ class File {
         // special case for < at start of file
         if (count && buffer[0] === 0x3c) {
           let start = 1
-          return {ptr: start, len: end - start}
+          return [start, end - start] // ptr, len
         }
 
         throw new Error('can\'t find logjson start marker')
@@ -119,28 +111,24 @@ class File {
   async write(value, is_root) {
     if (typeof value === 'object' && value !== null)
       if (value instanceof Array) {
-        let value1 = []
+        let new_value = []
         for (let i = 0; i < value.length; ++i) {
           let item = value[i]
-          if (typeof item === 'object' && item !== null) {
-            let {ptr, len} = await this.write(item, false)
-            item = [ptr, len]
-          }
-          value1.push(item)
+          //if (typeof item === 'object' && item !== null)
+            item = await this.write(item, false)
+          new_value.push(item)
         }
-        value = value1
+        value = new_value
       }
       else {
-        let value1 = {}
+        let new_value = {}
         for (let i in value) {
           let item = value[i]
-          if (typeof item === 'object' && item !== null) {
-            let {ptr, len} = await this.write(item, false)
-            item = [ptr, len]
-          }
-          value1[i] = item
+          //if (typeof item === 'object' && item !== null)
+            item = await this.write(item, false)
+          new_value[i] = item
         }
-        value = value1
+        value = new_value
       }
 
     let data = JSON.stringify(value, null, 2)
@@ -152,7 +140,7 @@ class File {
         (await this.log.write(buffer, 0, len, ptr)).bytesWritten === len
       )
       this.eof += len
-      return {ptr: ptr + 1, len: len - 3}
+      return [ptr + 1, len - 3] // ptr, len
     }
     let buffer = Buffer.from(`${data}\n`)
     let ptr = this.eof
@@ -161,25 +149,25 @@ class File {
       (await this.log.write(buffer, 0, len, ptr)).bytesWritten === len
     )
     this.eof += len
-    return {ptr, len: len - 1}
+    return [ptr, len - 1] // ptr, len
   }
 
   async get() {
-    if (this.value === undefined) {
-      let buffer = Buffer.alloc(this.len)
+    let [ptr, len, value] = this.value
+    if (value === undefined) {
+      let buffer = Buffer.alloc(len)
       assert(
-        (await this.log.read(buffer, 0, this.len, this.ptr)).bytesRead ===
-          this.len
+        (await this.log.read(buffer, 0, len, ptr)).bytesRead === len
       )
-      let value = JSON.parse(buffer.toString('utf-8'))
+      value = JSON.parse(buffer.toString('utf-8'))
       if (typeof value === 'object' && value !== null)
         value =
           value instanceof Array ?
             new LazyArray(this, value) :
             new LazyObject(this, value)
-      this.value = value
+      this.value[2] = value
     }
-    return this.value
+    return value
   }
 }
 
@@ -204,10 +192,6 @@ class Lazy {
   delete(key) {
     throw new Error('not implemented')
   }
-
-  keys() {
-    throw new Error('not implemented')
-  }
 }
 
 class LazyArray extends Lazy {
@@ -219,15 +203,15 @@ class LazyArray extends Lazy {
 
   has(key) {
     assert(typeof key === 'number')
-    return key in this.array
+    return key >= 0 && key < this.length
   }
 
   async get(key, default_value) {
     assert(typeof key === 'number')
-    if (!(key in this.array))
+    if (key < 0 || key >= this.length)
       return default_value
     let value = this.array[key]
-    if (value instanceof Array) {
+    //if (value instanceof Array) {
       let [ptr, len, new_value] = value
       if (new_value === undefined) {
         let buffer = Buffer.alloc(len)
@@ -243,17 +227,18 @@ class LazyArray extends Lazy {
         value[2] = new_value
       }
       value = new_value
-    }
+    //}
     return value
   }
 
   set(key, value) {
     assert(typeof key === 'number')
-    if (typeof value === 'object' && value !== null) {
-      assert(value instanceof Lazy)
-      value = [-1, 0, value]
-    }
-    this.array[key] = value
+    //if (typeof value === 'object' && value !== null) {
+    //  assert(value instanceof Lazy)
+    //  value = [-1, 0, value]
+    //}
+    //this.array[key] = value
+    this.array[key] = [-1, 0, value]
     this.length = this.array.length
   }
 
@@ -262,15 +247,16 @@ class LazyArray extends Lazy {
     this.length = this.array.length
   }
 
-  keys() {
-    let keys = []
-    // this does not work well as it returns an array of strings:
-    //for (let i in this.array)
-    //  keys.push(i)
-    for (let i = 0; i < this.array.length; ++i)
-      if (i in this.array)
-        keys.push(i)
-    return keys
+  push(value) {
+    set(this.length, value)
+  }
+
+  async pop() {
+    assert(this.length)
+    let i = this.length - 1
+    let value = await this.get(i)
+    this.delete(i)
+    return value
   }
 }
 
@@ -290,7 +276,7 @@ class LazyObject extends Lazy {
     if (!Object.prototype.hasOwnProperty.call(this.object, key))
       return default_value
     let value = this.object[key]
-    if (value instanceof Array) {
+    //if (value instanceof Array) {
       let [ptr, len, new_value] = value
       if (new_value === undefined) {
         let buffer = Buffer.alloc(len)
@@ -306,7 +292,7 @@ class LazyObject extends Lazy {
         value[2] = new_value
       }
       value = new_value
-    }
+    //}
     return value
   }
 
@@ -332,13 +318,20 @@ class LazyObject extends Lazy {
 }
 
 let logjson_to_json = async value => {
-  if (typeof value === 'object' && value !== null) {
-    assert(value instanceof Lazy)
-    let new_value = value instanceof LazyArray ? [] : {}
-    let keys = value.keys()
-    for (let i = 0; i < keys.length; ++i) {
-       let key = keys[i]
-       new_value[key] = await logjson_to_json(await value.get(key))
+  if (value instanceof Lazy) {
+    let new_value
+    if (value instanceof LazyArray) {
+      new_value = []
+      for (let i = 0; i < value.length; ++i)
+        new_value.push(await logjson_to_json(await value.get(i)))
+    }
+    else {
+      new_value = {}
+      let keys = value.keys()
+      for (let i = 0; i < keys.length; ++i) {
+        let key = keys[i]
+        new_value[key] = await logjson_to_json(await value.get(key))
+      }
     }
     value = new_value
   }
@@ -347,10 +340,17 @@ let logjson_to_json = async value => {
 
 let json_to_logjson = value => {
   if (typeof value === 'object' && value !== null) {
-    let new_value =
-      value instanceof Array ? new LazyArray() : new LazyObject()
-    for (let i in value)
-      new_value.set(i, json_to_logjson(value[i]))
+    let new_value
+    if (value instanceof Array) {
+      new_value = LazyArray()
+      for (let i = 0; i < value.length; ++i)
+        new_value.push(json_to_logjson(value[i]))
+    }
+    else {
+      new_value = LazyObject()
+      for (let i in value)
+        new_value.set(i, json_to_logjson(value[i]))
+    }
     value = new_value
   }
   return value