LCOV - code coverage report
Current view: top level - irohad/ametsuchi/impl/flat_file - flat_file.cpp (source / functions) Hit Total Coverage
Test: coverage_cleared.info Lines: 69 72 95.8 %
Date: 2018-12-05 17:11:35 Functions: 17 17 100.0 %

          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/flat_file/flat_file.hpp"
       7             : 
       8             : #include <boost/filesystem.hpp>
       9             : #include <boost/range/adaptor/indexed.hpp>
      10             : #include <boost/range/algorithm/find_if.hpp>
      11             : #include <iomanip>
      12             : #include <iostream>
      13             : #include <sstream>
      14             : #include "common/files.hpp"
      15             : 
      16             : using namespace iroha::ametsuchi;
      17             : using Identifier = FlatFile::Identifier;
      18             : 
      19             : // ----------| public API |----------
      20             : 
      21             : std::string FlatFile::id_to_name(Identifier id) {
      22        3169 :   std::ostringstream os;
      23        3170 :   os << std::setw(FlatFile::DIGIT_CAPACITY) << std::setfill('0') << id;
      24        3170 :   return os.str();
      25        3170 : }
      26             : 
      27             : boost::optional<std::unique_ptr<FlatFile>> FlatFile::create(
      28             :     const std::string &path) {
      29         480 :   auto log_ = logger::log("FlatFile::create()");
      30             : 
      31         480 :   boost::system::error_code err;
      32         480 :   if (not boost::filesystem::is_directory(path, err)
      33         480 :       and not boost::filesystem::create_directory(path, err)) {
      34           1 :     log_->error("Cannot create storage dir: {}\n{}", path, err.message());
      35           1 :     return boost::none;
      36             :   }
      37             : 
      38         479 :   auto res = FlatFile::check_consistency(path);
      39         479 :   return std::make_unique<FlatFile>(*res, path, private_tag{});
      40         480 : }
      41             : 
      42             : bool FlatFile::add(Identifier id, const Bytes &block) {
      43             :   // TODO(x3medima17): Change bool to generic Result return type
      44             : 
      45        1297 :   if (id != current_id_ + 1) {
      46           4 :     log_->warn("Cannot append non-consecutive block");
      47           4 :     return false;
      48             :   }
      49             : 
      50        1293 :   auto next_id = id;
      51        1293 :   const auto file_name = boost::filesystem::path{dump_dir_} / id_to_name(id);
      52             : 
      53             :   // Write block to binary file
      54        1293 :   if (boost::filesystem::exists(file_name)) {
      55             :     // File already exist
      56           1 :     log_->warn("insertion for {} failed, because file already exists", id);
      57           1 :     return false;
      58             :   }
      59             :   // New file will be created
      60        1292 :   boost::filesystem::ofstream file(file_name.native(), std::ofstream::binary);
      61        1292 :   if (not file.is_open()) {
      62           1 :     log_->warn("Cannot open file by index {} for writing", id);
      63           1 :     return false;
      64             :   }
      65             : 
      66        1291 :   auto val_size =
      67             :       sizeof(std::remove_reference<decltype(block)>::type::value_type);
      68             : 
      69        1291 :   file.write(reinterpret_cast<const char *>(block.data()),
      70        1291 :              block.size() * val_size);
      71             : 
      72             :   // Update internals, release lock
      73        1291 :   current_id_ = next_id;
      74        1291 :   return true;
      75        1297 : }
      76             : 
      77             : boost::optional<FlatFile::Bytes> FlatFile::get(Identifier id) const {
      78             :   const auto filename =
      79        1864 :       boost::filesystem::path{dump_dir_} / FlatFile::id_to_name(id);
      80        1864 :   if (not boost::filesystem::exists(filename)) {
      81         520 :     log_->info("get({}) file not found", id);
      82             :     return boost::none;
      83             :   }
      84        1344 :   const auto fileSize = boost::filesystem::file_size(filename);
      85        1344 :   Bytes buf;
      86        1344 :   buf.resize(fileSize);
      87        1343 :   boost::filesystem::ifstream file(filename, std::ifstream::binary);
      88        1345 :   if (not file.is_open()) {
      89           0 :     log_->info("get({}) problem with opening file", id);
      90           0 :     return boost::none;
      91             :   }
      92             :   file.read(reinterpret_cast<char *>(buf.data()), fileSize);
      93        1345 :   return buf;
      94        1865 : }
      95             : 
      96             : std::string FlatFile::directory() const {
      97           1 :   return dump_dir_;
      98             : }
      99             : 
     100             : Identifier FlatFile::last_id() const {
     101        2710 :   return current_id_.load();
     102             : }
     103             : 
     104             : void FlatFile::dropAll() {
     105         922 :   iroha::remove_dir_contents(dump_dir_);
     106         922 :   auto res = FlatFile::check_consistency(dump_dir_);
     107         922 :   current_id_.store(*res);
     108         922 : }
     109             : 
     110             : // ----------| private API |----------
     111             : 
     112             : FlatFile::FlatFile(Identifier current_id,
     113             :                    const std::string &path,
     114             :                    FlatFile::private_tag)
     115         479 :     : dump_dir_(path) {
     116         479 :   log_ = logger::log("FlatFile");
     117         479 :   current_id_.store(current_id);
     118         479 : }
     119             : 
     120             : boost::optional<Identifier> FlatFile::check_consistency(
     121             :     const std::string &dump_dir) {
     122        1402 :   auto log = logger::log("FLAT_FILE");
     123             : 
     124        1402 :   if (dump_dir.empty()) {
     125           1 :     log->error("check_consistency({}), not directory", dump_dir);
     126           1 :     return boost::none;
     127             :   }
     128             : 
     129             :   auto const files = [&dump_dir] {
     130        1401 :     std::vector<boost::filesystem::path> ps;
     131        1401 :     std::copy(boost::filesystem::directory_iterator{dump_dir},
     132        1401 :               boost::filesystem::directory_iterator{},
     133        1401 :               std::back_inserter(ps));
     134        1401 :     std::sort(ps.begin(), ps.end(), std::less<boost::filesystem::path>());
     135        1401 :     return ps;
     136        1401 :   }();
     137             : 
     138        1401 :   auto const missing = boost::range::find_if(
     139             :       files | boost::adaptors::indexed(1), [](const auto &it) {
     140           8 :         return FlatFile::id_to_name(it.index()) != it.value().filename();
     141           0 :       });
     142             : 
     143        1401 :   std::for_each(
     144             :       missing.get(), files.cend(), [](const boost::filesystem::path &p) {
     145           1 :         boost::filesystem::remove(p);
     146           1 :       });
     147             : 
     148        1401 :   return missing.get() - files.cbegin();
     149        1402 : }

Generated by: LCOV version 1.13