mafintosh / hyperdb

Distributed scalable database
MIT License
753 stars 75 forks source link

Checkouts: getting existing key fails due to previous gets #52

Closed andrewosh closed 6 years ago

andrewosh commented 6 years ago

Commit: ac253b761c9a9f44d87c91319fd830f7d284b911 OS: linux/x64

Stumbled on an odd bug today. It looks like get will update the heads incorrectly in checkouts -- getting a key that was inserted before a later key will cause subsequent gets for the later key to fail. At the surface level, I've noticed that this._heads is updated to point to an incorrect head (the node corresponding to the first insertion) during the first get operation.

Steps to reproduce:

  1. Create a DB and put two keys in it
  2. Get the version buffer for the database (version)
  3. Checkout a second database using the above version (db.checkout(version))
  4. get the first key inserted. This will succeed
  5. get the second key inserted. This will fail.

Here's a test case that currently fails:

var test = require('tape')

var ram = require('random-access-memory')
var hyperdb = require('.')

test('checkout gets should pass for all keys inserted before checkout seq', function (t) {
  t.plan(7)

  var db1 = hyperdb(ram)
  db1.put('a', 'b', function (err) {
    t.error(err)
    db1.put('c', 'd', function (err) {
      t.error(err)
      checkoutAndTest()
    })
  })

  function checkoutAndTest () {
    db1.version(function (err, version) {
      t.error(err)
      var db2 = db1.checkout(version)
      db2.get('a', function (err, nodes) {
        t.error(err)
        t.same(nodes[0].value, Buffer.from('b')) // This passes.
        db2.get('c', function (err, nodes) {
          t.error(err)
          t.same(nodes[0].value, Buffer.from('d')) // This fails.
        })
      })
    })
  }
})
mafintosh commented 6 years ago

i think this is fixed in master, re-open if not