<commit_before>#include "joedb/Readonly_Journal.h"
#include "joedb/Generic_File.h"
#include "joedb/Exception.h"

#include <vector>
#include <sstream>

const uint32_t joedb::Readonly_Journal::version_number = 0x00000004;
const uint32_t joedb::Readonly_Journal::compatible_version = 0x00000004;
const int64_t joedb::Readonly_Journal::header_size = 41;

#define FORMAT_EXCEPTION(x)\
 do {if (!ignore_errors) throw Exception(x);} while(false)

/////////////////////////////////////////////////////////////////////////////
joedb::Readonly_Journal::Readonly_Journal
/////////////////////////////////////////////////////////////////////////////
(
 Generic_File &file,
 bool ignore_errors
):
 file(file),
 checkpoint_index(0),
 checkpoint_position(0),
 table_of_last_operation(0),
 record_of_last_operation(0),
 field_of_last_update(0)
{
 //
 // Check the format of an existing joedb file
 //
 if (file.get_mode() != Open_Mode::create_new)
 {
  //
  // First, check for initial "joedb"
  //
  if (file.read<uint8_t>() != 'j' ||
      file.read<uint8_t>() != 'o' ||
      file.read<uint8_t>() != 'e' ||
      file.read<uint8_t>() != 'd' ||
      file.read<uint8_t>() != 'b')
  {
   FORMAT_EXCEPTION("File does not start by 'joedb'");
  }
  else
  {
   //
   // Check version number
   //
   const uint32_t version = file.read<uint32_t>();
   if (version < compatible_version || version > version_number)
    FORMAT_EXCEPTION("Unsupported format version");

   //
   // Find the most recent checkpoint
   //
   int64_t pos[4];
   for (int i = 0; i < 4; i++)
    pos[i] = file.read<int64_t>();

   if (pos[0] != pos[1] || pos[2] != pos[3])
    FORMAT_EXCEPTION("Checkpoint mismatch");

   checkpoint_position = 0;

   for (unsigned i = 0; i < 2; i++)
    if (pos[2 * i] == pos[2 * i + 1] && pos[2 * i] > checkpoint_position)
    {
     if (int64_t(size_t(pos[2 * i])) != pos[2 * i])
      throw Exception("size_t is too small for this file");
     checkpoint_position = pos[2 * i];
     checkpoint_index = i;
    }

   if (checkpoint_position < header_size)
    FORMAT_EXCEPTION("Checkpoint too small");

   //
   // Compare to file size (if available)
   //
   int64_t file_size = file.get_size();

   if (file_size > 0 && file_size != checkpoint_position)
    FORMAT_EXCEPTION("Checkpoint different from file size");

   if (ignore_errors)
    checkpoint_position = file_size;
  }
 }
}

#undef FORMAT_EXCEPTION

/////////////////////////////////////////////////////////////////////////////
void joedb::Readonly_Journal::replay_log(Writable &writable)
/////////////////////////////////////////////////////////////////////////////
{
 rewind();
 play_until_checkpoint(writable);
}

/////////////////////////////////////////////////////////////////////////////<commit_msg>replace ugly macro by lambda<commit_after>#include "joedb/Readonly_Journal.h"
#include "joedb/Generic_File.h"
#include "joedb/Exception.h"

#include <vector>
#include <sstream>

const uint32_t joedb::Readonly_Journal::version_number = 0x00000004;
const uint32_t joedb::Readonly_Journal::compatible_version = 0x00000004;
const int64_t joedb::Readonly_Journal::header_size = 41;

/////////////////////////////////////////////////////////////////////////////
joedb::Readonly_Journal::Readonly_Journal
/////////////////////////////////////////////////////////////////////////////
(
 Generic_File &file,
 bool ignore_errors
):
 file(file),
 checkpoint_index(0),
 checkpoint_position(0),
 table_of_last_operation(0),
 record_of_last_operation(0),
 field_of_last_update(0)
{
 auto format_exception = [ignore_errors](const char *message)
 {
  if (!ignore_errors)
   throw Exception(message);
 };

 //
 // Check the format of an existing joedb file
 //
 if (file.get_mode() != Open_Mode::create_new)
 {
  //
  // First, check for initial "joedb"
  //
  if (file.read<uint8_t>() != 'j' ||
      file.read<uint8_t>() != 'o' ||
      file.read<uint8_t>() != 'e' ||
      file.read<uint8_t>() != 'd' ||
      file.read<uint8_t>() != 'b')
  {
   format_exception("File does not start by 'joedb'");
  }
  else
  {
   //
   // Check version number
   //
   const uint32_t version = file.read<uint32_t>();
   if (version < compatible_version || version > version_number)
    format_exception("Unsupported format version");

   //
   // Find the most recent checkpoint
   //
   int64_t pos[4];
   for (int i = 0; i < 4; i++)
    pos[i] = file.read<int64_t>();

   if (pos[0] != pos[1] || pos[2] != pos[3])
    format_exception("Checkpoint mismatch");

   checkpoint_position = 0;

   for (unsigned i = 0; i < 2; i++)
    if (pos[2 * i] == pos[2 * i + 1] && pos[2 * i] > checkpoint_position)
    {
     if (int64_t(size_t(pos[2 * i])) != pos[2 * i])
      throw Exception("size_t is too small for this file");
     checkpoint_position = pos[2 * i];
     checkpoint_index = i;
    }

   if (checkpoint_position < header_size)
    format_exception("Checkpoint too small");

   //
   // Compare to file size (if available)
   //
   int64_t file_size = file.get_size();

   if (file_size > 0 && file_size != checkpoint_position)
    format_exception("Checkpoint different from file size");

   if (ignore_errors)
    checkpoint_position = file_size;
  }
 }
}

/////////////////////////////////////////////////////////////////////////////
void joedb::Readonly_Journal::replay_log(Writable &writable)
/////////////////////////////////////////////////////////////////////////////
{
 rewind();
 play_until_checkpoint(writable);
}

/////////////////////////////////////////////////////////////////////////////
{'fraction_non_alphanumeric': 0.26714801444043323, 'fraction_numerical': 0.023826714801444042, 'mean_word_length': 2.098993288590604, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 4, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6624521', 'n_tokens_mistral': 1828, 'n_tokens_neox': 1722, 'n_words': 373}