LCOV - code coverage report
Current view: top level - hdf5libs/test/apps - HDF5LIBS_TestRecoverFile.cpp (source / functions) Coverage Total Hit
Test: code.result Lines: 0.0 % 138 0
Test Date: 2025-12-21 13:07:08 Functions: 0.0 % 2 0

            Line data    Source code
       1              : /**
       2              :  * @file HDF5RecoverFile.cpp
       3              :  *
       4              :  * Preliminary utility to recover a raw data file that did not get closed properly.
       5              :  *
       6              :  * This is part of the DUNE DAQ Software Suite, copyright 2024.
       7              :  * Licensing/copyright details are in the COPYING file that you should have
       8              :  * received with this code.
       9              :  */
      10              : 
      11              : #include "hdf5libs/HDF5RawDataFile.hpp"
      12              : 
      13              : #include "daqdataformats/Fragment.hpp"
      14              : #include "daqdataformats/SourceID.hpp"
      15              : 
      16              : #include <string>
      17              : #include <sys/stat.h>
      18              : #include <time.h>
      19              : #include <unistd.h>
      20              : 
      21              : using namespace dunedaq::hdf5libs;
      22              : using namespace dunedaq::daqdataformats;
      23              : 
      24              : void
      25            0 : print_usage(const char* appname)
      26              : {
      27            0 :   std::cout << "Usage: " << appname << " [-R] <file_name>" << std::endl;
      28            0 :   std::cout << "The default behavior is to simply print out the changes that need to be made." << std::endl;
      29            0 :   std::cout << "The -R option causes the file to be modifed (Recovered)." << std::endl;
      30            0 : }
      31              : 
      32              : int
      33            0 : main(int argc, char** argv)
      34              : {
      35            0 :   bool do_recovery = false;
      36            0 :   signed char opt;
      37            0 :   while ((opt = getopt(argc, argv, "hR")) != -1) {
      38            0 :     switch (opt) {
      39            0 :       case 'h':
      40            0 :         print_usage(argv[0]);
      41              :         return 1;
      42              :       case 'R':
      43              :         do_recovery = true;
      44              :         break;
      45            0 :       default: /* '?' */
      46            0 :         print_usage(argv[0]);
      47              :         return 1;
      48              :     }
      49              :   }
      50              : 
      51            0 :   argc -= (optind - 1);
      52            0 :   argv += (optind - 1);
      53            0 :   if (argc != 2) {
      54            0 :     print_usage(argv[0]);
      55            0 :     return 1;
      56              :   }
      57              : 
      58            0 :   const std::string ifile_name = std::string(argv[1]);
      59              : 
      60              :   // open the file for reading, initially
      61            0 :   std::unique_ptr<HDF5RawDataFile> h5file_ptr(new HDF5RawDataFile(ifile_name, false));
      62              : 
      63              :   // determine a reasonable value for the file-closing time based on the Linux
      64              :   // file system last-modified time
      65            0 :   size_t last_modified_time = 0;
      66            0 :   struct stat stat_results;
      67            0 :   auto retcode = stat(ifile_name.c_str(), &stat_results);
      68            0 :   if (retcode == 0) {
      69            0 :     last_modified_time = 1000 * stat_results.st_mtime;
      70              :   } // msec
      71              : 
      72              :   // determine a reasonable value for the size of the recorded data in the file by
      73              :   // looping through all of the records and fragments
      74            0 :   size_t calculated_recorded_size = 0;
      75            0 :   auto records = h5file_ptr->get_all_record_ids();
      76            0 :   for (auto const& record_id : records) {
      77            0 :     if (h5file_ptr->is_timeslice_type()) {
      78            0 :       try {
      79            0 :         auto tsh_ptr = h5file_ptr->get_tsh_ptr(record_id);
      80            0 :         calculated_recorded_size += sizeof(*tsh_ptr);
      81            0 :       } catch (std::exception const& excpt) {
      82              :         // bad record header, we'll skip the whole TimeSlice
      83            0 :         continue;
      84            0 :       }
      85              :     } else {
      86            0 :       try {
      87            0 :         auto trh_ptr = h5file_ptr->get_trh_ptr(record_id);
      88            0 :         calculated_recorded_size += trh_ptr->get_total_size_bytes();
      89            0 :       } catch (std::exception const& excpt) {
      90              :         // bad record header, we'll skip the whole TriggerRecord
      91            0 :         continue;
      92            0 :       }
      93              :     }
      94            0 :     std::set<SourceID> frag_sid_list = h5file_ptr->get_fragment_source_ids(record_id);
      95            0 :     for (auto const& source_id : frag_sid_list) {
      96            0 :       try {
      97            0 :         auto frag_ptr = h5file_ptr->get_frag_ptr(record_id, source_id);
      98            0 :         calculated_recorded_size += frag_ptr->get_size();
      99            0 :       } catch (std::exception const& excpt) {
     100              :         // nothing to do, just leave this fragment out of the sum
     101            0 :       }
     102              :     }
     103            0 :   }
     104              : 
     105            0 :   std::vector<std::string> attr_names = h5file_ptr->get_attribute_names();
     106            0 :   bool ct_attr_exists = (std::count(attr_names.begin(), attr_names.end(), "closing_timestamp") >= 1);
     107            0 :   bool rs_attr_exists = (std::count(attr_names.begin(), attr_names.end(), "recorded_size") >= 1);
     108              : 
     109            0 :   size_t closing_timestamp = 0;
     110            0 :   if (ct_attr_exists) {
     111            0 :     if (h5file_ptr->get_file_layout().get_version() >= 6) {
     112            0 :       closing_timestamp = h5file_ptr->get_attribute<size_t>("closing_timestamp");
     113              :     } else {
     114            0 :       auto clts_string = h5file_ptr->get_attribute<std::string>("closing_timestamp");
     115            0 :       char* nds = 0;
     116            0 :       closing_timestamp = strtol(clts_string.c_str(), &nds, 10);
     117            0 :     }
     118              :   }
     119            0 :   size_t recorded_size = SIZE_MAX;
     120            0 :   if (rs_attr_exists) {
     121            0 :     recorded_size = h5file_ptr->get_attribute<size_t>("recorded_size");
     122              :   }
     123              : 
     124            0 :   std::cout << std::endl;
     125            0 :   std::cout << std::endl;
     126            0 :   std::cout << "========================================" << std::endl;
     127              : 
     128            0 :   if (do_recovery) {
     129              : 
     130              :     // re-open the file for reading and writing
     131            0 :     h5file_ptr.reset();
     132            0 :     h5file_ptr.reset(new HDF5RawDataFile(ifile_name, true));
     133              : 
     134            0 :     if (!ct_attr_exists) {
     135            0 :       if (h5file_ptr->get_file_layout().get_version() >= 6) {
     136            0 :         std::cout << "Setting the \"closing_timestamp\" Attribute value to " << last_modified_time << "." << std::endl;
     137            0 :         h5file_ptr->write_attribute("closing_timestamp", last_modified_time);
     138              :       } else {
     139            0 :         std::string file_closing_timestamp = std::to_string(last_modified_time);
     140            0 :         std::cout << "Setting the \"closing_timestamp\" Attribute value to " << file_closing_timestamp << "."
     141            0 :                   << std::endl;
     142            0 :         h5file_ptr->write_attribute("closing_timestamp", file_closing_timestamp);
     143            0 :       }
     144              :     } else {
     145            0 :       std::cout << "The \"closing_timestamp\" Attribute in the file is currently set to " << closing_timestamp
     146            0 :                 << ", and it will not be over-written." << std::endl;
     147              :     }
     148              : 
     149            0 :     if (!rs_attr_exists) {
     150            0 :       std::cout << "Setting the \"recorded_size\" Attribute value to " << calculated_recorded_size << "." << std::endl;
     151            0 :       h5file_ptr->write_attribute("recorded_size", calculated_recorded_size);
     152              :     } else {
     153            0 :       std::cout << "The \"recorded_size\" Attribute in the file is currently set to " << recorded_size
     154            0 :                 << ", and it will not be over-written." << std::endl;
     155              :     }
     156              : 
     157            0 :     if (std::count(attr_names.begin(), attr_names.end(), "file_recovery_timestamp") == 0) {
     158            0 :       int64_t timestamp =
     159            0 :         std::chrono::duration_cast<std::chrono::milliseconds>(system_clock::now().time_since_epoch()).count();
     160            0 :       std::cout << "Setting the \"file_recovery_timestamp\" Attribute value to " << timestamp << "." << std::endl;
     161            0 :       h5file_ptr->write_attribute("file_recovery_timestamp", timestamp);
     162              :     } else {
     163            0 :       size_t fr_timestamp = h5file_ptr->get_attribute<size_t>("file_recovery_timestamp");
     164            0 :       std::cout << "The \"file_recovery_timestamp\" Attribute in the file is currently set to " << fr_timestamp
     165            0 :                 << ", and it will not be over-written." << std::endl;
     166              :     }
     167              : 
     168              :     // the HDF5RawDataFile Destructor will handle the file renaming, if that is needed.
     169              : 
     170              :   } else {
     171              : 
     172            0 :     if (std::count(attr_names.begin(), attr_names.end(), "creation_timestamp") == 0) {
     173            0 :       std::cout << "The \"creation_timestamp\" Attribute is *not* currently set in the file." << std::endl;
     174              :     } else {
     175            0 :       size_t creation_timestamp = 0;
     176            0 :       if (h5file_ptr->get_file_layout().get_version() >= 6) {
     177            0 :         creation_timestamp = h5file_ptr->get_attribute<size_t>("creation_timestamp");
     178              :       } else {
     179            0 :         auto crts_string = h5file_ptr->get_attribute<std::string>("creation_timestamp");
     180            0 :         char* nds = 0;
     181            0 :         creation_timestamp = strtol(crts_string.c_str(), &nds, 10);
     182            0 :       }
     183            0 :       time_t tmp_time = creation_timestamp / 1000;
     184            0 :       tm* gmtm = gmtime(&tmp_time);
     185            0 :       std::cout << "The \"creation_timestamp\" Attribute in the file is currently set to " << creation_timestamp << ","
     186            0 :                 << std::endl
     187            0 :                 << "    which corresponds to (UTC) " << asctime(gmtm);
     188              :     }
     189              : 
     190            0 :     if (!ct_attr_exists) {
     191            0 :       std::cout << "The \"closing_timestamp\" Attribute is *not* currently set in the file, and it will be "
     192            0 :                 << std::endl
     193            0 :                 << "    set to " << last_modified_time << " if/when the file is recovered." << std::endl;
     194              :     } else {
     195            0 :       time_t tmp_time = closing_timestamp / 1000;
     196            0 :       tm* gmtm = gmtime(&tmp_time);
     197            0 :       std::cout << "The \"closing_timestamp\" Attribute in the file is currently set to " << closing_timestamp << ","
     198            0 :                 << std::endl
     199            0 :                 << "    which corresponds to (UTC) " << asctime(gmtm) // no std::endl needed with asctime()
     200            0 :                 << "    (The recalculated closing time is " << last_modified_time << ".)" << std::endl;
     201              :     }
     202              : 
     203            0 :     if (!rs_attr_exists) {
     204            0 :       std::cout << "The \"recorded_size\" Attribute is *not* currently set in the file, and it will be " << std::endl
     205            0 :                 << "    set to " << calculated_recorded_size << " if/when the file is recovered." << std::endl;
     206              :     } else {
     207            0 :       std::cout << "The \"recorded_size\" Attribute in the file is currently set to " << recorded_size << "."
     208            0 :                 << std::endl
     209            0 :                 << "    (The recalculated recorded size is " << calculated_recorded_size << ".)" << std::endl;
     210              :     }
     211              : 
     212            0 :     if (std::count(attr_names.begin(), attr_names.end(), "file_recovery_timestamp") == 0) {
     213            0 :       std::cout << "The \"file_recovery_timestamp\" Attribute is *not* currently set in the file." << std::endl;
     214              :     } else {
     215            0 :       size_t fr_timestamp = h5file_ptr->get_attribute<size_t>("file_recovery_timestamp");
     216            0 :       time_t tmp_time = fr_timestamp / 1000;
     217            0 :       tm* gmtm = gmtime(&tmp_time);
     218            0 :       std::cout << "The \"file_recovery_timestamp\" Attribute in the file is currently set to " << fr_timestamp << ","
     219            0 :                 << std::endl
     220            0 :                 << "    which corresponds to (UTC) " << asctime(gmtm);
     221              :     }
     222              : 
     223            0 :     if (ifile_name.rfind(HDF5RawDataFile::s_inprogress_suffix) != std::string::npos) {
     224            0 :       std::cout << "The file *does* have the \"" << HDF5RawDataFile::s_inprogress_suffix << "\" suffix, "
     225            0 :                 << "so it will be renamed if/when it is recovered." << std::endl;
     226              :     } else {
     227            0 :       std::cout << "The file name does not have the \"" << HDF5RawDataFile::s_inprogress_suffix << "\" suffix, "
     228            0 :                 << "so it will not be renamed." << std::endl;
     229              :     }
     230              :   }
     231              : 
     232            0 :   return 0;
     233              : } // NOLINT
        

Generated by: LCOV version 2.0-1