Browse Source

Remove LMDB

Performance of history writes was very poor even with
the code rewritten to accommodate the environment concept
(see db_abstraction branch)
master
Neil Booth 8 years ago
parent
commit
c958b3af49
  1. 1
      .travis.yml
  2. 8
      docs/ENVIRONMENT.rst
  3. 2
      samples/systemd/electrumx.conf
  4. 70
      server/storage.py

1
.travis.yml

@ -12,7 +12,6 @@ python:
# command to install dependencies # command to install dependencies
install: install:
- pip install aiohttp - pip install aiohttp
- pip install lmdb
- pip install plyvel - pip install plyvel
- pip install pyrocksdb - pip install pyrocksdb
- pip install pytest-cov - pip install pytest-cov

8
docs/ENVIRONMENT.rst

@ -66,11 +66,9 @@ These environment variables are optional:
* **DB_ENGINE** * **DB_ENGINE**
Database engine for the UTXO and history database. The default is Database engine for the UTXO and history database. The default is
`leveldb`. Supported alternatives are `rocksdb` and `lmdb`. You `leveldb`. The other alternative is `rocksdb`. You will need to
will need to install the appropriate python package for your engine. install the appropriate python package for your engine. The value
The value is not case sensitive. Note that the current way is not case sensitive.
ElectrumX uses LMDB results in poor performance. I intend to improve
this.
* **REORG_LIMIT** * **REORG_LIMIT**

2
samples/systemd/electrumx.conf

@ -44,7 +44,7 @@
#COIN = Bitcoin # lib/coins.py #COIN = Bitcoin # lib/coins.py
#NET = mainnet # lib/coins.py #NET = mainnet # lib/coins.py
#DB_ENGINE = leveldb #DB_ENGINE = leveldb
#leveldb, rocksdb, lmdb (You'll need to install appropriate python packages) #leveldb, rocksdb (You'll need to install appropriate python packages)
#REORG_LIMIT = 200 #REORG_LIMIT = 200
#maximum number of blocks to be able to handle in a chain #maximum number of blocks to be able to handle in a chain

70
server/storage.py

@ -5,10 +5,7 @@
# See the file "LICENCE" for information about the copyright # See the file "LICENCE" for information about the copyright
# and warranty status of this software. # and warranty status of this software.
'''Backend database abstraction. '''Backend database abstraction.'''
The abstraction needs to be improved to not heavily penalise LMDB.
'''
import os import os
from functools import partial from functools import partial
@ -161,68 +158,3 @@ class RocksDB(Storage):
def iterator(self, prefix=b'', reverse=False): def iterator(self, prefix=b'', reverse=False):
return RocksDB.Iterator(self.db, prefix, reverse) return RocksDB.Iterator(self.db, prefix, reverse)
class LMDB(Storage):
'''RocksDB database engine.'''
@classmethod
def import_module(cls):
import lmdb
cls.module = lmdb
def open(self, name, create):
# I don't see anything equivalent to max_open_files for for_sync
self.env = LMDB.module.Environment('.', subdir=True, create=create,
max_dbs=32, map_size=5 * 10 ** 10)
self.db = self.env.open_db(create=create)
def close(self):
self.env.close()
def get(self, key):
with self.env.begin(db=self.db) as tx:
return tx.get(key)
def put(self, key, value):
with self.env.begin(db=self.db, write=True) as tx:
tx.put(key, value)
def write_batch(self):
return self.env.begin(db=self.db, write=True)
def iterator(self, prefix=b'', reverse=False):
return LMDB.Iterator(self.db, self.env, prefix, reverse)
class Iterator:
def __init__(self, db, env, prefix, reverse):
self.transaction = env.begin(db=db)
self.transaction.__enter__()
self.db = db
self.prefix = prefix
self.reverse = reverse
self._stop = False
def __iter__(self):
self.iterator = LMDB.module.Cursor(self.db, self.transaction)
prefix = self.prefix
if self.reverse:
# Go to the first value after the prefix
prefix = increment_byte_string(prefix)
self.iterator.set_range(prefix)
if not self.iterator.key().startswith(self.prefix) and self.reverse:
# Go back to the first item starting with the prefix
self.iterator.prev()
return self
def __next__(self):
k, v = self.iterator.item()
if not k.startswith(self.prefix) or self._stop:
# We're already ahead of the prefix
self.transaction.__exit__()
raise StopIteration
next = self.iterator.next \
if not self.reverse else self.iterator.prev
# Stop after the next value if we're at the end of the DB
self._stop = not next()
return k, v

Loading…
Cancel
Save