//------------------------------------------------------------------------------ /* Copyright (c) 2011-2013, OpenCoin, Inc. */ //============================================================================== static const char* s_nodeStoreDBInit [] = { "PRAGMA synchronous=NORMAL;", "PRAGMA journal_mode=WAL;", "PRAGMA journal_size_limit=1582080;", #if (ULONG_MAX > UINT_MAX) && !defined (NO_SQLITE_MMAP) "PRAGMA mmap_size=171798691840;", #endif "BEGIN TRANSACTION;", "CREATE TABLE CommittedObjects ( \ Hash CHARACTER(64) PRIMARY KEY, \ ObjType CHAR(1) NOT NULL, \ LedgerIndex BIGINT UNSIGNED, \ Object BLOB \ );", "END TRANSACTION;" }; static int s_nodeStoreDBCount = NUMBER (s_nodeStoreDBInit); //------------------------------------------------------------------------------ class SqliteBackendFactory::Backend : public NodeStore::Backend { public: Backend (size_t keyBytes, std::string const& path) : m_keyBytes (keyBytes) , m_name (path) , m_db (new DatabaseCon(path, s_nodeStoreDBInit, s_nodeStoreDBCount)) { String s; // VFALCO TODO Remove this dependency on theConfig // s << "PRAGMA cache_size=-" << String (getConfig ().getSize(siHashNodeDBCache) * 1024); m_db->getDB()->executeSQL (s.toStdString ().c_str ()); } ~Backend() { } std::string getName() { return m_name; } //-------------------------------------------------------------------------- Status fetch (void const* key, NodeObject::Ptr* pObject) { Status result = ok; pObject->reset (); { ScopedLock sl (m_db->getDBLock()); uint256 const hash (uint256::fromVoid (key)); static SqliteStatement pSt (m_db->getDB()->getSqliteDB(), "SELECT ObjType,LedgerIndex,Object FROM CommittedObjects WHERE Hash = ?;"); pSt.bind (1, hash.GetHex()); if (pSt.isRow (pSt.step())) { // VFALCO NOTE This is unfortunately needed, // the DatabaseCon creates the blob? Blob data (pSt.getBlob (2)); *pObject = NodeObject::createObject ( getTypeFromString (pSt.peekString (0)), pSt.getUInt32 (1), data, hash); } else { result = notFound; } pSt.reset(); } return result; } void store (NodeObject::ref object) { NodeStore::Batch batch; batch.push_back (object); storeBatch (batch); } void storeBatch (NodeStore::Batch const& batch) { // VFALCO TODO Rewrite this to use Beast::db ScopedLock sl (m_db->getDBLock()); static SqliteStatement pStB (m_db->getDB()->getSqliteDB(), "BEGIN TRANSACTION;"); static SqliteStatement pStE (m_db->getDB()->getSqliteDB(), "END TRANSACTION;"); static SqliteStatement pSt (m_db->getDB()->getSqliteDB(), "INSERT OR IGNORE INTO CommittedObjects " "(Hash,ObjType,LedgerIndex,Object) VALUES (?, ?, ?, ?);"); pStB.step(); pStB.reset(); BOOST_FOREACH (NodeObject::Ptr const& object, batch) { doBind (pSt, object); pSt.step(); pSt.reset(); } pStE.step(); pStE.reset(); } void visitAll (VisitCallback& callback) { // No lock needed as per the visitAll() API uint256 hash; static SqliteStatement pSt(m_db->getDB()->getSqliteDB(), "SELECT ObjType,LedgerIndex,Object,Hash FROM CommittedObjects;"); while (pSt.isRow (pSt.step())) { hash.SetHexExact(pSt.getString(3)); // VFALCO NOTE This is unfortunately needed, // the DatabaseCon creates the blob? Blob data (pSt.getBlob (2)); NodeObject::Ptr const object (NodeObject::createObject ( getTypeFromString (pSt.peekString (0)), pSt.getUInt32 (1), data, hash)); callback.visitObject (object); } pSt.reset (); } int getWriteLoad () { return 0; } //-------------------------------------------------------------------------- void doBind (SqliteStatement& statement, NodeObject::ref object) { char const* type; switch (object->getType()) { case hotLEDGER: type = "L"; break; case hotTRANSACTION: type = "T"; break; case hotACCOUNT_NODE: type = "A"; break; case hotTRANSACTION_NODE: type = "N"; break; default: type = "U"; } statement.bind(1, object->getHash().GetHex()); statement.bind(2, type); statement.bind(3, object->getIndex()); statement.bindStatic(4, object->getData()); } NodeObjectType getTypeFromString (std::string const& s) { NodeObjectType type = hotUNKNOWN; if (!s.empty ()) { switch (s [0]) { case 'L': type = hotLEDGER; break; case 'T': type = hotTRANSACTION; break; case 'A': type = hotACCOUNT_NODE; break; case 'N': type = hotTRANSACTION_NODE; break; } } return type; } private: size_t const m_keyBytes; std::string const m_name; ScopedPointer m_db; }; //------------------------------------------------------------------------------ SqliteBackendFactory::SqliteBackendFactory () { } SqliteBackendFactory::~SqliteBackendFactory () { } SqliteBackendFactory& SqliteBackendFactory::getInstance () { static SqliteBackendFactory instance; return instance; } String SqliteBackendFactory::getName () const { return "Sqlite"; } NodeStore::Backend* SqliteBackendFactory::createInstance ( size_t keyBytes, StringPairArray const& keyValues, NodeStore::Scheduler& scheduler) { return new Backend (keyBytes, keyValues ["path"].toStdString ()); }