<commit_before>/**
 * This file is part of the CernVM file system.
 */

#include <fcntl.h>
#include <cerrno>
#include <cassert>

#include "platform.h"
#include "logging.h"

namespace sqlite {


template <class DerivedT>
Database<DerivedT>::Database(const std::string  &filename,
                             const OpenMode      open_mode) :
  sqlite_db_(NULL),
  db_file_guard_(filename, UnlinkGuard::kDisabled),
  read_write_(kOpenReadWrite == open_mode),
  schema_version_(0.0f),
  schema_revision_(0) {}


template <class DerivedT>
DerivedT* Database<DerivedT>::Create(const std::string &filename) {
  UniquePtr<DerivedT> database(new DerivedT(filename, kOpenReadWrite));

  if (! database.IsValid()) {
    LogCvmfs(kLogSql, kLogDebug, "Failed to create new database object");
    return NULL;
  }

  database->set_schema_version(DerivedT::kLatestSchema);
  database->set_schema_revision(DerivedT::kLatestSchemaRevision);

  const int open_flags = SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_READWRITE |
                         SQLITE_OPEN_CREATE;
  if (! database->OpenDatabase(open_flags)) {
    LogCvmfs(kLogSql, kLogDebug, "Failed to create new database file");
    return NULL;
  }

  if (! database->CreatePropertiesTable()) {
    database->PrintSqlError("Failed to create common properties table");
    return NULL;
  }

  if (! database->CreateEmptyDatabase()) {
    database->PrintSqlError("Failed to create empty database");
    return NULL;
  }

  if (! database->PrepareCommonQueries()) {
    database->PrintSqlError("Failed to initialize properties queries");
    return NULL;
  }

  if (! database->StoreSchemaRevision()) {
    database->PrintSqlError("Failed to store initial schema revision");
    return NULL;
  }

  return database.Release();
}


template <class DerivedT>
DerivedT* Database<DerivedT>::Open(const std::string  &filename,
                                   const OpenMode      open_mode) {
  UniquePtr<DerivedT> database(new DerivedT(filename, open_mode));

  if (! database.IsValid()) {
    LogCvmfs(kLogSql, kLogDebug, "Failed to open database file '%s' - errno: %d",
             filename.c_str(), errno);
    return NULL;
  }

  if (! database->Initialize()) {
    return NULL;
  }

  return database.Release();
}


template <class DerivedT>
bool Database<DerivedT>::Initialize() {
  const int flags = (read_write_) ? SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_READWRITE
                                  : SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_READONLY;

  const bool successful =
    OpenDatabase(flags) &&
    Configure()         &&
    FileReadAhead()     &&
    PrepareCommonQueries();
  if (! successful) {
    LogCvmfs(kLogSql, kLogDebug, "failed to open database file '%s'",
                                 filename().c_str());
    return false;
  }

  ReadSchemaRevision();
  LogCvmfs(kLogSql, kLogDebug, "opened database with schema version %f "
                               "and revision %u",
                               schema_version_, schema_revision_);

  if (! static_cast<DerivedT*>(this)->CheckSchemaCompatibility()) {
    LogCvmfs(kLogSql, kLogDebug, "schema version %f not supported (%s)",
             schema_version_, filename().c_str());
    return false;
  }

  if (read_write_ &&
      ! static_cast<DerivedT*>(this)->LiveSchemaUpgradeIfNecessary()) {
    LogCvmfs(kLogSql, kLogDebug, "failed tp upgrade schema revision");
    return false;
  }

  return true;
}


template <class DerivedT>
bool Database<DerivedT>::OpenDatabase(const int flags) {
  // Open database file (depending on the flags read-only or read-write)
  LogCvmfs(kLogSql, kLogDebug, "opening database file %s",
           filename().c_str());
  if (SQLITE_OK != sqlite3_open_v2(filename().c_str(), &sqlite_db_, flags, NULL))
  {
    LogCvmfs(kLogSql, kLogDebug, "cannot open database file %s",
             filename().c_str());
    return false;
  }

  const int retval = sqlite3_extended_result_codes(sqlite_db_, 1);
  assert (SQLITE_OK == retval);

  return true;
}


template <class DerivedT>
Database<DerivedT>::~Database() {
  if (NULL != sqlite_db_) {
    sqlite3_close(sqlite_db_);
    sqlite_db_ = NULL;
  }
}


template <class DerivedT>
bool Database<DerivedT>::Configure() {
  // Read-only databases should store temporary files in memory.  This avoids
  // unexpected open read-write file descriptors in the cache directory like
  // etilqs_<number>.
  if (!read_write_) {
    return Sql(sqlite_db_ , "PRAGMA temp_store=2;").Execute();
  }
  return true;
}


template <class DerivedT>
bool Database<DerivedT>::FileReadAhead() {
  // Read-ahead into file system buffers
  // TODO: mmap, re-readahead
  int fd_readahead = open(filename().c_str(), O_RDONLY);
  if (fd_readahead < 0) {
    LogCvmfs(kLogSql, kLogDebug, "failed to open %s for read-ahead (%d)",
             filename().c_str(), errno);
    return false;
  }<commit_msg>FIX: use sqlite3_close_v2() to properly close databases<commit_after>/**
 * This file is part of the CernVM file system.
 */

#include <fcntl.h>
#include <cerrno>
#include <cassert>

#include "platform.h"
#include "logging.h"

namespace sqlite {


template <class DerivedT>
Database<DerivedT>::Database(const std::string  &filename,
                             const OpenMode      open_mode) :
  sqlite_db_(NULL),
  db_file_guard_(filename, UnlinkGuard::kDisabled),
  read_write_(kOpenReadWrite == open_mode),
  schema_version_(0.0f),
  schema_revision_(0) {}


template <class DerivedT>
DerivedT* Database<DerivedT>::Create(const std::string &filename) {
  UniquePtr<DerivedT> database(new DerivedT(filename, kOpenReadWrite));

  if (! database.IsValid()) {
    LogCvmfs(kLogSql, kLogDebug, "Failed to create new database object");
    return NULL;
  }

  database->set_schema_version(DerivedT::kLatestSchema);
  database->set_schema_revision(DerivedT::kLatestSchemaRevision);

  const int open_flags = SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_READWRITE |
                         SQLITE_OPEN_CREATE;
  if (! database->OpenDatabase(open_flags)) {
    LogCvmfs(kLogSql, kLogDebug, "Failed to create new database file");
    return NULL;
  }

  if (! database->CreatePropertiesTable()) {
    database->PrintSqlError("Failed to create common properties table");
    return NULL;
  }

  if (! database->CreateEmptyDatabase()) {
    database->PrintSqlError("Failed to create empty database");
    return NULL;
  }

  if (! database->PrepareCommonQueries()) {
    database->PrintSqlError("Failed to initialize properties queries");
    return NULL;
  }

  if (! database->StoreSchemaRevision()) {
    database->PrintSqlError("Failed to store initial schema revision");
    return NULL;
  }

  return database.Release();
}


template <class DerivedT>
DerivedT* Database<DerivedT>::Open(const std::string  &filename,
                                   const OpenMode      open_mode) {
  UniquePtr<DerivedT> database(new DerivedT(filename, open_mode));

  if (! database.IsValid()) {
    LogCvmfs(kLogSql, kLogDebug, "Failed to open database file '%s' - errno: %d",
             filename.c_str(), errno);
    return NULL;
  }

  if (! database->Initialize()) {
    return NULL;
  }

  return database.Release();
}


template <class DerivedT>
bool Database<DerivedT>::Initialize() {
  const int flags = (read_write_) ? SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_READWRITE
                                  : SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_READONLY;

  const bool successful =
    OpenDatabase(flags) &&
    Configure()         &&
    FileReadAhead()     &&
    PrepareCommonQueries();
  if (! successful) {
    LogCvmfs(kLogSql, kLogDebug, "failed to open database file '%s'",
                                 filename().c_str());
    return false;
  }

  ReadSchemaRevision();
  LogCvmfs(kLogSql, kLogDebug, "opened database with schema version %f "
                               "and revision %u",
                               schema_version_, schema_revision_);

  if (! static_cast<DerivedT*>(this)->CheckSchemaCompatibility()) {
    LogCvmfs(kLogSql, kLogDebug, "schema version %f not supported (%s)",
             schema_version_, filename().c_str());
    return false;
  }

  if (read_write_ &&
      ! static_cast<DerivedT*>(this)->LiveSchemaUpgradeIfNecessary()) {
    LogCvmfs(kLogSql, kLogDebug, "failed tp upgrade schema revision");
    return false;
  }

  return true;
}


template <class DerivedT>
bool Database<DerivedT>::OpenDatabase(const int flags) {
  // Open database file (depending on the flags read-only or read-write)
  LogCvmfs(kLogSql, kLogDebug, "opening database file %s",
           filename().c_str());
  if (SQLITE_OK != sqlite3_open_v2(filename().c_str(), &sqlite_db_, flags, NULL))
  {
    LogCvmfs(kLogSql, kLogDebug, "cannot open database file %s",
             filename().c_str());
    return false;
  }

  const int retval = sqlite3_extended_result_codes(sqlite_db_, 1);
  assert (SQLITE_OK == retval);

  return true;
}


template <class DerivedT>
Database<DerivedT>::~Database() {
  if (NULL != sqlite_db_) {
    sqlite3_close_v2(sqlite_db_);
    sqlite_db_ = NULL;
  }
}


template <class DerivedT>
bool Database<DerivedT>::Configure() {
  // Read-only databases should store temporary files in memory.  This avoids
  // unexpected open read-write file descriptors in the cache directory like
  // etilqs_<number>.
  if (!read_write_) {
    return Sql(sqlite_db_ , "PRAGMA temp_store=2;").Execute();
  }
  return true;
}


template <class DerivedT>
bool Database<DerivedT>::FileReadAhead() {
  // Read-ahead into file system buffers
  // TODO: mmap, re-readahead
  int fd_readahead = open(filename().c_str(), O_RDONLY);
  if (fd_readahead < 0) {
    LogCvmfs(kLogSql, kLogDebug, "failed to open %s for read-ahead (%d)",
             filename().c_str(), errno);
    return false;
  }
{'fraction_non_alphanumeric': 0.120942140296979, 'fraction_numerical': 0.0023553507424475166, 'mean_word_length': 3.417005879692447, 'pattern_counts': {'":': 0, '<': 53, '<?xml version=': 0, '>': 79, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5583562', 'n_tokens_mistral': 3132, 'n_tokens_neox': 2996, 'n_words': 726}