LCOV - code coverage report
Current view: top level - irohad/ametsuchi/impl - storage_impl.cpp (source / functions) Hit Total Coverage
Test: cleared_cor.info Lines: 304 351 86.6 %
Date: 2019-03-07 14:46:43 Functions: 47 52 90.4 %

          Line data    Source code
       1             : /**
       2             :  * Copyright Soramitsu Co., Ltd. All Rights Reserved.
       3             :  * SPDX-License-Identifier: Apache-2.0
       4             :  */
       5             : 
       6             : #include "ametsuchi/impl/storage_impl.hpp"
       7             : 
       8             : #include <soci/postgresql/soci-postgresql.h>
       9             : #include <boost/format.hpp>
      10             : #include "ametsuchi/impl/flat_file/flat_file.hpp"
      11             : #include "ametsuchi/impl/mutable_storage_impl.hpp"
      12             : #include "ametsuchi/impl/peer_query_wsv.hpp"
      13             : #include "ametsuchi/impl/postgres_block_index.hpp"
      14             : #include "ametsuchi/impl/postgres_block_query.hpp"
      15             : #include "ametsuchi/impl/postgres_command_executor.hpp"
      16             : #include "ametsuchi/impl/postgres_query_executor.hpp"
      17             : #include "ametsuchi/impl/postgres_wsv_query.hpp"
      18             : #include "ametsuchi/impl/temporary_wsv_impl.hpp"
      19             : #include "backend/protobuf/permissions.hpp"
      20             : #include "common/bind.hpp"
      21             : #include "common/byteutils.hpp"
      22             : #include "converters/protobuf/json_proto_converter.hpp"
      23             : #include "logger/logger.hpp"
      24             : #include "logger/logger_manager.hpp"
      25             : 
      26             : namespace {
      27             :   void prepareStatements(soci::connection_pool &connections, size_t pool_size) {
      28        3135 :     for (size_t i = 0; i != pool_size; i++) {
      29        2850 :       soci::session &session = connections.at(i);
      30        2850 :       iroha::ametsuchi::PostgresCommandExecutor::prepareStatements(session);
      31        2850 :     }
      32         285 :   }
      33             : 
      34             :   /**
      35             :    * Verify whether postgres supports prepared transactions
      36             :    */
      37             :   bool preparedTransactionsAvailable(soci::session &sql) {
      38         285 :     int prepared_txs_count = 0;
      39             :     try {
      40         285 :       sql << "SHOW max_prepared_transactions;", soci::into(prepared_txs_count);
      41         285 :       return prepared_txs_count != 0;
      42           0 :     } catch (std::exception &e) {
      43           0 :       return false;
      44           0 :     }
      45         285 :   }
      46             : 
      47             : }  // namespace
      48             : 
      49             : namespace iroha {
      50             :   namespace ametsuchi {
      51             :     const char *kCommandExecutorError = "Cannot create CommandExecutorFactory";
      52             :     const char *kPsqlBroken = "Connection to PostgreSQL broken: %s";
      53             :     const char *kTmpWsv = "TemporaryWsv";
      54             : 
      55             :     ConnectionContext::ConnectionContext(
      56             :         std::unique_ptr<KeyValueStorage> block_store)
      57         285 :         : block_store(std::move(block_store)) {}
      58             : 
      59             :     StorageImpl::StorageImpl(
      60             :         std::string block_store_dir,
      61             :         PostgresOptions postgres_options,
      62             :         std::unique_ptr<KeyValueStorage> block_store,
      63             :         std::shared_ptr<soci::connection_pool> connection,
      64             :         std::shared_ptr<shared_model::interface::CommonObjectsFactory> factory,
      65             :         std::shared_ptr<shared_model::interface::BlockJsonConverter> converter,
      66             :         std::shared_ptr<shared_model::interface::PermissionToString>
      67             :             perm_converter,
      68             :         size_t pool_size,
      69             :         bool enable_prepared_blocks,
      70             :         logger::LoggerManagerTreePtr log_manager)
      71         285 :         : block_store_dir_(std::move(block_store_dir)),
      72         285 :           postgres_options_(std::move(postgres_options)),
      73         285 :           block_store_(std::move(block_store)),
      74         285 :           connection_(std::move(connection)),
      75         285 :           factory_(std::move(factory)),
      76         285 :           converter_(std::move(converter)),
      77         285 :           perm_converter_(std::move(perm_converter)),
      78         285 :           log_manager_(std::move(log_manager)),
      79         285 :           log_(log_manager_->getLogger()),
      80         285 :           pool_size_(pool_size),
      81         285 :           prepared_blocks_enabled_(enable_prepared_blocks),
      82         285 :           block_is_prepared(false) {
      83         285 :       prepared_block_name_ =
      84         285 :           "prepared_block" + postgres_options_.dbname().value_or("");
      85         285 :       soci::session sql(*connection_);
      86             :       // rollback current prepared transaction
      87             :       // if there exists any since last session
      88         285 :       if (prepared_blocks_enabled_) {
      89         285 :         rollbackPrepared(sql);
      90         285 :       }
      91             :       try {
      92         285 :         sql << init_;
      93         285 :         prepareStatements(*connection_, pool_size_);
      94         285 :       } catch (std::exception &e) {
      95           0 :         log_->error("Storage was not initialized. Reason: {}", e.what());
      96           0 :       }
      97         285 :     }
      98             : 
      99             :     expected::Result<std::unique_ptr<TemporaryWsv>, std::string>
     100             :     StorageImpl::createTemporaryWsv() {
     101         727 :       std::shared_lock<std::shared_timed_mutex> lock(drop_mutex);
     102         727 :       if (connection_ == nullptr) {
     103           0 :         return expected::makeError("Connection was closed");
     104             :       }
     105         727 :       auto sql = std::make_unique<soci::session>(*connection_);
     106             :       // if we create temporary storage, then we intend to validate a new
     107             :       // proposal. this means that any state prepared before that moment is not
     108             :       // needed and must be removed to prevent locking
     109         727 :       if (block_is_prepared) {
     110           1 :         rollbackPrepared(*sql);
     111           1 :       }
     112             : 
     113         727 :       return expected::makeValue<std::unique_ptr<TemporaryWsv>>(
     114         727 :           std::make_unique<TemporaryWsvImpl>(
     115         727 :               std::move(sql),
     116         727 :               factory_,
     117         727 :               perm_converter_,
     118         727 :               log_manager_->getChild("TemporaryWorldStateView")));
     119         727 :     }
     120             : 
     121             :     expected::Result<std::unique_ptr<MutableStorage>, std::string>
     122             :     StorageImpl::createMutableStorage() {
     123         554 :       boost::optional<shared_model::interface::types::HashType> top_hash;
     124             : 
     125         554 :       std::shared_lock<std::shared_timed_mutex> lock(drop_mutex);
     126         554 :       if (connection_ == nullptr) {
     127           4 :         return expected::makeError("Connection was closed");
     128             :       }
     129             : 
     130         550 :       auto sql = std::make_unique<soci::session>(*connection_);
     131             :       // if we create mutable storage, then we intend to mutate wsv
     132             :       // this means that any state prepared before that moment is not needed
     133             :       // and must be removed to prevent locking
     134         550 :       if (block_is_prepared) {
     135           2 :         rollbackPrepared(*sql);
     136           2 :       }
     137         550 :       auto block_result = getBlockQuery()->getTopBlock();
     138         550 :       return expected::makeValue<std::unique_ptr<MutableStorage>>(
     139         550 :           std::make_unique<MutableStorageImpl>(
     140         550 :               block_result.match(
     141             :                   [](expected::Value<
     142             :                       std::shared_ptr<shared_model::interface::Block>> &block) {
     143          20 :                     return block.value->hash();
     144             :                   },
     145             :                   [](expected::Error<std::string> &) {
     146         530 :                     return shared_model::interface::types::HashType("");
     147           0 :                   }),
     148         550 :               std::make_shared<PostgresCommandExecutor>(*sql, perm_converter_),
     149         550 :               std::move(sql),
     150         550 :               factory_,
     151         550 :               log_manager_->getChild("MutableStorageImpl")));
     152         554 :     }
     153             : 
     154             :     boost::optional<std::shared_ptr<PeerQuery>> StorageImpl::createPeerQuery()
     155             :         const {
     156        4598 :       auto wsv = getWsvQuery();
     157        4598 :       if (not wsv) {
     158         317 :         return boost::none;
     159             :       }
     160        4281 :       return boost::make_optional<std::shared_ptr<PeerQuery>>(
     161        4281 :           std::make_shared<PeerQueryWsv>(wsv));
     162        4598 :     }
     163             : 
     164             :     boost::optional<std::shared_ptr<BlockQuery>> StorageImpl::createBlockQuery()
     165             :         const {
     166        1936 :       auto block_query = getBlockQuery();
     167        1936 :       if (not block_query) {
     168           0 :         return boost::none;
     169             :       }
     170        1936 :       return boost::make_optional(block_query);
     171        1936 :     }
     172             : 
     173             :     boost::optional<std::shared_ptr<QueryExecutor>>
     174             :     StorageImpl::createQueryExecutor(
     175             :         std::shared_ptr<PendingTransactionStorage> pending_txs_storage,
     176             :         std::shared_ptr<shared_model::interface::QueryResponseFactory>
     177             :             response_factory) const {
     178         192 :       std::shared_lock<std::shared_timed_mutex> lock(drop_mutex);
     179         192 :       if (not connection_) {
     180           0 :         log_->info("connection to database is not initialised");
     181           0 :         return boost::none;
     182             :       }
     183         192 :       return boost::make_optional<std::shared_ptr<QueryExecutor>>(
     184         192 :           std::make_shared<PostgresQueryExecutor>(
     185         190 :               std::make_unique<soci::session>(*connection_),
     186         192 :               *block_store_,
     187         192 :               std::move(pending_txs_storage),
     188         192 :               converter_,
     189         192 :               std::move(response_factory),
     190         192 :               perm_converter_,
     191         192 :               log_manager_->getChild("QueryExecutor")));
     192         192 :     }
     193             : 
     194             :     bool StorageImpl::insertBlock(const shared_model::interface::Block &block) {
     195         247 :       log_->info("create mutable storage");
     196         247 :       auto storageResult = createMutableStorage();
     197         247 :       bool inserted = false;
     198         247 :       storageResult.match(
     199             :           [&](expected::Value<std::unique_ptr<ametsuchi::MutableStorage>>
     200             :                   &storage) {
     201         247 :             inserted = storage.value->apply(block);
     202         247 :             log_->info("block inserted: {}", inserted);
     203         247 :             commit(std::move(storage.value));
     204         247 :           },
     205             :           [&](expected::Error<std::string> &error) {
     206           0 :             log_->error(error.error);
     207           0 :           });
     208             : 
     209         247 :       return inserted;
     210         247 :     }
     211             : 
     212             :     bool StorageImpl::insertBlocks(
     213             :         const std::vector<std::shared_ptr<shared_model::interface::Block>>
     214             :             &blocks) {
     215         248 :       log_->info("create mutable storage");
     216         248 :       bool inserted = true;
     217         248 :       auto storageResult = createMutableStorage();
     218         248 :       storageResult.match(
     219             :           [&](iroha::expected::Value<std::unique_ptr<MutableStorage>>
     220             :                   &mutableStorage) {
     221             :             std::for_each(blocks.begin(), blocks.end(), [&](auto block) {
     222         249 :               inserted &= mutableStorage.value->apply(*block);
     223         249 :             });
     224         248 :             commit(std::move(mutableStorage.value));
     225         248 :           },
     226             :           [&](iroha::expected::Error<std::string> &error) {
     227           0 :             log_->error(error.error);
     228           0 :             inserted = false;
     229           0 :           });
     230             : 
     231         248 :       log_->info("insert blocks finished");
     232         248 :       return inserted;
     233         248 :     }
     234             : 
     235             :     void StorageImpl::reset() {
     236         657 :       log_->info("drop wsv records from db tables");
     237             :       try {
     238         657 :         soci::session sql(*connection_);
     239             :         // rollback possible prepared transaction
     240         657 :         if (block_is_prepared) {
     241           2 :           rollbackPrepared(sql);
     242           2 :         }
     243         657 :         sql << reset_;
     244         657 :         log_->info("drop blocks from disk");
     245         657 :         block_store_->dropAll();
     246         657 :       } catch (std::exception &e) {
     247           0 :         log_->warn("Drop wsv was failed. Reason: {}", e.what());
     248           0 :       }
     249         657 :     }
     250             : 
     251             :     void StorageImpl::dropStorage() {
     252         294 :       log_->info("drop storage");
     253         294 :       if (connection_ == nullptr) {
     254          11 :         log_->warn("Tried to drop storage without active connection");
     255          11 :         return;
     256             :       }
     257             : 
     258         283 :       if (auto dbname = postgres_options_.dbname()) {
     259         283 :         auto &db = dbname.value();
     260         283 :         std::unique_lock<std::shared_timed_mutex> lock(drop_mutex);
     261         283 :         log_->info("Drop database {}", db);
     262         283 :         freeConnections();
     263         283 :         soci::session sql(*soci::factory_postgresql(),
     264         283 :                           postgres_options_.optionsStringWithoutDbName());
     265             :         // perform dropping
     266             :         try {
     267         283 :           sql << "DROP DATABASE " + db;
     268         283 :         } catch (std::exception &e) {
     269           0 :           log_->warn("Drop database was failed. Reason: {}", e.what());
     270           0 :         }
     271         283 :       } else {
     272           0 :         soci::session(*connection_) << drop_;
     273             :       }
     274             : 
     275             :       // erase blocks
     276         283 :       log_->info("drop block store");
     277         283 :       block_store_->dropAll();
     278         294 :     }
     279             : 
     280             :     void StorageImpl::freeConnections() {
     281         568 :       if (connection_ == nullptr) {
     282         283 :         log_->warn("Tried to free connections without active connection");
     283         283 :         return;
     284             :       }
     285             :       // rollback possible prepared transaction
     286         285 :       if (block_is_prepared) {
     287           4 :         soci::session sql(*connection_);
     288           4 :         rollbackPrepared(sql);
     289           4 :       }
     290         285 :       std::vector<std::shared_ptr<soci::session>> connections;
     291        3135 :       for (size_t i = 0; i < pool_size_; i++) {
     292        2850 :         connections.push_back(std::make_shared<soci::session>(*connection_));
     293        2850 :         connections[i]->close();
     294        2850 :         log_->debug("Closed connection {}", i);
     295        2850 :       }
     296         285 :       connections.clear();
     297         285 :       connection_.reset();
     298         568 :     }
     299             : 
     300             :     expected::Result<bool, std::string> StorageImpl::createDatabaseIfNotExist(
     301             :         const std::string &dbname,
     302             :         const std::string &options_str_without_dbname) {
     303             :       try {
     304         286 :         soci::session sql(*soci::factory_postgresql(),
     305         286 :                           options_str_without_dbname);
     306             : 
     307             :         int size;
     308         285 :         std::string name = dbname;
     309             : 
     310         285 :         sql << "SELECT count(datname) FROM pg_catalog.pg_database WHERE "
     311         285 :                "datname = :dbname",
     312         285 :             soci::into(size), soci::use(name);
     313             : 
     314         285 :         if (size == 0) {
     315         283 :           std::string query = "CREATE DATABASE ";
     316         283 :           query += dbname;
     317         283 :           sql << query;
     318         283 :           return expected::makeValue(true);
     319         283 :         }
     320           2 :         return expected::makeValue(false);
     321         285 :       } catch (std::exception &e) {
     322           1 :         return expected::makeError<std::string>(
     323           1 :             std::string("Connection to PostgreSQL broken: ") + e.what());
     324           1 :       }
     325         286 :     }
     326             : 
     327             :     expected::Result<ConnectionContext, std::string>
     328             :     StorageImpl::initConnections(std::string block_store_dir,
     329             :                                  logger::LoggerPtr log) {
     330         285 :       log->info("Start storage creation");
     331             : 
     332         285 :       auto block_store = FlatFile::create(block_store_dir, log);
     333         285 :       if (not block_store) {
     334           0 :         return expected::makeError(
     335           0 :             (boost::format("Cannot create block store in %s") % block_store_dir)
     336           0 :                 .str());
     337             :       }
     338         285 :       log->info("block store created");
     339             : 
     340         285 :       return expected::makeValue(ConnectionContext(std::move(*block_store)));
     341         285 :     }
     342             : 
     343             :     expected::Result<std::shared_ptr<soci::connection_pool>, std::string>
     344             :     StorageImpl::initPostgresConnection(std::string &options_str,
     345             :                                         size_t pool_size) {
     346         285 :       auto pool = std::make_shared<soci::connection_pool>(pool_size);
     347             : 
     348             :       try {
     349        3135 :         for (size_t i = 0; i != pool_size; i++) {
     350        2850 :           soci::session &session = pool->at(i);
     351        2850 :           session.open(*soci::factory_postgresql(), options_str);
     352        2850 :         }
     353         285 :       } catch (const std::exception &e) {
     354           0 :         return expected::makeError(e.what());
     355           0 :       }
     356         285 :       return expected::makeValue(pool);
     357         285 :     }
     358             : 
     359             :     expected::Result<std::shared_ptr<StorageImpl>, std::string>
     360             :     StorageImpl::create(
     361             :         std::string block_store_dir,
     362             :         std::string postgres_options,
     363             :         std::shared_ptr<shared_model::interface::CommonObjectsFactory> factory,
     364             :         std::shared_ptr<shared_model::interface::BlockJsonConverter> converter,
     365             :         std::shared_ptr<shared_model::interface::PermissionToString>
     366             :             perm_converter,
     367             :         logger::LoggerManagerTreePtr log_manager,
     368             :         size_t pool_size) {
     369         286 :       boost::optional<std::string> string_res = boost::none;
     370             : 
     371         286 :       PostgresOptions options(postgres_options);
     372             : 
     373             :       // create database if
     374             :       options.dbname() | [&options, &string_res](const std::string &dbname) {
     375         286 :         createDatabaseIfNotExist(dbname, options.optionsStringWithoutDbName())
     376             :             .match([](expected::Value<bool> &val) {},
     377             :                    [&string_res](expected::Error<std::string> &error) {
     378           1 :                      string_res = error.error;
     379           1 :                    });
     380         286 :       };
     381             : 
     382         286 :       if (string_res) {
     383           1 :         return expected::makeError(string_res.value());
     384             :       }
     385             : 
     386             :       auto ctx_result =
     387         285 :           initConnections(block_store_dir, log_manager->getLogger());
     388         285 :       auto db_result = initPostgresConnection(postgres_options, pool_size);
     389         285 :       expected::Result<std::shared_ptr<StorageImpl>, std::string> storage;
     390         285 :       ctx_result.match(
     391             :           [&](expected::Value<ConnectionContext> &ctx) {
     392         285 :             db_result.match(
     393             :                 [&](expected::Value<std::shared_ptr<soci::connection_pool>>
     394             :                         &connection) {
     395         285 :                   soci::session sql(*connection.value);
     396         285 :                   bool enable_prepared_transactions =
     397         285 :                       preparedTransactionsAvailable(sql);
     398         285 :                   storage = expected::makeValue(std::shared_ptr<StorageImpl>(
     399         285 :                       new StorageImpl(block_store_dir,
     400         285 :                                       options,
     401         285 :                                       std::move(ctx.value.block_store),
     402         285 :                                       connection.value,
     403         285 :                                       factory,
     404         285 :                                       converter,
     405         285 :                                       perm_converter,
     406         285 :                                       pool_size,
     407         285 :                                       enable_prepared_transactions,
     408         285 :                                       std::move(log_manager))));
     409         285 :                 },
     410             :                 [&](expected::Error<std::string> &error) { storage = error; });
     411         285 :           },
     412             :           [&](expected::Error<std::string> &error) { storage = error; });
     413         285 :       return storage;
     414         286 :     }
     415             : 
     416             :     boost::optional<std::unique_ptr<LedgerState>> StorageImpl::commit(
     417             :         std::unique_ptr<MutableStorage> mutableStorage) {
     418         546 :       auto storage_ptr = std::move(mutableStorage);  // get ownership of storage
     419         546 :       auto storage = static_cast<MutableStorageImpl *>(storage_ptr.get());
     420        1095 :       for (const auto &block : storage->block_store_) {
     421         549 :         storeBlock(*block.second);
     422             :       }
     423             :       try {
     424         546 :         *(storage->sql_) << "COMMIT";
     425         546 :         storage->committed = true;
     426         546 :         return PostgresWsvQuery(*(storage->sql_),
     427         546 :                                 factory_,
     428         546 :                                 log_manager_->getChild("WsvQuery")->getLogger())
     429         546 :                    .getPeers()
     430         546 :             |
     431             :             [](auto &&peers) {
     432         546 :               return boost::optional<std::unique_ptr<LedgerState>>(
     433         546 :                   std::make_unique<LedgerState>(
     434         546 :                       std::make_shared<PeerList>(std::move(peers))));
     435           0 :             };
     436           0 :       } catch (std::exception &e) {
     437           0 :         storage->committed = false;
     438           0 :         log_->warn("Mutable storage is not committed. Reason: {}", e.what());
     439           0 :         return boost::none;
     440           0 :       }
     441         546 :     }
     442             : 
     443             :     boost::optional<std::unique_ptr<LedgerState>> StorageImpl::commitPrepared(
     444             :         const shared_model::interface::Block &block) {
     445         723 :       if (not prepared_blocks_enabled_) {
     446           0 :         log_->warn("prepared blocks are not enabled");
     447           0 :         return boost::none;
     448             :       }
     449             : 
     450         723 :       if (not block_is_prepared) {
     451           4 :         log_->info("there are no prepared blocks");
     452           4 :         return boost::none;
     453             :       }
     454         719 :       log_->info("applying prepared block");
     455             : 
     456             :       try {
     457         719 :         std::shared_lock<std::shared_timed_mutex> lock(drop_mutex);
     458         719 :         if (not connection_) {
     459           1 :           log_->info("connection to database is not initialised");
     460           1 :           return boost::none;
     461             :         }
     462         718 :         soci::session sql(*connection_);
     463         718 :         sql << "COMMIT PREPARED '" + prepared_block_name_ + "';";
     464         718 :         PostgresBlockIndex block_index(
     465         718 :             sql, log_manager_->getChild("BlockIndex")->getLogger());
     466         718 :         block_index.index(block);
     467         718 :         block_is_prepared = false;
     468         718 :         return PostgresWsvQuery(sql,
     469         718 :                                 factory_,
     470         718 :                                 log_manager_->getChild("WsvQuery")->getLogger())
     471         718 :                        .getPeers()
     472             :                    | [this, &block](auto &&peers)
     473             :                    -> boost::optional<std::unique_ptr<LedgerState>> {
     474         718 :           if (this->storeBlock(block)) {
     475         718 :             return boost::optional<std::unique_ptr<LedgerState>>(
     476         718 :                 std::make_unique<LedgerState>(
     477         718 :                     std::make_shared<PeerList>(std::move(peers))));
     478             :           }
     479           0 :           return boost::none;
     480         718 :         };
     481         719 :       } catch (const std::exception &e) {
     482           0 :         log_->warn("failed to apply prepared block {}: {}",
     483           0 :                    block.hash().hex(),
     484           0 :                    e.what());
     485           0 :         return boost::none;
     486           0 :       }
     487         723 :     }
     488             : 
     489             :     std::shared_ptr<WsvQuery> StorageImpl::getWsvQuery() const {
     490        4602 :       std::shared_lock<std::shared_timed_mutex> lock(drop_mutex);
     491        4602 :       if (not connection_) {
     492         317 :         log_->info("connection to database is not initialised");
     493         317 :         return nullptr;
     494             :       }
     495        4285 :       return std::make_shared<PostgresWsvQuery>(
     496        4285 :           std::make_unique<soci::session>(*connection_),
     497        4285 :           factory_,
     498        4285 :           log_manager_->getChild("WsvQuery")->getLogger());
     499        4602 :     }
     500             : 
     501             :     std::shared_ptr<BlockQuery> StorageImpl::getBlockQuery() const {
     502        8152 :       std::shared_lock<std::shared_timed_mutex> lock(drop_mutex);
     503        8152 :       if (not connection_) {
     504          86 :         log_->info("connection to database is not initialised");
     505          86 :         return nullptr;
     506             :       }
     507        8064 :       return std::make_shared<PostgresBlockQuery>(
     508        8006 :           std::make_unique<soci::session>(*connection_),
     509        8067 :           *block_store_,
     510        8053 :           converter_,
     511        8053 :           log_manager_->getChild("PostgresBlockQuery")->getLogger());
     512        8138 :     }
     513             : 
     514             :     rxcpp::observable<std::shared_ptr<shared_model::interface::Block>>
     515             :     StorageImpl::on_commit() {
     516         249 :       return notifier_.get_observable();
     517           0 :     }
     518             : 
     519             :     void StorageImpl::prepareBlock(std::unique_ptr<TemporaryWsv> wsv) {
     520         727 :       auto &wsv_impl = static_cast<TemporaryWsvImpl &>(*wsv);
     521         727 :       if (not prepared_blocks_enabled_) {
     522           0 :         log_->warn("prepared block are not enabled");
     523           0 :         return;
     524             :       }
     525         727 :       if (not block_is_prepared) {
     526         727 :         soci::session &sql = *wsv_impl.sql_;
     527             :         try {
     528         727 :           sql << "PREPARE TRANSACTION '" + prepared_block_name_ + "';";
     529         727 :           block_is_prepared = true;
     530         727 :         } catch (const std::exception &e) {
     531           0 :           log_->warn("failed to prepare state: {}", e.what());
     532           0 :         }
     533             : 
     534         727 :         log_->info("state prepared successfully");
     535         727 :       }
     536         727 :     }
     537             : 
     538             :     StorageImpl::~StorageImpl() {
     539         285 :       freeConnections();
     540         285 :     }
     541             : 
     542             :     void StorageImpl::rollbackPrepared(soci::session &sql) {
     543             :       try {
     544         294 :         sql << "ROLLBACK PREPARED '" + prepared_block_name_ + "';";
     545           9 :         block_is_prepared = false;
     546         285 :       } catch (const std::exception &e) {
     547         285 :         log_->info(e.what());
     548         285 :       }
     549         294 :     }
     550             : 
     551             :     bool StorageImpl::storeBlock(const shared_model::interface::Block &block) {
     552        1267 :       auto json_result = converter_->serialize(block);
     553        1267 :       return json_result.match(
     554             :           [this, &block](const expected::Value<std::string> &v) {
     555        1267 :             block_store_->add(block.height(), stringToBytes(v.value));
     556        1267 :             notifier_.get_subscriber().on_next(clone(block));
     557        1267 :             return true;
     558           0 :           },
     559             :           [this](const expected::Error<std::string> &e) {
     560           0 :             log_->error(e.error);
     561           0 :             return false;
     562             :           });
     563        1267 :     }
     564             : 
     565             :     const std::string &StorageImpl::drop_ = R"(
     566             : DROP TABLE IF EXISTS account_has_signatory;
     567             : DROP TABLE IF EXISTS account_has_asset;
     568             : DROP TABLE IF EXISTS role_has_permissions CASCADE;
     569             : DROP TABLE IF EXISTS account_has_roles;
     570             : DROP TABLE IF EXISTS account_has_grantable_permissions CASCADE;
     571             : DROP TABLE IF EXISTS account;
     572             : DROP TABLE IF EXISTS asset;
     573             : DROP TABLE IF EXISTS domain;
     574             : DROP TABLE IF EXISTS signatory;
     575             : DROP TABLE IF EXISTS peer;
     576             : DROP TABLE IF EXISTS role;
     577             : DROP TABLE IF EXISTS height_by_hash;
     578             : DROP INDEX IF EXISTS tx_status_by_hash_hash_index;
     579             : DROP TABLE IF EXISTS tx_status_by_hash;
     580             : DROP TABLE IF EXISTS height_by_account_set;
     581             : DROP TABLE IF EXISTS index_by_creator_height;
     582             : DROP TABLE IF EXISTS position_by_account_asset;
     583             : )";
     584             : 
     585             :     const std::string &StorageImpl::reset_ = R"(
     586             : DELETE FROM account_has_signatory;
     587             : DELETE FROM account_has_asset;
     588             : DELETE FROM role_has_permissions CASCADE;
     589             : DELETE FROM account_has_roles;
     590             : DELETE FROM account_has_grantable_permissions CASCADE;
     591             : DELETE FROM account;
     592             : DELETE FROM asset;
     593             : DELETE FROM domain;
     594             : DELETE FROM signatory;
     595             : DELETE FROM peer;
     596             : DELETE FROM role;
     597             : DELETE FROM position_by_hash;
     598             : DELETE FROM tx_status_by_hash;
     599             : DELETE FROM height_by_account_set;
     600             : DELETE FROM index_by_creator_height;
     601             : DELETE FROM position_by_account_asset;
     602             : )";
     603             : 
     604             :     const std::string &StorageImpl::init_ =
     605          41 :         R"(
     606             : CREATE TABLE IF NOT EXISTS role (
     607             :     role_id character varying(32),
     608             :     PRIMARY KEY (role_id)
     609             : );
     610             : CREATE TABLE IF NOT EXISTS domain (
     611             :     domain_id character varying(255),
     612             :     default_role character varying(32) NOT NULL REFERENCES role(role_id),
     613             :     PRIMARY KEY (domain_id)
     614             : );
     615             : CREATE TABLE IF NOT EXISTS signatory (
     616             :     public_key varchar NOT NULL,
     617             :     PRIMARY KEY (public_key)
     618             : );
     619             : CREATE TABLE IF NOT EXISTS account (
     620             :     account_id character varying(288),
     621             :     domain_id character varying(255) NOT NULL REFERENCES domain,
     622             :     quorum int NOT NULL,
     623             :     data JSONB,
     624             :     PRIMARY KEY (account_id)
     625             : );
     626             : CREATE TABLE IF NOT EXISTS account_has_signatory (
     627             :     account_id character varying(288) NOT NULL REFERENCES account,
     628             :     public_key varchar NOT NULL REFERENCES signatory,
     629             :     PRIMARY KEY (account_id, public_key)
     630             : );
     631             : CREATE TABLE IF NOT EXISTS peer (
     632             :     public_key varchar NOT NULL,
     633             :     address character varying(261) NOT NULL UNIQUE,
     634             :     PRIMARY KEY (public_key)
     635             : );
     636             : CREATE TABLE IF NOT EXISTS asset (
     637             :     asset_id character varying(288),
     638             :     domain_id character varying(255) NOT NULL REFERENCES domain,
     639             :     precision int NOT NULL,
     640             :     data json,
     641             :     PRIMARY KEY (asset_id)
     642             : );
     643             : CREATE TABLE IF NOT EXISTS account_has_asset (
     644             :     account_id character varying(288) NOT NULL REFERENCES account,
     645             :     asset_id character varying(288) NOT NULL REFERENCES asset,
     646             :     amount decimal NOT NULL,
     647             :     PRIMARY KEY (account_id, asset_id)
     648             : );
     649             : CREATE TABLE IF NOT EXISTS role_has_permissions (
     650             :     role_id character varying(32) NOT NULL REFERENCES role,
     651             :     permission bit()"
     652          41 :         + std::to_string(shared_model::interface::RolePermissionSet::size())
     653          41 :         + R"() NOT NULL,
     654             :     PRIMARY KEY (role_id)
     655             : );
     656             : CREATE TABLE IF NOT EXISTS account_has_roles (
     657             :     account_id character varying(288) NOT NULL REFERENCES account,
     658             :     role_id character varying(32) NOT NULL REFERENCES role,
     659             :     PRIMARY KEY (account_id, role_id)
     660             : );
     661             : CREATE TABLE IF NOT EXISTS account_has_grantable_permissions (
     662             :     permittee_account_id character varying(288) NOT NULL REFERENCES account,
     663             :     account_id character varying(288) NOT NULL REFERENCES account,
     664             :     permission bit()"
     665          41 :         + std::to_string(
     666          41 :               shared_model::interface::GrantablePermissionSet::size())
     667          41 :         + R"() NOT NULL,
     668             :     PRIMARY KEY (permittee_account_id, account_id)
     669             : );
     670             : CREATE TABLE IF NOT EXISTS position_by_hash (
     671             :     hash varchar,
     672             :     height text,
     673             :     index text
     674             : );
     675             : 
     676             : CREATE TABLE IF NOT EXISTS tx_status_by_hash (
     677             :     hash varchar,
     678             :     status boolean
     679             : );
     680             : CREATE INDEX IF NOT EXISTS tx_status_by_hash_hash_index ON tx_status_by_hash USING hash (hash);
     681             : 
     682             : CREATE TABLE IF NOT EXISTS height_by_account_set (
     683             :     account_id text,
     684             :     height text
     685             : );
     686             : CREATE TABLE IF NOT EXISTS index_by_creator_height (
     687             :     id serial,
     688             :     creator_id text,
     689             :     height text,
     690             :     index text
     691             : );
     692             : CREATE TABLE IF NOT EXISTS position_by_account_asset (
     693             :     account_id text,
     694             :     asset_id text,
     695             :     height text,
     696             :     index text
     697             : );
     698             : )";
     699             :   }  // namespace ametsuchi
     700             : }  // namespace iroha

Generated by: LCOV version 1.13