}
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')
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')
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(
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()