CoreyKaylor / Lightning.NET

.NET library for LMDB key-value store
Other
398 stars 82 forks source link

cur.MoveToFirstDuplicate() throws #41

Closed buybackoff closed 9 years ago

buybackoff commented 9 years ago

It looks like this native call doesn't return a key-value pair but only positions the cursor. (or I am calling this in a wrong way)

When I add operation check in the middle of the following methods, it works as expected, but without it keyStruct.ToByteArray(res) throws because the returned ValueStructures are empty.

private KeyValuePair<byte[], byte[]>? Get(CursorOperation operation, ValueStructure? key = null, ValueStructure? value = null)
        {
            var keyStruct = key.GetValueOrDefault();
            var valueStruct = value.GetValueOrDefault();

            var res = NativeMethods.Read(lib => lib.mdb_cursor_get(_handle, ref keyStruct, ref valueStruct, operation));

             // HERE need to check and provide current values
            if (operation == CursorOperation.FirstDuplicate) {
                res = NativeMethods.Read(lib => lib.mdb_cursor_get(_handle, ref keyStruct, ref valueStruct, CursorOperation.GetCurrent));
            }

            return res == NativeMethods.MDB_NOTFOUND
                ? (KeyValuePair<byte[], byte[]>?) null
                : new KeyValuePair<byte[], byte[]>(keyStruct.ToByteArray(res), valueStruct.ToByteArray(res));
        }

The whole test below. Note the expected behavior right before the last loop:

[Test]
        public void CursorShouldPutDupValues() {

            var db2 = _txn.OpenDatabase("dup",
                DBFlags.Create | DBFlags.DuplicatesSort
                | DBFlags.DuplicatesFixed | DBFlags.IntegerDuplicates);

            using (var cur = _txn.CreateCursor(db2)) {
                var keys = Enumerable.Range(1, 50000).ToArray();
                foreach (var k in keys) {
                    cur.Put(Encoding.UTF8.GetBytes("key"), k, CursorPutOptions.None);
                }
                // overwrite
                foreach (var k in keys) {
                    cur.Put(Encoding.UTF8.GetBytes("key"), k, CursorPutOptions.None);
                }

                var kvp = cur.MoveToFirst();
                kvp = cur.MoveNextDuplicate();
                kvp = cur.MoveNextDuplicate();
                kvp = cur.MoveToFirstDuplicate(); // cancel the moves above and start from the beginning
                foreach (var k in keys) {
                    //var kvp = cur.GetCurrent();
                    Assert.AreEqual(k, BitConverter.ToInt32(kvp.Value.Value, 0));
                    kvp = cur.MoveNextDuplicate();
                }
            }
        }
ilyalukyanov commented 9 years ago

Not sire I remember how it should work) Need to take closer look.