Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/MariaDB/storage/mroonga/lib/   (MariaDB Server Version 8.1-8.4©)  Datei vom 1.9.2026 mit Größe 10 kB image not shown  

Quelle  mrn_database_manager.cpp   Sprache: C

 

/* -*- c-basic-offset: 2 -*- */
/*
  Copyright(C) 2010 Tetsuro IKEDA
  Copyright(C) 2010-2013 Kentoku SHIBA
  Copyright(C) 2011-2015 Kouhei Sutou <kou@clear-code.com>

  This 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.1 of the License, or (at your option) any later version.

  This 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 this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1335  USA
*/


#include <mrn_mysql.h>

#include "mrn_database_manager.hpp"
#include "mrn_encoding.hpp"
#include "mrn_lock.hpp"
#include "mrn_path_mapper.hpp"

#include <groonga/plugin.h>

// for debug
#define MRN_CLASS_NAME "mrn::DatabaseManager"

#ifdef WIN32
#  include <direct.h>
#  define MRN_MKDIR(pathname, mode) _mkdir((pathname))
#else
#  include <dirent.h>
#  include <unistd.h>
#  define MRN_MKDIR(pathname, mode) mkdir((pathname), (mode))
#endif

extern "C" {
  grn_rc GRN_PLUGIN_IMPL_NAME_TAGGED(init, normalizers_mysql)(grn_ctx *ctx);
  grn_rc GRN_PLUGIN_IMPL_NAME_TAGGED(register, normalizers_mysql)(grn_ctx *ctx);
}

namespace mrn {
  DatabaseManager::DatabaseManager(grn_ctx *ctx, mysql_mutex_t *mutex)
    : ctx_(ctx),
      cache_(NULL),
      mutex_(mutex) {
  }

  DatabaseManager::~DatabaseManager(void) {
    if (cache_) {
      void *db_address;
      GRN_HASH_EACH(ctx_, cache_, id, NULL, 0, &db_address, {
        Database *db;
        memcpy(&db, db_address, sizeof(grn_obj *));
        delete db;
      });
      grn_hash_close(ctx_, cache_);
    }
  }

  bool DatabaseManager::init(void) {
    MRN_DBUG_ENTER_METHOD();
    cache_ = grn_hash_create(ctx_,
                             NULL,
                             GRN_TABLE_MAX_KEY_SIZE,
                             sizeof(grn_obj *),
                             GRN_OBJ_KEY_VAR_SIZE);
    if (!cache_) {
      GRN_LOG(ctx_, GRN_LOG_ERROR,
              "failed to initialize hash table for caching opened databases");
      DBUG_RETURN(false);
    }

    DBUG_RETURN(true);
  }

  int DatabaseManager::open(const char *path, Database **db) {
    MRN_DBUG_ENTER_METHOD();

    int error = 0;
    *db = NULL;

    mrn::PathMapper mapper(path);
    mrn::Lock lock(mutex_);

    error = mrn::encoding::set(ctx_, system_charset_info);
    if (error) {
      DBUG_RETURN(error);
    }

    grn_id id;
    void *db_address;
    id = grn_hash_get(ctx_, cache_,
                      mapper.db_name(), strlen(mapper.db_name()),
                      &db_address);
    if (id == GRN_ID_NIL) {
      grn_obj *grn_db;
      struct stat db_stat;
      if (stat(mapper.db_path(), &db_stat)) {
        GRN_LOG(ctx_, GRN_LOG_INFO,
                "database not found. creating...: <%s>", mapper.db_path());
        if (path[0] == FN_CURLIB &&
            mrn_is_directory_separator(path[1])) {
          ensure_database_directory();
        }
        grn_db = grn_db_create(ctx_, mapper.db_path(), NULL);
        if (ctx_->rc) {
          error = ER_CANT_CREATE_TABLE;
          my_message(error, ctx_->errbuf, MYF(0));
          DBUG_RETURN(error);
        }
      } else {
        grn_db = grn_db_open(ctx_, mapper.db_path());
        if (ctx_->rc) {
          error = ER_CANT_OPEN_FILE;
          my_message(error, ctx_->errbuf, MYF(0));
          DBUG_RETURN(error);
        }
      }
      *db = new Database(ctx_, grn_db);
      grn_hash_add(ctx_, cache_,
                   mapper.db_name(), strlen(mapper.db_name()),
                   &db_address, NULL);
      memcpy(db_address, db, sizeof(Database *));
      error = ensure_normalizers_registered((*db)->get());
      if (!error) {
        if ((*db)->is_broken()) {
          error = ER_CANT_OPEN_FILE;
          char error_message[MRN_MESSAGE_BUFFER_SIZE];
          snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
                   "mroonga: database: open: "
                   "The database maybe broken. "
                   "We recommend you to recreate the database. "
                   "If the database isn't broken, "
                   "you can remove this error by running "
                   "'groonga %s table_remove mroonga_operations' "
                   "on server. But the latter isn't recommended.",
                   mapper.db_path());
          my_message(error, error_message, MYF(0));
        }
      }
    } else {
      memcpy(db, db_address, sizeof(Database *));
      grn_ctx_use(ctx_, (*db)->get());
    }

