ssbc / async-append-only-log

A new append-only-log for SSB purposes
16 stars 6 forks source link

NaN RangeError when deleting records #90

Closed staltz closed 2 years ago

staltz commented 2 years ago

Similar to #89 but seems different enough to be its own issue

Versions

Reproduction

Block someone and wait for Manyverse to use ssb-friends-purge to call db2 deleteFeed() (and in turn,) AAOL del().

Stack trace

RangeError [ERR_OUT_OF_RANGE]: The value of "position" is out of range. It must be an integer. Received NaN
    at Object.read (node:fs:653:3)
    at RandomAccessFile._read (/home/staltz/oss/manyverse/desktop/index.js:20533:6)
    at Request._run (/home/staltz/oss/manyverse/desktop/index.js:114867:40)
    at RandomAccessFile.RandomAccess.run (/home/staltz/oss/manyverse/desktop/index.js:114775:12)
    at RandomAccessFile.RandomAccess.read (/home/staltz/oss/manyverse/desktop/index.js:114720:8)
    at getBlock (/home/staltz/oss/manyverse/desktop/index.js:93605:11)
    at del (/home/staltz/oss/manyverse/desktop/index.js:93665:7)
    at Object.waitForLogLoaded [as del] (/home/staltz/oss/manyverse/desktop/index.js:93984:12)
    at Timeout._onTimeout (/home/staltz/oss/manyverse/desktop/index.js:5522:38)
    at listOnTimeout (node:internal/timers:557:17)

Stack trace expanded

(not an actual git diff, I'm just using diff syntax to show the line that throws)

1 random-access-file

 RandomAccessFile.prototype._read = function (req) {
   var self = this
   var data = req.data || this._alloc(req.size)
   var fd = this.fd

   if (!req.size) return process.nextTick(readEmpty, req)
-  fs.read(fd, data, 0, req.size, req.offset, onread)

   function onread (err, read) {
     if (err) return req.callback(err)
     if (!read) return req.callback(createReadError(self.filename, req.offset, req.size))

     req.size -= read
     req.offset += read

     if (!req.size) return req.callback(null, data)
     fs.read(fd, data, data.length - req.size, req.size, req.offset, onread)
   }
 }

2 random-access-storage

 Request.prototype._run = function () {
   var ra = this.storage
   ra._pending++

   this._sync = true

   switch (this.type) {
     case READ_OP:
-      if (this._openAndNotClosed()) ra._read(this)
       break

3 random-access-storage

 RandomAccess.prototype.run = function (req) {
   if (this._needsOpen) this.open(noop)
   if (this._queued.length) this._queued.push(req)
-  else req._run()
 }

4 random-access-storage

 RandomAccess.prototype.read = function (offset, size, cb) {
-  this.run(new Request(this, READ_OP, offset, size, null, cb))
 }

5 async-append-only-log

  function getBlock(offset, cb) {
    const blockIndex = getBlockIndex(offset)

    if (cache.has(blockIndex)) {
      debug('getting offset %d from cache', offset)
      const cachedBlockBuf = cache.get(blockIndex)
      cb(null, cachedBlockBuf)
    } else {
      debug('getting offset %d from disc', offset)
      const blockStart = getBlockStart(offset)
-     raf.read(blockStart, blockSize, function onRAFReadDone(err, blockBuf) {
        cache.set(blockIndex, blockBuf)
        cb(err, blockBuf)
      })
    }
  }

6 async-append-only-log

  function del(offset, cb) {
    if (compaction) {
      cb(delDuringCompactErr())
      return
    }
    const blockIndex = getBlockIndex(offset)
    if (blocksToBeWritten.has(blockIndex)) {
      onDrain(function delAfterDrained() {
        del(offset, cb)
      })
      return
    }

    if (blocksWithDeletables.has(blockIndex)) {
      const blockBuf = blocksWithDeletables.get(blockIndex)
      gotBlockForDelete(null, blockBuf)
    } else {
-     getBlock(offset, gotBlockForDelete)
    }
    function gotBlockForDelete(err, blockBuf) {
      if (err) return cb(err)
      const actualBlockBuf = blocksWithDeletables.get(blockIndex) || blockBuf
      Record.overwriteWithZeroes(actualBlockBuf, getOffsetInBlock(offset))
      deletedBytes += Record.readSize(actualBlockBuf, getOffsetInBlock(offset))
      blocksWithDeletables.set(blockIndex, actualBlockBuf)
      scheduleFlushDelete()
      cb()
    }
  }
staltz commented 2 years ago

NEVERMIND, this one was caused by a silly code I wrote when drunk at 3:00AM with this double del() call:

https://github.com/staltz/manyverse/blob/8980e59cff9a0bc887f0d4194c5725a3ae1f096b/src/backend/patches/ssb-db2%2B6.2.5.patch#L8-L10