LCOV - code coverage report
Current view: top level - irohad/ametsuchi/impl/flat_file - flat_file.cpp (source / functions) Hit Total Coverage
Test: cleared_cor.info Lines: 68 71 95.8 %
Date: 2019-03-07 14:46:43 Functions: 13 13 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 <ciso646>
       9             : #include <iomanip>
      10             : #include <iostream>
      11             : #include <sstream>
      12             : 
      13             : #include <boost/filesystem.hpp>
      14             : #include <boost/range/adaptor/indexed.hpp>
      15             : #include <boost/range/algorithm/find_if.hpp>
      16             : #include "common/files.hpp"
      17             : #include "logger/logger.hpp"
      18             : 
      19             : using namespace iroha::ametsuchi;
      20             : using Identifier = FlatFile::Identifier;
      21             : 
      22             : // ----------| public API |----------
      23             : 
      24             : std::string FlatFile::id_to_name(Identifier id) {
      25        3422 :   std::ostringstream os;
      26        3422 :   os << std::setw(FlatFile::DIGIT_CAPACITY) << std::setfill('0') << id;
      27        3422 :   return os.str();
      28        3422 : }
      29             : 
      30             : boost::optional<std::unique_ptr<FlatFile>> FlatFile::create(
      31             :     const std::string &path,
      32             :     logger::LoggerPtr log) {
      33         333 :   boost::system::error_code err;
      34         333 :   if (not boost::filesystem::is_directory(path, err)
      35         333 :       and not boost::filesystem::create_directory(path, err)) {
      36           1 :     log->error("Cannot create storage dir: {}\n{}", path, err.message());
      37           1 :     return boost::none;
      38             :   }
      39             : 
      40         332 :   auto res = FlatFile::check_consistency(path, log);
      41         332 :   return std::make_unique<FlatFile>(*res, path, private_tag{}, std::move(log));
      42         333 : }
      43             : 
      44             : bool FlatFile::add(Identifier id, const Bytes &block) {
      45             :   // TODO(x3medima17): Change bool to generic Result return type
      46             : 
      47        1304 :   if (id != current_id_ + 1) {
      48           4 :     log_->warn("Cannot append non-consecutive block");
      49           4 :     return false;
      50             :   }
      51             : 
      52        1300 :   auto next_id = id;
      53        1300 :   const auto file_name = boost::filesystem::path{dump_dir_} / id_to_name(id);
      54             : 
      55             :   // Write block to binary file
      56        1300 :   if (boost::filesystem::exists(file_name)) {
      57             :     // File already exist
      58           1 :     log_->warn("insertion for {} failed, because file already exists", id);
      59           1 :     return false;
      60             :   }
      61             :   // New file will be created
      62        1299 :   boost::filesystem::ofstream file(file_name.native(), std::ofstream::binary);
      63        1299 :   if (not file.is_open()) {
      64           1 :     log_->warn("Cannot open file by index {} for writing", id);
      65           1 :     return false;
      66             :   }
      67             : 
      68        1298 :   auto val_size =
      69             :       sizeof(std::remove_reference<decltype(block)>::type::value_type);
      70             : 
      71        1298 :   file.write(reinterpret_cast<const char *>(block.data()),
      72        1298 :              block.size() * val_size);
      73             : 
      74             :   // Update internals, release lock
      75        1298 :   current_id_ = next_id;
      76        1298 :   return true;
      77        1304 : }
      78             : 
      79             : boost::optional<FlatFile::Bytes> FlatFile::get(Identifier id) const {
      80             :   const auto filename =
      81        2110 :       boost::filesystem::path{dump_dir_} / FlatFile::id_to_name(id);
      82        2109 :   if (not boost::filesystem::exists(filename)) {
      83         533 :     log_->info("get({}) file not found", id);
      84         533 :     return boost::none;
      85             :   }
      86        1577 :   const auto fileSize = boost::filesystem::file_size(filename);
      87        1576 :   Bytes buf;
      88        1576 :   buf.resize(fileSize);
      89        1575 :   boost::filesystem::ifstream file(filename, std::ifstream::binary);
      90        1576 :   if (not file.is_open()) {
      91           0 :     log_->info("get({}) problem with opening file", id);
      92           0 :     return boost::none;
      93             :   }
      94        1575 :   file.read(reinterpret_cast<char *>(buf.data()), fileSize);
      95        1577 :   return buf;
      96        2110 : }
      97             : 
      98             : std::string FlatFile::directory() const {
      99           1 :   return dump_dir_;
     100             : }
     101             : 
     102             : Identifier FlatFile::last_id() const {
     103        3248 :   return current_id_.load();
     104             : }
     105             : 
     106             : void FlatFile::dropAll() {
     107         940 :   iroha::remove_dir_contents(dump_dir_, log_);
     108         940 :   auto res = FlatFile::check_consistency(dump_dir_, log_);
     109         940 :   current_id_.store(*res);
     110         940 : }
     111             : 
     112             : // ----------| private API |----------
     113             : 
     114             : FlatFile::FlatFile(Identifier current_id,
     115             :                    const std::string &path,
     116             :                    FlatFile::private_tag,
     117             :                    logger::LoggerPtr log)
     118         332 :     : dump_dir_(path), log_{std::move(log)} {
     119         332 :   current_id_.store(current_id);
     120         332 : }
     121             : 
     122             : boost::optional<Identifier> FlatFile::check_consistency(
     123             :     const std::string &dump_dir, logger::LoggerPtr log) {
     124        1273 :   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        1272 :     std::vector<boost::filesystem::path> ps;
     131        1272 :     std::copy(boost::filesystem::directory_iterator{dump_dir},
     132        1272 :               boost::filesystem::directory_iterator{},
     133        1272 :               std::back_inserter(ps));
     134        1272 :     std::sort(ps.begin(), ps.end(), std::less<boost::filesystem::path>());
     135        1272 :     return ps;
     136        1272 :   }();
     137             : 
     138        1272 :   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        1272 :   std::for_each(
     144             :       missing.get(), files.cend(), [](const boost::filesystem::path &p) {
     145           1 :         boost::filesystem::remove(p);
     146           1 :       });
     147             : 
     148        1272 :   return missing.get() - files.cbegin();
     149        1273 : }

Generated by: LCOV version 1.13