Skip to content

Commit b4686f5

Browse files
sergey-shilovAndrew Nikitin
authored and
Andrew Nikitin
committed
INDY-1205: Use RocksDB as a key-value storage (hyperledger#561)
* INDY-1205: Add rocksdb as a key-value backend. Signed-off-by: Sergey Shilov <[email protected]> * Add tests for rocksdb. Signed-off-by: Sergey Shilov <[email protected]> * Add rocksdb support. Signed-off-by: Sergey Shilov <[email protected]> * Use rocksdb as a backend storage. Signed-off-by: Sergey Shilov <[email protected]> * Fix initialisation of rocksdb kvstore. Signed-off-by: Sergey Shilov <[email protected]> * Fix test_kv_rocksdb. Signed-off-by: Sergey Shilov <[email protected]> * Fix comparator of KeyValueStorageRocksdbIntKeys class. Signed-off-by: Sergey Shilov <[email protected]> * Fix test_state_rocksdb. Signed-off-by: Sergey Shilov <[email protected]> * Add unified config-based creation of hash store. Signed-off-by: Sergey Shilov <[email protected]> * Change default hash storage from file to rocksdb. Signed-off-by: Sergey Shilov <[email protected]> * Integrate rocksdb into state tests. Signed-off-by: Sergey Shilov <[email protected]> * Merge kv storages tests into single module. Signed-off-by: Sergey Shilov <[email protected]> * Temporary rollback to leveldb. Signed-off-by: Sergey Shilov <[email protected]> * Re-factor tests. Signed-off-by: Sergey Shilov <[email protected]> * Implement the first version of installation of rocksdb and python-rocksdb. Signed-off-by: Sergey Shilov <[email protected]> * Merge leveldb and rocksdb hash storages implementations into single storage. Signed-off-by: Sergey Shilov <[email protected]> * Use RocksDB as a key-value storage. Signed-off-by: Sergey Shilov <[email protected]> * Tempoprary use leveldb as a default storage for the ledger. Signed-off-by: Sergey Shilov <[email protected]> * Adopt getAllTxn() for working with rocksdb iterator. Signed-off-by: Sergey Shilov <[email protected]> * Fix db_path property for leveldb and rocksdb, fix test. Signed-off-by: Sergey Shilov <[email protected]> * Add build procedure for python-rocksdb and setuptool, use librocksdb deb from sovrin. Signed-off-by: Sergey Shilov <[email protected]> * Add missed libs to docker file. Signed-off-by: Sergey Shilov <[email protected]> * Change rocksdb package. Signed-off-by: Sergey Shilov <[email protected]> * Change rocksdb package for 3d parties build. Signed-off-by: Sergey Shilov <[email protected]> * Implement get_equal_or_prev() functionality for KeyValueStorageRocksdbIntKeys. Signed-off-by: Sergey Shilov <[email protected]> * Add a helper for init of k/v storage with int keys. Signed-off-by: Sergey Shilov <[email protected]> * Add rocksdb tests for the equal-or-prev functionality. Signed-off-by: Sergey Shilov <[email protected]> * Fallback to leveldb as we do not want to migrate to rocksdb right now. Signed-off-by: Sergey Shilov <[email protected]>
1 parent 62548bc commit b4686f5

26 files changed

+367
-250
lines changed

build-scripts/ubuntu-1604/Dockerfile

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
FROM ubuntu:16.04
22

3+
RUN apt-get update -y && apt-get install -y \
4+
apt-transport-https \
5+
ca-certificates
6+
7+
RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 68DB5E88 && \
8+
echo "deb https://repo.sovrin.org/test/deb xenial rocksdb" >> /etc/apt/sources.list && \
9+
apt-get update
10+
311
RUN apt-get update -y && apt-get install -y \
412
# common stuff
513
git \
@@ -9,12 +17,20 @@ RUN apt-get update -y && apt-get install -y \
917
python3-pip \
1018
python-setuptools \
1119
python3-venv \
12-
# fmp
20+
# fpm
1321
ruby \
1422
ruby-dev \
1523
rubygems \
1624
gcc \
17-
make
25+
make \
26+
# rocksdb python wrapper
27+
libbz2-dev \
28+
zlib1g-dev \
29+
liblz4-dev \
30+
libsnappy-dev \
31+
rocksdb=5.8.8
32+
33+
RUN pip3 install -U setuptools
1834

1935
# install fpm
2036
RUN gem install --no-ri --no-rdoc fpm

build-scripts/ubuntu-1604/build-3rd-parties.sh

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,13 @@ function build_from_pypi {
1717
PREREM_TMP=prerm-${PACKAGE_NAME}
1818
cp postinst ${POSTINST_TMP}
1919
cp prerm ${PREREM_TMP}
20-
sed -i 's/{package_name}/python3-'${PACKAGE_NAME}'/' ${POSTINST_TMP}
21-
sed -i 's/{package_name}/python3-'${PACKAGE_NAME}'/' ${PREREM_TMP}
20+
if [[ ${PACKAGE_NAME} =~ ^python-* ]]; then
21+
PACKAGE_NAME_TMP="${PACKAGE_NAME/python-/}"
22+
else
23+
PACKAGE_NAME_TMP=$PACKAGE_NAME
24+
fi
25+
sed -i 's/{package_name}/python3-'${PACKAGE_NAME_TMP}'/' ${POSTINST_TMP}
26+
sed -i 's/{package_name}/python3-'${PACKAGE_NAME_TMP}'/' ${PREREM_TMP}
2227

2328
fpm --input-type "python" \
2429
--output-type "deb" \
@@ -50,3 +55,5 @@ build_from_pypi pyzmq 16.0.2
5055
build_from_pypi intervaltree 2.1.0
5156
build_from_pypi portalocker 0.5.7
5257
build_from_pypi sortedcontainers 1.5.7
58+
build_from_pypi setuptools 38.5.2
59+
build_from_pypi python-rocksdb 0.6.9

ci/ubuntu.dockerfile

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,19 @@ ARG uid=1000
55
ARG user=indy
66
ARG venv=venv
77

8+
RUN echo "deb https://repo.sovrin.org/test/deb xenial rocksdb" >> /etc/apt/sources.list && \
9+
apt-get update
10+
811
RUN apt-get update -y && apt-get install -y \
912
python3-nacl \
1013
libindy-crypto=0.2.0 \
11-
libindy=1.3.1~403
14+
libindy=1.3.1~403 \
15+
# rocksdb python wrapper
16+
libbz2-dev \
17+
zlib1g-dev \
18+
liblz4-dev \
19+
libsnappy-dev \
20+
rocksdb=5.8.8
1221

1322
RUN indy_ci_add_user $uid $user $venv
1423

ledger/ledger.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from ledger.tree_hasher import TreeHasher
1111
from ledger.util import F, ConsistencyVerificationFailed
1212
from storage.kv_store import KeyValueStorage
13-
from storage.kv_store_leveldb_int_keys import KeyValueStorageLeveldbIntKeys
13+
from storage.kv_store_rocksdb_int_keys import KeyValueStorageRocksdbIntKeys
1414

1515

1616
class Ledger(ImmutableStore):
@@ -19,7 +19,7 @@ def _defaultStore(dataDir,
1919
logName,
2020
ensureDurability,
2121
open=True) -> KeyValueStorage:
22-
return KeyValueStorageLeveldbIntKeys(dataDir, logName, open)
22+
return KeyValueStorageRocksdbIntKeys(dataDir, logName, open)
2323

2424
def __init__(self,
2525
tree: MerkleTree,
@@ -222,8 +222,11 @@ def reset(self):
222222
# TODO: rename getAllTxn to get_txn_slice with required parameters frm to
223223
# add get_txn_all without args.
224224
def getAllTxn(self, frm: int = None, to: int = None):
225-
yield from ((int(seq_no), self.txn_serializer.deserialize(txn))
226-
for seq_no, txn in self._transactionLog.iterator(start=frm, end=to))
225+
for seq_no, txn in self._transactionLog.iterator(start=frm, end=to):
226+
if to is None or int(seq_no) <= to:
227+
yield (int(seq_no), self.txn_serializer.deserialize(txn))
228+
else:
229+
break
227230

228231
@staticmethod
229232
def hashToStr(h):

plenum/bls/bls_store.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from common.serializers.serialization import multi_sig_store_serializer
2-
from plenum.persistence.storage import initKeyValueStorage
2+
from storage.helper import initKeyValueStorage
33
from crypto.bls.bls_multi_signature import MultiSignature
44
from typing import Optional
55

plenum/common/constants.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ class StorageType(IntEnum):
141141
class KeyValueStorageType(IntEnum):
142142
Leveldb = 1
143143
Memory = 2
144+
Rocksdb = 3
144145

145146

146147
@unique
@@ -165,6 +166,7 @@ class LedgerState(IntEnum):
165166
HS_FILE = "file"
166167
HS_MEMORY = "memory"
167168
HS_LEVELDB = 'leveldb'
169+
HS_ROCKSDB = 'rocksdb'
168170

169171
PLUGIN_BASE_DIR_PATH = "PluginBaseDirPath"
170172
POOL_LEDGER_ID = 0

plenum/common/stack_manager.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
from abc import abstractmethod, ABCMeta
22
from collections import OrderedDict
3-
import os
43

54
from ledger.genesis_txn.genesis_txn_initiator_from_file import GenesisTxnInitiatorFromFile
65
from plenum.common.keygen_utils import initRemoteKeys
76
from plenum.common.tools import lazy_field
8-
from plenum.persistence.leveldb_hash_store import LevelDbHashStore
7+
from storage.helper import initHashStore
98
from stp_core.types import HA
109
from stp_core.network.exceptions import RemoteNotFound
1110
from stp_core.common.log import getlogger
@@ -43,8 +42,7 @@ def ledgerFile(self) -> str:
4342

4443
@lazy_field
4544
def hashStore(self):
46-
return LevelDbHashStore(dataDir=self.ledgerLocation,
47-
fileNamePrefix='pool')
45+
return initHashStore(self.ledgerLocation, 'pool', self.config)
4846

4947
# noinspection PyTypeChecker
5048
@lazy_field

plenum/config.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55

66
import logging
77

8-
from plenum.common.constants import ClientBootStrategy, HS_FILE, KeyValueStorageType
8+
from plenum.common.constants import ClientBootStrategy, HS_FILE, HS_LEVELDB, \
9+
HS_ROCKSDB, HS_MEMORY, KeyValueStorageType
910
from plenum.common.types import PLUGIN_TYPE_STATS_CONSUMER
1011

1112
# Each entry in registry is (stack name, ((host, port), verkey, pubkey))
@@ -59,7 +60,7 @@
5960
clientBootStrategy = ClientBootStrategy.PoolTxn
6061

6162
hashStore = {
62-
"type": HS_FILE
63+
"type": HS_LEVELDB
6364
}
6465

6566
primaryStorage = None

plenum/persistence/client_txn_log.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from plenum.common.has_file_storage import HasFileStorage
55
from plenum.common.txn_util import getTxnOrderedFields
66
from plenum.common.util import updateFieldsWithSeqNo
7-
from storage.kv_store_leveldb import KeyValueStorageLeveldb
7+
from storage.kv_store_rocksdb import KeyValueStorageRocksdb
88

99

1010
class ClientTxnLog(HasFileStorage):
@@ -17,9 +17,7 @@ def __init__(self, dataLocation):
1717
self.clientDataLocation = self.dataLocation
1818
if not os.path.exists(self.clientDataLocation):
1919
os.makedirs(self.clientDataLocation)
20-
# self.transactionLog = TextFileStore(self.clientDataLocation,
21-
# "transactions")
22-
self.transactionLog = KeyValueStorageLeveldb(
20+
self.transactionLog = KeyValueStorageRocksdb(
2321
self.clientDataLocation, "transactions")
2422
self.serializer = ledger_txn_serializer
2523

plenum/persistence/leveldb_hash_store.py renamed to plenum/persistence/db_hash_store.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
1+
import storage.helper
2+
13
from ledger.hash_stores.hash_store import HashStore
2-
from storage.kv_store_leveldb import KeyValueStorageLeveldb
4+
from plenum.common.constants import KeyValueStorageType, HS_LEVELDB, HS_ROCKSDB
35
from stp_core.common.log import getlogger
46

57
logger = getlogger()
68

79

8-
class LevelDbHashStore(HashStore):
9-
def __init__(self, dataDir, fileNamePrefix=""):
10+
class DbHashStore(HashStore):
11+
def __init__(self, dataDir, fileNamePrefix="", db_type=HS_ROCKSDB):
1012
self.dataDir = dataDir
13+
assert db_type == HS_ROCKSDB or db_type == HS_LEVELDB
14+
self.db_type = KeyValueStorageType.Leveldb if db_type == HS_LEVELDB \
15+
else KeyValueStorageType.Rocksdb
1116
self.nodesDb = None
1217
self.leavesDb = None
1318
self._leafCount = 0
@@ -76,9 +81,10 @@ def closed(self):
7681
(self.nodesDb.closed and self.leavesDb.closed)
7782

7883
def open(self):
79-
self.nodesDb = KeyValueStorageLeveldb(self.dataDir, self.nodes_db_name)
80-
self.leavesDb = KeyValueStorageLeveldb(
81-
self.dataDir, self.leaves_db_name)
84+
self.nodesDb = storage.helper.initKeyValueStorage(
85+
self.db_type, self.dataDir, self.nodes_db_name)
86+
self.leavesDb = storage.helper.initKeyValueStorage(
87+
self.db_type, self.dataDir, self.leaves_db_name)
8288
self._leafCount = self.leavesDb.size
8389

8490
def close(self):

plenum/persistence/storage.py

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
from abc import abstractmethod, ABC
22

3-
from plenum.common.constants import StorageType, KeyValueStorageType
4-
from plenum.common.exceptions import DataDirectoryNotFound, KeyValueStorageConfigNotFound
3+
from plenum.common.constants import StorageType
4+
from plenum.common.exceptions import DataDirectoryNotFound
55
from plenum.common.messages.node_messages import Reply
6-
from storage.kv_in_memory import KeyValueStorageInMemory
7-
from storage.kv_store import KeyValueStorage
8-
from storage.kv_store_leveldb import KeyValueStorageLeveldb
96
from storage.text_file_store import TextFileStore
107

118

@@ -27,16 +24,6 @@ async def get(self, identifier: str, reqId: int, **kwargs):
2724
pass
2825

2926

30-
def initKeyValueStorage(keyValueType, dataLocation,
31-
keyValueStorageName) -> KeyValueStorage:
32-
if keyValueType == KeyValueStorageType.Leveldb:
33-
return KeyValueStorageLeveldb(dataLocation, keyValueStorageName)
34-
elif keyValueType == KeyValueStorageType.Memory:
35-
return KeyValueStorageInMemory()
36-
else:
37-
raise KeyValueStorageConfigNotFound
38-
39-
4027
def initStorage(storageType, name, dataDir=None, config=None):
4128
if storageType == StorageType.File:
4229
if dataDir is None:

plenum/server/node.py

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,15 @@
1111
from intervaltree import IntervalTree
1212
from ledger.compact_merkle_tree import CompactMerkleTree
1313
from ledger.genesis_txn.genesis_txn_initiator_from_file import GenesisTxnInitiatorFromFile
14-
from ledger.hash_stores.file_hash_store import FileHashStore
1514
from ledger.hash_stores.hash_store import HashStore
16-
from ledger.hash_stores.memory_hash_store import MemoryHashStore
1715
from ledger.util import F
1816
from plenum.bls.bls_bft_factory import create_default_bls_bft_factory
1917
from plenum.bls.bls_crypto_factory import create_default_bls_crypto_factory
2018
from plenum.client.wallet import Wallet
2119
from plenum.common.config_util import getConfig
2220
from plenum.common.constants import POOL_LEDGER_ID, DOMAIN_LEDGER_ID, \
2321
CLIENT_BLACKLISTER_SUFFIX, CONFIG_LEDGER_ID, \
24-
NODE_BLACKLISTER_SUFFIX, NODE_PRIMARY_STORAGE_SUFFIX, HS_FILE, HS_LEVELDB, \
22+
NODE_BLACKLISTER_SUFFIX, NODE_PRIMARY_STORAGE_SUFFIX, \
2523
TXN_TYPE, LEDGER_STATUS, \
2624
CLIENT_STACK_SUFFIX, PRIMARY_SELECTION_PREFIX, VIEW_CHANGE_PREFIX, \
2725
OP_FIELD_NAME, CATCH_UP_PREFIX, NYM, \
@@ -58,9 +56,8 @@
5856
from plenum.common.util import friendlyEx, getMaxFailures, pop_keys, \
5957
compare_3PC_keys, get_utc_epoch
6058
from plenum.common.verifier import DidVerifier
61-
from plenum.persistence.leveldb_hash_store import LevelDbHashStore
6259
from plenum.persistence.req_id_to_txn import ReqIdrToTxn
63-
from plenum.persistence.storage import Storage, initStorage, initKeyValueStorage
60+
from plenum.persistence.storage import Storage, initStorage
6461
from plenum.server.blacklister import Blacklister
6562
from plenum.server.blacklister import SimpleBlacklister
6663
from plenum.server.client_authn import ClientAuthNr, SimpleAuthNr, CoreAuthNr
@@ -91,6 +88,7 @@
9188
from plenum.common.config_helper import PNodeConfigHelper
9289
from state.pruning_state import PruningState
9390
from state.state import State
91+
from storage.helper import initKeyValueStorage, initHashStore
9492
from stp_core.common.log import getlogger
9593
from stp_core.crypto.signer import Signer
9694
from stp_core.network.exceptions import RemoteNotFound
@@ -447,9 +445,7 @@ def setup_config_req_handler(self):
447445
self.register_req_handler(CONFIG_LEDGER_ID, self.configReqHandler)
448446

449447
def getConfigLedger(self):
450-
hashStore = LevelDbHashStore(
451-
dataDir=self.dataLocation, fileNamePrefix='config')
452-
return Ledger(CompactMerkleTree(hashStore=hashStore),
448+
return Ledger(CompactMerkleTree(hashStore=self.getHashStore('config')),
453449
dataDir=self.dataLocation,
454450
fileName=self.config.configTransactionsFile,
455451
ensureDurability=self.config.EnsureLedgerDurability)
@@ -717,15 +713,7 @@ def getHashStore(self, name) -> HashStore:
717713
"""
718714
Create and return a hashStore implementation based on configuration
719715
"""
720-
hsConfig = self.config.hashStore['type'].lower()
721-
if hsConfig == HS_FILE:
722-
return FileHashStore(dataDir=self.dataLocation,
723-
fileNamePrefix=name)
724-
elif hsConfig == HS_LEVELDB:
725-
return LevelDbHashStore(dataDir=self.dataLocation,
726-
fileNamePrefix=name)
727-
else:
728-
return MemoryHashStore()
716+
return initHashStore(self.dataLocation, name, self.config)
729717

730718
def get_new_ledger_manager(self) -> LedgerManager:
731719
ledger_sync_order = self.ledger_ids
@@ -940,7 +928,7 @@ def onStopping(self):
940928

941929
def closeAllKVStores(self):
942930
# Clear leveldb lock files
943-
logger.debug("{} closing level dbs".format(self), extra={"cli": False})
931+
logger.debug("{} closing key-value storages".format(self), extra={"cli": False})
944932
for ledgerId in self.ledgerManager.ledgerRegistry:
945933
state = self.getState(ledgerId)
946934
if state:

plenum/server/pool_manager.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from plenum.common.exceptions import UnsupportedOperation
1515
from plenum.common.stack_manager import TxnStackManager
1616
from plenum.common.types import NodeDetail
17-
from plenum.persistence.storage import initKeyValueStorage
17+
from storage.helper import initKeyValueStorage
1818
from plenum.persistence.util import pop_merkle_info
1919
from plenum.server.pool_req_handler import PoolRequestHandler
2020
from state.pruning_state import PruningState

plenum/test/plugin/demo_plugin/storage.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
from ledger.compact_merkle_tree import CompactMerkleTree
22
from plenum.common.ledger import Ledger
3-
from plenum.persistence.leveldb_hash_store import LevelDbHashStore
4-
from plenum.persistence.storage import initKeyValueStorage
3+
from plenum.persistence.db_hash_store import DbHashStore
54
from state.pruning_state import PruningState
5+
from storage.helper import initKeyValueStorage
6+
from plenum.common.constants import HS_LEVELDB
67

78

89
def get_auction_hash_store(data_dir):
9-
return LevelDbHashStore(dataDir=data_dir,
10-
fileNamePrefix='auction')
10+
return DbHashStore(dataDir=data_dir,
11+
fileNamePrefix='auction',
12+
db_type=HS_LEVELDB)
1113

1214

1315
def get_auction_ledger(data_dir, name, hash_store, config):

0 commit comments

Comments
 (0)