isar / hive

Lightweight and blazing fast key-value database written in pure Dart.
Apache License 2.0
4.1k stars 407 forks source link

Key randomly becomes null. Unable to .delete() object or .put() #1102

Open TreyThomas93 opened 2 years ago

TreyThomas93 commented 2 years ago

Issue I randomly encounter events where the object key for a hive object is null.

For example:

await queuedItem.delete();

and

 await _cacheService.queuedItems.put(
                      queuedItem.key,
                      queuedItem.copyWith(
                          serverResponseType:
                              ServerResponseType.sentButFailedToRemove));

will output the following issue:

Null check operator used on a null value

[package:hive/src/util/indexable_skip_list.dart 173 in IndexableSkipList._getNode, package:hive/src/util/indexable_skip_list.dart 155 in IndexableSkipList.get, package:hive/src/box/keystore.dart 93 in Keystore.containsKey]

And when I print out the hive object key, it is null, but not every time. Most of the time, it works fine.

I am running a simple compaction strategy:

await Hive.openBox<QueuedItem>('QueuedItemsDB',
      path: root?.path,
      encryptionCipher: HiveAesCipher(encryptionKey),
      compactionStrategy: (entries, deletedEntries) =>
          deletedEntries > 50);

Can compaction cause this issue? Maybe removing keys?

Any help would be great!

Version

WillianSalceda commented 2 years ago

I am not sure if it is the same problem, but I had something at least similar, and found a solution (more of a workaround, but still). Check it out: #1103

TreyThomas93 commented 2 years ago

I am not sure if it is the same problem, but I had something at least similar. Check it out: #1103

Not sure if it is, but it's random. It's only affecting some users. And I can't narrow it down.

For the time being, I simply wrap the .delete() in a try/catch, and if there is an exception, then the alternative is to remove it by index.

TreyThomas93 commented 2 years ago

@WillianSalceda Here is the trimmed stacktrace:

[package:hive/src/util/indexable_skip_list.dart 173 in IndexableSkipList._getNode, package:hive/src/util/indexable_skip_list.dart 38 in IndexableSkipList.insert, package:hive/src/box/keystore.dart 163 in Keystore.insert, package:hive/src/box/keystore.dart 191 in Keystore.beginTransaction, package:hive/src/box/box_impl.dart 85 in BoxImpl._writeFrames]

I have narrowed it down to this private method:

_Node<K, V>? _getNode(K key) {
    var prev = _head;
    _Node<K, V>? node;
    for (var i = _height - 1; i >= 0; i--) {
      node = prev.next[i];

     // [node.key] is actually null, but it contains a bang operator implying it should not be null.
     // This is where I get the exception.
     // This is also recently occurring when I use the .addAll() method.
      while (node != null && _comparator(key, node.key!) > 0) {
        prev = node;
        node = node.next[i];
      }
    }

    if (node != null && _comparator(key, node.key!) == 0) {
      return node;
    }
    return null;
  }