/* This file is part of TON Blockchain Library. TON Blockchain Library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. TON Blockchain Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . Copyright 2017-2020 Telegram Systems LLP */ #pragma once #include "td/utils/port/path.h" #include "td/utils/filesystem.h" #include "td/actor/actor.h" #include "td/utils/buffer.h" #include "common/errorcode.h" namespace ton { namespace validator { namespace db { class WriteFile : public td::actor::Actor { public: void start_up() override { auto R = [&]() { td::uint32 cnt = 0; while (true) { cnt++; auto res = td::mkstemp(td::CSlice{tmp_dir_}); if (res.is_ok() || cnt >= 10) { return res; } } }(); if (R.is_error()) { promise_.set_error(R.move_as_error()); stop(); return; } auto res = R.move_as_ok(); auto file = std::move(res.first); auto old_name = res.second; auto status = write_data_(file); if (!status.is_error()) { status = file.sync(); } if (status.is_error()) { td::unlink(old_name).ignore(); promise_.set_error(std::move(status)); stop(); return; } if (new_name_.length() > 0) { status = td::rename(old_name, new_name_); if (status.is_error()) { promise_.set_error(std::move(status)); } else { promise_.set_value(std::move(new_name_)); } } else { promise_.set_value(std::move(old_name)); } stop(); } WriteFile(std::string tmp_dir, std::string new_name, std::function write_data, td::Promise promise) : tmp_dir_(tmp_dir), new_name_(new_name), write_data_(std::move(write_data)), promise_(std::move(promise)) { } WriteFile(std::string tmp_dir, std::string new_name, td::BufferSlice data, td::Promise promise) : tmp_dir_(tmp_dir), new_name_(new_name), promise_(std::move(promise)) { write_data_ = [data_ptr = std::make_shared(std::move(data))] (td::FileFd& fd) { auto data = std::move(*data_ptr); while (data.size() > 0) { auto piece_size = std::min(data.size(), 1 << 30); TRY_RESULT(s, fd.write(data.as_slice().substr(0, piece_size))); data.confirm_read(s); } return td::Status::OK(); }; } private: const std::string tmp_dir_; std::string new_name_; std::function write_data_; td::Promise promise_; }; class ReadFile : public td::actor::Actor { public: enum Flags : td::uint32 { f_disable_log = 1 }; void start_up() override { auto S = td::read_file(file_name_, max_length_, offset_); if (S.is_ok()) { promise_.set_result(S.move_as_ok()); } else { // TODO check error code if (flags_ & Flags::f_disable_log) { LOG(DEBUG) << "missing file " << file_name_; } else { LOG(ERROR) << "missing file " << file_name_; } promise_.set_error(td::Status::Error(ErrorCode::notready, "file does not exist")); } stop(); } ReadFile(std::string file_name, td::int64 offset, td::int64 max_length, td::uint32 flags, td::Promise promise) : file_name_(file_name), offset_(offset), max_length_(max_length), flags_(flags), promise_(std::move(promise)) { } private: std::string file_name_; td::int64 offset_; td::int64 max_length_; td::uint32 flags_; td::Promise promise_; }; } // namespace db } // namespace validator } // namespace ton