LCOV - code coverage report
Current view: top level - model - SafeFile.cpp (source / functions) Coverage Total Hit
Test: final-coverage.info Lines: 100.0 % 101 101
Test Date: 2025-02-14 17:40:40 Functions: 100.0 % 11 11

            Line data    Source code
       1              : /*
       2              :  ___________________________________________
       3              : |    _     ___                        _     |
       4              : |   | |   |__ \                      | |    |
       5              : |   | |__    ) |__ _  __ _  ___ _ __ | |_   |
       6              : |   | '_ \  / // _` |/ _` |/ _ \ '_ \| __|  |  HTTP/2 AGENT FOR MOCK TESTING
       7              : |   | | | |/ /| (_| | (_| |  __/ | | | |_   |  Version 0.0.z
       8              : |   |_| |_|____\__,_|\__, |\___|_| |_|\__|  |  https://github.com/testillano/h2agent
       9              : |                     __/ |                 |
      10              : |                    |___/                  |
      11              : |___________________________________________|
      12              : 
      13              : Licensed under the MIT License <http://opensource.org/licenses/MIT>.
      14              : SPDX-License-Identifier: MIT
      15              : Copyright (c) 2021 Eduardo Ramos
      16              : 
      17              : Permission is hereby  granted, free of charge, to any  person obtaining a copy
      18              : of this software and associated  documentation files (the "Software"), to deal
      19              : in the Software  without restriction, including without  limitation the rights
      20              : to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
      21              : copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
      22              : furnished to do so, subject to the following conditions:
      23              : 
      24              : The above copyright notice and this permission notice shall be included in all
      25              : copies or substantial portions of the Software.
      26              : 
      27              : THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
      28              : IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
      29              : FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
      30              : AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
      31              : LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      32              : OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
      33              : SOFTWARE.
      34              : */
      35              : 
      36              : #include <string>
      37              : 
      38              : #include <ert/tracing/Logger.hpp>
      39              : 
      40              : #include <SafeFile.hpp>
      41              : #include <FileManager.hpp>
      42              : #include <functions.hpp>
      43              : 
      44              : 
      45              : namespace h2agent
      46              : {
      47              : namespace model
      48              : {
      49              : 
      50              : std::atomic<int> SafeFile::CurrentOpenedFiles(0);
      51              : std::mutex SafeFile::MutexOpenedFiles;
      52              : std::condition_variable SafeFile::OpenedFilesCV;
      53              : 
      54           13 : SafeFile::SafeFile (FileManager *fileManager, const std::string& path, boost::asio::io_context *timersIoContext, std::ios_base::openmode mode):
      55           13 :     path_(path),
      56           13 :     io_context_(timersIoContext),
      57           13 :     file_manager_(fileManager),
      58           13 :     opened_(false),
      59           13 :     read_cached_(false),
      60           13 :     timer_(nullptr)
      61              : {
      62           13 :     max_open_files_ = sysconf(_SC_OPEN_MAX /* 1024 probably */) - 10 /* margin just in case the process open other files */;
      63           13 :     open(mode);
      64           13 : }
      65              : 
      66           13 : SafeFile::~SafeFile() {
      67           13 :     close();
      68           13 :     delete timer_;
      69           13 : }
      70              : 
      71            1 : void SafeFile::delayedClose(unsigned int closeDelayUs) {
      72              :     // metrics
      73            1 :     file_manager_->incrementObservedDelayedCloseOperationCounter();
      74              : 
      75              :     //if (!io_context_) return; // protection
      76            1 :     if (!timer_) timer_ = new boost::asio::steady_timer(*io_context_, std::chrono::microseconds(closeDelayUs));
      77            1 :     timer_->cancel();
      78            1 :     timer_->expires_after(std::chrono::microseconds(closeDelayUs));
      79            1 :     timer_->async_wait([this] (const boost::system::error_code& e) {
      80            1 :         if( e ) return; // probably, we were cancelled (boost::asio::error::operation_aborted)
      81            1 :         close();
      82              :     });
      83            1 : }
      84              : 
      85           41 : bool SafeFile::open(std::ios_base::openmode mode) {
      86           41 :     std::unique_lock<std::mutex> lock(MutexOpenedFiles);
      87           41 :     if (opened_) return true;
      88              : 
      89              :     //Wait until we have data or a quit signal
      90           68 :     OpenedFilesCV.wait(lock, [this]
      91              :     {
      92           34 :         return (CurrentOpenedFiles.load() < max_open_files_);
      93              :     });
      94              : 
      95              :     // After wait, we own the lock
      96           34 :     file_.open(path_, mode);
      97           34 :     if (file_.is_open()) {
      98           29 :         opened_ = true;
      99           29 :         CurrentOpenedFiles++;
     100           29 :         LOGDEBUG(ert::tracing::Logger::debug(ert::tracing::Logger::asString("'%s' opened (currently opened: %d)", path_.c_str(), CurrentOpenedFiles.load()), ERT_FILE_LOCATION));
     101              :         // metrics
     102           29 :         file_manager_->incrementObservedOpenOperationCounter();
     103              :     }
     104              :     else {
     105            5 :         LOGWARNING(ert::tracing::Logger::warning(ert::tracing::Logger::asString("Failed to open '%s'", path_.c_str()), ERT_FILE_LOCATION));
     106              :         // metrics
     107            5 :         file_manager_->incrementObservedErrorOpenOperationCounter();
     108            5 :         return false;
     109              :     }
     110              :     //lock.unlock();
     111              : 
     112           29 :     return true;
     113           41 : }
     114              : 
     115           50 : void SafeFile::close() {
     116           50 :     std::unique_lock<std::mutex> lock(MutexOpenedFiles);
     117           50 :     if (!opened_) return;
     118              : 
     119           29 :     file_.close();
     120           29 :     opened_ = false;
     121           29 :     CurrentOpenedFiles--;
     122           29 :     LOGDEBUG(ert::tracing::Logger::debug(ert::tracing::Logger::asString("'%s' closed (currently opened: %d)", path_.c_str(), CurrentOpenedFiles.load()), ERT_FILE_LOCATION));
     123              :     // metrics
     124           29 :     file_manager_->incrementObservedCloseOperationCounter();
     125              : 
     126           29 :     lock.unlock();
     127           29 :     OpenedFilesCV.notify_one();
     128           50 : }
     129              : 
     130            9 : void SafeFile::empty() {
     131            9 :     close();
     132            9 :     open(std::ofstream::out | std::ofstream::trunc);
     133            9 :     close();
     134              :     // metrics
     135            9 :     file_manager_->incrementObservedEmptyOperationCounter();
     136            9 : }
     137              : 
     138           14 : std::string SafeFile::read(bool &success, std::ios_base::openmode mode, bool cached) {
     139              : 
     140              :     // Check cached data:
     141           14 :     if (cached && read_cached_) {
     142            2 :         success = true;
     143            2 :         return data_;
     144              :     }
     145              : 
     146           12 :     std::string result;
     147           12 :     success = false;
     148              : 
     149           12 :     if (open(mode)) {
     150           10 :         success = true;
     151           10 :         std::string chunk;
     152           18 :         while (std::getline (file_, chunk))
     153              :         {
     154            8 :             result += chunk;
     155              :         }
     156           10 :         LOGDEBUG(
     157              :             std::string output;
     158              :             h2agent::model::asAsciiString(result, output);
     159              :             ert::tracing::Logger::debug(ert::tracing::Logger::asString("Read '%s': %s", path_.c_str(), output.c_str()), ERT_FILE_LOCATION);
     160              :         );
     161           10 :     }
     162              : 
     163              :     // close the file after reading it:
     164           12 :     close();
     165              : 
     166           12 :     if (cached) {
     167            1 :         read_cached_ = success;
     168            1 :         data_ = std::move(result);
     169            1 :         return data_;
     170              :     }
     171              : 
     172           11 :     return result;
     173           12 : }
     174              : 
     175            7 : nlohmann::json SafeFile::getJson() const {
     176            7 :     nlohmann::json result;
     177              : 
     178            7 :     result["path"] = path_;
     179              : 
     180            7 :     std::ifstream file( path_, std::ofstream::in | std::ios::ate | std::ios::binary); // valid also for text files
     181            7 :     std::string::size_type size = file.tellg();
     182            7 :     if (size != std::string::npos /* -1 */) {
     183            6 :         result["bytes"] = (unsigned int)size;
     184            6 :         result["state"] = (opened_ ? "opened":"closed");
     185              :     }
     186              :     else {
     187            1 :         result["state"] = "missing";
     188              :     }
     189            7 :     file.close();
     190              : 
     191            7 :     if (read_cached_) result["readCache"] = "true";
     192              : 
     193           14 :     return result;
     194            7 : }
     195              : 
     196            7 : void SafeFile::write (const std::string& data, unsigned int closeDelayUs) {
     197              :     // Open file (lazy):
     198            7 :     if (!open()) return;
     199              : 
     200              :     // trace delay
     201            7 :     LOGDEBUG(ert::tracing::Logger::debug(ert::tracing::Logger::asString("Close delay for write operation is: %lu", closeDelayUs), ERT_FILE_LOCATION));
     202              : 
     203              :     // Write file:
     204            7 :     std::lock_guard<std::mutex> lock(mutex_);
     205            7 :     file_.write(data.c_str(), data.size());
     206            7 :     LOGDEBUG(ert::tracing::Logger::debug(ert::tracing::Logger::asString("Data written into '%s'", path_.c_str()), ERT_FILE_LOCATION));
     207              : 
     208              :     // metrics
     209            7 :     file_manager_->incrementObservedWriteOperationCounter();
     210              : 
     211              :     // Close file:
     212            7 :     if (io_context_ && closeDelayUs != 0) {
     213            1 :         delayedClose(closeDelayUs);
     214              :     }
     215              :     else {
     216            6 :         close();
     217              : 
     218              :         // metrics
     219            6 :         file_manager_->incrementObservedInstantCloseOperationCounter();
     220              :     }
     221            7 : }
     222              : 
     223              : }
     224              : }
     225              : 
        

Generated by: LCOV version 2.0-1