    DBUG_RETURN(error);
  }

  void DatabaseManager::close(const char *path) {
    MRN_DBUG_ENTER_METHOD();

    mrn::PathMapper mapper(path);
    mrn::Lock lock(mutex_);

    grn_id id;
    void *db_address;
    id = grn_hash_get(ctx_, cache_,
                      mapper.db_name(), strlen(mapper.db_name()),
                      &db_address);
    if (id == GRN_ID_NIL) {
      DBUG_VOID_RETURN;
    }

    Database *db = NULL;
    memcpy(&db, db_address, sizeof(Database *));
    grn_ctx_use(ctx_, db->get());
    if (db) {
      delete db;
    }

    grn_hash_delete_by_id(ctx_, cache_, id, NULL);

    DBUG_VOID_RETURN;
  }

  bool DatabaseManager::drop(const char *path) {
    MRN_DBUG_ENTER_METHOD();

    mrn::PathMapper mapper(path);
    mrn::Lock lock(mutex_);

    grn_id id;
    void *db_address;
    id = grn_hash_get(ctx_, cache_,
                      mapper.db_name(), strlen(mapper.db_name()),
                      &db_address);

    Database *db = NULL;
    if (id == GRN_ID_NIL) {
      struct stat dummy;
      if (stat(mapper.db_path(), &dummy) == 0) {
        grn_obj *grn_db = grn_db_open(ctx_, mapper.db_path());
        db = new Database(ctx_, grn_db);
      }
    } else {
      memcpy(&db, db_address, sizeof(Database *));
      grn_ctx_use(ctx_, db->get());
    }

    if (!db) {
      DBUG_RETURN(false);
    }

    if (db->remove() == GRN_SUCCESS) {
      if (id != GRN_ID_NIL) {
        grn_hash_delete_by_id(ctx_, cache_, id, NULL);
      }
      delete db;
      DBUG_RETURN(true);
    } else {
      GRN_LOG(ctx_, GRN_LOG_ERROR,
              "failed to drop database: <%s>: <%s>",
              mapper.db_path(), ctx_->errbuf);
      if (id == GRN_ID_NIL) {
        delete db;
      }
      DBUG_RETURN(false);
    }
  }

  int DatabaseManager::clear(void) {
    MRN_DBUG_ENTER_METHOD();

    int error = 0;

    mrn::Lock lock(mutex_);

    grn_hash_cursor *cursor;
    cursor = grn_hash_cursor_open(ctx_, cache_,
                                  NULL, 0, NULL, 0,
                                  0, -1, 0);
    if (ctx_->rc) {
      my_message(ER_ERROR_ON_READ, ctx_->errbuf, MYF(0));
      DBUG_RETURN(ER_ERROR_ON_READ);
    }

    while (grn_hash_cursor_next(ctx_, cursor) != GRN_ID_NIL) {
      if (ctx_->rc) {
        error = ER_ERROR_ON_READ;
        my_message(error, ctx_->errbuf, MYF(0));
        break;
      }
      void *db_address;
      Database *db;
      grn_hash_cursor_get_value(ctx_, cursor, &db_address);
      memcpy(&db, db_address, sizeof(Database *));
      grn_ctx_use(ctx_, db->get());
      grn_rc rc = grn_hash_cursor_delete(ctx_, cursor, NULL);
      if (rc) {
        error = ER_ERROR_ON_READ;
        my_message(error, ctx_->errbuf, MYF(0));
        break;
      }
      delete db;
    }
    grn_hash_cursor_close(ctx_, cursor);

    DBUG_RETURN(error);
  }

  const char *DatabaseManager::error_message() {
    MRN_DBUG_ENTER_METHOD();
    DBUG_RETURN(ctx_->errbuf);
  }

  void DatabaseManager::mkdir_p(const char *directory) {
    MRN_DBUG_ENTER_METHOD();

    int i = 0;
    char sub_directory[MRN_MAX_PATH_SIZE];
    sub_directory[0] = '\0';
    while (true) {
      if (mrn_is_directory_separator(directory[i]) ||
          directory[i] == '\0') {
        sub_directory[i] = '\0';
        struct stat directory_status;
        if (stat(sub_directory, &directory_status) != 0) {
          DBUG_PRINT("info", ("mroonga: creating directory: <%s>", sub_directory));
          GRN_LOG(ctx_, GRN_LOG_INFO, "creating directory: <%s>", sub_directory);
          if (MRN_MKDIR(sub_directory, S_IRWXU) == 0) {
            DBUG_PRINT("info",
                       ("mroonga: created directory: <%s>", sub_directory));
            GRN_LOG(ctx_, GRN_LOG_INFO, "created directory: <%s>", sub_directory);
          } else {
            DBUG_PRINT("error",
                       ("mroonga: failed to create directory: <%s>: <%s>",
                        sub_directory, strerror(errno)));
            GRN_LOG(ctx_, GRN_LOG_ERROR,
                    "failed to create directory: <%s>: <%s>",
                    sub_directory, strerror(errno));
            DBUG_VOID_RETURN;
          }
        }
      }

      if (directory[i] == '\0') {
        break;
      }

      sub_directory[i] = directory[i];
      ++i;
    }

    DBUG_VOID_RETURN;
  }

  void DatabaseManager::ensure_database_directory(void) {
    MRN_DBUG_ENTER_METHOD();

    const char *path_prefix = mrn::PathMapper::default_path_prefix;
    if (!path_prefix)
      DBUG_VOID_RETURN;

    const char *last_path_separator;
    last_path_separator = strrchr(path_prefix, FN_LIBCHAR);
#ifdef FN_LIBCHAR2
    if (!last_path_separator)
      last_path_separator = strrchr(path_prefix, FN_LIBCHAR2);
#endif
    if (!last_path_separator)
      DBUG_VOID_RETURN;
    if (path_prefix == last_path_separator)
      DBUG_VOID_RETURN;

    char database_directory[MRN_MAX_PATH_SIZE];
    size_t database_directory_length = last_path_separator - path_prefix;
    strncpy(database_directory, path_prefix, database_directory_length);
    database_directory[database_directory_length] = '\0';
    mkdir_p(database_directory);

    DBUG_VOID_RETURN;
  }

  int DatabaseManager::ensure_normalizers_registered(grn_obj *db) {
    MRN_DBUG_ENTER_METHOD();

    int error = 0;
#ifdef WITH_GROONGA_NORMALIZER_MYSQL
    {
#  ifdef MRN_GROONGA_NORMALIZER_MYSQL_EMBEDDED
      GRN_PLUGIN_IMPL_NAME_TAGGED(init, normalizers_mysql)(ctx_);
      GRN_PLUGIN_IMPL_NAME_TAGGED(register, normalizers_mysql)(ctx_);
#  else
      grn_obj *mysql_normalizer;
      mysql_normalizer = grn_ctx_get(ctx_, "NormalizerMySQLGeneralCI", -1);
      if (mysql_normalizer) {
        grn_obj_unlink(ctx_, mysql_normalizer);
      } else {
        grn_plugin_register(ctx_, GROONGA_NORMALIZER_MYSQL_PLUGIN_NAME);
      }
#  endif
    }
#endif

    DBUG_RETURN(error);
  }
}

Messung V0.5 in Prozent
C=100 H=97 G=98

¤ Dauer der Verarbeitung: 0.10 Sekunden  (vorverarbeitet am  2026-10-08) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.