susumu.yata
null+****@clear*****
Mon Feb 24 15:43:11 JST 2014
susumu.yata 2014-02-24 15:43:11 +0900 (Mon, 24 Feb 2014) New Revision: e33209c9c4cb1cf4b45aeff625a9342797a233bb https://github.com/groonga/grnxx/commit/e33209c9c4cb1cf4b45aeff625a9342797a233bb Message: Clear the repository for newly designed implementations. Added files: lib/grnxx/library.cpp lib/grnxx/library.hpp Removed files: lib/grnxx/array.cpp lib/grnxx/array.hpp lib/grnxx/array_impl.cpp lib/grnxx/array_impl.hpp lib/grnxx/backtrace.cpp lib/grnxx/backtrace.hpp lib/grnxx/broken_down_time.cpp lib/grnxx/broken_down_time.hpp lib/grnxx/bytes.hpp lib/grnxx/charset.cpp lib/grnxx/charset.hpp lib/grnxx/charset/Makefile.am lib/grnxx/charset/euc-jp.cpp lib/grnxx/charset/euc-jp.hpp lib/grnxx/charset/shift_jis.cpp lib/grnxx/charset/shift_jis.hpp lib/grnxx/charset/utf-8.cpp lib/grnxx/charset/utf-8.hpp lib/grnxx/common_header.cpp lib/grnxx/common_header.hpp lib/grnxx/duration.cpp lib/grnxx/duration.hpp lib/grnxx/errno.cpp lib/grnxx/errno.hpp lib/grnxx/exception.hpp lib/grnxx/features.hpp lib/grnxx/flags_impl.hpp lib/grnxx/geo_point.cpp lib/grnxx/geo_point.hpp lib/grnxx/grnxx.cpp lib/grnxx/grnxx.hpp lib/grnxx/intrinsic.hpp lib/grnxx/lock.hpp lib/grnxx/logger.cpp lib/grnxx/logger.hpp lib/grnxx/map.cpp lib/grnxx/map.hpp lib/grnxx/map/Makefile.am lib/grnxx/map/array_map.cpp lib/grnxx/map/array_map.hpp lib/grnxx/map/bytes_pool.cpp lib/grnxx/map/bytes_pool.hpp lib/grnxx/map/common_header.cpp lib/grnxx/map/common_header.hpp lib/grnxx/map/cursor_impl.cpp lib/grnxx/map/cursor_impl.hpp lib/grnxx/map/double_array.cpp lib/grnxx/map/double_array.hpp lib/grnxx/map/hash.hpp lib/grnxx/map/hash_table.cpp lib/grnxx/map/hash_table.hpp lib/grnxx/map/header.hpp lib/grnxx/map/helper.hpp lib/grnxx/map/key_pool.cpp lib/grnxx/map/key_pool.hpp lib/grnxx/map/patricia.cpp lib/grnxx/map/patricia.hpp lib/grnxx/map/pool.cpp lib/grnxx/map/pool.hpp lib/grnxx/map/scanner_impl.cpp lib/grnxx/map/scanner_impl.hpp lib/grnxx/map_cursor.cpp lib/grnxx/map_cursor.hpp lib/grnxx/map_cursor_query.hpp lib/grnxx/map_scanner.cpp lib/grnxx/map_scanner.hpp lib/grnxx/mutex.cpp lib/grnxx/mutex.hpp lib/grnxx/os.cpp lib/grnxx/os.hpp lib/grnxx/periodic_clock.cpp lib/grnxx/periodic_clock.hpp lib/grnxx/stopwatch.cpp lib/grnxx/stopwatch.hpp lib/grnxx/storage.cpp lib/grnxx/storage.hpp lib/grnxx/storage/Makefile.am lib/grnxx/storage/chunk-posix.cpp lib/grnxx/storage/chunk-posix.hpp lib/grnxx/storage/chunk-windows.cpp lib/grnxx/storage/chunk-windows.hpp lib/grnxx/storage/chunk.cpp lib/grnxx/storage/chunk.hpp lib/grnxx/storage/chunk_index.cpp lib/grnxx/storage/chunk_index.hpp lib/grnxx/storage/file-posix.cpp lib/grnxx/storage/file-posix.hpp lib/grnxx/storage/file-windows.cpp lib/grnxx/storage/file-windows.hpp lib/grnxx/storage/file.cpp lib/grnxx/storage/file.hpp lib/grnxx/storage/header.cpp lib/grnxx/storage/header.hpp lib/grnxx/storage/node_header.cpp lib/grnxx/storage/node_header.hpp lib/grnxx/storage/path.cpp lib/grnxx/storage/path.hpp lib/grnxx/storage/storage_impl.cpp lib/grnxx/storage/storage_impl.hpp lib/grnxx/string_builder.cpp lib/grnxx/string_builder.hpp lib/grnxx/string_format.hpp lib/grnxx/system_clock.cpp lib/grnxx/system_clock.hpp lib/grnxx/thread.cpp lib/grnxx/thread.hpp lib/grnxx/time.cpp lib/grnxx/time.hpp lib/grnxx/traits.hpp lib/grnxx/types.hpp obsolete/lib/grnxx/alpha/Makefile.am obsolete/lib/grnxx/alpha/double_array.cpp obsolete/lib/grnxx/alpha/double_array.hpp obsolete/lib/grnxx/alpha/dummy.cpp obsolete/lib/grnxx/alpha/dummy.hpp obsolete/lib/grnxx/alpha/map.cpp obsolete/lib/grnxx/alpha/map.hpp obsolete/lib/grnxx/alpha/map/Makefile.am obsolete/lib/grnxx/alpha/map/array.cpp obsolete/lib/grnxx/alpha/map/array.hpp obsolete/lib/grnxx/alpha/map/cursor.cpp obsolete/lib/grnxx/alpha/map/cursor.hpp obsolete/lib/grnxx/alpha/map/double_array-slice.cpp obsolete/lib/grnxx/alpha/map/double_array.cpp obsolete/lib/grnxx/alpha/map/double_array.hpp obsolete/lib/grnxx/alpha/map/header.hpp obsolete/lib/grnxx/alpha/map/scan.cpp obsolete/lib/grnxx/alpha/map/scan.hpp obsolete/lib/grnxx/alpha/map_range.hpp obsolete/lib/grnxx/alpha/paged_array.cpp obsolete/lib/grnxx/alpha/paged_array.hpp obsolete/lib/grnxx/basic.hpp obsolete/lib/grnxx/db/Makefile.am obsolete/lib/grnxx/db/blob_vector.cpp obsolete/lib/grnxx/db/blob_vector.hpp obsolete/lib/grnxx/db/vector.cpp obsolete/lib/grnxx/db/vector.hpp obsolete/lib/grnxx/io/Makefile.am obsolete/lib/grnxx/io/block.cpp obsolete/lib/grnxx/io/block.hpp obsolete/lib/grnxx/io/chunk.cpp obsolete/lib/grnxx/io/chunk.hpp obsolete/lib/grnxx/io/file-posix.cpp obsolete/lib/grnxx/io/file-posix.hpp obsolete/lib/grnxx/io/file-windows.cpp obsolete/lib/grnxx/io/file-windows.hpp obsolete/lib/grnxx/io/file.cpp obsolete/lib/grnxx/io/file.hpp obsolete/lib/grnxx/io/file_info.cpp obsolete/lib/grnxx/io/file_info.hpp obsolete/lib/grnxx/io/path.cpp obsolete/lib/grnxx/io/path.hpp obsolete/lib/grnxx/io/pool-impl.cpp obsolete/lib/grnxx/io/pool-impl.hpp obsolete/lib/grnxx/io/pool.cpp obsolete/lib/grnxx/io/pool.hpp obsolete/lib/grnxx/io/view-posix.cpp obsolete/lib/grnxx/io/view-posix.hpp obsolete/lib/grnxx/io/view-windows.cpp obsolete/lib/grnxx/io/view-windows.hpp obsolete/lib/grnxx/io/view.cpp obsolete/lib/grnxx/io/view.hpp obsolete/lib/grnxx/map.cpp obsolete/lib/grnxx/map.hpp obsolete/lib/grnxx/map/Makefile.am obsolete/lib/grnxx/map/da/Makefile.am obsolete/lib/grnxx/map/da/basic/Makefile.am obsolete/lib/grnxx/map/da/basic/id_cursor.cpp obsolete/lib/grnxx/map/da/basic/id_cursor.hpp obsolete/lib/grnxx/map/da/basic/key_cursor.cpp obsolete/lib/grnxx/map/da/basic/key_cursor.hpp obsolete/lib/grnxx/map/da/basic/predictive_cursor.cpp obsolete/lib/grnxx/map/da/basic/predictive_cursor.hpp obsolete/lib/grnxx/map/da/basic/prefix_cursor.cpp obsolete/lib/grnxx/map/da/basic/prefix_cursor.hpp obsolete/lib/grnxx/map/da/basic/trie.cpp obsolete/lib/grnxx/map/da/basic/trie.hpp obsolete/lib/grnxx/map/da/large/Makefile.am obsolete/lib/grnxx/map/da/large/id_cursor.cpp obsolete/lib/grnxx/map/da/large/id_cursor.hpp obsolete/lib/grnxx/map/da/large/key_cursor.cpp obsolete/lib/grnxx/map/da/large/key_cursor.hpp obsolete/lib/grnxx/map/da/large/predictive_cursor.cpp obsolete/lib/grnxx/map/da/large/predictive_cursor.hpp obsolete/lib/grnxx/map/da/large/prefix_cursor.cpp obsolete/lib/grnxx/map/da/large/prefix_cursor.hpp obsolete/lib/grnxx/map/da/large/trie.cpp obsolete/lib/grnxx/map/da/large/trie.hpp obsolete/lib/grnxx/map/da/trie.cpp obsolete/lib/grnxx/map/da/trie.hpp obsolete/lib/grnxx/map/double_array.cpp obsolete/lib/grnxx/map/double_array.hpp obsolete/lib/grnxx/recycler.cpp obsolete/lib/grnxx/recycler.hpp obsolete/lib/grnxx/slice.cpp obsolete/lib/grnxx/slice.hpp obsolete/lib/grnxx/string.cpp obsolete/lib/grnxx/string.hpp obsolete/test/test_alpha_double_array.cpp obsolete/test/test_alpha_map.cpp obsolete/test/test_io.cpp obsolete/test/test_map obsolete/test/test_map.cpp obsolete/test/test_map_da_basic_trie obsolete/test/test_map_da_basic_trie.cpp obsolete/test/test_map_da_large_trie obsolete/test/test_map_da_large_trie.cpp obsolete/test/test_map_double_array obsolete/test/test_map_double_array.cpp obsolete/test/test_recycler.cpp obsolete/test/test_slice.cpp obsolete/test/test_string.cpp test/test_array.cpp test/test_backtrace.cpp test/test_bytes.cpp test/test_charset.cpp test/test_db_blob_vector.cpp test/test_db_vector.cpp test/test_duration.cpp test/test_errno.cpp test/test_exception.cpp test/test_geo_point.cpp test/test_intrinsic.cpp test/test_logger.cpp test/test_map.cpp test/test_map_pool.cpp test/test_mutex.cpp test/test_os.cpp test/test_storage.cpp test/test_string_builder.cpp test/test_string_format.cpp test/test_thread.cpp test/test_time.cpp test/test_traits.cpp test/test_types.cpp Modified files: .gitignore configure.ac lib/grnxx/Makefile.am src/Makefile.am src/grnxx.cpp test/Makefile.am test/test_grnxx.cpp Renamed files: test/benchmark_grnxx.cpp (from test/test_features.cpp) Modified: .gitignore (+3 -24) =================================================================== --- .gitignore 2013-08-23 10:46:34 +0900 (0f4b205) +++ .gitignore 2014-02-24 15:43:11 +0900 (a2a80b1) @@ -4,7 +4,6 @@ *.dat *.dll *.exe -*.grn *.la *.lai *.lo @@ -26,27 +25,7 @@ ltmain.sh missing src/grnxx stamp-h1 -temp/ -test/test_array -test/test_backtrace -test/test_bytes -test/test_charset -test/test_duration -test/test_errno -test/test_exception -test/test_features -test/test_geo_point +test/*.trs test/test_grnxx -test/test_intrinsic -test/test_logger -test/test_map -test/test_map_pool -test/test_mutex -test/test_os -test/test_storage -test/test_string_builder -test/test_string_format -test/test_thread -test/test_time -test/test_traits -test/test_types +test/benchmark_grnxx +test-driver Modified: configure.ac (+9 -21) =================================================================== --- configure.ac 2013-08-23 10:46:34 +0900 (06d5f23) +++ configure.ac 2014-02-24 15:43:11 +0900 (c611975) @@ -2,22 +2,19 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ([2.67]) -AC_INIT([grnxx], [pre-alpha], [groonga �� razil.jp]) -AC_CONFIG_SRCDIR([lib/grnxx/grnxx.hpp]) -AC_CONFIG_HEADERS(config.h) +AC_INIT([grnxx], [dummy12], [groonga �� razil.jp]) +AC_CONFIG_SRCDIR([lib/grnxx/library.hpp]) +AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE # Checks for programs. LT_INIT([win32-dll]) -AC_PROG_CXX +AC_PROG_CXX([clang++ g++-4.8]) AC_PROG_INSTALL AC_CONFIG_MACRO_DIR([m4]) -AM_CXXFLAGS="-Wall -Wextra -std=c++11 -fno-strict-aliasing -I\${top_srcdir}/lib" - -AC_SUBST([AM_CXXFLAGS]) -AC_SUBST([AM_LTLDFLAGS]) +AM_CXXFLAGS="-Wall -std=c++11 -fno-strict-aliasing -I\${top_srcdir}/lib" AC_C_BIGENDIAN AC_CANONICAL_HOST @@ -32,6 +29,9 @@ case "${host}" in ;; esac +AC_SUBST([AM_CXXFLAGS]) +AC_SUBST([AM_LTLDFLAGS]) + # Checks for libraries. AC_ARG_ENABLE([backtrace], @@ -47,22 +47,10 @@ if test "x$enable_backtrace" != "xno"; then fi AC_CHECK_LIB([rt], [clock_gettime]) -AC_CHECK_LIB([pthread], [pthread_create]) -AC_CHECK_LIB([pthread], [pthread_create], - [AM_CXXFLAGS="${AM_CXXFLAGS} -pthread"]) - -# For std::this_thread::yield() and std::this_thread::sleep_for(). -#AC_CHECK_FUNC([sched_yield], -# [AM_CXXFLAGS="${AM_CXXFLAGS} -D_GLIBCXX_USE_SCHED_YIELD"]) -#AC_CHECK_FUNC([nanosleep], -# [AM_CXXFLAGS="${AM_CXXFLAGS} -D_GLIBCXX_USE_NANOSLEEP"]) AC_CONFIG_FILES([Makefile lib/Makefile lib/grnxx/Makefile - lib/grnxx/charset/Makefile - lib/grnxx/map/Makefile - lib/grnxx/storage/Makefile src/Makefile test/Makefile]) AC_OUTPUT @@ -79,4 +67,4 @@ echo "Paths:" echo " Install path prefix: ${prefix}" echo -echo "Now type 'make' to build $PACKAGE_NAME $PACKAGE_VERSION!" +echo "Now type 'make' to build ${PACKAGE_NAME} ${PACKAGE_VERSION}!" Modified: lib/grnxx/Makefile.am (+6 -64) =================================================================== --- lib/grnxx/Makefile.am 2013-08-23 10:46:34 +0900 (0909220) +++ lib/grnxx/Makefile.am 2014-02-24 15:43:11 +0900 (df693e0) @@ -1,77 +1,19 @@ -SUBDIRS = \ - charset \ - map \ - storage +#SUBDIRS = \ +# sub lib_LTLIBRARIES = libgrnxx.la -libgrnxx_la_LIBADD = \ - charset/libgrnxx_charset.la \ - map/libgrnxx_map.la \ - storage/libgrnxx_storage.la +#libgrnxx_la_LIBADD = \ +# sub/libgrnxx_sub.la libgrnxx_la_LDFLAGS = @AM_LTLDFLAGS@ libgrnxx_la_SOURCES = \ - array.cpp \ - array_impl.cpp \ - backtrace.cpp \ - broken_down_time.cpp \ - charset.cpp \ - common_header.cpp \ - duration.cpp \ - errno.cpp \ - geo_point.cpp \ - grnxx.cpp \ - logger.cpp \ - map.cpp \ - map_cursor.cpp \ - map_scanner.cpp \ - mutex.cpp \ - os.cpp \ - periodic_clock.cpp \ - stopwatch.cpp \ - storage.cpp \ - string_builder.cpp \ - system_clock.cpp \ - thread.cpp \ - time.cpp + library.cpp libgrnxx_includedir = ${includedir}/grnxx libgrnxx_include_HEADERS = \ - array.hpp \ - array_impl.hpp \ - backtrace.hpp \ - broken_down_time.hpp \ - bytes.hpp \ - charset.hpp \ - common_header.hpp \ - duration.hpp \ - errno.hpp \ - exception.hpp \ - features.hpp \ - flags_impl.hpp \ - geo_point.hpp \ - grnxx.hpp \ - intrinsic.hpp \ - lock.hpp \ - logger.hpp \ - map.hpp \ - map_cursor.hpp \ - map_cursor_query.hpp \ - map_scanner.hpp \ - mutex.hpp \ - os.hpp \ - periodic_clock.hpp \ - stopwatch.hpp \ - storage.hpp \ - string_builder.hpp \ - string_format.hpp \ - system_clock.hpp \ - thread.hpp \ - time.hpp \ - traits.hpp \ - types.hpp \ + library.hpp \ version.h EXTRA_DIST = version.sh Deleted: lib/grnxx/array.cpp (+0 -30) 100644 =================================================================== --- lib/grnxx/array.cpp 2013-08-23 10:46:34 +0900 (e33768b) +++ /dev/null @@ -1,30 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/array.hpp" - -#include "grnxx/exception.hpp" -#include "grnxx/logger.hpp" - -namespace grnxx { - -void ArrayErrorHandler::throw_memory_error() { - GRNXX_ERROR() << "new grnxx::Array failed"; - throw MemoryError(); -} - -} // namespace grnxx Deleted: lib/grnxx/array.hpp (+0 -118) 100644 =================================================================== --- lib/grnxx/array.hpp 2013-08-23 10:46:34 +0900 (550607c) +++ /dev/null @@ -1,118 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_ARRAY_HPP -#define GRNXX_ARRAY_HPP - -#include "grnxx/features.hpp" - -#include <memory> -#include <new> - -#include "grnxx/array_impl.hpp" -#include "grnxx/types.hpp" - -namespace grnxx { - -class Storage; - -struct ArrayErrorHandler { - static void throw_memory_error(); -}; - -template <typename T, uint64_t PAGE_SIZE = 0, uint64_t TABLE_SIZE = 0> -class Array { - using Impl = ArrayImpl<T, PAGE_SIZE, TABLE_SIZE>; - - public: - using Value = typename Impl::Value; - using ValueArg = typename Impl::ValueArg; - using ValueRef = typename Impl::ValueRef; - using Unit = typename Impl::Unit; - - // Create an array. - static Array *create(Storage *storage, uint32_t storage_node_id, - uint64_t size) { - std::unique_ptr<Array> array(create_instance()); - array->impl_.create(storage, storage_node_id, size); - return array.release(); - } - // Create an array with default value. - static Array *create(Storage *storage, uint32_t storage_node_id, - uint64_t size, ValueArg default_value) { - std::unique_ptr<Array> array(create_instance()); - array->impl_.create(storage, storage_node_id, size, default_value); - return array.release(); - } - - // Open an array. - static Array *open(Storage *storage, uint32_t storage_node_id) { - std::unique_ptr<Array> array(create_instance()); - array->impl_.open(storage, storage_node_id); - return array.release(); - } - - // Unlink an array. - static void unlink(Storage *storage, uint32_t storage_node_id) { - Impl::unlink(storage, storage_node_id); - } - - // Return the storage node ID. - uint32_t storage_node_id() const { - return impl_.storage_node_id(); - } - // Return the number of values. - uint64_t size() const { - return impl_.size(); - } - - // Get a value. - Value get(uint64_t value_id) { - return get_value(value_id); - } - // Set a value. - void set(uint64_t value_id, ValueArg value) { - get_value(value_id) = value; - } - - // Get a reference to a value. - ValueRef get_value(uint64_t value_id) { - return impl_.get_value(value_id); - } - // Get a reference to a unit. - Unit &get_unit(uint64_t unit_id) { - return impl_.get_unit(unit_id); - } - - private: - Impl impl_; - - Array() : impl_() {} - - // Create an instance or throw an exception on failure. - static Array *create_instance() { - Array * const array = new (std::nothrow) Array; - if (!array) { - ArrayErrorHandler::throw_memory_error(); - } - return array; - } -}; - -} // namespace grnxx - -#endif // GRNXX_ARRAY_HPP Deleted: lib/grnxx/array_impl.cpp (+0 -599) 100644 =================================================================== --- lib/grnxx/array_impl.cpp 2013-08-23 10:46:34 +0900 (be98765) +++ /dev/null @@ -1,599 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/array_impl.hpp" - -#include <new> - -#include "grnxx/bytes.hpp" -#include "grnxx/common_header.hpp" -#include "grnxx/exception.hpp" -#include "grnxx/intrinsic.hpp" -#include "grnxx/lock.hpp" -#include "grnxx/logger.hpp" -#include "grnxx/storage.hpp" - -namespace grnxx { -namespace { - -constexpr char FORMAT_STRING[] = "grnxx::Array"; - -struct DummyTable { - void **pages; - uint32_t reference_count; - Mutex mutex; - - DummyTable() : pages(nullptr), reference_count(0), mutex() {} -}; - -class DummyTableManager { - public: - // Get a singleton. - static DummyTableManager &get(); - - // Get a dummy table. - void **get_dummy_table(uint64_t table_size); - // Free a dummy table. - void free_dummy_table(uint64_t table_size); - - private: - DummyTable dummy_tables_[64]; - - DummyTableManager() : dummy_tables_() {} - - DummyTableManager(const DummyTableManager &) = delete; - DummyTableManager &operator=(const DummyTableManager &) = delete; -}; - -DummyTableManager &DummyTableManager::get() { - static DummyTableManager singleton; - return singleton; -} - -void **DummyTableManager::get_dummy_table(uint64_t table_size) { - const uint64_t table_id = bit_scan_reverse(table_size); - DummyTable &dummy_table = dummy_tables_[table_id]; - Lock lock(&dummy_table.mutex); - if (dummy_table.reference_count == 0) { - if (dummy_table.pages) { - GRNXX_ERROR() << "already exists: table_size = " << table_size; - throw LogicError(); - } - // Create a dummy table. - dummy_table.pages = new (std::nothrow) void *[table_size]; - if (!dummy_table.pages) { - GRNXX_ERROR() << "new void *[] failed: size = " << table_size; - throw MemoryError(); - } - for (uint64_t i = 0; i < table_size; ++i) { - dummy_table.pages[i] = Array3D::invalid_page(); - } - } else if (!dummy_table.pages) { - GRNXX_ERROR() << "invalid pages: table_size = " << table_size; - throw LogicError(); - } - ++dummy_table.reference_count; - return dummy_table.pages; -} - -void DummyTableManager::free_dummy_table(uint64_t table_size) { - const uint64_t table_id = bit_scan_reverse(table_size); - DummyTable &dummy_table = dummy_tables_[table_id]; - Lock lock(&dummy_table.mutex); - if (!dummy_table.pages || (dummy_table.reference_count == 0)) { - GRNXX_ERROR() << "already freed: table_size = " << table_size; - throw LogicError(); - } - if (dummy_table.reference_count == 1) { - // Free a dummy table. - delete [] dummy_table.pages; - dummy_table.pages = nullptr; - } - --dummy_table.reference_count; -} - -} // namespace - -struct ArrayHeader { - CommonHeader common_header; - uint64_t value_size; - uint64_t page_size; - uint64_t table_size; - uint64_t secondary_table_size; - uint64_t size; - uint32_t has_default_value; - union { - uint32_t page_storage_node_id; - uint32_t table_storage_node_id; - uint32_t secondary_table_storage_node_id; - }; - Mutex page_mutex; - Mutex table_mutex; - - // Initialize the members except "common_header". - ArrayHeader(); - - // Return true iff the header seems to be correct. - explicit operator bool() const; -}; - -ArrayHeader::ArrayHeader() - : common_header(FORMAT_STRING), - value_size(0), - page_size(0), - table_size(0), - secondary_table_size(0), - size(0), - has_default_value(0), - page_storage_node_id(STORAGE_INVALID_NODE_ID), - page_mutex(), - table_mutex() {} - -ArrayHeader::operator bool() const { - return common_header.format() == FORMAT_STRING; -} - -Array1D::Array1D() - : page_(nullptr), - size_(0), - storage_node_id_(STORAGE_INVALID_NODE_ID) {} - -Array1D::~Array1D() {} - -void Array1D::create(Storage *storage, uint32_t storage_node_id, - uint64_t value_size, uint64_t, - uint64_t, uint64_t size, - const void *default_value, ArrayFillPage fill_page) { - if (!storage) { - GRNXX_ERROR() << "invalid argument: storage = nullptr"; - throw LogicError(); - } - StorageNode storage_node = - storage->create_node(storage_node_id, sizeof(ArrayHeader)); - storage_node_id_ = storage_node.id(); - try { - ArrayHeader * const header = - static_cast<ArrayHeader *>(storage_node.body()); - *header = ArrayHeader(); - header->value_size = value_size; - header->page_size = size; - header->size = size; - // Create a page. - StorageNode page_node = - storage->create_node(storage_node_id_, value_size * size); - header->page_storage_node_id = page_node.id(); - page_ = page_node.body(); - if (default_value) { - header->has_default_value = 1; - fill_page(page_, size, default_value); - } - size_ = size; - } catch (...) { - storage->unlink_node(storage_node_id_); - throw; - } -} - -void Array1D::open(Storage *storage, uint32_t storage_node_id, - uint64_t value_size, uint64_t, - uint64_t, ArrayFillPage) { - if (!storage) { - GRNXX_ERROR() << "invalid argument: storage = nullptr"; - throw LogicError(); - } - StorageNode storage_node = storage->open_node(storage_node_id); - if (storage_node.size() < sizeof(ArrayHeader)) { - GRNXX_ERROR() << "too small header: size = " << storage_node.size(); - throw LogicError(); - } - storage_node_id_ = storage_node.id(); - const ArrayHeader * const header = - static_cast<ArrayHeader *>(storage_node.body()); - if (!*header) { - GRNXX_ERROR() << "wrong format: expected = " << FORMAT_STRING - << ", actual = " << header->common_header.format(); - throw LogicError(); - } - if (header->value_size != value_size) { - GRNXX_ERROR() << "wrong value_size: expected = " << value_size - << ", actual = " << header->value_size; - throw LogicError(); - } - StorageNode page_node = storage->open_node(header->page_storage_node_id); - page_ = page_node.body(); - size_ = header->size; -} - -void Array1D::unlink(Storage *storage, uint32_t storage_node_id, - uint64_t value_size, uint64_t page_size, - uint64_t table_size) { - Array1D array; - array.open(storage, storage_node_id, - value_size, page_size, table_size, nullptr); - storage->unlink_node(storage_node_id); -} - -Array2D::Array2D() - : pages_(), - size_(0), - storage_(nullptr), - storage_node_id_(STORAGE_INVALID_NODE_ID), - header_(nullptr), - fill_page_(nullptr), - table_(nullptr), - mutex_() {} - -Array2D::~Array2D() {} - -void Array2D::create(Storage *storage, uint32_t storage_node_id, - uint64_t value_size, uint64_t page_size, - uint64_t, uint64_t size, - const void *default_value, ArrayFillPage fill_page) { - if (!storage) { - GRNXX_ERROR() << "invalid argument: storage = nullptr"; - throw LogicError(); - } - if ((size % page_size) != 0) { - const uint64_t adjusted_size = size + page_size - (size % page_size); - GRNXX_WARNING() << "size adjustment: before = " << size - << ", after = " << adjusted_size - << ", page_size = " << page_size; - size = adjusted_size; - } - storage_ = storage; - uint64_t storage_node_size = sizeof(ArrayHeader); - if (default_value) { - storage_node_size += value_size; - } - StorageNode storage_node = - storage->create_node(storage_node_id, storage_node_size); - storage_node_id_ = storage_node.id(); - try { - header_ = static_cast<ArrayHeader *>(storage_node.body()); - *header_ = ArrayHeader(); - header_->value_size = value_size; - header_->page_size = page_size; - header_->table_size = size / page_size; - header_->size = size; - if (default_value) { - header_->has_default_value = 1; - std::memcpy(header_ + 1, default_value, value_size); - fill_page_ = fill_page; - } - // Create a table. - StorageNode table_node = storage->create_node( - storage_node_id_, sizeof(uint32_t) * header_->table_size); - header_->table_storage_node_id = table_node.id(); - table_ = static_cast<uint32_t *>(table_node.body()); - for (uint64_t i = 0; i < header_->table_size; ++i) { - table_[i] = STORAGE_INVALID_NODE_ID; - } - reserve_pages(); - size_ = size; - } catch (...) { - storage->unlink_node(storage_node_id_); - throw; - } -} - -void Array2D::open(Storage *storage, uint32_t storage_node_id, - uint64_t value_size, uint64_t page_size, - uint64_t , ArrayFillPage fill_page) { - if (!storage) { - GRNXX_ERROR() << "invalid argument: storage = nullptr"; - throw LogicError(); - } - storage_ = storage; - StorageNode storage_node = storage->open_node(storage_node_id); - if (storage_node.size() < sizeof(ArrayHeader)) { - GRNXX_ERROR() << "too small header: size = " << storage_node.size(); - throw LogicError(); - } - storage_node_id_ = storage_node.id(); - header_ = static_cast<ArrayHeader *>(storage_node.body()); - if (!*header_) { - GRNXX_ERROR() << "wrong format: expected = " << FORMAT_STRING - << ", actual = " << header_->common_header.format(); - throw LogicError(); - } - if (header_->value_size != value_size) { - GRNXX_ERROR() << "wrong value_size: expected = " << value_size - << ", actual = " << header_->value_size; - throw LogicError(); - } - if (header_->page_size != page_size) { - GRNXX_ERROR() << "wrong page_size: expected = " << page_size - << ", actual = " << header_->page_size; - throw LogicError(); - } - if (header_->has_default_value) { - fill_page_ = fill_page; - } - StorageNode table_node = storage->open_node(header_->table_storage_node_id); - table_ = static_cast<uint32_t *>(table_node.body()); - reserve_pages(); - size_ = header_->size; -} - -void Array2D::unlink(Storage *storage, uint32_t storage_node_id, - uint64_t value_size, uint64_t page_size, - uint64_t table_size) { - Array2D array; - array.open(storage, storage_node_id, - value_size, page_size, table_size, nullptr); - storage->unlink_node(storage_node_id); -} - -void Array2D::reserve_pages() { - // Create a table cache. - pages_.reset(new (std::nothrow) void *[header_->table_size]); - if (!pages_) { - GRNXX_ERROR() << "new void *[] failed: size = " << header_->table_size; - throw MemoryError(); - } - for (uint64_t i = 0; i < header_->table_size; ++i) { - pages_[i] = invalid_page(); - } -} - -void Array2D::reserve_page(uint64_t page_id) { - Lock inter_thread_lock(&mutex_); - if (pages_[page_id] == invalid_page()) { - StorageNode page_node; - if (table_[page_id] == STORAGE_INVALID_NODE_ID) { - Lock inter_process_lock(&header_->table_mutex); - if (table_[page_id] == STORAGE_INVALID_NODE_ID) { - // Create a page. - page_node = - storage_->create_node(header_->table_storage_node_id, - header_->value_size * header_->page_size); - if (header_->has_default_value) { - fill_page_(page_node.body(), header_->page_size, header_ + 1); - } - table_[page_id] = page_node.id(); - } - } - if (!page_node) { - page_node = storage_->open_node(table_[page_id]); - } - pages_[page_id] = static_cast<char *>(page_node.body()) - - (header_->value_size * header_->page_size * page_id); - } -} - -Array3D::Array3D() - : tables_(), - size_(0), - table_size_(0), - secondary_table_size_(0), - storage_(nullptr), - storage_node_id_(STORAGE_INVALID_NODE_ID), - header_(nullptr), - fill_page_(nullptr), - secondary_table_(nullptr), - dummy_table_(nullptr), - page_mutex_(), - table_mutex_() {} - -Array3D::~Array3D() { - // A destructor must not access a header because it may be already lost. - if (tables_) { - uint64_t offset = 0; - for (uint64_t i = 0; i < secondary_table_size_; ++i) { - if (tables_[i] != (dummy_table_ - offset)) { - delete [] (tables_[i] + offset); - } - offset += table_size_; - } - } - if (dummy_table_) { - DummyTableManager::get().free_dummy_table(table_size_); - } -} - -void Array3D::create(Storage *storage, uint32_t storage_node_id, - uint64_t value_size, uint64_t page_size, - uint64_t table_size, uint64_t size, - const void *default_value, ArrayFillPage fill_page) { - if (!storage) { - GRNXX_ERROR() << "invalid argument: storage = nullptr"; - throw LogicError(); - } - if ((size % (page_size * table_size)) != 0) { - const uint64_t adjusted_size = - size + (page_size * table_size) - (size % (page_size * table_size)); - GRNXX_WARNING() << "size adjustment: before = " << size - << ", after = " << adjusted_size - << ", page_size = " << page_size - << ", table_size = " << table_size; - size = adjusted_size; - } - storage_ = storage; - uint64_t storage_node_size = sizeof(ArrayHeader); - if (default_value) { - storage_node_size += value_size; - } - StorageNode storage_node = - storage->create_node(storage_node_id, storage_node_size); - storage_node_id_ = storage_node.id(); - try { - header_ = static_cast<ArrayHeader *>(storage_node.body()); - *header_ = ArrayHeader(); - header_->value_size = value_size; - header_->page_size = page_size; - header_->table_size = table_size; - header_->secondary_table_size = size / (page_size * table_size); - header_->size = size; - if (default_value) { - header_->has_default_value = 1; - std::memcpy(header_ + 1, default_value, value_size); - fill_page_ = fill_page; - } - // Create a secondary table. - StorageNode secondary_table_node = storage->create_node( - storage_node_id_, sizeof(uint32_t) * header_->secondary_table_size); - header_->secondary_table_storage_node_id = secondary_table_node.id(); - secondary_table_ = static_cast<uint32_t *>(secondary_table_node.body()); - for (uint64_t i = 0; i < header_->secondary_table_size; ++i) { - secondary_table_[i] = STORAGE_INVALID_NODE_ID; - } - size_ = header_->size; - table_size_ = header_->table_size; - secondary_table_size_ = header_->secondary_table_size; - reserve_tables(); - } catch (...) { - storage->unlink_node(storage_node_id_); - throw; - } -} - -void Array3D::open(Storage *storage, uint32_t storage_node_id, - uint64_t value_size, uint64_t page_size, - uint64_t table_size, ArrayFillPage fill_page) { - if (!storage) { - GRNXX_ERROR() << "invalid argument: storage = nullptr"; - throw LogicError(); - } - storage_ = storage; - StorageNode storage_node = storage->open_node(storage_node_id); - if (storage_node.size() < sizeof(ArrayHeader)) { - GRNXX_ERROR() << "too small header: size = " << storage_node.size(); - throw LogicError(); - } - storage_node_id_ = storage_node.id(); - header_ = static_cast<ArrayHeader *>(storage_node.body()); - if (!*header_) { - GRNXX_ERROR() << "wrong format: expected = " << FORMAT_STRING - << ", actual = " << header_->common_header.format(); - throw LogicError(); - } - if (header_->value_size != value_size) { - GRNXX_ERROR() << "wrong value_size: expected = " << value_size - << ", actual = " << header_->value_size; - throw LogicError(); - } - if (header_->page_size != page_size) { - GRNXX_ERROR() << "wrong page_size: expected = " << page_size - << ", actual = " << header_->page_size; - throw LogicError(); - } - if (header_->table_size != table_size) { - GRNXX_ERROR() << "wrong table_size: expected = " << table_size - << ", actual = " << header_->table_size; - throw LogicError(); - } - if (header_->has_default_value) { - fill_page_ = fill_page; - } - StorageNode secondary_table_node = - storage->open_node(header_->secondary_table_storage_node_id); - secondary_table_ = static_cast<uint32_t *>(secondary_table_node.body()); - size_ = header_->size; - table_size_ = header_->table_size; - secondary_table_size_ = header_->secondary_table_size; - reserve_tables(); -} - -void Array3D::unlink(Storage *storage, uint32_t storage_node_id, - uint64_t value_size, uint64_t page_size, - uint64_t table_size) { - Array3D array; - array.open(storage, storage_node_id, - value_size, page_size, table_size, nullptr); - storage->unlink_node(storage_node_id); -} - -void Array3D::reserve_tables() { - dummy_table_ = DummyTableManager::get().get_dummy_table(header_->table_size); - // Create a secondary table cache. - tables_.reset(new (std::nothrow) void **[header_->secondary_table_size]); - if (!tables_) { - GRNXX_ERROR() << "new void **[] failed: size = " - << header_->secondary_table_size; - throw MemoryError(); - } - // Fill the secondary table cache with the dummy table cache. - uint64_t offset = 0; - for (uint64_t i = 0; i < header_->secondary_table_size; ++i) { - tables_[i] = dummy_table_ - offset; - offset += header_->table_size; - } -} - -void Array3D::reserve_page(uint64_t page_id) { - const uint64_t table_id = page_id / header_->table_size; - if (tables_[table_id] == (dummy_table_ - (header_->table_size * table_id))) { - reserve_table(table_id); - } - Lock inter_thread_lock(&page_mutex_); - if (tables_[table_id][page_id] == invalid_page()) { - StorageNode page_node; - StorageNode table_node = storage_->open_node(secondary_table_[table_id]); - uint32_t * const table = static_cast<uint32_t *>(table_node.body()) - - (header_->table_size * table_id); - if (table[page_id] == STORAGE_INVALID_NODE_ID) { - Lock inter_process_lock(&header_->page_mutex); - if (table[page_id] == STORAGE_INVALID_NODE_ID) { - // Create a page. - page_node = storage_->create_node( - secondary_table_[table_id], - header_->value_size * header_->page_size); - if (header_->has_default_value) { - fill_page_(page_node.body(), header_->page_size, header_ + 1); - } - table[page_id] = page_node.id(); - } - } - if (!page_node) { - page_node = storage_->open_node(table[page_id]); - } - tables_[table_id][page_id] = static_cast<char *>(page_node.body()) - - (header_->value_size * header_->page_size * page_id); - } -} - -void Array3D::reserve_table(uint64_t table_id) { - Lock inter_thread_lock(&table_mutex_); - if (tables_[table_id] == (dummy_table_ - (header_->table_size * table_id))) { - if (secondary_table_[table_id] == STORAGE_INVALID_NODE_ID) { - Lock inter_process_lock(&header_->table_mutex); - if (secondary_table_[table_id] == STORAGE_INVALID_NODE_ID) { - // Create a table. - StorageNode table_node = - storage_->create_node(header_->secondary_table_storage_node_id, - sizeof(uint32_t) * header_->table_size); - uint32_t * const table = static_cast<uint32_t *>(table_node.body()); - for (uint64_t i = 0; i < header_->table_size; ++i) { - table[i] = STORAGE_INVALID_NODE_ID; - } - secondary_table_[table_id] = table_node.id(); - } - } - // Create a table cache. - void ** const pages = new (std::nothrow) void *[header_->table_size]; - if (!pages) { - GRNXX_ERROR() << "new void *[] failed: size = " << header_->table_size; - throw MemoryError(); - } - for (uint64_t i = 0; i < header_->table_size; ++i) { - pages[i] = invalid_page(); - } - tables_[table_id] = pages - (header_->table_size * table_id); - } -} - -} // namespace grnxx Deleted: lib/grnxx/array_impl.hpp (+0 -424) 100644 =================================================================== --- lib/grnxx/array_impl.hpp 2013-08-23 10:46:34 +0900 (b407bb4) +++ /dev/null @@ -1,424 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_ARRAY_IMPL_HPP -#define GRNXX_ARRAY_IMPL_HPP - -#include "grnxx/features.hpp" - -#include <memory> - -#include "grnxx/mutex.hpp" -#include "grnxx/traits.hpp" -#include "grnxx/types.hpp" - -namespace grnxx { - -class Storage; - -struct ArrayHeader; - -// Fill "page" with "value". -using ArrayFillPage = void (*)(void *page, uint64_t page_size, - const void *value); - -class Array1D { - public: - Array1D(); - ~Array1D(); - - // Create an array. - void create(Storage *storage, uint32_t storage_node_id, - uint64_t value_size, uint64_t page_size, - uint64_t table_size, uint64_t size, - const void *default_value, ArrayFillPage fill_page); - // Open an array. - void open(Storage *storage, uint32_t storage_node_id, - uint64_t value_size, uint64_t page_size, - uint64_t table_size, ArrayFillPage fill_page); - - // Unlink an array. - static void unlink(Storage *storage, uint32_t storage_node_id, - uint64_t value_size, uint64_t page_size, - uint64_t table_size); - - // Return the storage node ID. - uint32_t storage_node_id() const { - return storage_node_id_; - } - // Return the number of values. - uint64_t size() const { - return size_; - } - - // Return a reference to a value. - template <typename T, uint64_t, uint64_t> - T &get_value(uint64_t value_id) { - return static_cast<T *>(page_)[value_id]; - } - - private: - void *page_; - uint64_t size_; - uint32_t storage_node_id_; -}; - -class Array2D { - public: - Array2D(); - ~Array2D(); - - // Create an array. - void create(Storage *storage, uint32_t storage_node_id, - uint64_t value_size, uint64_t page_size, - uint64_t table_size, uint64_t size, - const void *default_value, ArrayFillPage fill_page); - // Open an array. - void open(Storage *storage, uint32_t storage_node_id, - uint64_t value_size, uint64_t page_size, - uint64_t table_size, ArrayFillPage fill_page); - - // Unlink an array. - static void unlink(Storage *storage, uint32_t storage_node_id, - uint64_t value_size, uint64_t page_size, - uint64_t table_size); - - // Return the storage node ID. - uint32_t storage_node_id() const { - return storage_node_id_; - } - // Return the number of values. - uint64_t size() const { - return size_; - } - - // Return a reference to a value. - template <typename T, uint64_t PAGE_SIZE, uint64_t TABLE_SIZE> - T &get_value(uint64_t value_id) { - const uint64_t page_id = value_id / PAGE_SIZE; - if (pages_[page_id] == invalid_page()) { - reserve_page(page_id); - } - return static_cast<T *>(pages_[page_id])[value_id]; - } - - private: - std::unique_ptr<void *[]> pages_; - uint64_t size_; - Storage *storage_; - uint32_t storage_node_id_; - ArrayHeader *header_; - ArrayFillPage fill_page_; - uint32_t *table_; - Mutex mutex_; - - // Initialize "pages_". - void reserve_pages(); - // Open or create a page. - void reserve_page(uint64_t page_id); - - // Return a pointer to an invalid page. - static void *invalid_page() { - return static_cast<char *>(nullptr) - 1; - } -}; - -class Array3D { - using ArrayPageFiller = void (*)(void *page, const void *value); - - public: - Array3D(); - ~Array3D(); - - // Create an array. - void create(Storage *storage, uint32_t storage_node_id, - uint64_t value_size, uint64_t page_size, - uint64_t table_size, uint64_t size, - const void *default_value, ArrayFillPage fill_page); - // Open an array. - void open(Storage *storage, uint32_t storage_node_id, - uint64_t value_size, uint64_t page_size, - uint64_t table_size, ArrayFillPage fill_page); - - // Unlink an array. - static void unlink(Storage *storage, uint32_t storage_node_id, - uint64_t value_size, uint64_t page_size, - uint64_t table_size); - - // Return the storage node ID. - uint32_t storage_node_id() const { - return storage_node_id_; - } - // Return the number of values. - uint64_t size() const { - return size_; - } - - // Return a reference to a value. - template <typename T, uint64_t PAGE_SIZE, uint64_t TABLE_SIZE> - T &get_value(uint64_t value_id) { - const uint64_t table_id = value_id / (PAGE_SIZE * TABLE_SIZE); - const uint64_t page_id = value_id / PAGE_SIZE; - if (tables_[table_id][page_id] == invalid_page()) { - reserve_page(page_id); - } - return static_cast<T *>(tables_[table_id][page_id])[value_id]; - } - - // Return a pointer to an invalid page. - static void *invalid_page() { - return static_cast<char *>(nullptr) + 1; - } - - private: - std::unique_ptr<void **[]> tables_; - uint64_t size_; - uint64_t table_size_; - uint64_t secondary_table_size_; - Storage *storage_; - uint32_t storage_node_id_; - ArrayHeader *header_; - ArrayFillPage fill_page_; - uint32_t *secondary_table_; - void **dummy_table_; - Mutex page_mutex_; - Mutex table_mutex_; - - // Initialize "tables_". - void reserve_tables(); - // Open or create a page. - void reserve_page(uint64_t page_id); - // Open or create a table. - void reserve_table(uint64_t table_id); -}; - -template <uint64_t PAGE_SIZE, uint64_t TABLE_SIZE> -struct ArrayImplSelector; - -// Use Array1D. -template <> -struct ArrayImplSelector<0, 0> { - using Type = Array1D; -}; - -// Use Array2D. -template <uint64_t PAGE_SIZE> -struct ArrayImplSelector<PAGE_SIZE, 0> { - using Type = Array2D; -}; - -// Use Array3D. -template <uint64_t PAGE_SIZE, uint64_t TABLE_SIZE> -struct ArrayImplSelector { - using Type = Array3D; -}; - -template <typename T> -struct ArrayPageFiller { - // Fill "page" with "value". - // This function is used to initialize a page. - static void fill_page(void *page, uint64_t page_size, const void *value) { - for (uint64_t i = 0; i < page_size; ++i) { - static_cast<T *>(page)[i] = *static_cast<const T *>(value); - } - } -}; - -template <typename T, uint64_t PAGE_SIZE, uint64_t TABLE_SIZE> -class ArrayImpl { - // Test template parameters. - static_assert((PAGE_SIZE != 0) || (TABLE_SIZE == 0), - "TABLE_SIZE must be zero if PAGE_SIZE is zero"); - static_assert((PAGE_SIZE & (PAGE_SIZE - 1)) == 0, - "PAGE_SIZE must be zero or a power of two"); - static_assert((TABLE_SIZE & (TABLE_SIZE - 1)) == 0, - "TABLE_SIZE must be zero or a power of two"); - - using Impl = typename ArrayImplSelector<PAGE_SIZE, TABLE_SIZE>::Type; - - public: - using Value = typename Traits<T>::Type; - using ValueArg = typename Traits<T>::ArgumentType; - using ValueRef = Value &; - using Unit = Value; - - // Create an array. - void create(Storage *storage, uint32_t storage_node_id, uint64_t size) { - impl_.create(storage, storage_node_id, - sizeof(Value), PAGE_SIZE, TABLE_SIZE, size, - nullptr, ArrayPageFiller<Value>::fill_page); - } - // Create an array with the default value. - void create(Storage *storage, uint32_t storage_node_id, uint64_t size, - ValueArg default_value) { - impl_.create(storage, storage_node_id, - sizeof(Value), PAGE_SIZE, TABLE_SIZE, size, - &default_value, ArrayPageFiller<Value>::fill_page); - } - // Open an array. - void open(Storage *storage, uint32_t storage_node_id) { - impl_.open(storage, storage_node_id, - sizeof(Value), PAGE_SIZE, TABLE_SIZE, - ArrayPageFiller<Value>::fill_page); - } - - // Unlink an array. - static void unlink(Storage *storage, uint32_t storage_node_id) { - Impl::unlink(storage, storage_node_id, - sizeof(Value), PAGE_SIZE, TABLE_SIZE); - } - - // Return the storage node ID. - uint32_t storage_node_id() const { - return impl_.storage_node_id(); - } - // Return the number of values. - uint64_t size() const { - return impl_.size(); - } - - // Return a reference to a value. - ValueRef get_value(uint64_t value_id) { - return impl_. template get_value<Value, PAGE_SIZE, TABLE_SIZE>(value_id); - } - // Return a reference to a unit. - Unit &get_unit(uint64_t unit_id) { - return get_value(unit_id); - } - - private: - Impl impl_; -}; - -// A reference to a bit. -class ArrayBitRef { - public: - using Unit = uint64_t; - - // Create a reference to a bit. - ArrayBitRef(Unit &unit, Unit mask) : unit_(unit), mask_(mask) {} - - // Get a bit. - operator bool() const { - return (unit_ & mask_) != 0; - } - - // Set a bit. - ArrayBitRef &operator=(bool value) { - if (value) { - unit_ |= mask_; - } else { - unit_ &= ~mask_; - } - return *this; - } - - // Copy a bit. - ArrayBitRef &operator=(const ArrayBitRef &rhs) { - return *this = bool(rhs); - } - - // Compare bits. - bool operator==(bool rhs) const { - return bool(*this) == rhs; - } - bool operator!=(bool rhs) const { - return bool(*this) != rhs; - } - - private: - Unit &unit_; - Unit mask_; -}; - -// An array of bits. -template <uint64_t PAGE_SIZE_IN_BITS, uint64_t TABLE_SIZE> -class ArrayImpl<bool, PAGE_SIZE_IN_BITS, TABLE_SIZE> { - static constexpr uint64_t UNIT_SIZE = sizeof(ArrayBitRef::Unit) * 8; - static constexpr uint64_t PAGE_SIZE = PAGE_SIZE_IN_BITS / UNIT_SIZE; - - // Test template parameters. - static_assert((PAGE_SIZE_IN_BITS % UNIT_SIZE) == 0, - "(PAGE_SIZE_IN_BITS % UNIT_SIZE) != 0"); - static_assert((PAGE_SIZE != 0) || (TABLE_SIZE == 0), - "TABLE_SIZE must be zero if PAGE_SIZE is zero"); - static_assert((PAGE_SIZE & (PAGE_SIZE - 1)) == 0, - "PAGE_SIZE must be zero or a power of two"); - static_assert((TABLE_SIZE & (TABLE_SIZE - 1)) == 0, - "TABLE_SIZE must be zero or a power of two"); - - using Impl = typename ArrayImplSelector<PAGE_SIZE, TABLE_SIZE>::Type; - - public: - using Value = typename Traits<bool>::Type; - using ValueArg = typename Traits<bool>::ArgumentType; - using ValueRef = ArrayBitRef; - using Unit = ArrayBitRef::Unit; - - // Create an array. - void create(Storage *storage, uint32_t storage_node_id, uint64_t size) { - impl_.create(storage, storage_node_id, - sizeof(Unit), PAGE_SIZE, TABLE_SIZE, size / UNIT_SIZE, - nullptr, ArrayPageFiller<Unit>::fill_page); - } - // Create an array with the default value. - void create(Storage *storage, uint32_t storage_node_id, uint64_t size, - ValueArg default_value) { - const Unit default_unit = default_value ? ~(Unit)0 : (Unit)0; - impl_.create(storage, storage_node_id, - sizeof(Unit), PAGE_SIZE, TABLE_SIZE, size / UNIT_SIZE, - &default_unit, ArrayPageFiller<Unit>::fill_page); - } - // Open an array. - void open(Storage *storage, uint32_t storage_node_id) { - impl_.open(storage, storage_node_id, - sizeof(Unit), PAGE_SIZE, TABLE_SIZE, - ArrayPageFiller<Unit>::fill_page); - } - - // Unlink an array. - static void unlink(Storage *storage, uint32_t storage_node_id) { - Impl::unlink(storage, storage_node_id, - sizeof(Unit), PAGE_SIZE, TABLE_SIZE); - } - - // Return the storage node ID. - uint32_t storage_node_id() const { - return impl_.storage_node_id(); - } - // Return the number of values. - uint64_t size() const { - return impl_.size() * UNIT_SIZE; - } - - // Return a reference to a value. - ValueRef get_value(uint64_t value_id) { - return ValueRef(get_unit(value_id / UNIT_SIZE), - Unit(1) << (value_id % UNIT_SIZE)); - } - // Return a reference to a unit. - Unit &get_unit(uint64_t unit_id) { - return impl_. template get_value<Unit, PAGE_SIZE, TABLE_SIZE>(unit_id); - } - - private: - Impl impl_; -}; - -} // namespace grnxx - -#endif // GRNXX_ARRAY_IMPL_HPP Deleted: lib/grnxx/backtrace.cpp (+0 -421) 100644 =================================================================== --- lib/grnxx/backtrace.cpp 2013-08-23 10:46:34 +0900 (361a154) +++ /dev/null @@ -1,421 +0,0 @@ -/* - Copyright (C) 2012 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/backtrace.hpp" - -#include "../config.h" - -#ifdef HAVE_BACKTRACE - -#include <cxxabi.h> -#include <dlfcn.h> -#include <execinfo.h> - -#ifdef HAVE_LIBBFD -# include <bfd.h> -# ifdef GRNXX_APPLE -# include <mach-o/dyld.h> -# else // GRNXX_APPLE -# include <link.h> -# endif // GRNXX_APPLE -#endif // HAVE_LIBBFD - -#include <cstdlib> -#include <cstring> -#include <sstream> - -#include "grnxx/lock.hpp" -#include "grnxx/mutex.hpp" - -namespace grnxx { -namespace { - -class Resolver { - public: - static bool resolve(void *address, std::ostream *stream); - - private: -#ifdef HAVE_LIBBFD - bfd *bfd_; - asymbol **bfd_symbols_; - - static bool bfd_initialized_; -#endif // HAVE_LIBBFD - - Resolver(); - ~Resolver(); - -#ifdef HAVE_LIBBFD - bool resolve_(const char *image_name, bfd_vma address, std::ostream *stream); -#endif // HAVE_LIBBFD - - Resolver(const Resolver &); - Resolver &operator=(const Resolver &); -}; - -#ifdef HAVE_LIBBFD -struct Match { - const char *image_name; - uintptr_t address; -}; - -// FIXME: The default image name depends on the environment. -// http://stackoverflow.com/questions/1023306/finding-current-executables-path-without-proc-self-exe -const char DEFAULT_IMAGE_NAME[] = "/proc/self/exe"; - -# ifdef GRNXX_APPLE -// TODO: Not tested yet. -bool find_match(Match *match) { - const uint32_t image_count = ::_dyld_image_count(); - for (uint32_t image_id = 0; image_id < image_count; ++image_id) { - const struct mach_header *header = ::_dyld_get_image_header(image_id); - const struct load_command *command; - if (header->magic == MH_MAGIC_64) { - command = reinterpret_cast<const struct load_command *>( - reinterpret_cast<const struct mach_header_64 *>(header) + 1); - } else { - command = reinterpret_cast<const struct load_command *>(header + 1); - } - - const intptr_t slide = ::_dyld_get_image_vmaddr_slide(image_id); - for (uint32_t command_id = 0; command_id < header->ncmds; ++command_id) { - switch (command->cmd) { - case LC_SEGMENT: { - const struct segment_command *segment = - reinterpret_cast<const struct segment_command *>(command); - if ((address >= (segment->vmaddr + slide)) && - (address < (segment->vmaddr + slide + segment->vmsize))) { - match.address = segment->vmaddr - slide; - match.image_name = ::_dyld_get_image_name(image_id); - return true; - } - break; - } - case LC_SEGMENT_64: { - const struct segment_command_64 *segment = - reinterpret_cast<const struct segment_command_64 *>(command); - if ((address >= (segment->vmaddr + slide)) && - (address < (segment->vmaddr + slide + segment->vmsize))) { - match.address = segment->vmaddr - slide; - match.image_name = ::_dyld_get_image_name(i); - return true; - } - break; - } - } - command = reinterpret_cast<const struct load_command *>( - reinterpret_cast<const char *>(command) + cmd->cmdsize); - } - } - return false; -} -# else // GRNXX_APPLE -int find_match_callback(struct dl_phdr_info *info, size_t, void *user_data) { - Match * const match = static_cast<Match *>(user_data); - for (ElfW(Half) i = 0; i < info->dlpi_phnum; ++i) { - if (info->dlpi_phdr[i].p_type == PT_LOAD) { - ElfW(Addr) address = info->dlpi_phdr[i].p_vaddr + info->dlpi_addr; - if ((match->address >= address) && - (match->address < (address + info->dlpi_phdr[i].p_memsz))) { - if (!info->dlpi_name || (info->dlpi_name[0] == '\0')) { - match->image_name = DEFAULT_IMAGE_NAME; - } else { - match->image_name = info->dlpi_name; - } - match->address -= (uintptr_t)info->dlpi_addr; - return 1; - } - } - } - return 0; -} - -bool find_match(Match *match) { - return dl_iterate_phdr(find_match_callback, match) != 0; -} -# endif // GRNXX_APPLE - -bool Resolver::bfd_initialized_ = false; - -bool Resolver::resolve(void *address, std::ostream *stream) { - // Just to be safe, call ::bfd_init() only once. - if (!bfd_initialized_) { - ::bfd_init(); - bfd_initialized_ = true; - } - - Match match; - match.address = reinterpret_cast<uintptr_t>(address) - 1; - if (find_match(&match)) { - *stream << address; - return Resolver().resolve_(match.image_name, - static_cast<bfd_vma>(match.address), stream); - } - return false; -} - -class Detail { - public: - Detail(asymbol **symbols_, bfd_vma address_) - : symbols(symbols_), - address(address_), - filename(nullptr), - function(nullptr), - line(0), - found(false) {} - - asymbol **symbols; - bfd_vma address; - const char *filename; - const char *function; - unsigned int line; - bool found; -}; - -void callback_for_each_section(bfd *bfd_, asection *section, void *user_data) { - Detail * const detail = static_cast<Detail *>(user_data); - if (detail->found) { - return; - } - - if ((bfd_get_section_flags(bfd_, section) & SEC_ALLOC) == 0) { - return; - } - - bfd_vma address = bfd_get_section_vma(bfd_, section); - if (detail->address < address) { - return; - } - - bfd_size_type size = bfd_section_size(bfd_, section); - if (detail->address >= (address + size)) { - return; - } - - if (bfd_find_nearest_line(bfd_, section, detail->symbols, - detail->address - address, &detail->filename, - &detail->function, &detail->line) != 0) { - detail->found = true; - } -} - -Resolver::Resolver() : bfd_(nullptr), bfd_symbols_(nullptr) {} - -Resolver::~Resolver() { - if (bfd_symbols_) { - std::free(bfd_symbols_); - } - if (bfd_) { - ::bfd_close(bfd_); - } -} - -bool Resolver::resolve_(const char *image_name, bfd_vma address, - std::ostream *stream) { - bfd_ = ::bfd_openr(image_name, nullptr); - if (!bfd_) { - return false; - } - - if (::bfd_check_format(bfd_, ::bfd_archive)) { - return false; - } - - char **matches = nullptr; - if (!::bfd_check_format_matches(bfd_, ::bfd_object, &matches)) { - if (::bfd_get_error() == ::bfd_error_file_ambiguously_recognized) { - std::free(matches); - } - return false; - } - - if ((bfd_get_file_flags(bfd_) & HAS_SYMS) == 0) { - return false; - } - - unsigned int size = 0; - long num_symbols = bfd_read_minisymbols(bfd_, false, - (void **)&bfd_symbols_, &size); - if (num_symbols == 0) { - std::free(bfd_symbols_); - bfd_symbols_ = nullptr; - num_symbols = bfd_read_minisymbols(bfd_, true, - (void**)&bfd_symbols_, &size); - } - if (num_symbols <= 0) { - return false; - } - - Detail detail(bfd_symbols_, address); - ::bfd_map_over_sections(bfd_, callback_for_each_section, &detail); - if (!detail.found) { - return false; - } - - *stream << ": "; - if (!detail.function || (detail.function[0] == '\0')) { - *stream << "???"; - } else { - int status = 0; - char *demangled_function = - ::abi::__cxa_demangle(detail.function, 0, 0, &status); - if (demangled_function) { - *stream << demangled_function; - std::free(demangled_function); - } else { - *stream << detail.function; - } - } - - *stream << " ("; - if (!detail.filename || (detail.filename[0] == '\0') || (detail.line == 0)) { - *stream << "???:???"; - } else { - *stream << ::basename(detail.filename) << ':' << detail.line; - } - - if (std::strcmp(image_name, DEFAULT_IMAGE_NAME) != 0) { - *stream << " in " << image_name; - } - *stream << ')'; - -// bfd_find_inliner_info(bfd_, &detail.filename, &detail.function, -// &detail.line); - - return true; -} -#else // HAVE_LIBBFD -bool Resolver::resolve(void *, std::ostream *) { - return false; -} -#endif // HAVE_LIBBFD - -} // namespace - -bool Backtrace::backtrace(int skip_count, std::vector<void *> *addresses) try { - static Mutex mutex; - Lock lock(&mutex); - - if ((skip_count < BACKTRACE_MIN_SKIP_COUNT) || - (skip_count > BACKTRACE_MAX_SKIP_COUNT)) { - return false; - } - if (!addresses) { - return false; - } - ++skip_count; - - std::vector<void *> buf(BACKTRACE_MIN_BUF_SIZE); - for ( ; ; ) { - const int depth = ::backtrace(&buf[0], static_cast<int>(buf.size())); - if (depth < static_cast<int>(buf.size())) { - if (depth <= skip_count) { - return false; - } - buf.resize(depth); - break; - } - if (buf.size() >= BACKTRACE_MAX_BUF_SIZE) { - break; - } - buf.resize(buf.size() * 2); - } - addresses->assign(buf.begin() + skip_count, buf.end()); - return true; -} catch (...) { - return false; -} - -bool Backtrace::resolve(void *address, std::string *entry) try { - static Mutex mutex; - Lock lock(&mutex); - - if (!address || !entry) { - return false; - } - - std::ostringstream stream; - if (Resolver::resolve(address, &stream)) { - entry->assign(stream.str()); - return true; - } - - char **symbols = ::backtrace_symbols(&address, 1); - if (!symbols) { - return false; - } - char *first_symbol = symbols[0]; - std::free(symbols); - if (!first_symbol) { - return false; - } - entry->append(first_symbol); - return true; -} catch (...) { - return false; -} - -bool Backtrace::pretty_backtrace(int skip_count, - std::vector<std::string> *entries) try { - if ((skip_count < BACKTRACE_MIN_SKIP_COUNT) || - (skip_count > BACKTRACE_MAX_SKIP_COUNT)) { - return false; - } - if (!entries) { - return false; - } - ++skip_count; - - std::vector<void *> addresses; - if (!backtrace(skip_count, &addresses)) { - return false; - } - - entries->clear(); - for (std::size_t i = 0; i < addresses.size(); ++i) { - std::string entry; - if (resolve(addresses[i], &entry)) { - entry.insert(0, (i == 0) ? "at " : "by ", 3); - entries->push_back(entry); - } - } - return true; -} catch (...) { - return false; -} - -} // namespace grnxx - -#else // HAVE_BACKTRACE - -namespace grnxx { - -bool Backtrace::backtrace(int, std::vector<void *> *) { - return false; -} - -bool Backtrace::resolve(void *, std::string *) { - return false; -} - -bool Backtrace::pretty_backtrace(int, std::vector<std::string> *) { - return false; -} - -} // namespace grnxx - -#endif // HAVE_BACKTRACE Deleted: lib/grnxx/backtrace.hpp (+0 -56) 100644 =================================================================== --- lib/grnxx/backtrace.hpp 2013-08-23 10:46:34 +0900 (2707b03) +++ /dev/null @@ -1,56 +0,0 @@ -/* - Copyright (C) 2012 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_BACKTRACE_HPP -#define GRNXX_BACKTRACE_HPP - -#include "grnxx/features.hpp" - -#include <string> -#include <vector> - -#include "grnxx/types.hpp" - -namespace grnxx { - -constexpr int BACKTRACE_MIN_SKIP_COUNT = 0; -constexpr int BACKTRACE_MAX_SKIP_COUNT = 16; - -constexpr size_t BACKTRACE_MIN_BUF_SIZE = 16; -constexpr size_t BACKTRACE_MAX_BUF_SIZE = 1024; - -class Backtrace { - public: - // The following functions return true on success, false on failure. - - // backtrace() writes a list of addresses to function calls into 'addresses'. - // 'skip_count' specfies the number of function calls to be skipped. - static bool backtrace(int skip_count, std::vector<void *> *addresses); - - // resolve() writes a function call referred to by 'address' in - // human-readable format into 'entry'. - static bool resolve(void *address, std::string *entry); - - // pretty_backtrace() writes a list of function calls in human-readable - // format. 'skip_count' specfies the number of function calls to be skipped. - static bool pretty_backtrace(int skip_count, - std::vector<std::string> *entries); -}; - -} // namespace grnxx - -#endif // GRNXX_BACKTRACE_HPP Deleted: lib/grnxx/broken_down_time.cpp (+0 -39) 100644 =================================================================== --- lib/grnxx/broken_down_time.cpp 2013-08-23 10:46:34 +0900 (14fad5c) +++ /dev/null @@ -1,39 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/broken_down_time.hpp" - -#include "grnxx/string_builder.hpp" -#include "grnxx/string_format.hpp" - -namespace grnxx { - -StringBuilder &operator<<(StringBuilder &builder, const BrokenDownTime &time) { - if (!builder) { - return builder; - } - builder << (1900 + time.year) << '-' - << StringFormat::align_right(time.mon + 1, 2, '0') << '-' - << StringFormat::align_right(time.mday, 2, '0') << ' ' - << StringFormat::align_right(time.hour, 2, '0') << ':' - << StringFormat::align_right(time.min, 2, '0') << ':' - << StringFormat::align_right(time.sec, 2, '0') << '.' - << StringFormat::align_right(time.usec, 6, '0'); - return builder; -} - -} // namespace grnxx Deleted: lib/grnxx/broken_down_time.hpp (+0 -48) 100644 =================================================================== --- lib/grnxx/broken_down_time.hpp 2013-08-23 10:46:34 +0900 (7ec2275) +++ /dev/null @@ -1,48 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_BROKEN_DOWN_TIME_HPP -#define GRNXX_BROKEN_DOWN_TIME_HPP - -#include "grnxx/features.hpp" - -namespace grnxx { - -class StringBuilder; - -struct BrokenDownTime { - int usec; // Microseconds. - int sec; // Seconds. - int min; // Minutes. - int hour; // Hours. - int mday; // Day of the month. - int mon; // Month. - int year; // Year. - int wday; // Day of the week. - int yday; // Day in the year. - int isdst; // Daylight saving time. - - static constexpr BrokenDownTime invalid_value() { - return BrokenDownTime{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - } -}; - -StringBuilder &operator<<(StringBuilder &builder, const BrokenDownTime &time); - -} // namespace grnxx - -#endif // GRNXX_BROKEN_DOWN_TIME_HPP Deleted: lib/grnxx/bytes.hpp (+0 -168) 100644 =================================================================== --- lib/grnxx/bytes.hpp 2013-08-23 10:46:34 +0900 (26c267c) +++ /dev/null @@ -1,168 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_BYTES_HPP -#define GRNXX_BYTES_HPP - -#include "grnxx/features.hpp" - -#include <cstring> - -#include "grnxx/types.hpp" - -namespace grnxx { - -// A reference to a sequence of bytes. -class Bytes { - public: - // Trivial default constructor. - Bytes() = default; - // Create a reference to an empty (zero-size) sequence. - Bytes(nullptr_t) : data_(nullptr), size_(0) {} - // Create a reference to a zero-terminated string. - Bytes(const char *str) - : data_(reinterpret_cast<const uint8_t *>(str)), - size_(std::strlen(str)) {} - // Create a reference to a sequence of bytes. - Bytes(const void *data, uint64_t size) - : data_(static_cast<const uint8_t *>(data)), - size_(size) {} - - // Return true iff the sequence is not empty. - explicit operator bool() const { - return size_ != 0; - } - - // Skip the first "n" bytes and extract the subsequent "m" bytes. - Bytes extract(uint64_t n, uint64_t m) const { - return Bytes(data_ + n, m); - } - // Remove the first "n" bytes and the last "m" bytes. - Bytes trim(uint64_t n, uint64_t m) const { - return Bytes(data_ + n, size_ - n - m); - } - - // Extract the first "n" bytes. - Bytes prefix(uint64_t n) const { - return Bytes(data_, n); - } - // Extract the last "n" bytes. - Bytes suffix(uint64_t n) const { - return Bytes(data_ + size_ - n, n); - } - - // Remove the first "n" bytes. - Bytes except_prefix(uint64_t n) const { - return Bytes(data_ + n, size_ - n); - } - // Remove the last "n" bytes. - Bytes except_suffix(uint64_t n) const { - return Bytes(data_, size_ - n); - } - - // Return true iff "*this" == "rhs". - bool operator==(const Bytes &rhs) const { - return (size_ == rhs.size_) && (std::memcmp(data_, rhs.data_, size_) == 0); - } - // Return true iff "*this" != "rhs". - bool operator!=(const Bytes &rhs) const { - return !operator==(rhs); - } - // Return true iff "*this" < "rhs". - bool operator<(const Bytes &rhs) const { - const uint64_t min_size = (size_ < rhs.size_) ? size_ : rhs.size_; - int result = std::memcmp(data_, rhs.data_, min_size); - return (result < 0) || ((result == 0) && (size_ < rhs.size_)); - } - // Return true iff "*this" > "rhs". - bool operator>(const Bytes &rhs) const { - return rhs.operator<(*this); - } - // Return true iff "*this" <= "rhs". - bool operator<=(const Bytes &rhs) const { - return !operator>(rhs); - } - // Return true iff "*this" >= "rhs". - bool operator>=(const Bytes &rhs) const { - return !operator<(rhs); - } - - // Compare "*this" and "bytes" and return a negative value - // if "*this" < "bytes", zero if "*this" == "bytes", or a positive value - // otherwise (if "*this" > "bytes"). - int compare(const Bytes &bytes) const { - const uint64_t min_size = (size_ < bytes.size_) ? size_ : bytes.size_; - int result = std::memcmp(data_, bytes.data_, min_size); - if (result != 0) { - return result; - } - return (size_ < bytes.size_) ? -1 : (size_ > bytes.size_); - } - - // Return true iff "bytes" is a prefix of "*this". - bool starts_with(const Bytes &bytes) const { - return (size_ >= bytes.size_) && (prefix(bytes.size_) == bytes); - } - // Return true iff "bytes" is a suffix of "*this". - bool ends_with(const Bytes &bytes) const { - return (size_ >= bytes.size_) && (suffix(bytes.size_) == bytes); - } - - // Return the "i"-th byte. - uint8_t operator[](uint64_t i) const { - return data_[i]; - } - // Return the starting address. - const void *address() const { - return data_; - } - // Return a pointer to the sequence. - const uint8_t *data() const { - return data_; - } - // Return the number of bytes. - uint64_t size() const { - return size_; - } - - private: - const uint8_t *data_; - uint64_t size_; -}; - -inline bool operator==(const char *lhs, const Bytes &rhs) { - return Bytes(lhs) == rhs; -} -inline bool operator!=(const char *lhs, const Bytes &rhs) { - return Bytes(lhs) != rhs; -} -inline bool operator<(const char *lhs, const Bytes &rhs) { - return Bytes(lhs) < rhs; -} -inline bool operator>(const char *lhs, const Bytes &rhs) { - return Bytes(lhs) > rhs; -} -inline bool operator<=(const char *lhs, const Bytes &rhs) { - return Bytes(lhs) <= rhs; -} -inline bool operator>=(const char *lhs, const Bytes &rhs) { - return Bytes(lhs) >= rhs; -} - -} // namespace grnxx - -#endif // GRNXX_BYTES_HPP Deleted: lib/grnxx/charset.cpp (+0 -68) 100644 =================================================================== --- lib/grnxx/charset.cpp 2013-08-23 10:46:34 +0900 (f7653be) +++ /dev/null @@ -1,68 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/charset.hpp" - -#include "grnxx/charset/euc-jp.hpp" -#include "grnxx/charset/shift_jis.hpp" -#include "grnxx/charset/utf-8.hpp" -#include "grnxx/exception.hpp" -#include "grnxx/logger.hpp" -#include "grnxx/string_builder.hpp" - -namespace grnxx { - -StringBuilder &operator<<(StringBuilder &builder, CharsetCode code) { - switch (code) { - case CHARSET_SHIFT_JIS: { - return builder << "Shift_JIS"; - } - case CHARSET_EUC_JP: { - return builder << "EUC-JP"; - } - case CHARSET_UTF_8: { - return builder << "UTF-8"; - } - case CHARSET_UNKNOWN: { - break; - } - } - return builder << "n/a"; -} - -Charset::Charset() {} -Charset::~Charset() {} - -const Charset *Charset::get(CharsetCode code) { - switch (code) { - case CHARSET_SHIFT_JIS: { - return charset::Shift_JIS::get(); - } - case CHARSET_EUC_JP: { - return charset::EUC_JP::get(); - } - case CHARSET_UTF_8: { - return charset::UTF_8::get(); - } - default: { - GRNXX_ERROR() << "invalid argument: code = " << code; - throw LogicError(); - } - } -} - -} // namespace grnxx Deleted: lib/grnxx/charset.hpp (+0 -62) 100644 =================================================================== --- lib/grnxx/charset.hpp 2013-08-23 10:46:34 +0900 (aa67228) +++ /dev/null @@ -1,62 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_CHARSET_HPP -#define GRNXX_CHARSET_HPP - -#include "grnxx/features.hpp" - -#include "grnxx/bytes.hpp" -#include "grnxx/types.hpp" - -namespace grnxx { - -class StringBuilder; - -// The values correspond to MIB enum numbers. -// Reference: http://www.iana.org/assignments/character-sets/character-sets.xml -enum CharsetCode : uint16_t { - CHARSET_SHIFT_JIS = 17, - CHARSET_EUC_JP = 18, - CHARSET_UTF_8 = 106, - CHARSET_UNKNOWN = 65535 -}; - -StringBuilder &operator<<(StringBuilder &builder, CharsetCode code); - -class Charset { - public: - Charset(); - virtual ~Charset(); - - // Return a reference to a specific charset. - static const Charset *get(CharsetCode code); - - // Return the charset code. - virtual CharsetCode code() const = 0; - - // Return the first character of "bytes". This function may return an empty - // sequence if "bytes" is empty or an invalid sequence. - virtual Bytes get_char(const Bytes &bytes) const = 0; - // Return the size of the first character of "bytes". This function may - // return 0 if "bytes" is empty or an invalid sequence. - virtual size_t get_char_size(const Bytes &bytes) const = 0; -}; - -} // namespace grnxx - -#endif // GRNXX_CHARSET_HPP Deleted: lib/grnxx/charset/Makefile.am (+0 -14) 100644 =================================================================== --- lib/grnxx/charset/Makefile.am 2013-08-23 10:46:34 +0900 (25db000) +++ /dev/null @@ -1,14 +0,0 @@ -noinst_LTLIBRARIES = libgrnxx_charset.la - -libgrnxx_charset_la_LDFLAGS = @AM_LTLDFLAGS@ - -libgrnxx_charset_la_SOURCES = \ - euc-jp.cpp \ - shift_jis.cpp \ - utf-8.cpp - -libgrnxx_charset_includedir = ${includedir}/grnxx/charset -libgrnxx_charset_include_HEADERS = \ - euc-jp.hpp \ - shift_jis.hpp \ - utf-8.hpp Deleted: lib/grnxx/charset/euc-jp.cpp (+0 -80) 100644 =================================================================== --- lib/grnxx/charset/euc-jp.cpp 2013-08-23 10:46:34 +0900 (ea4f287) +++ /dev/null @@ -1,80 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/charset/euc-jp.hpp" - -namespace grnxx { -namespace charset { - -const Charset *EUC_JP::get() { - static EUC_JP singleton; - return &singleton; -} - -CharsetCode EUC_JP::code() const { - return CHARSET_EUC_JP; -} - -Bytes EUC_JP::get_char(const Bytes &bytes) const { - return bytes.prefix(get_char_size(bytes)); -} - -size_t EUC_JP::get_char_size(const Bytes &bytes) const { - if (!bytes) { - return 0; - } - // Reference: http://ja.wikipedia.org/wiki/EUC-JP - if (bytes[0] & 0x80) { - // A 3-byte character starts with 0x8F. - if (bytes[0] == 0x8F) { - // Return 0 if the character is incomplete. - if (bytes.size() < 3) { - return 0; - } - // Return 0 if the 2nd byte is invalid. - // In fact, only bytes in [A1, A8], [B0, ED], and [F3, FE] are valid. - if (static_cast<unsigned>(bytes[1] - 0xA1) > (0xFE - 0xA1)) { - return 0; - } - // Return 0 if the 3rd byte is invalid. - if (static_cast<unsigned>(bytes[2] - 0xA1) > (0xFE - 0xA1)) { - return 0; - } - return 3; - } else { - // Return 0 if the 1st byte is invalid. - // In fact, only bytes in [A1, A8], [AD, AD], and [B0, FE] are valid. - if (static_cast<unsigned>(bytes[0] - 0xA1) > (0xFE - 0xA1)) { - return 0; - } - // Return 0 if the character is incomplete. - if (bytes.size() < 2) { - return 0; - } - // Return 0 if the 2nd byte is invalid. - if (static_cast<unsigned>(bytes[1] - 0xA1) > (0xFE - 0xA1)) { - return 0; - } - return 2; - } - } - // Return 1 for an ASCII character. - return 1; -} - -} // namespace charset -} // namespace grnxx Deleted: lib/grnxx/charset/euc-jp.hpp (+0 -43) 100644 =================================================================== --- lib/grnxx/charset/euc-jp.hpp 2013-08-23 10:46:34 +0900 (a997cd6) +++ /dev/null @@ -1,43 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_CHARSET_EUC_JP_HPP -#define GRNXX_CHARSET_EUC_JP_HPP - -#include "grnxx/features.hpp" - -#include "grnxx/bytes.hpp" -#include "grnxx/charset.hpp" - -namespace grnxx { -namespace charset { - -// EUC-JP: Extended_UNIX_Code_Packed_Format_for_Japanese. -class EUC_JP : public Charset { - public: - static const Charset *get(); - - CharsetCode code() const; - - Bytes get_char(const Bytes &bytes) const; - size_t get_char_size(const Bytes &bytes) const; -}; - -} // namespace charset -} // namespace grnxx - -#endif // GRNXX_CHARSET_EUC_JP_HPP Deleted: lib/grnxx/charset/shift_jis.cpp (+0 -58) 100644 =================================================================== --- lib/grnxx/charset/shift_jis.cpp 2013-08-23 10:46:34 +0900 (3e57265) +++ /dev/null @@ -1,58 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/charset/shift_jis.hpp" - -namespace grnxx { -namespace charset { - -const Charset *Shift_JIS::get() { - static Shift_JIS singleton; - return &singleton; -} - -CharsetCode Shift_JIS::code() const { - return CHARSET_SHIFT_JIS; -} - -Bytes Shift_JIS::get_char(const Bytes &bytes) const { - return bytes.prefix(get_char_size(bytes)); -} - -size_t Shift_JIS::get_char_size(const Bytes &bytes) const { - if (!bytes) { - return 0; - } - // The 1st byte of a multibyte character is in [81, 9F] or [E0, FC]. - // Reference: http://www.st.rim.or.jp/~phinloda/cqa/cqa15.html#Q4 - if (static_cast<unsigned>((bytes[0] ^ 0x20) - 0xA1) < 0x3C) { - // Return 0 if the character is incomplete. - if (bytes.size() < 2) { - return 0; - } - // Return 0 if the 2nd byte is invalid. - if (static_cast<unsigned>(bytes[1] - 0x40) > (0xFC - 0x40)) { - return 0; - } - return 2; - } - // Return 1 for an ASCII character. - return 1; -} - -} // namespace charset -} // namespace grnxx Deleted: lib/grnxx/charset/shift_jis.hpp (+0 -43) 100644 =================================================================== --- lib/grnxx/charset/shift_jis.hpp 2013-08-23 10:46:34 +0900 (910d6c3) +++ /dev/null @@ -1,43 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_CHARSET_SHIFT_JIS_HPP -#define GRNXX_CHARSET_SHIFT_JIS_HPP - -#include "grnxx/features.hpp" - -#include "grnxx/bytes.hpp" -#include "grnxx/charset.hpp" - -namespace grnxx { -namespace charset { - -// Shift_JIS. -class Shift_JIS : public Charset { - public: - static const Charset *get(); - - CharsetCode code() const; - - Bytes get_char(const Bytes &bytes) const; - size_t get_char_size(const Bytes &bytes) const; -}; - -} // namespace charset -} // namespace grnxx - -#endif // GRNXX_CHARSET_SHIFT_JIS_HPP Deleted: lib/grnxx/charset/utf-8.cpp (+0 -84) 100644 =================================================================== --- lib/grnxx/charset/utf-8.cpp 2013-08-23 10:46:34 +0900 (a833f2e) +++ /dev/null @@ -1,84 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/charset/utf-8.hpp" - -#include "grnxx/bytes.hpp" -#include "grnxx/intrinsic.hpp" - -namespace grnxx { -namespace charset { - -const Charset *UTF_8::get() { - static UTF_8 singleton; - return &singleton; -} - -CharsetCode UTF_8::code() const { - return CHARSET_UTF_8; -} - -Bytes UTF_8::get_char(const Bytes &bytes) const { - return bytes.prefix(get_char_size(bytes)); -} - -size_t UTF_8::get_char_size(const Bytes &bytes) const { - if (!bytes) { - return 0; - } - if (bytes[0] & 0x80) { - // A multibyte character can be 2, 3, or 4 bytes long. Also, the 2nd, - // 3rd, and 4th byte must be 10xxxxxx, the most significant 2 bits must - // be 10. - const size_t char_size = - 31 - bit_scan_reverse(~(static_cast<uint32_t>(bytes[0]) << 24)); - // Return 0 if the character is incomplete. - if (char_size > bytes.size()) { - return 0; - } - switch (char_size) { - case 4: { - // Return 0 if the 4th byte is invalid. - if ((bytes[3] & 0xC0) != 0x80) { - return 0; - } - } - case 3: { - // Return 0 if the 3rd byte is invalid. - if ((bytes[2] & 0xC0) != 0x80) { - return 0; - } - } - case 2: { - // Return 0 if the 2nd byte is invalid. - if ((bytes[1] & 0xC0) != 0x80) { - return 0; - } - return char_size; - } - default: { - // Return 0 if the character size is invalid. - return 0; - } - } - } - // Return 1 for an ASCII character. - return 1; -} - -} // namespace charset -} // namespace grnxx Deleted: lib/grnxx/charset/utf-8.hpp (+0 -43) 100644 =================================================================== --- lib/grnxx/charset/utf-8.hpp 2013-08-23 10:46:34 +0900 (481a161) +++ /dev/null @@ -1,43 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_CHARSET_UTF_8_HPP -#define GRNXX_CHARSET_UTF_8_HPP - -#include "grnxx/features.hpp" - -#include "grnxx/bytes.hpp" -#include "grnxx/charset.hpp" - -namespace grnxx { -namespace charset { - -// UTF-8. -class UTF_8 : public Charset { - public: - static const Charset *get(); - - CharsetCode code() const; - - Bytes get_char(const Bytes &bytes) const; - size_t get_char_size(const Bytes &bytes) const; -}; - -} // namespace charset -} // namespace grnxx - -#endif // GRNXX_CHARSET_UTF_8_HPP Deleted: lib/grnxx/common_header.cpp (+0 -69) 100644 =================================================================== --- lib/grnxx/common_header.cpp 2013-08-23 10:46:34 +0900 (1339e6a) +++ /dev/null @@ -1,69 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/common_header.hpp" - -#include <cstring> - -#include "grnxx/exception.hpp" -#include "grnxx/grnxx.hpp" -#include "grnxx/logger.hpp" - -namespace grnxx { - -CommonHeader::CommonHeader(const char *format) : format_{}, version_{} { - // Copy the format string. - if (!format) { - GRNXX_ERROR() << "invalid format: format = nullptr"; - throw LogicError(); - } - const std::size_t format_length = std::strlen(format); - if (format_length >= FORMAT_SIZE) { - GRNXX_ERROR() << "too long format: format = " << format; - throw LogicError(); - } - std::memcpy(format_, format, format_length); - - // Copy the current version string. - const char * const current_version = Grnxx::version(); - if (!current_version) { - GRNXX_ERROR() << "invalid version: current_version = nullptr"; - throw LogicError(); - } - const std::size_t current_version_length = std::strlen(current_version); - if (current_version_length >= VERSION_SIZE) { - GRNXX_ERROR() << "too long version: current_version = " << current_version; - throw LogicError(); - } - std::memcpy(version_, current_version, current_version_length); -} - -Bytes CommonHeader::format() const { - if (format_[FORMAT_SIZE - 1] == '\0') { - return Bytes(format_); - } - return Bytes(format_, FORMAT_SIZE); -} - -Bytes CommonHeader::version() const { - if (version_[VERSION_SIZE - 1] == '\0') { - return Bytes(version_); - } - return Bytes(version_, VERSION_SIZE); -} - -} // namespace grnxx Deleted: lib/grnxx/common_header.hpp (+0 -51) 100644 =================================================================== --- lib/grnxx/common_header.hpp 2013-08-23 10:46:34 +0900 (cd3f0ec) +++ /dev/null @@ -1,51 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_COMMON_HEADER_HPP -#define GRNXX_COMMON_HEADER_HPP - -#include "grnxx/features.hpp" - -#include "grnxx/bytes.hpp" -#include "grnxx/types.hpp" - -namespace grnxx { - -class CommonHeader { - public: - // Buffer size for "format_" and "version_". - static constexpr size_t FORMAT_SIZE = 64; - static constexpr size_t VERSION_SIZE = 32; - - // Trivial default constructor. - CommonHeader() = default; - // Create a common header with "format" and the current version. - explicit CommonHeader(const char *format); - - // Return the format string. - Bytes format() const; - // Return the version string. - Bytes version() const; - - private: - char format_[FORMAT_SIZE]; - char version_[VERSION_SIZE]; -}; - -} // namespace grnxx - -#endif // GRNXX_COMMON_HEADER_HPP Deleted: lib/grnxx/duration.cpp (+0 -44) 100644 =================================================================== --- lib/grnxx/duration.cpp 2013-08-23 10:46:34 +0900 (01bc6be) +++ /dev/null @@ -1,44 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/duration.hpp" - -#include "grnxx/string_builder.hpp" -#include "grnxx/string_format.hpp" - -namespace grnxx { - -StringBuilder &operator<<(StringBuilder &builder, Duration duration) { - if (!builder) { - return builder; - } - uint64_t count; - if (duration.count() >= 0) { - count = duration.count(); - } else { - builder << '-'; - count = -duration.count(); - } - builder << (count / 1000000); - count %= 1000000; - if (count != 0) { - builder << '.' << StringFormat::align_right(count, 6, '0'); - } - return builder; -} - -} // namespace grnxx Deleted: lib/grnxx/duration.hpp (+0 -172) 100644 =================================================================== --- lib/grnxx/duration.hpp 2013-08-23 10:46:34 +0900 (f734d53) +++ /dev/null @@ -1,172 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_DURATION_HPP -#define GRNXX_DURATION_HPP - -#include "grnxx/features.hpp" - -#include <limits> - -#include "grnxx/types.hpp" - -namespace grnxx { - -class StringBuilder; - -// Time difference in microseconds. -// 64-bit tick count (usec) is used. -class Duration { - public: - // Trivial default constructor. - Duration() = default; - // Construct a duration object whose tick count is "count". - explicit constexpr Duration(int64_t count) : count_(count) {} - - // Return the minimum tick count. - static constexpr Duration min() { - return Duration(std::numeric_limits<int64_t>::min()); - } - // Return the maximum tick count. - static constexpr Duration max() { - return Duration(std::numeric_limits<int64_t>::max()); - } - - // Return a duration of "count" microseconds. - static constexpr Duration microseconds(int64_t count) { - return Duration(count); - } - // Return a duration of "count" milliseconds. - static constexpr Duration milliseconds(int64_t count) { - return Duration(count * 1000); - } - // Return a duration of "count" seconds. - static constexpr Duration seconds(int64_t count) { - return Duration(count * 1000000); - } - // Return a duration of "count" minutes. - static constexpr Duration minutes(int64_t count) { - return Duration(count * 1000000 * 60); - } - // Return a duration of "count" hours. - static constexpr Duration hours(int64_t count) { - return Duration(count * 1000000 * 60 * 60); - } - // Return a duration of "count" days. - static constexpr Duration days(int64_t count) { - return Duration(count * 1000000 * 60 * 60 * 24); - } - // Return a duration of "count" weeks. - static constexpr Duration weeks(int64_t count) { - return Duration(count * 1000000 * 60 * 60 * 24 * 7); - } - - // Return the tick count. - constexpr int64_t count() const { - return count_; - } - // Set the tick count. - void set_count(int64_t count) { - count_ = count; - } - - private: - int64_t count_; - - // Copyable. -}; - -inline constexpr Duration operator+(Duration duration) { - return duration; -} -inline constexpr Duration operator-(Duration duration) { - return Duration(-duration.count()); -} - -inline Duration &operator+=(Duration &lhs, Duration rhs) { - lhs.set_count(lhs.count() + rhs.count()); - return lhs; -} -inline Duration &operator-=(Duration &lhs, Duration rhs) { - lhs.set_count(lhs.count() - rhs.count()); - return lhs; -} -inline Duration &operator*=(Duration &lhs, int64_t rhs) { - lhs.set_count(lhs.count() * rhs); - return lhs; -} -inline Duration &operator/=(Duration &lhs, int64_t rhs) { - if (rhs == 0) { - lhs.set_count(0); - } else { - lhs.set_count(lhs.count() / rhs); - } - return lhs; -} -inline Duration &operator%=(Duration &lhs, Duration rhs) { - if (rhs.count() == 0) { - lhs.set_count(0); - } else { - lhs.set_count(lhs.count() % rhs.count()); - } - return lhs; -} - -inline constexpr Duration operator+(Duration lhs, Duration rhs) { - return Duration(lhs.count() + rhs.count()); -} -inline constexpr Duration operator-(Duration lhs, Duration rhs) { - return Duration(lhs.count() - rhs.count()); -} -inline constexpr Duration operator*(Duration lhs, int64_t rhs) { - return Duration(lhs.count() * rhs); -} -inline constexpr Duration operator*(int64_t lhs, Duration rhs) { - return Duration(lhs * rhs.count()); -} -inline constexpr Duration operator/(Duration lhs, int64_t rhs) { - return (rhs != 0) ? Duration(lhs.count() / rhs) : Duration(0); -} -inline constexpr Duration operator%(Duration lhs, Duration rhs) { - return (rhs.count() != 0) ? - Duration(lhs.count() % rhs.count()) : Duration(0); -} - -inline constexpr bool operator==(Duration lhs, Duration rhs) { - return lhs.count() == rhs.count(); -} -inline constexpr bool operator!=(Duration lhs, Duration rhs) { - return lhs.count() != rhs.count(); -} -inline constexpr bool operator<(Duration lhs, Duration rhs) { - return lhs.count() < rhs.count(); -} -inline constexpr bool operator<=(Duration lhs, Duration rhs) { - return lhs.count() <= rhs.count(); -} -inline constexpr bool operator>(Duration lhs, Duration rhs) { - return lhs.count() > rhs.count(); -} -inline constexpr bool operator>=(Duration lhs, Duration rhs) { - return lhs.count() >= rhs.count(); -} - -StringBuilder &operator<<(StringBuilder &builder, Duration duration); - -} // namespace grnxx - -#endif // GRNXX_DURATION_HPP Deleted: lib/grnxx/errno.cpp (+0 -96) 100644 =================================================================== --- lib/grnxx/errno.cpp 2013-08-23 10:46:34 +0900 (b0e1b34) +++ /dev/null @@ -1,96 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/errno.hpp" - -#include <string.h> - -#ifdef GRNXX_WINDOWS -# include <windows.h> -#endif // GRNXX_WINDOWS - -#include <memory> - -#include "grnxx/string_builder.hpp" - -namespace grnxx { -namespace { - -constexpr size_t MESSAGE_BUF_SIZE = 256; - -#ifdef GRNXX_WINDOWS -class Freer { - public: - void operator()(void *ptr) const { - ::LocalFree(ptr); - } -}; -#endif // GRNXX_WINDOWS - -} // namespace - -StringBuilder &Errno::write_to(StringBuilder &builder) const { - switch (type_) { - case STANDARD_ERRNO: { - // Note that a string returned by ::strerror() may be modified by a - // subsequent call to ::perror() or ::strerror(). - const char *message = "n/a"; -#ifdef GRNXX_MSC - char message_buf[MESSAGE_BUF_SIZE]; - if (::strerror_s(message_buf, MESSAGE_BUF_SIZE, standard_errno_) == 0) { - message = message_buf; - } -#elif defined(GRNXX_HAS_XSI_STRERROR) - char message_buf[MESSAGE_BUF_SIZE]; - if (::strerror_r(standard_errno_, message_buf, MESSAGE_BUF_SIZE) == 0) { - message = message_buf; - } -#elif defined(GRNXX_HAS_GNU_STRERROR) - // ::strerror_r() may not use "message_buf" when an immutable error - // message is available. - char message_buf[MESSAGE_BUF_SIZE]; - message = ::strerror_r(standard_errno_, message_buf, MESSAGE_BUF_SIZE); -#else // defined(GRNXX_HAS_GNU_STRERROR) - message = ::strerror(standard_errno_); -#endif // defined(GRNXX_HAS_GNU_STRERROR) - return builder << standard_errno_ << " (" << message << ')'; - } -#ifdef GRNXX_WINDOWS - case WINDOWS_ERRNO: { - char *message; - if (::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - nullptr, windows_errno_, - MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), - reinterpret_cast<LPSTR>(&message), - 0, nullptr) != 0) { - std::unique_ptr<char[], Freer> message_freer(message); - builder << windows_errno_ << " (" << message << ')'; - } else { - builder << windows_errno << " (n/a)"; - } - return builder; - } -#endif // GRNXX_WINDOWS - default: { - return builder << "n/a"; - } - } -} - -} // namespace grnxx Deleted: lib/grnxx/errno.hpp (+0 -82) 100644 =================================================================== --- lib/grnxx/errno.hpp 2013-08-23 10:46:34 +0900 (74e8124) +++ /dev/null @@ -1,82 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_ERRNO_HPP -#define GRNXX_ERRNO_HPP - -#include "grnxx/features.hpp" - -namespace grnxx { - -class StringBuilder; - -enum ErrnoType { - STANDARD_ERRNO, -#ifdef GRNXX_WINDOWS - WINDOWS_ERRNO -#endif // GRNXX_WINDOWS -}; - -class GRNXX_EXPORT Errno { - public: - Errno() = default; - // For errno. - explicit Errno(int error_code) - : type_(STANDARD_ERRNO), - standard_errno_(error_code) {} -#ifdef GRNXX_WINDOWS - // For DWORD returned by ::GetLastErrno(). - explicit Errno(unsigned long error_code) - : type_(WINDOWS_ERRNO), - windows_errno_(error_code) {} -#endif // GRNXX_WINDOWS - - // Return the errno type. - ErrnoType type() const { - return type_; - } - // Return the standard errno. - int standard_errno() const { - return standard_errno_; - } -#ifdef GRNXX_WINDOWS - // Return the windows errno. - unsigned long windows_errno() const { - return windows_errno_; - } -#endif // GRNXX_WINDOWS - - // Write a human-readable error message to "builder". - StringBuilder &write_to(StringBuilder &builder) const; - - private: - ErrnoType type_; - union { - int standard_errno_; -#ifdef GRNXX_WINDOWS - unsigned long windows_errno_; -#endif // GRNXX_WINDOWS - }; -}; - -inline StringBuilder &operator<<(StringBuilder &builder, const Errno &error) { - return error.write_to(builder); -} - -} // namespace grnxx - -#endif // GRNXX_ERRNO_HPP Deleted: lib/grnxx/exception.hpp (+0 -97) 100644 =================================================================== --- lib/grnxx/exception.hpp 2013-08-23 10:46:34 +0900 (f831500) +++ /dev/null @@ -1,97 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_EXCEPTION_HPP -#define GRNXX_EXCEPTION_HPP - -#include "grnxx/features.hpp" - -#include <exception> - -#include "grnxx/errno.hpp" - -namespace grnxx { - -// The base exception class. -class Exception : std::exception { - public: - Exception() noexcept {} - virtual ~Exception() noexcept {} - - virtual const char *what() const noexcept { - return "grnxx::Exception"; - } -}; - -// Thrown as an exception when a logical error occurs. -class LogicError : public Exception { - public: - LogicError() noexcept {} - virtual ~LogicError() noexcept {} - - virtual const char *what() const noexcept { - return "grnxx::LogicError"; - } -}; - -// Thrown as an exception when memory allocation fails. -class MemoryError : public Exception { - public: - MemoryError() noexcept {} - virtual ~MemoryError() noexcept {} - - virtual const char *what() const noexcept { - return "grnxx::MemoryError"; - } -}; - -// Thrown as as exception when an exception generated by the standard library -// is caught. -class StandardError : public Exception { - public: - StandardError(const std::exception &exception) noexcept - : exception_(exception) {} - virtual ~StandardError() noexcept {} - - virtual const char *what() const noexcept { - return exception_.what(); - } - - private: - const std::exception &exception_; -}; - -// Thrown as an exception when a system call fails. -class SystemError : public Exception { - public: - explicit SystemError(const Errno &code) noexcept : code_(code) {} - virtual ~SystemError() noexcept {} - - const Errno &code() const noexcept { - return code_; - } - virtual const char *what() const noexcept { - return "grnxx::SystemError"; - } - - private: - Errno code_; -}; - -} // namespace grnxx - -#endif // GRNXX_EXCEPTION_HPP Deleted: lib/grnxx/features.hpp (+0 -238) 100644 =================================================================== --- lib/grnxx/features.hpp 2013-08-23 10:46:34 +0900 (60cc702) +++ /dev/null @@ -1,238 +0,0 @@ -/* - Copyright (C) 2012 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_FEATURES_HPP -#define GRNXX_FEATURES_HPP - -// Operating system features. - -#ifdef _WIN32 -# define GRNXX_WINDOWS -# ifdef _WIN64 -# define GRNXX_WIN64 _WIN64 -# else // _WIN64 -# define GRNXX_WIN32 _WIN32 -# endif // _WIN64 -#endif // _WIN32 - -#if defined(__APPLE__) && defined(__MACH__) -# define GRNXX_APPLE -#endif // defined(__APPLE__) && defined(__MACH__) - -#if defined(sun) || defined(__sun) -# define GRNXX_SOLARIS -#endif // defined(sun) || defined(__sun) - -// Compiler features. - -#ifdef _MSC_VER -# define GRNXX_MSC -# define GRNXX_MSC_VERSION _MSC_VER -# ifdef GRNXX_WIN32 -# define GRNXX_MSC32 -# else // GRNXX_WIN32 -# define GRNXX_MSC64 -# endif // GRNXX_WIN32 -#endif // _MSC_VER - -#ifdef __MINGW32__ -# define GRNXX_MINGW -# ifdef __MINGW64__ -# define GRNXX_MINGW64 -# else // __MINGW64__ -# define GRNXX_MINGW32 -# endif // __MINGW64__ -#endif // __MINGW32__ - -#ifdef __clang__ -# define GRNXX_CLANG -# define GRNXX_CLANG_MAJOR __clang_major__ -# define GRNXX_CLANG_MINOR __clang_minor__ -# define GRNXX_CLANG_PATCH_LEVEL __clang_patchlevel__ -# define GRNXX_CLANG_VERSION __clang_version__ -#endif // __clang__ - -#ifdef __GNUC__ -# define GRNXX_GNUC -# define GRNXX_GNUC_MAJOR __GNUC__ -# ifdef __GNUC_MINOR__ -# define GRNXX_GNUC_MINOR __GNUC_MINOR__ -# else // __GNUC_MINOR__ -# define GRNXX_GNUC_MINOR 0 -# endif // __GNUC_MINOR__ -# ifdef __GNUC_PATCHLEVEL__ -# define GRNXX_GNUC_PATCH_LEVEL __GNUC_PATCHLEVEL__ -# else // __GNUC_PATCHLEVEL__ -# define GRNXX_GNUC_PATCH_LEVEL 0 -# endif // __GNUC_PATCHLEVEL__ -# define GRNXX_GNUC_MAKE_VERSION(major, minor, patch_level)\ - ((major * 10000) + (minor * 100) + patch_level) -# define GRNXX_GNUC_VERSION GRNXX_GNUC_MAKE_VERSION(\ - GRNXX_GNUC_MAJOR, GRNXX_GNUC_MINOR, GRNXX_GNUC_PATCH_LEVEL) -#endif // defined(__GNUC__) - -#ifdef GRNXX_CLANG -# ifdef __has_builtin -# define GRNXX_CLANG_HAS_BUILTIN(builtin) __has_builtin(builtin) -# else -# define GRNXX_CLANG_HAS_BUILTIN(builtin) false -# endif // __has_builtin -# ifdef __has_feature -# define GRNXX_CLANG_HAS_FEATURE(feature) __has_feature(feature) -# else -# define GRNXX_CLANG_HAS_FEATURE(feature) false -# endif // __has_feature -# ifdef __has_extension -# define GRNXX_CLANG_HAS_EXTENSION(extension) __has_extension(extension) -# else -# define GRNXX_CLANG_HAS_EXTENSION(extension) false -# endif // __has_extension -# define GRNXX_CLANG_HAS(thing) (GRNXX_CLANG_HAS_BUILTIN(thing) |\ - GRNXX_CLANG_HAS_FEATURE(thing) | GRNXX_CLANG_HAS_EXTENSION(thing)) -#endif // GRNXX_CLANG - -#ifdef GRNXX_CLANG -# if GRNXX_CLANG_HAS(__builtin_bswap16) -# define GRNXX_HAS_GNUC_BUILTIN_BSWAP16 -# endif // GRNXX_CLANG_HAS(__builtin_bswap16) -# if GRNXX_CLANG_HAS(__builtin_bswap32) -# define GRNXX_HAS_GNUC_BUILTIN_BSWAP32 -# endif // GRNXX_CLANG_HAS(__builtin_bswap32) -# if GRNXX_CLANG_HAS(__builtin_bswap64) -# define GRNXX_HAS_GNUC_BUILTIN_BSWAP64 -# endif // GRNXX_CLANG_HAS(__builtin_bswap64) -# if GRNXX_CLANG_HAS(__builtin_clz) -# define GRNXX_HAS_GNUC_BUILTIN_CLZ -# endif // GRNXX_CLANG_HAS(__builtin_clz) -# if GRNXX_CLANG_HAS(__sync_bool_compare_and_swap) -# define GRNXX_HAS_GNUC_BUILTIN_SYNC -# endif // GRNXX_CLANG_HAS(__sync_bool_compare_and_swap) -# if GRNXX_CLANG_HAS(__atomic_compare_exchange_n) -# define GRNXX_HAS_GNUC_BUILTIN_ATOMIC -# endif // GRNXX_CLANG_HAS(__atomic_compare_exchange_n) -# if GRNXX_CLANG_HAS(c_atomic) -# define GRNXX_HAS_CLANG_BUILTIN_ATOMIC -# endif // GRNXX_CLANG_HAS(c_atomic) -#elif defined(GRNXX_GNUC) -# define GRNXX_HAS_GNUC_BUILTIN_CLZ -# if GRNXX_GNUC_VERSION >= GRNXX_GNUC_MAKE_VERSION(4, 2, 0) -# define GRNXX_HAS_GNUC_BUILTIN_SYNC -# define GRNXX_HAS_GNUC_BUILTIN_BSWAP32 -# define GRNXX_HAS_GNUC_BUILTIN_BSWAP64 -# endif // GRNXX_GNUC_VERSION >= GRNXX_GNUC_MAKE_VERSION(4, 2, 0) -# if GRNXX_GNUC_VERSION >= GRNXX_GNUC_MAKE_VERSION(4, 7, 0) -# define GRNXX_HAS_GNUC_BUILTIN_ATOMIC -# endif // GRNXX_GNUC_VERSION >= GRNXX_GNUC_MAKE_VERSION(4, 7, 0) -# if GRNXX_GNUC_VERSION >= GRNXX_GNUC_MAKE_VERSION(4, 8, 0) -# define GRNXX_HAS_GNUC_BUILTIN_BSWAP16 -# endif // GRNXX_GNUC_VERSION >= GRNXX_GNUC_MAKE_VERSION(4, 8, 0) -#endif // defined(GRNXX_GNUC) - -// Source features. - -#ifdef _GNU_SOURCE -# define GRNXX_GNU_SOURCE _GNU_SOURCE -#else // _GNU_SOURCE -# define GRNXX_GNU_SOURCE 0 -#endif // _GNU_SOURCE - -#ifdef _POSIX_C_SOURCE -# define GRNXX_POSIX_C_SOURCE _POSIX_C_SOURCE -#else // _POSIX_C_SOURCE -# define GRNXX_POSIX_C_SOURCE 0 -#endif // _POSIX_C_SOURCE - -#ifdef _XOPEN_SOURCE -# define GRNXX_XOPEN_SOURCE _XOPEN_SOURCE -#else // _XOPEN_SOURCE -# define GRNXX_XOPEN_SOURCE 0 -#endif // _XOPEN_SOURCE - -#ifdef _XOPEN_SOURCE_EXTENDED -# define GRNXX_XOPEN_SOURCE_EXTENDED _XOPEN_SOURCE_EXTENDED -#else // _XOPEN_SOURCE_EXTENDED -# define GRNXX_XOPEN_SOURCE_EXTENDED 0 -#endif // _XOPEN_SOURCE_EXTENDED - -#ifdef _BSD_SOURCE -# define GRNXX_BSD_SOURCE _BSD_SOURCE -#else // _BSD_SOURCE -# define GRNXX_BSD_SOURCE 0 -#endif // _BSD_SOURCE - -#ifdef _SVID_SOURCE -# define GRNXX_SVID_SOURCE _SVID_SOURCE -#else // _SVID_SOURCE -# define GRNXX_SVID_SOURCE 0 -#endif // _SVID_SOURCE - -#ifdef _POSIX_SOURCE -# define GRNXX_POSIX_SOURCE _POSIX_SOURCE -#else // _POSIX_SOURCE -# define GRNXX_POSIX_SOURCE 0 -#endif // _POSIX_SOURCE - -// Available functions. - -#if ((GRNXX_POSIX_C_SOURCE >= 20112L) || (GRNXX_XOPEN_SOURCE >= 600)) &&\ - !GRNXX_GNU_SOURCE -# define GRNXX_HAS_XSI_STRERROR -#else // ((GRNXX_POSIX_C_SOURCE >= 20112L) || ... -# define GRNXX_HAS_GNU_STRERROR -#endif // ((GRNXX_POSIX_C_SOURCE >= 20112L) || ... - -#if GRNXX_POSIX_C_SOURCE >= 199309L -# define GRNXX_HAS_NANOSLEEP -#endif // GRNXX_POSIX_C_SOURCE >= 199309L - -#if (GRNXX_POSIX_C_SOURCE >= 1) || GRNXX_XOPEN_SOURCE || GRNXX_BSD_SOURCE ||\ - GRNXX_SVID_SOURCE || GRNXX_POSIX_SOURCE -# define GRNXX_HAS_GMTIME_R -# define GRNXX_HAS_LOCALTIME_R -#endif // (GRNXX_POSIX_C_SOURCE >= 1) || ... - -#if (GRNXX_XOPEN_SOURCE >= 500) || (GRNXX_POSIX_C_SOURCE >= 200809L) -# define GRNXX_HAS_PREAD -# define GRNXX_HAS_PWRITE -#endif // (GRNXX_XOPEN_SOURCE >= 500) || (GRNXX_POSIX_C_SOURCE >= 200809L) - -#ifndef GRNXX_WINDOWS -# include <unistd.h> -# ifdef _POSIX_TIMERS -# if _POSIX_TIMERS > 0 -# define GRNXX_HAS_POSIX_TIMER -# define GRNXX_HAS_CLOCK_GETTIME -# endif // _POSIX_TIMERS > 0 -# endif // _POSIX_TIMERS -# ifdef _POSIX_PRIORITY_SCHEDULING -# define GRNXX_HAS_SCHED_YIELD -# endif // _POSIX_PRIORITY_SCHEDULING -#endif // GRNXX_WINDOWS - -// DLL features. - -#ifdef GRNXX_WINDOWS -# ifdef DLL_EXPORT -# define GRNXX_EXPORT __declspec(dllexport) -# else // DLL_EXPORT -# define GRNXX_EXPORT __declspec(dllimport) -# endif // DLL_EXPORT -#else // GRNXX_WINDOWS -# define GRNXX_EXPORT -#endif // GRNXX_WINDOWS - -#endif // GRNXX_FEATURES_HPP Deleted: lib/grnxx/flags_impl.hpp (+0 -84) 100644 =================================================================== --- lib/grnxx/flags_impl.hpp 2013-08-23 10:46:34 +0900 (c5fe933) +++ /dev/null @@ -1,84 +0,0 @@ -/* - Copyright (C) 2012 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_FLAGS_IMPL_HPP -#define GRNXX_FLAGS_IMPL_HPP - -#include "grnxx/features.hpp" - -#include "grnxx/types.hpp" - -namespace grnxx { - -template <typename T, typename U = uint32_t> -class FlagsImpl { - public: - using Identifier = T; - using Type = U; - - FlagsImpl() = default; - - constexpr explicit operator bool() const { - return flags_ != 0; - } - - constexpr FlagsImpl operator&(FlagsImpl rhs) const { - return FlagsImpl(flags_ & rhs.flags_); - } - constexpr FlagsImpl operator|(FlagsImpl rhs) const { - return FlagsImpl(flags_ | rhs.flags_); - } - constexpr FlagsImpl operator^(FlagsImpl rhs) const { - return FlagsImpl(flags_ ^ rhs.flags_); - } - constexpr FlagsImpl operator~() const { - return FlagsImpl(~flags_); - } - - constexpr bool operator==(FlagsImpl rhs) const { - return flags_ == rhs.flags_; - } - constexpr bool operator!=(FlagsImpl rhs) const { - return flags_ == rhs.flags_; - } - - FlagsImpl &operator&=(FlagsImpl rhs) { - flags_ &= rhs.flags_; - return *this; - } - FlagsImpl &operator|=(FlagsImpl rhs) { - flags_ |= rhs.flags_; - return *this; - } - FlagsImpl &operator^=(FlagsImpl rhs) { - flags_ ^= rhs.flags_; - return *this; - } - - static constexpr FlagsImpl define(Type flags) { - return FlagsImpl(flags); - } - - private: - Type flags_; - - explicit constexpr FlagsImpl(Type flags) : flags_(flags) {} -}; - -} // namespace grnxx - -#endif // GRNXX_FLAGS_IMPL_HPP Deleted: lib/grnxx/geo_point.cpp (+0 -46) 100644 =================================================================== --- lib/grnxx/geo_point.cpp 2013-08-23 10:46:34 +0900 (4735281) +++ /dev/null @@ -1,46 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/geo_point.hpp" - -#include "grnxx/string_builder.hpp" - -namespace grnxx { - -uint64_t GeoPoint::interleave() const { - const Point point = reinterpret_cast<const Point &>(value_); - uint64_t latitude = static_cast<uint32_t>(point.latitude); - uint64_t longitude = static_cast<uint32_t>(point.longitude); - latitude = (latitude | (latitude << 16)) & 0x0000FFFF0000FFFFULL; - latitude = (latitude | (latitude << 8)) & 0x00FF00FF00FF00FFULL; - latitude = (latitude | (latitude << 4)) & 0x0F0F0F0F0F0F0F0FULL; - latitude = (latitude | (latitude << 2)) & 0x3333333333333333ULL; - latitude = (latitude | (latitude << 1)) & 0x5555555555555555ULL; - longitude = (longitude | (longitude << 16)) & 0x0000FFFF0000FFFFULL; - longitude = (longitude | (longitude << 8)) & 0x00FF00FF00FF00FFULL; - longitude = (longitude | (longitude << 4)) & 0x0F0F0F0F0F0F0F0FULL; - longitude = (longitude | (longitude << 2)) & 0x3333333333333333ULL; - longitude = (longitude | (longitude << 1)) & 0x5555555555555555ULL; - return (latitude << 1) | longitude; -} - -StringBuilder &operator<<(StringBuilder &builder, const GeoPoint &point) { - return builder << "{ latitude = " << point.latitude() - << ", longitude = " << point.longitude() << " }"; -} - -} // namespace Deleted: lib/grnxx/geo_point.hpp (+0 -93) 100644 =================================================================== --- lib/grnxx/geo_point.hpp 2013-08-23 10:46:34 +0900 (098939d) +++ /dev/null @@ -1,93 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_GEO_POINT_HPP -#define GRNXX_GEO_POINT_HPP - -#include "grnxx/features.hpp" - -#include "grnxx/types.hpp" - -namespace grnxx { - -class StringBuilder; - -// Latitude and longitude (lat/long). -class GeoPoint { - private: - struct Point { - int32_t latitude; - int32_t longitude; - }; - - public: - // Trivial default constructor. - GeoPoint() = default; - // Copy the lat/long as uint64_t. - explicit GeoPoint(uint64_t x) : value_(x) {} - // Copy the lat/long. - GeoPoint(int32_t latitude, int32_t longitude) : value_() { - Point point{ latitude, longitude }; - value_ = reinterpret_cast<const uint64_t &>(point); - } - - // Interleave the lat/long. - uint64_t interleave() const; - - // Return the latitude. - int32_t latitude() const { - return reinterpret_cast<const Point &>(value_).latitude; - } - // Return the longitude. - int32_t longitude() const { - return reinterpret_cast<const Point &>(value_).longitude; - } - // Return the lat/long as uint64_t. - uint64_t value() const { - return value_; - } - - // Set the latitude. - void set_latitude(int32_t x) { - reinterpret_cast<Point &>(value_).latitude = x; - } - // Set the longitude. - void set_longitude(int32_t x) { - reinterpret_cast<Point &>(value_).longitude = x; - } - // Set the lat/long as uint64_t. - void set_value(uint64_t x) { - value_ = x; - } - - private: - // Force 8-byte alignment and atomic copy/assignment. - uint64_t value_; -}; - -inline bool operator==(const GeoPoint &lhs, const GeoPoint &rhs) { - return lhs.value() == rhs.value(); -} -inline bool operator!=(const GeoPoint &lhs, const GeoPoint &rhs) { - return lhs.value() != rhs.value(); -} - -StringBuilder &operator<<(StringBuilder &builder, const GeoPoint &point); - -} // namespace - -#endif // GRNXX_GEO_POINT_HPP Deleted: lib/grnxx/grnxx.cpp (+0 -37) 100644 =================================================================== --- lib/grnxx/grnxx.cpp 2013-08-23 10:46:34 +0900 (e984a31) +++ /dev/null @@ -1,37 +0,0 @@ -/* - Copyright (C) 2012 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/grnxx.hpp" - -#include "../config.h" -#include "grnxx/version.h" - -namespace grnxx { - -const char *Grnxx::bugreport() { - return PACKAGE_BUGREPORT; -} - -const char *Grnxx::version() { -#ifdef GRNXX_VERSION - return GRNXX_VERSION; -#else // GRNXX_VERSION - return PACKAGE_VERSION; -#endif // GRNXX_VERSION -} - -} // namespace grnxx Deleted: lib/grnxx/grnxx.hpp (+0 -36) 100644 =================================================================== --- lib/grnxx/grnxx.hpp 2013-08-23 10:46:34 +0900 (f66b0d3) +++ /dev/null @@ -1,36 +0,0 @@ -/* - Copyright (C) 2012 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_GRNXX_HPP -#define GRNXX_GRNXX_HPP - -#include "grnxx/features.hpp" - -namespace grnxx { - -class GRNXX_EXPORT Grnxx { - public: - // The e-mail address for bug reports. - static const char *bugreport(); - - // The version. - static const char *version(); -}; - -} // namespace grnxx - -#endif // GRNXX_GRNXX_HPP Deleted: lib/grnxx/intrinsic.hpp (+0 -847) 100644 =================================================================== --- lib/grnxx/intrinsic.hpp 2013-08-23 10:46:34 +0900 (3ce60ee) +++ /dev/null @@ -1,847 +0,0 @@ -/* - Copyright (C) 2012 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_INTRINSIC_HPP -#define GRNXX_INTRINSIC_HPP - -#include "grnxx/features.hpp" - -#ifdef GRNXX_MSC -# include <intrin.h> -# pragma intrinsic(_BitScanReverse) -# pragma intrinsic(_BitScanForward) -# pragma intrinsic(_InterlockedCompareExchange) -# pragma intrinsic(_InterlockedCompareExchange64) -# pragma intrinsic(_InterlockedExchangeAdd) -# pragma intrinsic(_InterlockedOr) -# pragma intrinsic(_InterlockedAnd) -# pragma intrinsic(_InterlockedXor) -# ifdef GRNXX_MSC64 -# pragma intrinsic(_BitScanReverse64) -# pragma intrinsic(_BitScanForward64) -# pragma intrinsic(_InterlockedExchangeAdd64) -# pragma intrinsic(_InterlockedOr64) -# pragma intrinsic(_InterlockedAnd64) -# pragma intrinsic(_InterlockedXor64) -# endif // GRNXX_MSC64 -#endif // GRNXX_MSC - -#include <type_traits> - -#include "grnxx/types.hpp" - -namespace grnxx { - -// bit_scan_reverse() returns the position of the most significant 1 bit. -// For example, if value == 0x1010, bit_scan_reverse() returns 12. -// Note that if value == 0, the result is undefined. -template <typename Value> -inline uint8_t bit_scan_reverse(Value value); - -// bit_scan_forward() returns the position of the most insignificant 1 bit. -// For example, if value == 0x1010, bit_scan_forward() returns 4. -// Note that if value == 0, the result is undefined. -template <typename Value> -inline uint8_t bit_scan_forward(Value value); - -// byte_swap() returns the byte-swapped value. -// For example, byte_swap(0x12345678U) returns 0x78564312U. -inline uint8_t byte_swap(uint8_t value); -inline uint16_t byte_swap(uint16_t value); -inline uint32_t byte_swap(uint32_t value); -inline uint64_t byte_swap(uint64_t value); - -// atomic_compare_and_swap() atomically performs the following. -// if (*value == expected) { -// *value = desired; -// return true; -// } else { -// return false; -// } -template <typename Value> -inline bool atomic_compare_and_swap(Value expected, Value desired, - volatile Value *value); - -// atomic_fetch_and_add() atomically performs the following: -// temp = *value; -// *value += plus; -// return temp; -template <typename Plus, typename Value> -inline Value atomic_fetch_and_add(Plus plus, volatile Value *value); - -// atomic_fetch_or() atomically performs the following: -// temp = *value; -// *value |= plus; -// return temp; -template <typename Value> -inline Value atomic_fetch_and_or(Value mask, volatile Value *value); - -// atomic_fetch_and() atomically performs the following: -// temp = *value; -// *value &= plus; -// return temp; -template <typename Value> -inline Value atomic_fetch_and_and(Value mask, volatile Value *value); - -// atomic_fetch_xor() atomically performs the following: -// temp = *value; -// *value ^= plus; -// return temp; -template <typename Value> -inline Value atomic_fetch_and_xor(Value mask, volatile Value *value); - -// Implementation of bit_scan_reverse. - -#if defined(GRNXX_MSC) || defined(GRNXX_HAS_GNUC_BUILTIN_CLZ) - -template <size_t ValueSize> -class BitScanReverse { - public: - template <typename Value> - uint8_t operator()(Value value) const { -# ifdef GRNXX_MSC - unsigned long index; - ::_BitScanReverse(&index, static_cast<unsigned long>(value)); - return static_cast<uint8_t>(index); -# else // GRNXX_MSC - return static_cast<uint8_t>( - 31 - ::__builtin_clz(static_cast<unsigned int>(value))); -# endif // GRNXX_MSC - } -}; - -template <> -class BitScanReverse<8> { - public: - template <typename Value> - uint8_t operator()(Value value) const { -# ifdef GRNXX_MSC -# ifdef GRNXX_MSC64 - unsigned long index; - ::_BitScanReverse64(&index, static_cast<unsigned __int64>(value)); - return static_cast<uint8_t>(index); -# else // GRNXX_MSC64 - if ((value >> 32) != 0) { - return static_cast<uint8_t>(BitScanReverse<4>(value >> 32) + 32); - } - return BitScanReverse<4>(value); -# endif // GRNXX_MSC64 -# else // GRNXX_MSC - return static_cast<uint8_t>( - 63 - ::__builtin_clzll(static_cast<unsigned long long>(value))); -# endif // GRNXX_MSC - } -}; - -#endif // defined(GRNXX_MSC) || defined(GRNXX_HAS_GNUC_BUILTIN_CLZ) - -template <typename Value> -inline uint8_t bit_scan_reverse(Value value) { - static_assert(std::is_integral<Value>::value, - "bit_scan_reverse accepts only integer types"); - using UValue = typename std::make_unsigned<Value>::type; - -#if defined(GRNXX_MSC) || defined(GRNXX_HAS_GNUC_BUILTIN_CLZ) - return BitScanReverse<sizeof(Value)>()(static_cast<UValue>(value)); -#else // defined(GRNXX_MSC) || defined(GRNXX_HAS_GNUC_BUILTIN_CLZ) - uint8_t result = 0; - for (uint8_t shift = static_cast<uint8_t>(sizeof(Value) * 4); - shift != 0; shift /= 2) { - if ((static_cast<UValue>(value) >> shift) != 0) { - value = static_cast<UValue>(value) >> shift; - result += shift; - } - } - return result; -#endif // defined(GRNXX_MSC) || defined(GRNXX_HAS_GNUC_BUILTIN_CLZ) -} - -// Implementation of bit_scan_forward. - -#if defined(GRNXX_MSC) || defined(GRNXX_HAS_GNUC_BUILTIN_CLZ) - -template <size_t ValueSize> -class BitScanForward { - public: - template <typename Value> - uint8_t operator()(Value value) const { -# ifdef GRNXX_MSC - unsigned long index; - ::_BitScanForward(&index, static_cast<unsigned long>(value)); - return static_cast<uint8_t>(index); -# else // GRNXX_MSC - return static_cast<uint8_t>( - ::__builtin_ctz(static_cast<unsigned int>(value))); -# endif // GRNXX_MSC - } -}; - -template <> -class BitScanForward<8> { - public: - template <typename Value> - uint8_t operator()(Value value) const { -# ifdef GRNXX_MSC -# ifdef GRNXX_MSC64 - unsigned long index; - ::_BitScanForward64(&index, static_cast<unsigned __int64>(value)); - return static_cast<uint8_t>(index); -# else // GRNXX_MSC64 - if ((value & 0xFFFFFFFFU) == 0) { - return static_cast<uint8_t>(BitScanForward<4>(value >> 32) + 32); - } - return BitScanForward<4>(value); -# endif // GRNXX_MSC64 -# else // GRNXX_MSC - return static_cast<uint8_t>( - ::__builtin_ctzll(static_cast<unsigned long long>(value))); -# endif // GRNXX_MSC - } -}; - -#endif // defined(GRNXX_MSC) || defined(GRNXX_HAS_GNUC_BUILTIN_CLZ) - -template <typename Value> -inline uint8_t bit_scan_forward(Value value) { - static_assert(std::is_integral<Value>::value, - "bit_scan_forward accepts only integer types"); - using UValue = typename std::make_unsigned<Value>::type; - -#if defined(GRNXX_MSC) || defined(GRNXX_HAS_GNUC_BUILTIN_CLZ) - return BitScanForward<sizeof(Value)>()(static_cast<UValue>(value)); -#else // defined(GRNXX_MSC) || defined(GRNXX_HAS_GNUC_BUILTIN_CLZ) - uint8_t result = static_cast<uint8_t>(sizeof(Value) * 8) - 1; - for (uint8_t shift = static_cast<uint8_t>(sizeof(Value) * 4); - shift != 0; shift /= 2) { - if (static_cast<Value>(value << shift) != 0) { - value <<= shift; - result -= shift; - } - } - return result; -#endif // defined(GRNXX_MSC) || defined(GRNXX_HAS_GNUC_BUILTIN_CLZ) -} - -// Helper classes. - -template <size_t ValueSize> class IntrinsicType; - -#ifdef GRNXX_MSC -template <> class IntrinsicType<1> { public: typedef char Value; }; -template <> class IntrinsicType<2> { public: typedef short Value; }; -template <> class IntrinsicType<4> { public: typedef long Value; }; -template <> class IntrinsicType<8> { public: typedef __int64 Value; }; -#else // GRNXX_MSC -template <> class IntrinsicType<1> { public: typedef uint8_t Value; }; -template <> class IntrinsicType<2> { public: typedef uint16_t Value; }; -template <> class IntrinsicType<4> { public: typedef uint32_t Value; }; -template <> class IntrinsicType<8> { public: typedef uint64_t Value; }; -#endif // GRNXX_MSC - -template <typename Value> -class Intrinsic { - public: - typedef typename IntrinsicType<sizeof(Value)>::Value InternalValue; - typedef volatile InternalValue *InternalPointer; -}; - -// Implementation of byte_swap. - -inline uint8_t byte_swap(uint8_t value) { - return value; -} - -inline uint16_t byte_swap(uint16_t value) { -#ifdef GRNXX_MSC - return ::_byteswap_ushort(value); -#elif defined(GRNXX_HAS_GNUC_BUILTIN_BSWAP16) - return ::__builtin_bswap16(value); -#else // defined(GRNXX_HAS_GNUC_BUILTIN_BSWAP16) - return (value << 8) | (value >> 8); -#endif // defined(GRNXX_HAS_GNUC_BUILTIN_BSWAP16) -} - -inline uint32_t byte_swap(uint32_t value) { -#ifdef GRNXX_MSC - return ::_byteswap_ulong(value); -#elif defined(GRNXX_HAS_GNUC_BUILTIN_BSWAP32) - return ::__builtin_bswap32(value); -#else // defined(GRNXX_HAS_GNUC_BUILTIN_BSWAP32) - return (value << 24) | - ((value & (0xFF << 8)) << 8) | - ((value & (0xFF << 16)) >> 8) | - (value >> 24); -#endif // defined(GRNXX_HAS_GNUC_BUILTIN_BSWAP32) -} - -inline uint64_t byte_swap(uint64_t value) { -#ifdef GRNXX_MSC - return ::_byteswap_uint64(value); -#elif defined(GRNXX_HAS_GNUC_BUILTIN_BSWAP64) - return ::__builtin_bswap64(value); -#else // defined(GRNXX_HAS_GNUC_BUILTIN_BSWAP64) - return (value << 56) | - ((value & (0xFFULL << 8)) << 40) | - ((value & (0xFFULL << 16)) << 24) | - ((value & (0xFFULL << 24)) << 8) | - ((value & (0xFFULL << 32)) >> 8) | - ((value & (0xFFULL << 40)) >> 24) | - ((value & (0xFFULL << 48)) >> 40) | - (value >> 56); -#endif // defined(GRNXX_HAS_GNUC_BUILTIN_BSWAP64) -} - -// Implementation of atomic_compare_and_swap. - -#ifdef GRNXX_MSC - -template <typename Value> -class AtomicCompareAndSwap; - -template <> -class AtomicCompareAndSwap<long> { - public: - bool operator()(long expected, long desired, - volatile long *value) const { - return ::_InterlockedCompareExchange(value, desired, expected) == expected; - } -}; - -template <> -class AtomicCompareAndSwap<__int64> { - public: - bool operator()(__int64 expected, __int64 desired, - volatile __int64 *value) const { - return ::_InterlockedCompareExchange64(value, desired, expected) == expected; - } -}; - -template <typename Value> -class AtomicCompareAndSwap { - public: - typedef typename Intrinsic<Value>::InternalValue InternalValue; - typedef typename Intrinsic<Value>::InternalPointer InternalPointer; - - bool operator()(Value expected, Value desired, volatile Value *value) const { - return AtomicCompareAndSwap<InternalValue>()( - reinterpret_cast<const InternalValue &>(expected), - reinterpret_cast<const InternalValue &>(desired), - reinterpret_cast<InternalPointer>(value)); - } -}; - -#elif defined(GRNXX_HAS_GNUC_BUILTIN_ATOMIC) ||\ - defined(GRNXX_HAS_GNUC_BUILTIN_SYNC) - -// GNUC builtin functions for atomic operations accept integer types and -// pointer types. Other types require type casting. -template <typename Value, bool RequiresCast> -class InternalAtomicCompareAndSwap; - -template <typename Value> -class InternalAtomicCompareAndSwap<Value, false> { - public: - bool operator()(Value expected, Value desired, - volatile Value *value) const { -#ifdef GRNXX_HAS_GNUC_BUILTIN_ATOMIC - return ::__atomic_compare_exchange_n( - value, &expected, desired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); -#else // GRNXX_HAS_GNUC_BUILTIN_ATOMIC - return ::__sync_bool_compare_and_swap(value, expected, desired); -#endif // GRNXX_HAS_GNUC_BUILTIN_ATOMIC - } -}; - -template <typename Value> -class InternalAtomicCompareAndSwap<Value, true> { - public: - typedef typename Intrinsic<Value>::InternalValue InternalValue; - typedef typename Intrinsic<Value>::InternalPointer InternalPointer; - - bool operator()(Value expected, Value desired, volatile Value *value) const { - return InternalAtomicCompareAndSwap<InternalValue, false>()( - reinterpret_cast<const InternalValue &>(expected), - reinterpret_cast<const InternalValue &>(desired), - reinterpret_cast<InternalPointer>(value)); - } -}; - -template <typename Value> -class AtomicCompareAndSwap { - public: - typedef typename Intrinsic<Value>::InternalValue InternalValue; - typedef typename Intrinsic<Value>::InternalPointer InternalPointer; - - bool operator()(Value expected, Value desired, volatile Value *value) const { - return InternalAtomicCompareAndSwap<Value, - !std::is_integral<Value>::value && !std::is_pointer<Value>::value>()( - expected, desired, value); - } -}; - -#else // defined(GRNXX_HAS_GNUC_BUILTIN_ATOMIC) || ... - -template <typename Value> -class AtomicCompareAndSwap { - public: - bool operator()(Value expected, Value desired, volatile Value *value) const { - // Non-atomic implementation. - if (*value == expected) { - *value = desired; - return true; - } else { - return false; - } - } -}; - -#endif // defined(GRNXX_HAS_GNUC_BUILTIN_ATOMIC) || ... - -template <typename Value> -inline bool atomic_compare_and_swap(Value expected, Value desired, - volatile Value *value) { - static_assert((sizeof(Value) == 4) || (sizeof(Value) == 8), - "atomic_compare_and_swap is supported only for 4/8 bytes values."); - - return AtomicCompareAndSwap<Value>()(expected, desired, value); -} - -// Implementation of atomic_fetch_and_add. - -#ifdef GRNXX_MSC - -template <typename Value> -class InternalAtomicFetchAndAdd; - -template <> -class InternalAtomicFetchAndAdd<long> { - public: - long operator()(long plus, volatile long *value) const { - return ::_InterlockedExchangeAdd(plus, value); - } -}; - -template <> -class InternalAtomicFetchAndAdd<__int64> { - public: - __int64 operator()(__int64 plus, volatile __int64 *value) const { -#ifdef GRNXX_MSC64 - return ::_InterlockedExchangeAdd64(plus, value); -#else // GRNXX_MSC64 - for ( ; ; ) { - const __int64 expected = *value; - const __int64 desired = expected + plus; - if (atomic_compare_and_swap(expected, desired, value)) { - return expected; - } - } -#endif // GRNXX_MSC64 - } -}; - -template <typename Value> -class InternalAtomicFetchAndAdd { - public: - typedef typename Intrinsic<Value>::InternalValue InternalValue; - typedef typename Intrinsic<Value>::InternalPointer InternalPointer; - - Value operator()(Value plus, volatile Value *value) const { - return static_cast<Value>(InternalAtomicFetchAndAdd<InternalValue>()( - static_cast<InternalValue>(plus), - reinterpret_cast<InternalPointer>(value))); - } -}; - -#elif defined(GRNXX_HAS_GNUC_BUILTIN_ATOMIC) ||\ - defined(GRNXX_HAS_GNUC_BUILTIN_SYNC) - -template <typename Value> -class InternalAtomicFetchAndAdd { - public: - Value operator()(Value plus, volatile Value *value) const { -#ifdef GRNXX_HAS_GNUC_BUILTIN_ATOMIC - return ::__atomic_fetch_add(value, plus, __ATOMIC_SEQ_CST); -#else // GRNXX_HAS_GNUC_BUILTIN_ATOMIC - return ::__sync_fetch_and_add(value, plus); -#endif // GRNXX_HAS_GNUC_BUILTIN_ATOMIC - } -}; - -#else // defined(GRNXX_HAS_GNUC_BUILTIN_ATOMIC) || ... - -template <typename Value> -class InternalAtomicFetchAndAdd { - public: - Value operator()(Value plus, volatile Value *value) const { - for ( ; ; ) { - const Value expected = *value; - const Value desired = expected + plus; - if (atomic_compare_and_swap(expected, desired, value)) { - return expected; - } - } - } -}; - -#endif - -template <typename Plus, typename Value, bool PlusAndValueAreIntegers> -class AtomicFetchAndAdd; - -template <typename Plus, typename Value> -class AtomicFetchAndAdd<Plus, Value, true> { - public: - Value operator()(Plus plus, volatile Value *value) const { - return InternalAtomicFetchAndAdd<Value>()(static_cast<Value>(plus), value); - } -}; - -template <typename Plus, typename Value> -class AtomicFetchAndAdd<Plus, Value, false> { - public: - Value operator()(Plus plus, volatile Value *value) const { - for ( ; ; ) { - const Value expected = *value; - const Value desired = expected + plus; - if (atomic_compare_and_swap(expected, desired, value)) { - return expected; - } - } - } -}; - -template <typename Plus, typename Value> -inline Value atomic_fetch_and_add(Plus plus, volatile Value *value) { - static_assert((sizeof(Value) == 4) || (sizeof(Value) == 8), - "atomic_fetch_and_add is supported only for 4/8 bytes values."); - - return AtomicFetchAndAdd<Plus, Value, std::is_integral<Plus>::value && - std::is_integral<Value>::value>()(plus, value); -} - -// Implementation of atomic_fetch_and_or. - -#ifdef GRNXX_MSC - -template <typename Value> -class AtomicFetchAndOr; - -template <> -class AtomicFetchAndOr<char> { - public: - char operator()(char mask, volatile char *value) const { - return ::_InterlockedOr8(mask, value); - } -}; - -template <> -class AtomicFetchAndOr<short> { - public: - short operator()(short mask, volatile short *value) const { - return ::_InterlockedOr16(mask, value); - } -}; - -template <> -class AtomicFetchAndOr<long> { - public: - long operator()(long mask, volatile long *value) const { - return ::_InterlockedOr(mask, value); - } -}; - -template <> -class AtomicFetchAndOr<__int64> { - public: - __int64 operator()(__int64 mask, volatile __int64 *value) const { -#ifdef GRNXX_MSC64 - return ::_InterlockedOr64(mask, value); -#else // GRNXX_MSC64 - for ( ; ; ) { - const __int64 expected = *value; - const __int64 desired = expected | mask; - if (atomic_compare_and_swap(expected, desired, value)) { - return expected; - } - } -#endif // GRNXX_MSC64 - } -}; - -template <typename Value> -class AtomicFetchAndOr { - public: - typedef typename Intrinsic<Value>::InternalValue InternalValue; - typedef typename Intrinsic<Value>::InternalPointer InternalPointer; - - Value operator()(Value plus, volatile Value *value) const { - return static_cast<Value>(AtomicFetchAndOr<InternalValue>()( - static_cast<InternalValue>(mask), - reinterpret_cast<InternalPointer>(value))); - } -}; - -#elif defined(GRNXX_HAS_GNUC_BUILTIN_ATOMIC) ||\ - defined(GRNXX_HAS_GNUC_BUILTIN_SYNC) - -template <typename Value> -class AtomicFetchAndOr { - public: - Value operator()(Value mask, volatile Value *value) const { -#ifdef GRNXX_HAS_GNUC_BUILTIN_ATOMIC - return ::__atomic_fetch_or(value, mask, __ATOMIC_SEQ_CST); -#else // GRNXX_HAS_GNUC_BUILTIN_ATOMIC - return ::__sync_fetch_and_or(value, mask); -#endif // GRNXX_HAS_GNUC_BUILTIN_ATOMIC - } -}; - -#else // defined(GRNXX_HAS_GNUC_BUILTIN_ATOMIC) || ... - -template <typename Value> -class AtomicFetchAndOr { - public: - Value operator()(Value mask, volatile Value *value) const { - for ( ; ; ) { - const Value expected = *value; - const Value desired = expected | mask; - if (atomic_compare_and_swap(expected, desired, value)) { - return expected; - } - } - } -}; - -#endif - -template <typename Value> -inline Value atomic_fetch_and_or(Value mask, volatile Value *value) { - static_assert(std::is_integral<Value>::value, - "atomic_fetch_and_or accepts only integer types."); - - return AtomicFetchAndOr<Value>()(mask, value); -} - -// Implementation of atomic_fetch_and_and. - -#ifdef GRNXX_MSC - -template <typename Value> -class AtomicFetchAndAnd; - -template <> -class AtomicFetchAndAnd<char> { - public: - char operator()(char mask, volatile char *value) const { - return ::_InterlockedAnd8(mask, value); - } -}; - -template <> -class AtomicFetchAndAnd<short> { - public: - short operator()(short mask, volatile short *value) const { - return ::_InterlockedAnd16(mask, value); - } -}; - -template <> -class AtomicFetchAndAnd<long> { - public: - long operator()(long mask, volatile long *value) const { - return ::_InterlockedAnd(mask, value); - } -}; - -template <> -class AtomicFetchAndAnd<__int64> { - public: - __int64 operator()(__int64 mask, volatile __int64 *value) const { -#ifdef GRNXX_MSC64 - return ::_InterlockedAnd64(mask, value); -#else // GRNXX_MSC64 - for ( ; ; ) { - const __int64 expected = *value; - const __int64 desired = expected & mask; - if (atomic_compare_and_swap(expected, desired, value)) { - return expected; - } - } -#endif // GRNXX_MSC64 - } -}; - -template <typename Value> -class AtomicFetchAndAnd { - public: - typedef typename Intrinsic<Value>::InternalValue InternalValue; - typedef typename Intrinsic<Value>::InternalPointer InternalPointer; - - Value operator()(Value plus, volatile Value *value) const { - return static_cast<Value>(AtomicFetchAndAnd<InternalValue>()( - static_cast<InternalValue>(mask), - reinterpret_cast<InternalPointer>(value))); - } -}; - -#elif defined(GRNXX_HAS_GNUC_BUILTIN_ATOMIC) ||\ - defined(GRNXX_HAS_GNUC_BUILTIN_SYNC) - -template <typename Value> -class AtomicFetchAndAnd { - public: - Value operator()(Value mask, volatile Value *value) const { -#ifdef GRNXX_HAS_GNUC_BUILTIN_ATOMIC - return ::__atomic_fetch_and(value, mask, __ATOMIC_SEQ_CST); -#else // GRNXX_HAS_GNUC_BUILTIN_ATOMIC - return ::__sync_fetch_and_and(value, mask); -#endif // GRNXX_HAS_GNUC_BUILTIN_ATOMIC - } -}; - -#else // defined(GRNXX_HAS_GNUC_BUILTIN_ATOMIC) || ... - -template <typename Value> -class AtomicFetchAndAnd { - public: - Value operator()(Value mask, volatile Value *value) const { - for ( ; ; ) { - const Value expected = *value; - const Value desired = expected & mask; - if (atomic_compare_and_swap(expected, desired, value)) { - return expected; - } - } - } -}; - -#endif - -template <typename Value> -inline Value atomic_fetch_and_and(Value mask, volatile Value *value) { - static_assert(std::is_integral<Value>::value, - "atomic_fetch_and_and accepts only integer types."); - - return AtomicFetchAndAnd<Value>()(mask, value); -} - -// Implementation of atomic_fetch_and_xor. - -#ifdef GRNXX_MSC - -template <typename Value> -class AtomicFetchAndXor; - -template <> -class AtomicFetchAndXor<char> { - public: - char operator()(char mask, volatile char *value) const { - return ::_InterlockedXor8(mask, value); - } -}; - -template <> -class AtomicFetchAndXor<short> { - public: - short operator()(short mask, volatile short *value) const { - return ::_InterlockedXor16(mask, value); - } -}; - -template <> -class AtomicFetchAndXor<long> { - public: - long operator()(long mask, volatile long *value) const { - return ::_InterlockedXor(mask, value); - } -}; - -template <> -class AtomicFetchAndXor<__int64> { - public: - __int64 operator()(__int64 mask, volatile __int64 *value) const { -#ifdef GRNXX_MSC64 - return ::_InterlockedXor64(mask, value); -#else // GRNXX_MSC64 - for ( ; ; ) { - const __int64 expected = *value; - const __int64 desired = expected ^ mask; - if (atomic_compare_and_swap(expected, desired, value)) { - return expected; - } - } -#endif // GRNXX_MSC64 - } -}; - -template <typename Value> -class AtomicFetchAndXor { - public: - typedef typename Intrinsic<Value>::InternalValue InternalValue; - typedef typename Intrinsic<Value>::InternalPointer InternalPointer; - - Value operator()(Value plus, volatile Value *value) const { - return static_cast<Value>(AtomicFetchAndXor<InternalValue>()( - static_cast<InternalValue>(mask), - reinterpret_cast<InternalPointer>(value))); - } -}; - -#elif defined(GRNXX_HAS_GNUC_BUILTIN_ATOMIC) ||\ - defined(GRNXX_HAS_GNUC_BUILTIN_SYNC) - -template <typename Value> -class AtomicFetchAndXor { - public: - Value operator()(Value mask, volatile Value *value) const { -#ifdef GRNXX_HAS_GNUC_BUILTIN_ATOMIC - return ::__atomic_fetch_xor(value, mask, __ATOMIC_SEQ_CST); -#else // GRNXX_HAS_GNUC_BUILTIN_ATOMIC - return ::__sync_fetch_and_xor(value, mask); -#endif // GRNXX_HAS_GNUC_BUILTIN_ATOMIC - } -}; - -#else // defined(GRNXX_HAS_GNUC_BUILTIN_ATOMIC) || ... - -template <typename Value> -class AtomicFetchAndXor { - public: - Value operator()(Value mask, volatile Value *value) const { - for ( ; ; ) { - const Value expected = *value; - const Value desired = expected ^ mask; - if (atomic_compare_and_swap(expected, desired, value)) { - return expected; - } - } - } -}; - -#endif - -template <typename Value> -inline Value atomic_fetch_and_xor(Value mask, volatile Value *value) { - static_assert(std::is_integral<Value>::value, - "atomic_fetch_and_xor accepts only integer types."); - - return AtomicFetchAndXor<Value>()(mask, value); -} - -} // namespace grnxx - -#endif // INTRINSIC_HPP Added: lib/grnxx/library.cpp (+11 -0) 100644 =================================================================== --- /dev/null +++ lib/grnxx/library.cpp 2014-02-24 15:43:11 +0900 (e4cdaad) @@ -0,0 +1,11 @@ +#include "grnxx/library.hpp" + +#include "grnxx/version.h" + +namespace grnxx { + +const char *Library::version() { + return GRNXX_VERSION; +} + +} // namespace grnxx Added: lib/grnxx/library.hpp (+13 -0) 100644 =================================================================== --- /dev/null +++ lib/grnxx/library.hpp 2014-02-24 15:43:11 +0900 (3e8c877) @@ -0,0 +1,13 @@ +#ifndef GRNXX_LIBRARY_HPP +#define GRNXX_LIBRARY_HPP + +namespace grnxx { + +class Library { + public: + static const char *version(); +}; + +} // namespace grnxx + +#endif // GRNXX_LIBRARY_HPP Deleted: lib/grnxx/lock.hpp (+0 -53) 100644 =================================================================== --- lib/grnxx/lock.hpp 2013-08-23 10:46:34 +0900 (9c36c5c) +++ /dev/null @@ -1,53 +0,0 @@ -/* - Copyright (C) 2012 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_LOCK_HPP -#define GRNXX_LOCK_HPP - -#include "grnxx/features.hpp" - -#include "grnxx/duration.hpp" -#include "grnxx/mutex.hpp" - -namespace grnxx { - -class Lock { - public: - Lock() = delete; - explicit Lock(Mutex *mutex) : mutex_((mutex->lock(), mutex)) {} - Lock(Mutex *mutex, Duration timeout) - : mutex_(mutex->lock(timeout) ? mutex : nullptr) {} - ~Lock() { - if (mutex_) { - mutex_->unlock(); - } - } - - Lock(const Lock &) = delete; - Lock &operator=(const Lock &) = delete; - - explicit operator bool() const { - return mutex_ != nullptr; - } - - private: - Mutex *mutex_; -}; - -} // namespace grnxx - -#endif // GRNXX_LOCK_HPP Deleted: lib/grnxx/logger.cpp (+0 -244) 100644 =================================================================== --- lib/grnxx/logger.cpp 2013-08-23 10:46:34 +0900 (66e68e7) +++ /dev/null @@ -1,244 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/logger.hpp" - -#include <cstring> -#include <fstream> -#include <iostream> -#include <memory> -#include <new> -#include <string> -#include <utility> -#include <vector> - -#include "grnxx/backtrace.hpp" -#include "grnxx/lock.hpp" -#include "grnxx/system_clock.hpp" - -namespace grnxx { - -class LoggerSingleton { - public: - static bool write(const StringBuilder &builder); - - static bool open(const char *path); - static void close(); - - private: - std::unique_ptr<char[]> path_; - std::unique_ptr<std::ofstream> file_; - - // These variables may be used even after the instance termination. - static volatile bool initialized_; - static LoggerSingleton * volatile instance_; - static Mutex mutex_; - - LoggerSingleton() : path_(), file_() {} - ~LoggerSingleton() { - Lock lock(&mutex_); - instance_ = nullptr; - } - - static void initialize_once() { - if (!initialized_) { - // C++11 guarantees that a static local variable is initialized once. - // However, some compilers don't provide the guarantee. - static Mutex mutex; - Lock lock(&mutex); - if (!initialized_) { - initialize(); - } - } - } - static void initialize() { - static LoggerSingleton instance; - instance_ = &instance; - initialized_ = true; - } - - LoggerSingleton(const LoggerSingleton &) = delete; - LoggerSingleton &operator=(const LoggerSingleton &) = delete; -}; - -volatile bool LoggerSingleton::initialized_ = false; -LoggerSingleton * volatile LoggerSingleton::instance_ = nullptr; -Mutex LoggerSingleton::mutex_; - -bool LoggerSingleton::write(const StringBuilder &builder) { - initialize_once(); - Lock lock(&mutex_); - if (!instance_) { - return false; - } - static constexpr LoggerFlags OUTPUT_FLAGS = - LOGGER_ENABLE_COUT | LOGGER_ENABLE_CERR | LOGGER_ENABLE_CLOG; - const LoggerFlags flags = Logger::flags(); - if (!(flags & OUTPUT_FLAGS)) { - if (!instance_->file_ || !*instance_->file_) { - return false; - } - } - if (instance_->file_ && *instance_->file_) { - instance_->file_->write(builder.c_str(), builder.length()) << std::endl; - } - if (flags & LOGGER_ENABLE_COUT) { - std::cout.write(builder.c_str(), builder.length()) << '\n'; - } - if (flags & LOGGER_ENABLE_CERR) { - std::cerr.write(builder.c_str(), builder.length()) << '\n'; - } - if (flags & LOGGER_ENABLE_CLOG) { - std::clog.write(builder.c_str(), builder.length()) << '\n'; - } - return true; -} - -bool LoggerSingleton::open(const char *path) { - if (!path) { - return false; - } - initialize_once(); - Lock lock(&mutex_); - if (!instance_) { - return false; - } - try { - const size_t buf_size = std::strlen(path) + 1; - std::unique_ptr<char[]> path_clone(new (std::nothrow) char[buf_size]); - if (!path_clone) { - return false; - } - std::memcpy(path_clone.get(), path, buf_size); - std::unique_ptr<std::ofstream> new_file( - new (std::nothrow) std::ofstream(path_clone.get(), - std::ios::out | std::ios::app | std::ios::binary)); - if (!new_file || !*new_file) { - return false; - } - instance_->path_ = std::move(path_clone); - instance_->file_.swap(new_file); - return true; - } catch (...) { - return false; - } -} - -void LoggerSingleton::close() { - initialize_once(); - Lock lock(&mutex_); - if (instance_) { - instance_->file_.reset(); - instance_->path_.reset(); - } -} - -LoggerFlags Logger::flags_ = LOGGER_DEFAULT; -int Logger::max_level_ = NOTICE_LOGGER; -int Logger::backtrace_level_ = ERROR_LOGGER; - -Logger::Logger(const char *file, int line, const char *func, int level) - : buf_(), - builder_(buf_, string_builder_flags()), - file_(file), - line_(line), - func_(func), - level_(level) { - append_line_header(); -} - -Logger::~Logger() { - if (level_ <= backtrace_level()) { - builder_ << backtrace(); - } - LoggerSingleton::write(builder_); -} - -bool Logger::open(const char *path) { - return LoggerSingleton::open(path); -} - -void Logger::close() { - return LoggerSingleton::close(); -} - -void Logger::append_line_header() { - if (!builder_) { - return; - } - const LoggerFlags flags = Logger::flags(); - if (flags & LOGGER_WITH_DATE_TIME) { - builder_ << SystemClock::now().local_time() << ": "; - } - if (flags & LOGGER_WITH_LOCATION) { - builder_ << file_ << ':' << line_ << ": In " << func_ << "(): "; - } - if (flags & LOGGER_WITH_LEVEL) { - switch (level_) { - case ERROR_LOGGER: { - builder_ << "error: "; - break; - } - case WARNING_LOGGER: { - builder_ << "warning: "; - break; - } - case NOTICE_LOGGER: { - builder_ << "notice: "; - break; - } - default: { - builder_ << "n/a (" << level_ << "): "; - break; - } - } - } -} - -StringBuilderFlags Logger::string_builder_flags() { - StringBuilderFlags flags = STRING_BUILDER_NOEXCEPT; - if (Logger::flags() & LOGGER_ENABLE_AUTO_RESIZE) { - flags |= STRING_BUILDER_AUTO_RESIZE; - } - return flags; -} - -StringBuilder &operator<<(StringBuilder &builder, const Logger::NewLine &) { - if (!builder) { - return builder; - } - builder << '\n'; - Logger * const logger = reinterpret_cast<Logger *>( - (reinterpret_cast<char *>(&builder) - LOGGER_BUF_SIZE)); - logger->append_line_header(); - return builder; -} - -StringBuilder &operator<<(StringBuilder &builder, const Logger::Backtrace &) { - if (!builder) { - return builder; - } - std::vector<std::string> backtrace; - if (Backtrace::pretty_backtrace(1, &backtrace)) { - for (size_t i = 0; i < backtrace.size(); ++i) { - builder << Logger::new_line() << backtrace[i].c_str(); - } - } - return builder; -} - -} // namespace grnxx Deleted: lib/grnxx/logger.hpp (+0 -148) 100644 =================================================================== --- lib/grnxx/logger.hpp 2013-08-23 10:46:34 +0900 (e34f772) +++ /dev/null @@ -1,148 +0,0 @@ -/* - Copyright (C) 2012 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_LOGGER_HPP -#define GRNXX_LOGGER_HPP - -#include "grnxx/features.hpp" - -#include "grnxx/flags_impl.hpp" -#include "grnxx/string_builder.hpp" -#include "grnxx/types.hpp" - -#define GRNXX_ERROR() GRNXX_LOGGER(grnxx::ERROR_LOGGER) -#define GRNXX_WARNING() GRNXX_LOGGER(grnxx::WARNING_LOGGER) -#define GRNXX_NOTICE() GRNXX_LOGGER(grnxx::NOTICE_LOGGER) - -#define GRNXX_LOGGER(level)\ - ((level) > grnxx::Logger::max_level()) ? (void)0 :\ - grnxx::Logger::Voidify() &\ - grnxx::Logger(__FILE__, __LINE__, __func__, (level)).builder() - -namespace grnxx { - -constexpr size_t LOGGER_BUF_SIZE = 4096; - -enum LoggerLevel { - ERROR_LOGGER = 0, - WARNING_LOGGER = 1, - NOTICE_LOGGER = 2 -}; - -class Logger; -typedef FlagsImpl<Logger> LoggerFlags; - -// Use the default settings. -constexpr LoggerFlags LOGGER_DEFAULT = LoggerFlags::define(0x0000); - -// Logging with data and time. -constexpr LoggerFlags LOGGER_WITH_DATE_TIME = LoggerFlags::define(0x0001); -// Logging with __FILE__, __LINE__, and __func__. -constexpr LoggerFlags LOGGER_WITH_LOCATION = LoggerFlags::define(0x0002); -// Logging with LoggerLevel. -constexpr LoggerFlags LOGGER_WITH_LEVEL = LoggerFlags::define(0x0004); -// Enable all the LOGGER_WITH_* flags. -constexpr LoggerFlags LOGGER_WITH_ALL = LoggerFlags::define(0x0007); - -// Logging to the standard output. -constexpr LoggerFlags LOGGER_ENABLE_COUT = LoggerFlags::define(0x0100); -// Logging to the standard error. -constexpr LoggerFlags LOGGER_ENABLE_CERR = LoggerFlags::define(0x0200); -// Logging to the standard log. -constexpr LoggerFlags LOGGER_ENABLE_CLOG = LoggerFlags::define(0x0400); - -// Dynamically allocate memory when LOGGER_BUF_SIZE is not enough to store a -// logging message. -constexpr LoggerFlags LOGGER_ENABLE_AUTO_RESIZE = LoggerFlags::define(0x1000); - -class Logger { - public: - Logger(const char *file, int line, const char *func, int level); - ~Logger(); - - // Open or create a file to which logs are written. - static bool open(const char *path); - // Close a file opened with open(). - static void close(); - - static LoggerFlags flags() { - return flags_; - } - static int max_level() { - return max_level_; - } - static int backtrace_level() { - return backtrace_level_; - } - - static void set_flags(LoggerFlags value) { - flags_ = value; - } - static void set_max_level(int value) { - max_level_ = value; - } - static void set_backtrace_level(int value) { - backtrace_level_ = value; - } - - struct NewLine {}; - struct Backtrace {}; - - static NewLine new_line() { - return NewLine(); - } - static Backtrace backtrace() { - return Backtrace(); - } - - // Use an operator&() to voidify StringBuilder. - // The operators & and << are both left-to-right and << is prior to &. - struct Voidify { - void operator&(StringBuilder &) const {} - }; - - StringBuilder &builder() { - return builder_; - } - - void append_line_header(); - - private: - char buf_[LOGGER_BUF_SIZE]; - StringBuilder builder_; - const char * const file_; - const int line_; - const char * const func_; - const int level_; - - static LoggerFlags flags_; - static int max_level_; - static int backtrace_level_; - - static StringBuilderFlags string_builder_flags(); - - Logger(const Logger &) = delete; - Logger &operator=(const Logger &) = delete; -}; - -// These operators must not be called with a regular (non-logger) builder. -StringBuilder &operator<<(StringBuilder &builder, const Logger::NewLine &); -StringBuilder &operator<<(StringBuilder &builder, const Logger::Backtrace &); - -} // namespace grnxx - -#endif // GRNXX_LOGGER_HPP Deleted: lib/grnxx/map.cpp (+0 -306) 100644 =================================================================== --- lib/grnxx/map.cpp 2013-08-23 10:46:34 +0900 (8a2f65f) +++ /dev/null @@ -1,306 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/map.hpp" - -#include <limits> - -#include "grnxx/bytes.hpp" -#include "grnxx/exception.hpp" -#include "grnxx/geo_point.hpp" -#include "grnxx/logger.hpp" -#include "grnxx/storage.hpp" -#include "grnxx/string_builder.hpp" -#include "grnxx/map/array_map.hpp" -#include "grnxx/map/common_header.hpp" -#include "grnxx/map/cursor_impl.hpp" -#include "grnxx/map/double_array.hpp" -#include "grnxx/map/hash_table.hpp" -#include "grnxx/map/helper.hpp" -#include "grnxx/map/patricia.hpp" -#include "grnxx/map/scanner_impl.hpp" - -namespace grnxx { - -StringBuilder &operator<<(StringBuilder &builder, MapType type) { - switch (type) { - case MAP_ARRAY: { - return builder << "MAP_ARRAY"; - } - case MAP_DOUBLE_ARRAY: { - return builder << "MAP_DOUBLE_ARRAY"; - } - case MAP_PATRICIA: { - return builder << "MAP_PATRICIA"; - } - case MAP_HASH_TABLE: { - return builder << "MAP_HASH_TABLE"; - } - default: { - return builder << "n/a"; - } - } -} - -MapOptions::MapOptions() {} - -template <typename T> -Map<T>::Map() {} - -template <typename T> -Map<T>::~Map() {} - -template <typename T> -Map<T> *Map<T>::create(Storage *storage, uint32_t storage_node_id, - MapType type, const MapOptions &options) { - if (!storage) { - GRNXX_ERROR() << "invalid argument: storage == nullptr"; - throw LogicError(); - } - switch (type) { - case MAP_ARRAY: { - return map::ArrayMap<T>::create(storage, storage_node_id, options); - } - case MAP_DOUBLE_ARRAY: { - return map::DoubleArray<T>::create(storage, storage_node_id, options); - } - case MAP_PATRICIA: { - return map::Patricia<T>::create(storage, storage_node_id, options); - } - case MAP_HASH_TABLE: { - return map::HashTable<T>::create(storage, storage_node_id, options); - } - default: { - GRNXX_ERROR() << "invalid argument: type = " << type; - throw LogicError(); - } - } -} - -template <typename T> -Map<T> *Map<T>::open(Storage *storage, uint32_t storage_node_id) { - if (!storage) { - GRNXX_ERROR() << "invalid argument: storage == nullptr"; - throw LogicError(); - } - StorageNode storage_node = storage->open_node(storage_node_id); - const map::CommonHeader * const common_header = - static_cast<const map::CommonHeader *>(storage_node.body()); - if (!*common_header) { - GRNXX_ERROR() << "wrong header: format = " << common_header->format(); - throw LogicError(); - } - switch (common_header->type()) { - case MAP_ARRAY: { - return map::ArrayMap<T>::open(storage, storage_node_id); - } - case MAP_DOUBLE_ARRAY: { - return map::DoubleArray<T>::open(storage, storage_node_id); - } - case MAP_PATRICIA: { - return map::Patricia<T>::open(storage, storage_node_id); - } - case MAP_HASH_TABLE: { - return map::HashTable<T>::open(storage, storage_node_id); - } - default: { - GRNXX_ERROR() << "invalid format: type = " << common_header->type(); - throw LogicError(); - } - } -} - -template <typename T> -void Map<T>::unlink(Storage *storage, uint32_t storage_node_id) { - std::unique_ptr<Map<T>> map(open(storage, storage_node_id)); - storage->unlink_node(storage_node_id); -} - -template <typename T> -bool Map<T>::get(int64_t, Key *) { - GRNXX_ERROR() << "invalid operation"; - throw LogicError(); -} - -template <typename T> -bool Map<T>::get_next(int64_t key_id, int64_t *next_key_id, Key *next_key) { - // Naive implementation. - if ((key_id < MAP_MIN_KEY_ID) || (key_id > MAP_MAX_KEY_ID)) { - key_id = MAP_MIN_KEY_ID - 1; - } - for (++key_id; key_id <= max_key_id(); ++key_id) { - if (get(key_id, next_key)) { - if (next_key_id) { - *next_key_id = key_id; - } - return true; - } - } - return false; -} - -template <typename T> -bool Map<T>::unset(int64_t key_id) { - // Naive implementation. - Key key; - if (!get(key_id, &key)) { - return false; - } - return remove(key); -} - -template <typename T> -bool Map<T>::reset(int64_t key_id, KeyArg dest_key) { - // Naive implementation. - Key src_key; - if (!get(key_id, &src_key)) { - return false; - } - return replace(src_key, dest_key); -} - -template <typename T> -bool Map<T>::find(KeyArg key, int64_t *key_id) { - // Naive implementation. - const Key normalized_key = map::Helper<T>::normalize(key); - int64_t next_key_id = MAP_INVALID_KEY_ID; - Key next_key; - while (get_next(next_key_id, &next_key_id, &next_key)) { - if (map::Helper<T>::equal_to(normalized_key, next_key)) { - if (key_id) { - *key_id = next_key_id; - } - return true; - } - } - return false; -} - -template <typename T> -bool Map<T>::add(KeyArg, int64_t *) { - GRNXX_ERROR() << "invalid operation"; - throw LogicError(); -} - -template <typename T> -bool Map<T>::remove(KeyArg) { - GRNXX_ERROR() << "invalid operation"; - throw LogicError(); -} - -template <typename T> -bool Map<T>::replace(KeyArg, KeyArg, int64_t *) { - GRNXX_ERROR() << "invalid operation"; - throw LogicError(); -} - -template <typename T> -bool Map<T>::find_longest_prefix_match(KeyArg, int64_t *, Key *) { - GRNXX_ERROR() << "invalid operation"; - throw LogicError(); -} - -template <> -bool Map<Bytes>::find_longest_prefix_match(KeyArg query, int64_t *key_id, - Key *key) { - // Naive implementation. - int64_t next_key_id = MAP_INVALID_KEY_ID; - int64_t longest_prefix_key_id = MAP_INVALID_KEY_ID; - Key next_key; - Key longest_prefix_key = nullptr; - while (get_next(next_key_id, &next_key_id, &next_key)) { - if (query.starts_with(next_key)) { - if (next_key.size() >= longest_prefix_key.size()) { - longest_prefix_key_id = next_key_id; - longest_prefix_key = next_key; - } - } - } - if (longest_prefix_key_id != MAP_INVALID_KEY_ID) { - if (key_id) { - *key_id = longest_prefix_key_id; - } - if (key) { - *key = longest_prefix_key; - } - return true; - } - return false; -} - -template <typename T> -void Map<T>::defrag() { - GRNXX_ERROR() << "invalid operation"; - throw LogicError(); -} - -template <typename T> -void Map<T>::truncate() { - GRNXX_ERROR() << "invalid operation"; - throw LogicError(); -} - -template <typename T> -MapCursor<T> *Map<T>::create_cursor(MapCursorAllKeys<T>, - const MapCursorOptions &options) { - return map::AllKeysCursor<T>::create(this, options); -} - -template <typename T> -MapCursor<T> *Map<T>::create_cursor(const MapCursorKeyIDRange<T> &query, - const MapCursorOptions &options) { - return map::KeyIDRangeCursor<T>::create(this, query, options); -} - -template <typename T> -MapCursor<T> *Map<T>::create_cursor(const MapCursorKeyRange<T> &query, - const MapCursorOptions &options) { - return map::KeyRangeCursor<T>::create(this, query, options); -} - -template <> -MapCursor<GeoPoint> *Map<GeoPoint>::create_cursor( - const MapCursorKeyRange<GeoPoint> &, const MapCursorOptions &) { - GRNXX_ERROR() << "invalid operation"; - throw LogicError(); -} - -template <typename T> -MapScanner<T> *Map<T>::create_scanner(KeyArg, const Charset *) { - GRNXX_ERROR() << "invalid operation"; - throw LogicError(); -} - -template <> -MapScanner<Bytes> *Map<Bytes>::create_scanner(KeyArg query, - const Charset *charset) { - return map::ScannerImpl<Bytes>::create(this, query, charset); -} - -template class Map<int8_t>; -template class Map<uint8_t>; -template class Map<int16_t>; -template class Map<uint16_t>; -template class Map<int32_t>; -template class Map<uint32_t>; -template class Map<int64_t>; -template class Map<uint64_t>; -template class Map<double>; -template class Map<GeoPoint>; -template class Map<Bytes>; - -} // namespace grnxx Deleted: lib/grnxx/map.hpp (+0 -163) 100644 =================================================================== --- lib/grnxx/map.hpp 2013-08-23 10:46:34 +0900 (36e6fa9) +++ /dev/null @@ -1,163 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_MAP_HPP -#define GRNXX_MAP_HPP - -#include "grnxx/features.hpp" - -#include "grnxx/map_cursor.hpp" -#include "grnxx/map_cursor_query.hpp" -#include "grnxx/map_scanner.hpp" -#include "grnxx/traits.hpp" -#include "grnxx/types.hpp" - -namespace grnxx { - -class Charset; -class Storage; -class StringBuilder; - -constexpr int64_t MAP_MIN_KEY_ID = 0; -constexpr int64_t MAP_MAX_KEY_ID = (1LL << 40) - 2; -constexpr int64_t MAP_INVALID_KEY_ID = MAP_MAX_KEY_ID + 1; - -enum MapType : uint32_t { - MAP_ARRAY = 0, // Array-based implementation. - MAP_HASH_TABLE = 1, // HashTable-based implementation. - MAP_PATRICIA = 2, // Patricia-based implementation. - MAP_DOUBLE_ARRAY = 3 // DoubleArray-based implementation. -}; - -StringBuilder &operator<<(StringBuilder &builder, MapType type); - -struct MapOptions { - // Initialize the members. - MapOptions(); -}; - -template <typename T> -class Map { - public: - using Key = typename Traits<T>::Type; - using KeyArg = typename Traits<T>::ArgumentType; - using Cursor = MapCursor<T>; - using Scanner = MapScanner<T>; - - Map(); - virtual ~Map(); - - // Create a map. - static Map *create(Storage *storage, uint32_t storage_node_id, - MapType type, const MapOptions &options = MapOptions()); - // Open a map. - static Map *open(Storage *storage, uint32_t storage_node_id); - - // Unlink a map. - static void unlink(Storage *storage, uint32_t storage_node_id); - - // Return the storage node ID. - virtual uint32_t storage_node_id() const = 0; - // Return the implementation type. - virtual MapType type() const = 0; - - // Return the minimum key ID. - constexpr int64_t min_key_id() const { - return MAP_MIN_KEY_ID; - } - // Return the maximum key ID ever used. - // The return value can be a negative value iff the map is empty. - virtual int64_t max_key_id() = 0; - // Return the number of keys. - virtual uint64_t num_keys() = 0; - - // Get a key associated with "key_id" and return true on success. - // Assign the found key to "*key" iff "key" != nullptr. - virtual bool get(int64_t key_id, Key *key = nullptr); - // Find the next key and return true on success. The next key means the key - // associated with the smallest valid ID that is greater than "key_id". - // If "key_id" > MAP_MAX_KEY_ID, this finds the first key. - // Assign the ID to "*next_key_id" iff "next_key_id" != nullptr. - // Assign the key to "*next_key" iff "next_key" != nullptr. - virtual bool get_next(int64_t key_id, int64_t *next_key_id = nullptr, - Key *next_key = nullptr); - // Remove a key associated with "key_id" and return true on success. - virtual bool unset(int64_t key_id); - // Replace a key associated with "key_id" with "dest_key" and return true - // on success. - virtual bool reset(int64_t key_id, KeyArg dest_key); - - // Find "key" and return true on success. - // Assign the ID to "*key_id" iff "key_id" != nullptr. - virtual bool find(KeyArg key, int64_t *key_id = nullptr); - // Add "key" and return true on success. - // Assign the ID to "*key_id" iff "key_id" != nullptr. - virtual bool add(KeyArg key, int64_t *key_id = nullptr); - // Remove "key" and return true on success. - virtual bool remove(KeyArg key); - // Replace "src_key" with "dest_key" and return true on success. - // Assign the ID to "*key_id" iff "key_id" != nullptr. - virtual bool replace(KeyArg src_key, KeyArg dest_key, - int64_t *key_id = nullptr); - - // Perform longest prefix matching and return true on success. - // Assign the ID to "*key_id" iff "key_id" != nullptr. - // Assign the key to "*key" iff "key" != nullptr. - virtual bool find_longest_prefix_match(KeyArg query, - int64_t *key_id = nullptr, - Key *key = nullptr); - - // Defrag components. - virtual void defrag(); - - // Remove all the keys in "*this" and return true on success. - virtual void truncate(); - - // Return a reference to create a cursor query. - MapCursorAllKeys<T> all_keys() const { - return MapCursorAllKeys<T>(); - } - // Return a reference to create a cursor query. - MapCursorKeyID<T> key_id() const { - return MapCursorKeyID<T>(); - } - // Return a reference to create a cursor query. - MapCursorKey<T> key() const { - return MapCursorKey<T>(); - } - - // Create a cursor for accessing all the keys. - virtual Cursor *create_cursor( - MapCursorAllKeys<T> query, - const MapCursorOptions &options = MapCursorOptions()); - // Create a cursor for accessing keys that satisfy "query". - virtual Cursor *create_cursor( - const MapCursorKeyIDRange<T> &query, - const MapCursorOptions &options = MapCursorOptions()); - // Create a cursor for accessing keys that satisfy "query". - virtual Cursor *create_cursor( - const MapCursorKeyRange<T> &query, - const MapCursorOptions &options = MapCursorOptions()); - - // Create a MapScanner object to find keys in "query". - virtual Scanner *create_scanner(KeyArg query, - const Charset *charset = nullptr); -}; - -} // namespace grnxx - -#endif // GRNXX_MAP_HPP Deleted: lib/grnxx/map/Makefile.am (+0 -31) 100644 =================================================================== --- lib/grnxx/map/Makefile.am 2013-08-23 10:46:34 +0900 (a841299) +++ /dev/null @@ -1,31 +0,0 @@ -noinst_LTLIBRARIES = libgrnxx_map.la - -libgrnxx_map_la_LDFLAGS = @AM_LTLDFLAGS@ - -libgrnxx_map_la_SOURCES = \ - array_map.cpp \ - bytes_pool.cpp \ - common_header.cpp \ - cursor_impl.cpp \ - double_array.cpp \ - hash_table.cpp \ - key_pool.cpp \ - patricia.cpp \ - pool.cpp \ - scanner_impl.cpp - -libgrnxx_map_includedir = ${includedir}/grnxx/map -libgrnxx_map_include_HEADERS = \ - array_map.hpp \ - bytes_pool.hpp \ - common_header.hpp \ - cursor_impl.hpp \ - double_array.hpp \ - hash.hpp \ - hash_table.hpp \ - header.hpp \ - helper.hpp \ - key_pool.hpp \ - patricia.hpp \ - pool.hpp \ - scanner_impl.hpp Deleted: lib/grnxx/map/array_map.cpp (+0 -376) 100644 =================================================================== --- lib/grnxx/map/array_map.cpp 2013-08-23 10:46:34 +0900 (568daa6) +++ /dev/null @@ -1,376 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/map/array_map.hpp" - -#include <new> - -#include "grnxx/bytes.hpp" -#include "grnxx/exception.hpp" -#include "grnxx/geo_point.hpp" -#include "grnxx/lock.hpp" -#include "grnxx/logger.hpp" -#include "grnxx/map/common_header.hpp" -#include "grnxx/map/helper.hpp" -#include "grnxx/map/pool.hpp" -#include "grnxx/storage.hpp" - -namespace grnxx { -namespace map { -namespace { - -constexpr char FORMAT_STRING[] = "grnxx::map::ArrayMap"; - -} // namespace - -struct ArrayMapHeader { - CommonHeader common_header; - uint32_t pool_storage_node_id; - uint64_t pool_id; - Mutex mutex; - - // Initialize the member variables. - ArrayMapHeader(); - - // Return true iff the header seems to be correct. - explicit operator bool() const; -}; - -ArrayMapHeader::ArrayMapHeader() - : common_header(FORMAT_STRING, MAP_ARRAY), - pool_storage_node_id(STORAGE_INVALID_NODE_ID), - pool_id(0) {} - -ArrayMapHeader::operator bool() const { - return common_header.format() == FORMAT_STRING; -} - -template <typename T> -ArrayMap<T>::ArrayMap() - : storage_(nullptr), - storage_node_id_(STORAGE_INVALID_NODE_ID), - header_(nullptr), - pool_(), - queue_(), - pool_id_(0), - clock_() {} - -template <typename T> -ArrayMap<T>::~ArrayMap() {} - -template <typename T> -ArrayMap<T> *ArrayMap<T>::create(Storage *storage, uint32_t storage_node_id, - const MapOptions &options) { - std::unique_ptr<ArrayMap> map(new (std::nothrow) ArrayMap); - if (!map) { - GRNXX_ERROR() << "new grnxx::map::ArrayMap failed"; - throw MemoryError(); - } - map->create_map(storage, storage_node_id, options); - return map.release(); -} - -template <typename T> -ArrayMap<T> *ArrayMap<T>::open(Storage *storage, uint32_t storage_node_id) { - std::unique_ptr<ArrayMap> map(new (std::nothrow) ArrayMap); - if (!map) { - GRNXX_ERROR() << "new grnxx::map::ArrayMap failed"; - throw MemoryError(); - } - map->open_map(storage, storage_node_id); - return map.release(); -} - -template <typename T> -uint32_t ArrayMap<T>::storage_node_id() const { - return storage_node_id_; -} - -template <typename T> -MapType ArrayMap<T>::type() const { - return MAP_ARRAY; -} - -template <typename T> -int64_t ArrayMap<T>::max_key_id() { - refresh_if_possible(); - return pool_->max_key_id(); -} - -template <typename T> -uint64_t ArrayMap<T>::num_keys() { - refresh_if_possible(); - return pool_->num_keys(); -} - -template <typename T> -bool ArrayMap<T>::get(int64_t key_id, Key *key) { - refresh_if_possible(); - Pool * const pool = pool_.get(); - if ((key_id < MAP_MIN_KEY_ID) || (key_id > pool->max_key_id())) { - // Out of range. - return false; - } - if (key) { - return pool->get(key_id, key); - } - return pool->get_bit(key_id); -} - -template <typename T> -bool ArrayMap<T>::unset(int64_t key_id) { - refresh_if_possible(); - if ((key_id < MAP_MIN_KEY_ID) || (key_id > pool_->max_key_id())) { - // Out of range. - return false; - } - if (!pool_->get_bit(key_id)) { - // Not found. - return false; - } - pool_->unset(key_id); - return true; -} - -template <typename T> -bool ArrayMap<T>::reset(int64_t key_id, KeyArg dest_key) { - refresh_if_possible(); - if ((key_id < MAP_MIN_KEY_ID) || (key_id > pool_->max_key_id())) { - // Out of range. - return false; - } - if (!pool_->get_bit(key_id)) { - // Not found. - return false; - } - if (find(dest_key)) { - // Found. - return false; - } - pool_->reset(key_id, Helper<T>::normalize(dest_key)); - return true; -} - -template <typename T> -bool ArrayMap<T>::find(KeyArg key, int64_t *key_id) { - refresh_if_possible(); - Pool * const pool = pool_.get(); - const Key normalized_key = map::Helper<T>::normalize(key); - const int64_t max_key_id = pool->max_key_id(); - for (int64_t i = MAP_MIN_KEY_ID; i <= max_key_id; ++i) { - Key stored_key; - if (pool->get(i, &stored_key)) { - if (Helper<T>::equal_to(normalized_key, stored_key)) { - // Found. - if (key_id) { - *key_id = i; - } - return true; - } - } - } - return false; -} - -template <typename T> -bool ArrayMap<T>::add(KeyArg key, int64_t *key_id) { - refresh_if_possible(); - const Key normalized_key = Helper<T>::normalize(key); - const int64_t max_key_id = pool_->max_key_id(); - for (int64_t i = MAP_MIN_KEY_ID; i <= max_key_id; ++i) { - Key stored_key; - if (pool_->get(i, &stored_key)) { - if (Helper<T>::equal_to(normalized_key, stored_key)) { - // Found. - if (key_id) { - *key_id = i; - } - return false; - } - } - } - if (key_id) { - *key_id = pool_->add(normalized_key); - } else { - pool_->add(normalized_key); - } - return true; -} - -template <typename T> -bool ArrayMap<T>::remove(KeyArg key) { - refresh_if_possible(); - int64_t key_id; - if (!find(key, &key_id)) { - // Not found. - return false; - } - pool_->unset(key_id); - return true; -} - -template <typename T> -bool ArrayMap<T>::replace(KeyArg src_key, KeyArg dest_key, int64_t *key_id) { - refresh_if_possible(); - const Key normalized_src_key = Helper<T>::normalize(src_key); - const Key normalized_dest_key = Helper<T>::normalize(dest_key); - int64_t src_key_id = MAP_INVALID_KEY_ID; - const int64_t max_key_id = pool_->max_key_id(); - for (int64_t i = MAP_MIN_KEY_ID; i <= max_key_id; ++i) { - Key stored_key; - if (pool_->get(i, &stored_key)) { - if (Helper<T>::equal_to(normalized_src_key, stored_key)) { - // Source key found. - src_key_id = i; - } - if (Helper<T>::equal_to(normalized_dest_key, stored_key)) { - // Destination key found. - return false; - } - } - } - if (src_key_id == MAP_INVALID_KEY_ID) { - // Not found. - return false; - } - pool_->reset(src_key_id, normalized_dest_key); - if (key_id) { - *key_id = src_key_id; - } - return true; -} - -template <typename T> -void ArrayMap<T>::defrag() { - refresh_if_possible(); - pool_->defrag(); -} - -template <typename T> -void ArrayMap<T>::sweep(Duration lifetime) { - refresh_if_possible(); - const Time threshold = clock_.now() - lifetime; - while (!queue_.empty()) { - QueueEntry &queue_entry = queue_.front(); - if (queue_entry.time <= threshold) { - queue_.pop(); - } - } - pool_->sweep(lifetime); -} - -template <typename T> -void ArrayMap<T>::truncate() { - refresh_if_possible(); - if (pool_->max_key_id() == 0) { - // Nothing to do. - return; - } - std::unique_ptr<Pool> new_pool(Pool::create(storage_, storage_node_id_)); - const uint32_t old_pool_storage_node_id = pool_->storage_node_id(); - { - // Validate a new pool. - Lock lock(&header_->mutex); - header_->pool_storage_node_id = new_pool->storage_node_id(); - ++header_->pool_id; - pool_.swap(new_pool); - pool_id_ = header_->pool_id; - } - Pool::unlink(storage_, old_pool_storage_node_id); - try { - queue_.push(QueueEntry{ std::move(new_pool), clock_.now() }); - } catch (const std::exception &exception) { - GRNXX_ERROR() << "std::queue::push() failed"; - throw StandardError(exception); - } -} - -template <typename T> -void ArrayMap<T>::create_map(Storage *storage, uint32_t storage_node_id, - const MapOptions &) { - storage_ = storage; - StorageNode storage_node = - storage->create_node(storage_node_id, sizeof(Header)); - storage_node_id_ = storage_node.id(); - try { - header_ = static_cast<Header *>(storage_node.body()); - *header_ = Header(); - pool_.reset(Pool::create(storage, storage_node_id_)); - header_->pool_storage_node_id = pool_->storage_node_id(); - pool_id_ = ++header_->pool_id; - } catch (...) { - storage->unlink_node(storage_node_id_); - throw; - } -} - -template <typename T> -void ArrayMap<T>::open_map(Storage *storage, uint32_t storage_node_id) { - storage_ = storage; - StorageNode storage_node = storage->open_node(storage_node_id); - if (storage_node.size() < sizeof(Header)) { - GRNXX_ERROR() << "invalid format: size = " << storage_node.size() - << ", header_size = " << sizeof(Header); - throw LogicError(); - } - storage_node_id_ = storage_node_id; - header_ = static_cast<Header *>(storage_node.body()); - if (!*header_) { - GRNXX_ERROR() << "wrong format: expected = " << FORMAT_STRING - << ", actual = " << header_->common_header.format(); - throw LogicError(); - } -} - -template <typename T> -void ArrayMap<T>::refresh_if_possible() { - if (pool_id_ != header_->pool_id) { - refresh(); - } -} - -template <typename T> -void ArrayMap<T>::refresh() { - Lock lock(&header_->mutex); - if (pool_id_ != header_->pool_id) { - std::unique_ptr<Pool> new_pool( - Pool::open(storage_, header_->pool_storage_node_id)); - pool_.swap(new_pool); - pool_id_ = header_->pool_id; - try { - queue_.push(QueueEntry{ std::move(new_pool), clock_.now() }); - } catch (const std::exception &exception) { - GRNXX_ERROR() << "std::queue::push() failed"; - throw StandardError(exception); - } - } -} - -template class ArrayMap<int8_t>; -template class ArrayMap<uint8_t>; -template class ArrayMap<int16_t>; -template class ArrayMap<uint16_t>; -template class ArrayMap<int32_t>; -template class ArrayMap<uint32_t>; -template class ArrayMap<int64_t>; -template class ArrayMap<uint64_t>; -template class ArrayMap<double>; -template class ArrayMap<GeoPoint>; -template class ArrayMap<Bytes>; - -} // namespace map -} // namespace grnxx Deleted: lib/grnxx/map/array_map.hpp (+0 -105) 100644 =================================================================== --- lib/grnxx/map/array_map.hpp 2013-08-23 10:46:34 +0900 (b331877) +++ /dev/null @@ -1,105 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_MAP_ARRAY_MAP_HPP -#define GRNXX_MAP_ARRAY_MAP_HPP - -#include "grnxx/features.hpp" - -#include <memory> -#include <queue> - -#include "grnxx/duration.hpp" -#include "grnxx/map.hpp" -#include "grnxx/mutex.hpp" -#include "grnxx/periodic_clock.hpp" -#include "grnxx/time.hpp" -#include "grnxx/types.hpp" - -namespace grnxx { - -class Storage; - -namespace map { - -template <typename T> class Pool; - -struct ArrayMapHeader; - -template <typename T> -class ArrayMap : public Map<T> { - using Header = ArrayMapHeader; - using Pool = map::Pool<T>; - - struct QueueEntry { - std::unique_ptr<Pool> pool; - Time time; - }; - - public: - using Key = typename Map<T>::Key; - using KeyArg = typename Map<T>::KeyArg; - using Cursor = typename Map<T>::Cursor; - - ArrayMap(); - ~ArrayMap(); - - static ArrayMap *create(Storage *storage, uint32_t storage_node_id, - const MapOptions &options = MapOptions()); - static ArrayMap *open(Storage *storage, uint32_t storage_node_id); - - uint32_t storage_node_id() const; - MapType type() const; - - int64_t max_key_id(); - uint64_t num_keys(); - - bool get(int64_t key_id, Key *key = nullptr); - bool unset(int64_t key_id); - bool reset(int64_t key_id, KeyArg dest_key); - - bool find(KeyArg key, int64_t *key_id = nullptr); - bool add(KeyArg key, int64_t *key_id = nullptr); - bool remove(KeyArg key); - bool replace(KeyArg src_key, KeyArg dest_key, int64_t *key_id = nullptr); - - void defrag(); - void sweep(Duration lifetime); - - void truncate(); - - private: - Storage *storage_; - uint32_t storage_node_id_; - Header *header_; - std::unique_ptr<Pool> pool_; - std::queue<QueueEntry> queue_; - uint64_t pool_id_; - PeriodicClock clock_; - - void create_map(Storage *storage, uint32_t storage_node_id, - const MapOptions &options); - void open_map(Storage *storage, uint32_t storage_node_id); - - inline void refresh_if_possible(); - void refresh(); -}; - -} // namespace map -} // namespace grnxx - -#endif // GRNXX_MAP_ARRAY_MAP_HPP Deleted: lib/grnxx/map/bytes_pool.cpp (+0 -366) 100644 =================================================================== --- lib/grnxx/map/bytes_pool.cpp 2013-08-23 10:46:34 +0900 (0402fd1) +++ /dev/null @@ -1,366 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/map/bytes_pool.hpp" - -#include <cstring> -#include <new> - -#include "grnxx/common_header.hpp" -#include "grnxx/exception.hpp" -#include "grnxx/logger.hpp" -#include "grnxx/storage.hpp" -#include "grnxx/string_builder.hpp" - -namespace grnxx { -namespace map { -namespace { - -constexpr char FORMAT_STRING[] = "grnxx::map::BytesPool"; - -constexpr uint64_t POOL_SIZE = 1ULL << 48; -constexpr uint64_t PAGE_HEADER_ARRAY_SIZE = POOL_SIZE / BytesPool::page_size(); - -constexpr uint32_t MAX_PAGE_ID = PAGE_HEADER_ARRAY_SIZE - 1; -constexpr uint32_t INVALID_PAGE_ID = MAX_PAGE_ID + 1; - -} // namespace - -struct BytesPoolHeader { - grnxx::CommonHeader common_header; - uint64_t next_offset; - uint32_t max_page_id; - uint32_t latest_empty_page_id; - uint32_t latest_idle_page_id; - uint32_t pool_storage_node_id; - uint32_t page_headers_storage_node_id; - uint32_t reserved; - - // Initialize the member variables. - BytesPoolHeader(); - - // Return true iff the header seems to be correct. - explicit operator bool() const; -}; - -BytesPoolHeader::BytesPoolHeader() - : common_header(FORMAT_STRING), - next_offset(0), - max_page_id(0), - latest_empty_page_id(INVALID_PAGE_ID), - latest_idle_page_id(INVALID_PAGE_ID), - pool_storage_node_id(STORAGE_INVALID_NODE_ID), - page_headers_storage_node_id(STORAGE_INVALID_NODE_ID), - reserved(0) {} - -BytesPoolHeader::operator bool() const { - return common_header.format() == FORMAT_STRING; -} - -StringBuilder &operator<<(StringBuilder &builder, BytesPoolPageStatus status) { - switch (status) { - case BYTES_POOL_PAGE_ACTIVE: { - return builder << "BYTES_POOL_PAGE_ACTIVE"; - } - case BYTES_POOL_PAGE_IN_USE: { - return builder << "BYTES_POOL_PAGE_IN_USE"; - } - case BYTES_POOL_PAGE_EMPTY: { - return builder << "BYTES_POOL_PAGE_EMPTY"; - } - case BYTES_POOL_PAGE_IDLE: { - return builder << "BYTES_POOL_PAGE_IDLE"; - } - default: { - return builder << "n/a"; - } - } -} - -BytesPoolPageHeader::BytesPoolPageHeader() - : status(BYTES_POOL_PAGE_ACTIVE), - size_in_use(0), - modified_time(0) {} - -BytesPool::BytesPool() - : storage_(nullptr), - storage_node_id_(STORAGE_INVALID_NODE_ID), - header_(nullptr), - pool_(), - page_headers_() {} - -BytesPool *BytesPool::create(Storage *storage, uint32_t storage_node_id) { - if (!storage) { - GRNXX_ERROR() << "invalid argument: storage == nullptr"; - throw LogicError(); - } - std::unique_ptr<BytesPool> pool(new (std::nothrow) BytesPool); - if (!pool) { - GRNXX_ERROR() << "new grnxx::map::BytesPool failed"; - throw MemoryError(); - } - pool->create_pool(storage, storage_node_id); - return pool.release(); -} - -BytesPool *BytesPool::open(Storage *storage, uint32_t storage_node_id) { - if (!storage) { - GRNXX_ERROR() << "invalid argument: storage == nullptr"; - throw LogicError(); - } - std::unique_ptr<BytesPool> pool(new (std::nothrow) BytesPool); - if (!pool) { - GRNXX_ERROR() << "new grnxx::map::BytesPool failed"; - throw MemoryError(); - } - pool->open_pool(storage, storage_node_id); - return pool.release(); -} - -void BytesPool::unlink(Storage *storage, uint32_t storage_node_id) { - std::unique_ptr<BytesPool> pool(BytesPool::open(storage, storage_node_id)); - storage->unlink_node(storage_node_id); -} - -void BytesPool::unset(uint64_t value_id) { - const uint64_t offset = get_offset(value_id); - const uint32_t size = get_size(value_id); - const uint32_t page_id = get_page_id(offset); - if ((size > MAX_VALUE_SIZE) || (page_id > header_->max_page_id)) { - GRNXX_ERROR() << "invalid argument: offset = " << offset - << ", size = " << size - << ", page_id = " << page_id - << ", max_size = " << MAX_VALUE_SIZE - << ", max_page_id = " << header_->max_page_id; - throw LogicError(); - } - PageHeader * const page_header = &page_headers_->get_value(page_id); - if ((page_header->status != BYTES_POOL_PAGE_ACTIVE) && - (page_header->status != BYTES_POOL_PAGE_IN_USE)) { - GRNXX_ERROR() << "wrong page: page_id = " << page_id - << ", status = " << page_header->status; - throw LogicError(); - } - if (size > page_header->size_in_use) { - GRNXX_ERROR() << "wrong page: size = " << size - << ", size_in_use = " << page_header->size_in_use; - throw LogicError(); - } - if ((page_header->status == BYTES_POOL_PAGE_ACTIVE) || - (size < page_header->size_in_use)) { - // This operation does not change the page status. - page_header->size_in_use -= size; - } else { - // This operation makes the page EMPTY. - make_page_empty(page_id, page_header); - } -} - -uint64_t BytesPool::add(ValueArg value) { - if (value.size() > MAX_VALUE_SIZE) { - GRNXX_ERROR() << "invalid argument: size = " << value.size() - << ", max_size = " << MAX_VALUE_SIZE; - throw LogicError(); - } - uint64_t offset = header_->next_offset; - uint32_t size = static_cast<uint32_t>(value.size()); - uint32_t page_id = get_page_id(offset); - PageHeader *page_header = &page_headers_->get_value(page_id); - uint32_t offset_in_page = get_offset_in_page(offset); - const uint32_t size_left = POOL_PAGE_SIZE - offset_in_page; - if (size >= size_left) { - uint32_t next_page_id; - PageHeader *next_page_header = reserve_active_page(&next_page_id); - if (size > size_left) { - // Skip the remaining space of the previous ACTIVE page. - if (page_header->size_in_use == 0) { - // Change the page status from ACTIVE to EMPTY. - make_page_empty(page_id, page_header); - } else { - // Change the page status from ACTIVE to IN_USE. - page_header->status = BYTES_POOL_PAGE_IN_USE; - page_header->modified_time = clock_.now(); - } - // Use the new ACTIVE page. - header_->next_offset = next_page_id * POOL_PAGE_SIZE; - offset = header_->next_offset; - page_id = next_page_id; - page_header = next_page_header; - } else { - // Use the previous ACTIVE page. - page_header->status = BYTES_POOL_PAGE_IN_USE; - page_header->modified_time = clock_.now(); - header_->next_offset = next_page_id * POOL_PAGE_SIZE; - } - } - uint8_t * const value_buf = &pool_->get_value(offset); - std::memcpy(value_buf, value.data(), size); - page_header->size_in_use += size; - if (offset == header_->next_offset) { - header_->next_offset += size; - } - return get_value_id(offset, size); -} - -void BytesPool::truncate() { - for (uint64_t page_id = 0; page_id < header_->max_page_id; ++page_id) { - PageHeader *page_header = &page_headers_->get_value(page_id); - if (page_header->status == BYTES_POOL_PAGE_IN_USE) { - make_page_empty(page_id, page_header); - } - } -} - -void BytesPool::sweep(Duration lifetime) { - if (header_->latest_empty_page_id == INVALID_PAGE_ID) { - // Nothing to do. - return; - } - PageHeader * const latest_empty_page_header = - &page_headers_->get_value(header_->latest_empty_page_id); - const Time threshold = clock_.now() - lifetime; - do { - const uint32_t oldest_empty_page_id = - latest_empty_page_header->next_page_id; - PageHeader * const oldest_empty_page_header = - &page_headers_->get_value(oldest_empty_page_id); - if (oldest_empty_page_header->status != BYTES_POOL_PAGE_EMPTY) { - GRNXX_ERROR() << "status conflict: status = " - << oldest_empty_page_header->status; - throw LogicError(); - } - if (oldest_empty_page_header->modified_time > threshold) { - // The remaining empty pages are not ready. - break; - } - const uint32_t next_oldest_empty_page_id = - oldest_empty_page_header->next_page_id; - make_page_idle(oldest_empty_page_id, oldest_empty_page_header); - if (oldest_empty_page_header != latest_empty_page_header) { - latest_empty_page_header->next_page_id = next_oldest_empty_page_id; - } else { - header_->latest_empty_page_id = INVALID_PAGE_ID; - } - } while (header_->latest_empty_page_id != INVALID_PAGE_ID); -} - -BytesPool::~BytesPool() {} - -void BytesPool::create_pool(Storage *storage, uint32_t storage_node_id) { - storage_ = storage; - StorageNode storage_node = - storage->create_node(storage_node_id, sizeof(Header)); - storage_node_id_ = storage_node.id(); - try { - header_ = static_cast<Header *>(storage_node.body()); - *header_ = Header(); - pool_.reset(Pool::create(storage, storage_node_id_, POOL_SIZE)); - page_headers_.reset(PageHeaderArray::create(storage, storage_node_id, - PAGE_HEADER_ARRAY_SIZE)); - header_->pool_storage_node_id = pool_->storage_node_id(); - header_->page_headers_storage_node_id = page_headers_->storage_node_id(); - } catch (...) { - storage->unlink_node(storage_node_id_); - throw; - } -} - -void BytesPool::open_pool(Storage *storage, uint32_t storage_node_id) { - storage_ = storage; - StorageNode storage_node = storage->open_node(storage_node_id); - storage_node_id_ = storage_node.id(); - header_ = static_cast<Header *>(storage_node.body()); - if (!*header_) { - GRNXX_ERROR() << "wrong format: expected = " << FORMAT_STRING - << ", actual = " << header_->common_header.format(); - throw LogicError(); - } - pool_.reset(Pool::open(storage, header_->pool_storage_node_id)); - page_headers_.reset( - PageHeaderArray::open(storage, header_->page_headers_storage_node_id)); -} - -BytesPoolPageHeader *BytesPool::reserve_active_page(uint32_t *page_id) { - PageHeader *latest_idle_page_header = nullptr; - uint32_t next_page_id; - if (header_->latest_idle_page_id != INVALID_PAGE_ID) { - // Use the oldest IDLE page. - latest_idle_page_header = - &page_headers_->get_value(header_->latest_idle_page_id); - next_page_id = latest_idle_page_header->next_page_id; - } else { - // Create a new page. - next_page_id = header_->max_page_id + 1; - if (next_page_id > MAX_PAGE_ID) { - GRNXX_ERROR() << "too many pages: next_page_id = " << next_page_id - << ", max_page_id = " << MAX_PAGE_ID; - throw LogicError(); - } - } - PageHeader * const next_page_header = - &page_headers_->get_value(next_page_id); - if (latest_idle_page_header) { - if (next_page_id != header_->latest_idle_page_id) { - latest_idle_page_header->next_page_id = next_page_header->next_page_id; - } else { - header_->latest_idle_page_id = INVALID_PAGE_ID; - } - } else { - ++header_->max_page_id; - } - *next_page_header = PageHeader(); - next_page_header->modified_time = clock_.now(); - *page_id = next_page_id; - return next_page_header; -} - -void BytesPool::make_page_empty(uint32_t page_id, PageHeader *page_header) { - PageHeader *latest_empty_page_header = nullptr; - if (header_->latest_empty_page_id != INVALID_PAGE_ID) { - latest_empty_page_header = - &page_headers_->get_value(header_->latest_empty_page_id); - } - page_header->status = BYTES_POOL_PAGE_EMPTY; - if (latest_empty_page_header) { - page_header->next_page_id = latest_empty_page_header->next_page_id; - latest_empty_page_header->next_page_id = page_id; - } else { - page_header->next_page_id = page_id; - } - page_header->modified_time = clock_.now(); - header_->latest_empty_page_id = page_id; -} - -void BytesPool::make_page_idle(uint32_t page_id, PageHeader *page_header) { - PageHeader *latest_idle_page_header = nullptr; - if (header_->latest_idle_page_id != INVALID_PAGE_ID) { - latest_idle_page_header = - &page_headers_->get_value(header_->latest_idle_page_id); - } - page_header->status = BYTES_POOL_PAGE_IDLE; - if (latest_idle_page_header) { - page_header->next_page_id = latest_idle_page_header->next_page_id; - latest_idle_page_header->next_page_id = page_id; - } else { - page_header->next_page_id = page_id; - } - page_header->modified_time = clock_.now(); - header_->latest_idle_page_id = page_id; -} - -} // namespace map -} // namespace grnxx Deleted: lib/grnxx/map/bytes_pool.hpp (+0 -180) 100644 =================================================================== --- lib/grnxx/map/bytes_pool.hpp 2013-08-23 10:46:34 +0900 (b6c82bc) +++ /dev/null @@ -1,180 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_MAP_BYTES_POOL_HPP -#define GRNXX_MAP_BYTES_POOL_HPP - -#include "grnxx/features.hpp" - -#include <memory> - -#include "grnxx/array.hpp" -#include "grnxx/bytes.hpp" -#include "grnxx/duration.hpp" -#include "grnxx/periodic_clock.hpp" -#include "grnxx/time.hpp" -#include "grnxx/traits.hpp" -#include "grnxx/types.hpp" - -namespace grnxx { - -class Storage; - -namespace map { - -constexpr uint64_t BYTES_POOL_VALUE_ID_MASK = (1ULL << 61) - 1; -constexpr uint64_t BYTES_POOL_MAX_VALUE_ID = BYTES_POOL_VALUE_ID_MASK; - -struct BytesPoolHeader; - -enum BytesPoolPageStatus : uint32_t { - // The next byte sequence will be added to this page. - BYTES_POOL_PAGE_ACTIVE = 0, - // This page is in use. - BYTES_POOL_PAGE_IN_USE = 1, - // This page is empty but not ready-to-use. - BYTES_POOL_PAGE_EMPTY = 2, - // This page is empty and ready-to-use. - BYTES_POOL_PAGE_IDLE = 3 -}; - -struct BytesPoolPageHeader { - // ACTIVE, IN_USE, EMPTY, and IDLE. - BytesPoolPageStatus status; - union { - // ACTIVE and IN_USE. - uint32_t size_in_use; - // EMPTY and IDLE. - uint32_t next_page_id; - }; - // ACTIVE, IN_USE, EMPTY, and IDLE. - Time modified_time; - - // Initialize member variables. - BytesPoolPageHeader(); -}; - -class BytesPool { - using Header = BytesPoolHeader; - using PageHeader = BytesPoolPageHeader; - - static constexpr uint32_t POOL_PAGE_SIZE = 1U << 20; - static constexpr uint32_t POOL_TABLE_SIZE = 1U << 14; - - static constexpr uint32_t MAX_VALUE_SIZE = 4096; - - // The number of bits allocated for representing a value size. - static constexpr uint8_t VALUE_ID_SIZE_BITS = 13; - static constexpr uint64_t VALUE_ID_SIZE_MASK = - (1ULL << VALUE_ID_SIZE_BITS) - 1; - - using Pool = Array<uint8_t, POOL_PAGE_SIZE, POOL_TABLE_SIZE>; - using PageHeaderArray = Array<PageHeader, POOL_TABLE_SIZE>; - - public: - using Value = typename Traits<Bytes>::Type; - using ValueArg = typename Traits<Bytes>::ArgumentType; - - ~BytesPool(); - - // Create a pool. - static BytesPool *create(Storage *storage, uint32_t storage_node_id); - // Opena pool. - static BytesPool *open(Storage *storage, uint32_t storage_node_id); - - // Unlink a pool. - static void unlink(Storage *storage, uint32_t storage_node_id); - - // Return the storage node ID. - uint32_t storage_node_id() const { - return storage_node_id_; - } - - // Return the page size. - static constexpr uint64_t page_size() { - return POOL_PAGE_SIZE; - } - - // Get a byte sequence. - Value get(uint64_t value_id) { - const uint64_t offset = get_offset(value_id); - const uint32_t size = get_size(value_id); - return Value(&pool_->get_value(offset), size); - } - // Remove a byte sequence. - void unset(uint64_t value_id); - // Add a byte sequence and return its ID. - uint64_t add(ValueArg value); - - // Return the actually used size of a page in use. - // If a page is not in use, return the page size. - uint64_t get_page_size_in_use(uint64_t page_id) { - const PageHeader &page_header = page_headers_->get_value(page_id); - if (page_header.status == BYTES_POOL_PAGE_IN_USE) { - return page_header.size_in_use; - } else { - return page_size(); - } - } - - // Remove all the byte sequences. - void truncate(); - - // Sweep empty pages whose modified time <= (now - lifetime). - void sweep(Duration lifetime); - - private: - Storage *storage_; - uint32_t storage_node_id_; - BytesPoolHeader *header_; - std::unique_ptr<Pool> pool_; - std::unique_ptr<PageHeaderArray> page_headers_; - PeriodicClock clock_; - - BytesPool(); - - void create_pool(Storage *storage, uint32_t storage_node_id); - void open_pool(Storage *storage, uint32_t storage_node_id); - - // Reserve a page. - PageHeader *reserve_active_page(uint32_t *page_id); - // Make a page empty. - void make_page_empty(uint32_t page_id, PageHeader *page_header); - // Make a page idle. - void make_page_idle(uint32_t page_id, PageHeader *page_header); - - static uint64_t get_value_id(uint64_t offset, uint32_t size) { - return (offset * (VALUE_ID_SIZE_MASK + 1)) | size; - } - static uint64_t get_offset(uint64_t value_id) { - return value_id / (VALUE_ID_SIZE_MASK + 1); - } - static uint32_t get_size(uint64_t value_id) { - return static_cast<uint32_t>(value_id & VALUE_ID_SIZE_MASK); - } - static uint32_t get_page_id(uint64_t offset) { - return static_cast<uint32_t>(offset / POOL_PAGE_SIZE); - } - static uint32_t get_offset_in_page(uint64_t offset) { - return static_cast<uint32_t>(offset % POOL_PAGE_SIZE); - } -}; - -} // namespace map -} // namespace grnxx - -#endif // GRNXX_MAP_BYTES_POOL_HPP Deleted: lib/grnxx/map/common_header.cpp (+0 -38) 100644 =================================================================== --- lib/grnxx/map/common_header.cpp 2013-08-23 10:46:34 +0900 (a5cb0a6) +++ /dev/null @@ -1,38 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/map/common_header.hpp" - -namespace grnxx { -namespace map { -namespace { - -// Implementations are defined in a namespace "grnxx::map". -constexpr char FORMAT_PREFIX[] = "grnxx::map::"; - -} // namespace - -CommonHeader::CommonHeader(const char *format, MapType type) - : common_header_(format), - type_(type) {} - -CommonHeader::operator bool() const { - return common_header_.format().starts_with(FORMAT_PREFIX); -} - -} // namespace map -} // namespace grnxx Deleted: lib/grnxx/map/common_header.hpp (+0 -57) 100644 =================================================================== --- lib/grnxx/map/common_header.hpp 2013-08-23 10:46:34 +0900 (aef4a60) +++ /dev/null @@ -1,57 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_MAP_HEADER_HPP -#define GRNXX_MAP_HEADER_HPP - -#include "grnxx/bytes.hpp" -#include "grnxx/common_header.hpp" -#include "grnxx/map.hpp" - -namespace grnxx { -namespace map { - -class CommonHeader { - public: - // Create a common header with "format", the current version, and "type". - CommonHeader(const char *format, MapType type); - - // Return true iff the header seems to be correct. - explicit operator bool() const; - - // Return the format string. - Bytes format() const { - return common_header_.format(); - } - // Return the version string. - Bytes version() const { - return common_header_.version(); - } - // Return the implementation type. - MapType type() const { - return type_; - } - - private: - grnxx::CommonHeader common_header_; - MapType type_; -}; - -} // namespace map -} // namespace grnxx - -#endif // GRNXX_MAP_HEADER_HPP Deleted: lib/grnxx/map/cursor_impl.cpp (+0 -351) 100644 =================================================================== --- lib/grnxx/map/cursor_impl.cpp 2013-08-23 10:46:34 +0900 (98ae596) +++ /dev/null @@ -1,351 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/map/cursor_impl.hpp" - -#include <memory> -#include <new> - -#include "grnxx/bytes.hpp" -#include "grnxx/exception.hpp" -#include "grnxx/geo_point.hpp" -#include "grnxx/logger.hpp" -#include "grnxx/map.hpp" - -namespace grnxx { -namespace map { - -template <typename T> -AllKeysCursor<T>::AllKeysCursor() - : MapCursor<T>(), map_(), cur_(), end_(), step_(), count_(0), options_() {} - -template <typename T> -AllKeysCursor<T>::~AllKeysCursor() {} - -template <typename T> -AllKeysCursor<T> *AllKeysCursor<T>::create( - Map<T> *map, const MapCursorOptions &options) { - std::unique_ptr<AllKeysCursor<T>> cursor( - new (std::nothrow) AllKeysCursor<T>); - if (!cursor) { - GRNXX_ERROR() << "new grnxx::map::AllKeysCursor<T> failed"; - throw MemoryError(); - } - cursor->init(map, options); - return cursor.release(); -} - -template <typename T> -bool AllKeysCursor<T>::next() { - if (count_ >= options_.limit) { - return false; - } - while (cur_ != end_) { - cur_ += step_; - if (map_->get(cur_, &this->key_)) { - this->key_id_ = cur_; - ++count_; - return true; - } - } - return false; -} - -template <typename T> -bool AllKeysCursor<T>::remove() { - return map_->unset(this->key_id_); -} - -template <typename T> -void AllKeysCursor<T>::init(Map<T> *map, const MapCursorOptions &options) { - map_ = map; - options_ = options; - options_.flags = MAP_CURSOR_ORDER_BY_ID; - if (options.flags & MAP_CURSOR_REVERSE_ORDER) { - options_.flags |= MAP_CURSOR_REVERSE_ORDER; - } - - const int64_t min = map->min_key_id(); - const int64_t max = map->max_key_id(); - if (min > max) { - // There are no keys in the range [min, max]. - cur_ = end_ = 0; - return; - } - - if (options_.flags & MAP_CURSOR_REVERSE_ORDER) { - cur_ = max + 1; - end_ = min; - step_ = -1; - } else { - cur_ = min - 1; - end_ = max; - step_ = 1; - } - - // Skip the first "options_.offset" keys in range. - for (uint64_t count = 0; (count < options_.offset) && (cur_ != end_); ) { - cur_ += step_; - if (map_->get(cur_)) { - ++count; - } - } -} - -template <typename T> -KeyIDRangeCursor<T>::KeyIDRangeCursor() - : MapCursor<T>(), map_(), cur_(), end_(), step_(), count_(0), - query_(), options_() {} - -template <typename T> -KeyIDRangeCursor<T>::~KeyIDRangeCursor() {} - -template <typename T> -KeyIDRangeCursor<T> *KeyIDRangeCursor<T>::create( - Map<T> *map, - const MapCursorKeyIDRange<T> &query, - const MapCursorOptions &options) { - std::unique_ptr<KeyIDRangeCursor<T>> cursor( - new (std::nothrow) KeyIDRangeCursor<T>); - if (!cursor) { - GRNXX_ERROR() << "new grnxx::map::KeyIDRangeCursor<T> failed"; - throw MemoryError(); - } - cursor->init(map, query, options); - return cursor.release(); -} - -template <typename T> -bool KeyIDRangeCursor<T>::next() { - if (count_ >= options_.limit) { - return false; - } - while (cur_ != end_) { - cur_ += step_; - if (map_->get(cur_, &this->key_)) { - this->key_id_ = cur_; - ++count_; - return true; - } - } - return false; -} - -template <typename T> -bool KeyIDRangeCursor<T>::remove() { - return map_->unset(this->key_id_); -} - -template <typename T> -void KeyIDRangeCursor<T>::init(Map<T> *map, - const MapCursorKeyIDRange<T> &query, - const MapCursorOptions &options) { - map_ = map; - query_ = query; - options_ = options; - options_.flags = MAP_CURSOR_ORDER_BY_ID; - if (options.flags & MAP_CURSOR_REVERSE_ORDER) { - options_.flags |= MAP_CURSOR_REVERSE_ORDER; - } - - int64_t min; - if (query.flags & MAP_CURSOR_KEY_ID_GREATER) { - min = query_.min + 1; - } else if (query.flags & MAP_CURSOR_KEY_ID_GREATER_EQUAL) { - min = query_.min; - } else { - min = map->min_key_id(); - } - - int64_t max; - if (query.flags & MAP_CURSOR_KEY_ID_LESS) { - max = query_.max + 1; - } else if (query.flags & MAP_CURSOR_KEY_ID_LESS_EQUAL) { - max = query_.max; - } else { - max = map->max_key_id(); - } - - if (min > max) { - // There are no keys in the range [min, max]. - cur_ = end_ = 0; - return; - } - - if (options_.flags & MAP_CURSOR_REVERSE_ORDER) { - cur_ = max + 1; - end_ = min; - step_ = -1; - } else { - cur_ = min - 1; - end_ = max; - step_ = 1; - } - - // Skip the first "options_.offset" keys in range. - for (uint64_t count = 0; (count < options_.offset) && (cur_ != end_); ) { - cur_ += step_; - if (map_->get(cur_)) { - ++count; - } - } -} - -template <typename T> -KeyFilterCursor<T>::KeyFilterCursor() - : MapCursor<T>(), map_(), cur_(), end_(), step_(), count_(0), options_() {} - -template <typename T> -KeyFilterCursor<T>::~KeyFilterCursor() {} - -template <typename T> -bool KeyFilterCursor<T>::next() { - if (count_ >= options_.limit) { - return false; - } - while (cur_ != end_) { - cur_ += step_; - if (map_->get(cur_, &this->key_)) { - if (filter(this->key_)) { - this->key_id_ = cur_; - ++count_; - return true; - } - } - } - return false; -} - -template <typename T> -bool KeyFilterCursor<T>::remove() { - return map_->unset(this->key_id_); -} - -template <typename T> -void KeyFilterCursor<T>::init(Map<T> *map, const MapCursorOptions &options) { - map_ = map; - options_ = options; - options_.flags = MAP_CURSOR_ORDER_BY_ID; - if (options.flags & MAP_CURSOR_REVERSE_ORDER) { - options_.flags |= MAP_CURSOR_REVERSE_ORDER; - } - - if (options_.flags & MAP_CURSOR_REVERSE_ORDER) { - cur_ = map_->max_key_id() + 1; - end_ = 0; - step_ = -1; - } else { - cur_ = -1; - end_ = map_->max_key_id(); - step_ = 1; - } - - // Skip the first "options_.offset" keys in range. - for (uint64_t count = 0; (count < options_.offset) && (cur_ != end_); ) { - cur_ += step_; - if (map_->get(cur_, &this->key_)) { - if (filter(this->key_)) { - ++count; - } - } - } -} - -template <typename T> -KeyRangeCursor<T>::KeyRangeCursor() : KeyFilterCursor<T>(), query_() {} - -template <typename T> -KeyRangeCursor<T>::~KeyRangeCursor() {} - -template <typename T> -KeyRangeCursor<T> *KeyRangeCursor<T>::create( - Map<T> *map, - const MapCursorKeyRange<T> &query, - const MapCursorOptions &options) { - std::unique_ptr<KeyRangeCursor<T>> cursor( - new (std::nothrow) KeyRangeCursor<T>); - if (!cursor) { - GRNXX_ERROR() << "new grnxx::map::KeyRangeCursor<T> failed"; - throw MemoryError(); - } - cursor->query_ = query; - cursor->init(map, options); - return cursor.release(); -} - -template <typename T> -bool KeyRangeCursor<T>::filter(KeyArg key) const { - if (query_.flags & MAP_CURSOR_KEY_LESS) { - if (key >= query_.min) { - return false; - } - } else if (query_.flags & MAP_CURSOR_KEY_LESS_EQUAL) { - if (key > query_.min) { - return false; - } - } - if (query_.flags & MAP_CURSOR_KEY_GREATER) { - if (key <= query_.min) { - return false; - } - } else if (query_.flags & MAP_CURSOR_KEY_GREATER_EQUAL) { - if (key < query_.min) { - return false; - } - } - return true; -} - -template class AllKeysCursor<int8_t>; -template class AllKeysCursor<int16_t>; -template class AllKeysCursor<int32_t>; -template class AllKeysCursor<int64_t>; -template class AllKeysCursor<uint8_t>; -template class AllKeysCursor<uint16_t>; -template class AllKeysCursor<uint32_t>; -template class AllKeysCursor<uint64_t>; -template class AllKeysCursor<double>; -template class AllKeysCursor<GeoPoint>; -template class AllKeysCursor<Bytes>; - -template class KeyIDRangeCursor<int8_t>; -template class KeyIDRangeCursor<int16_t>; -template class KeyIDRangeCursor<int32_t>; -template class KeyIDRangeCursor<int64_t>; -template class KeyIDRangeCursor<uint8_t>; -template class KeyIDRangeCursor<uint16_t>; -template class KeyIDRangeCursor<uint32_t>; -template class KeyIDRangeCursor<uint64_t>; -template class KeyIDRangeCursor<double>; -template class KeyIDRangeCursor<GeoPoint>; -template class KeyIDRangeCursor<Bytes>; - -template class KeyRangeCursor<int8_t>; -template class KeyRangeCursor<int16_t>; -template class KeyRangeCursor<int32_t>; -template class KeyRangeCursor<int64_t>; -template class KeyRangeCursor<uint8_t>; -template class KeyRangeCursor<uint16_t>; -template class KeyRangeCursor<uint32_t>; -template class KeyRangeCursor<uint64_t>; -template class KeyRangeCursor<double>; -// GeoPoint does not support comparison operators (<, <=, >, >=). -//template class KeyRangeCursor<GeoPoint>; -template class KeyRangeCursor<Bytes>; - -} // namespace map -} // namespace grnxx Deleted: lib/grnxx/map/cursor_impl.hpp (+0 -134) 100644 =================================================================== --- lib/grnxx/map/cursor_impl.hpp 2013-08-23 10:46:34 +0900 (21a3116) +++ /dev/null @@ -1,134 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_MAP_CURSOR_IMPL_HPP -#define GRNXX_MAP_CURSOR_IMPL_HPP - -#include "grnxx/features.hpp" - -#include "grnxx/map_cursor.hpp" -#include "grnxx/map_cursor_query.hpp" -#include "grnxx/traits.hpp" -#include "grnxx/types.hpp" - -namespace grnxx { -namespace map { - -template <typename T> -class AllKeysCursor : public MapCursor<T> { - public: - using Key = typename Traits<T>::Type; - using KeyArg = typename Traits<T>::ArgumentType; - - AllKeysCursor(); - ~AllKeysCursor(); - - static AllKeysCursor *create(Map<T> *map, const MapCursorOptions &options); - - bool next(); - bool remove(); - - private: - Map<T> *map_; - int64_t cur_; - int64_t end_; - int64_t step_; - uint64_t count_; - MapCursorOptions options_; - - void init(Map<T> *map, const MapCursorOptions &options); -}; - -template <typename T> -class KeyIDRangeCursor : public MapCursor<T> { - public: - using Key = typename Traits<T>::Type; - using KeyArg = typename Traits<T>::ArgumentType; - - KeyIDRangeCursor(); - ~KeyIDRangeCursor(); - - static KeyIDRangeCursor *create(Map<T> *map, - const MapCursorKeyIDRange<T> &query, - const MapCursorOptions &options); - - bool next(); - bool remove(); - - private: - Map<T> *map_; - int64_t cur_; - int64_t end_; - int64_t step_; - uint64_t count_; - MapCursorKeyIDRange<T> query_; - MapCursorOptions options_; - - void init(Map<T> *map, - const MapCursorKeyIDRange<T> &query, - const MapCursorOptions &options); -}; - -template <typename T> -class KeyFilterCursor : public MapCursor<T> { - public: - using Key = typename Traits<T>::Type; - using KeyArg = typename Traits<T>::ArgumentType; - - KeyFilterCursor(); - virtual ~KeyFilterCursor(); - - bool next(); - bool remove(); - - protected: - Map<T> *map_; - int64_t cur_; - int64_t end_; - int64_t step_; - uint64_t count_; - MapCursorOptions options_; - - void init(Map<T> *map, const MapCursorOptions &options); - - // Return true if "key" satisfies the query. - virtual bool filter(KeyArg key) const = 0; -}; - -template <typename T> -class KeyRangeCursor : public KeyFilterCursor<T> { - public: - using Key = typename Traits<T>::Type; - using KeyArg = typename Traits<T>::ArgumentType; - - KeyRangeCursor(); - ~KeyRangeCursor(); - - static KeyRangeCursor *create(Map<T> *map, - const MapCursorKeyRange<T> &query, - const MapCursorOptions &options); - - private: - MapCursorKeyRange<T> query_; - - bool filter(KeyArg key) const; -}; - -} // namespace map -} // namespace grnxx - -#endif // GRNXX_MAP_CURSOR_IMPL_HPP Deleted: lib/grnxx/map/double_array.cpp (+0 -1507) 100644 =================================================================== --- lib/grnxx/map/double_array.cpp 2013-08-23 10:46:34 +0900 (48da750) +++ /dev/null @@ -1,1507 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/map/double_array.hpp" - -#include <new> - -#include "grnxx/array.hpp" -#include "grnxx/exception.hpp" -#include "grnxx/geo_point.hpp" -#include "grnxx/intrinsic.hpp" -#include "grnxx/lock.hpp" -#include "grnxx/logger.hpp" -#include "grnxx/map/common_header.hpp" -#include "grnxx/map/helper.hpp" -#include "grnxx/map/pool.hpp" -#include "grnxx/mutex.hpp" -#include "grnxx/storage.hpp" - -namespace grnxx { -namespace map { -namespace { - -constexpr char FORMAT_STRING[] = "grnxx::map::DoubleArray"; - -constexpr uint64_t BLOCK_MAX_FAILURE_COUNT = 4; -constexpr uint64_t BLOCK_MAX_LEVEL = 5; -constexpr uint64_t BLOCK_INVALID_ID = (1ULL << 40) - 1; -constexpr uint64_t BLOCK_SIZE = 1ULL << 9; -constexpr uint64_t BLOCK_MAX_COUNT = 16; - -constexpr uint64_t TERMINAL_LABEL = 0x100; -constexpr uint64_t MAX_LABEL = TERMINAL_LABEL; -constexpr uint64_t INVALID_LABEL = MAX_LABEL + 1; -constexpr uint64_t INVALID_OFFSET = 0; - -constexpr uint64_t ROOT_NODE_ID = 0; - -struct ImplHeader { - uint32_t nodes_storage_node_id; - uint32_t siblings_storage_node_id; - uint32_t blocks_storage_node_id; - uint64_t num_blocks; - uint64_t num_phantoms; - uint64_t num_zombies; - uint64_t latest_blocks[BLOCK_MAX_LEVEL + 1]; - - ImplHeader(); -}; - -ImplHeader::ImplHeader() - : nodes_storage_node_id(STORAGE_INVALID_NODE_ID), - siblings_storage_node_id(STORAGE_INVALID_NODE_ID), - blocks_storage_node_id(STORAGE_INVALID_NODE_ID), - num_blocks(0), - num_phantoms(0), - num_zombies(0), - latest_blocks() { - for (uint64_t i = 0; i <= BLOCK_MAX_LEVEL; ++i) { - latest_blocks[i] = BLOCK_INVALID_ID; - } -} - -// The internal structure of Block is as follows: -// - values_[0] -// 0-15 (16): first_phantom -// 16-23 ( 8): level -// 24-63 (40): next -// - values_[1] -// 0-15 (16): num_phantoms -// 16-23 ( 8): failure_count -// 24-63 (40): prev -// where 0 is the LSB and 63 is the MSB. -class Block { - // For values_[0]. - static constexpr uint64_t FIRST_PHANTOM_MASK = (1ULL << 16) - 1; - static constexpr uint8_t FIRST_PHANTOM_SHIFT = 0; - static constexpr uint64_t LEVEL_MASK = (1ULL << 8) - 1; - static constexpr uint8_t LEVEL_SHIFT = 16; - static constexpr uint64_t NEXT_MASK = (1ULL << 40) - 1; - static constexpr uint8_t NEXT_SHIFT = 24; - - // For values_[1]. - static constexpr uint64_t NUM_PHANTOMS_MASK = (1ULL << 16) - 1; - static constexpr uint8_t NUM_PHANTOMS_SHIFT = 0; - static constexpr uint64_t FAILURE_COUNT_MASK = (1ULL << 8) - 1; - static constexpr uint8_t FAILURE_COUNT_SHIFT = 16; - static constexpr uint64_t PREV_MASK = (1ULL << 40) - 1; - static constexpr uint8_t PREV_SHIFT = 24; - - public: - static Block empty_block() { - return Block(0, BLOCK_SIZE << NUM_PHANTOMS_SHIFT); - } - - // Return the first phantom node. - uint64_t first_phantom() const { - return (values_[0] >> FIRST_PHANTOM_SHIFT) & FIRST_PHANTOM_MASK; - } - // Return the level. - uint64_t level() const { - return (values_[0] >> LEVEL_SHIFT) & LEVEL_MASK; - } - // Return the next block ID of the same level. - uint64_t next() const { - return (values_[0] >> NEXT_SHIFT) & NEXT_MASK; - } - - // Return the number of phantom nodes. - uint64_t num_phantoms() const { - return (values_[1] >> NUM_PHANTOMS_SHIFT) & NUM_PHANTOMS_MASK; - } - // Return the failure count. - uint64_t failure_count() const { - return (values_[1] >> FAILURE_COUNT_SHIFT) & FAILURE_COUNT_MASK; - } - // Return the previous block ID of the same level. - uint64_t prev() const { - return (values_[1] >> PREV_SHIFT) & PREV_MASK; - } - - void set_first_phantom(uint64_t first_phantom) { - values_[0] = (values_[0] & ~(FIRST_PHANTOM_MASK << FIRST_PHANTOM_SHIFT)) | - ((first_phantom & FIRST_PHANTOM_MASK) << FIRST_PHANTOM_SHIFT); - } - void set_level(uint64_t level) { - values_[0] = (values_[0] & ~(LEVEL_MASK << LEVEL_SHIFT)) | - ((level & LEVEL_MASK) << LEVEL_SHIFT); - } - void set_next(uint64_t next) { - values_[0] = (values_[0] & ~(NEXT_MASK << NEXT_SHIFT)) | - ((next & NEXT_MASK) << NEXT_SHIFT); - } - - void set_num_phantoms(uint64_t num_phantoms) { - values_[1] = (values_[1] & ~(NUM_PHANTOMS_MASK << NUM_PHANTOMS_SHIFT)) | - ((num_phantoms & NUM_PHANTOMS_MASK) << NUM_PHANTOMS_SHIFT); - } - void set_failure_count(uint64_t failure_count) { - values_[1] = (values_[1] & ~(FAILURE_COUNT_MASK << FAILURE_COUNT_SHIFT)) | - ((failure_count & FAILURE_COUNT_MASK) << FAILURE_COUNT_SHIFT); - } - void set_prev(uint64_t prev) { - values_[1] = (values_[1] & ~(PREV_MASK << PREV_SHIFT)) | - ((prev & PREV_MASK) << PREV_SHIFT); - } - - private: - uint64_t values_[2]; - - Block(uint64_t value_0, uint64_t value_1) : values_{ value_0, value_1 } {} -}; - -// The internal structure of DoubleArray is as follows: -// - Common -// 62 ( 1): is_phantom -// 63 ( 1): is_origin -// - Phantom: is_phantom -// 0- 8 ( 9): next -// 9-17 ( 9): prev -// 18-61 (44): reserved -// - NonPhantom: !is_phantom -// 0- 8 ( 9): label -// 60 ( 1): has_sibling -// 61 ( 1): is_leaf -// - Leaf: !is_phantom && is_leaf -// 9-48 (40): key_id -// 49-59 (11): reserved -// - NonLeaf: !is_phantom && !is_leaf -// 9-17 ( 9): child -// 18-59 (42): offset -// where 0 is the LSB and 63 is the MSB. -class Node { - static constexpr uint64_t IS_PHANTOM_FLAG = 1ULL << 62; - static constexpr uint64_t IS_ORIGIN_FLAG = 1ULL << 63; - - static constexpr uint64_t NEXT_MASK = (1ULL << 9) - 1; - static constexpr uint8_t NEXT_SHIFT = 0; - static constexpr uint64_t PREV_MASK = (1ULL << 9) - 1; - static constexpr uint8_t PREV_SHIFT = 9; - - static constexpr uint64_t LABEL_MASK = (1ULL << 9) - 1; - static constexpr uint8_t LABEL_SHIFT = 0; - static constexpr uint64_t HAS_SIBLING_FLAG = 1ULL << 60; - static constexpr uint64_t IS_LEAF_FLAG = 1ULL << 61; - - static constexpr uint64_t KEY_ID_MASK = (1ULL << 40) - 1; - static constexpr uint8_t KEY_ID_SHIFT = 9; - - static constexpr uint64_t CHILD_MASK = (1ULL << 9) - 1; - static constexpr uint8_t CHILD_SHIFT = 9; - static constexpr uint64_t OFFSET_MASK = (1ULL << 42) - 1; - static constexpr uint8_t OFFSET_SHIFT = 18; - - public: - // Create a phantom node. - static Node phantom_node(uint64_t next, uint64_t prev) { - return Node(IS_PHANTOM_FLAG | ((next & NEXT_MASK) << NEXT_SHIFT) | - ((prev & PREV_MASK) << PREV_SHIFT)); - } - - // Return true iff this node is a phantom node. - bool is_phantom() const { - return value_ & IS_PHANTOM_FLAG; - } - // Return true iff the ID of this node is used as an offset. - bool is_origin() const { - return value_ & IS_ORIGIN_FLAG; - } - - // Return the ID of the next phantom node in the same block. - uint64_t next() const { - return (value_ >> NEXT_SHIFT) & NEXT_MASK; - } - // Return the ID of the prev phantom node in the same block. - uint64_t prev() const { - return (value_ >> PREV_SHIFT) & PREV_MASK; - } - - // Return the label. - // Note that a phantom node returns an invalid label. - uint64_t label() const { - return (value_ >> LABEL_SHIFT) & - ((IS_PHANTOM_FLAG >> LABEL_SHIFT) | LABEL_MASK); - } - // Return true iff this node has a sibling with a greater label. - bool has_sibling() const { - return value_ & HAS_SIBLING_FLAG; - } - // Return true iff this node is a leaf node. - bool is_leaf() const { - return value_ & IS_LEAF_FLAG; - } - - // Return the associated key ID. - uint64_t key_id() const { - return (value_ >> KEY_ID_SHIFT) & KEY_ID_MASK; - } - - // Return the ID of the child node with the least label. - uint64_t child() const { - return (value_ >> CHILD_SHIFT) & CHILD_MASK; - } - // Return the offset to child nodes. - uint64_t offset() const { - return (value_ >> OFFSET_SHIFT) & OFFSET_MASK; - } - - void unset_is_phantom() { - value_ = (value_ & IS_ORIGIN_FLAG) | - (INVALID_LABEL << LABEL_SHIFT) | - (INVALID_LABEL << CHILD_SHIFT) | - (INVALID_OFFSET << OFFSET_SHIFT); - } - void set_is_origin(bool is_origin) { - if (is_origin) { - value_ |= IS_ORIGIN_FLAG; - } else { - value_ &= ~IS_ORIGIN_FLAG; - } - } - - void set_next(uint64_t next) { - value_ = (value_ & ~(NEXT_MASK << NEXT_SHIFT)) | - ((next & NEXT_MASK) << NEXT_SHIFT); - } - void set_prev(uint64_t prev) { - value_ = (value_ & ~(PREV_MASK << PREV_SHIFT)) | - ((prev & PREV_MASK) << PREV_SHIFT); - } - void set_next_and_prev(uint64_t next, uint64_t prev) { - constexpr uint64_t NEXT_AND_PREV_MASK = - (NEXT_MASK << NEXT_SHIFT) | (PREV_MASK << PREV_SHIFT); - value_ = (value_ & ~NEXT_AND_PREV_MASK) | - ((next & NEXT_MASK) << NEXT_SHIFT) | - ((prev & PREV_MASK) << PREV_SHIFT); - } - - void set_label(uint64_t label) { - value_ = (value_ & ~(LABEL_MASK << LABEL_SHIFT)) | - ((label & LABEL_MASK) << LABEL_SHIFT); - } - void set_has_sibling() { - value_ |= HAS_SIBLING_FLAG; - } - // set_is_leaf() is not provided because set_key_id() sets IS_LEAF_FLAG. - - void set_key_id(uint64_t key_id) { - value_ = (value_ & ~(KEY_ID_MASK << KEY_ID_SHIFT)) | IS_LEAF_FLAG | - ((key_id & KEY_ID_MASK) << KEY_ID_SHIFT); - } - - void set_child(uint64_t child) { - value_ = (value_ & ~(CHILD_MASK << CHILD_SHIFT)) | - ((child & CHILD_MASK) << CHILD_SHIFT); - } - void set_offset(uint64_t offset) { - if (value_ & IS_LEAF_FLAG) { - value_ = (value_ & ~(IS_LEAF_FLAG | (OFFSET_MASK << OFFSET_SHIFT) | - (CHILD_MASK << CHILD_SHIFT))) | - (offset << OFFSET_SHIFT) | - (INVALID_LABEL << CHILD_SHIFT); - } else { - value_ = (value_ & ~(OFFSET_MASK << OFFSET_SHIFT)) | - (offset << OFFSET_SHIFT); - } - } - - private: - uint64_t value_; - - explicit Node(uint64_t value) : value_(value) {} -}; - -} // namespace - -class DoubleArrayImpl { - using Header = ImplHeader; - using NodeArray = Array<Node, 65536, 8192>; // 42-bit - using SiblingArray = Array<uint8_t, 262144, 4096>; // 42-bit - using BlockArray = Array<Block, 8192, 1024>; // 33-bit - using Pool = map::Pool<Bytes>; - - static constexpr uint64_t NODE_ARRAY_SIZE = 1ULL << 42; - static constexpr uint64_t SIBLING_ARRAY_SIZE = 1ULL << 42; - static constexpr uint64_t BLOCK_ARRAY_SIZE = 1ULL << 33; - - public: - using Key = typename Map<Bytes>::Key; - using KeyArg = typename Map<Bytes>::KeyArg; - using Cursor = typename Map<Bytes>::Cursor; - - DoubleArrayImpl(); - ~DoubleArrayImpl(); - - static DoubleArrayImpl *create(Storage *storage, uint32_t storage_node_id, - Pool *pool); - static DoubleArrayImpl *create(Storage *storage, uint32_t storage_node_id, - DoubleArrayImpl *src_impl); - static DoubleArrayImpl *open(Storage *storage, uint32_t storage_node_id, - Pool *pool); - - static void unlink(Storage *storage, uint32_t storage_node_id) { - storage->unlink_node(storage_node_id); - } - - uint32_t storage_node_id() const { - return storage_node_id_; - } - - int64_t max_key_id() { - return pool_->max_key_id(); - } - uint64_t num_keys() { - return pool_->num_keys(); - } - - bool get(int64_t key_id, Key *key = nullptr); - bool unset(int64_t key_id); - bool reset(int64_t key_id, KeyArg dest_key); - - bool find(KeyArg key, int64_t *key_id = nullptr); - bool add(KeyArg key, int64_t *key_id = nullptr); - bool remove(KeyArg key); - bool replace(KeyArg src_key, KeyArg dest_key, int64_t *key_id = nullptr); - - bool find_longest_prefix_match(KeyArg query, - int64_t *key_id = nullptr, - Key *key = nullptr); - -// Cursor *create_cursor( -// MapCursorAllKeys<Bytes> query, -// const MapCursorOptions &options = MapCursorOptions()); -// Cursor *create_cursor( -// const MapCursorKeyIDRange<Bytes> &query, -// const MapCursorOptions &options = MapCursorOptions()); -// Cursor *create_cursor( -// const MapCursorKeyRange<Bytes> &query, -// const MapCursorOptions &options = MapCursorOptions()); - - private: - Storage *storage_; - uint32_t storage_node_id_; - Header *header_; - std::unique_ptr<NodeArray> nodes_; - std::unique_ptr<SiblingArray> siblings_; - std::unique_ptr<BlockArray> blocks_; - Pool *pool_; - - void create_impl(Storage *storage, uint32_t storage_node_id, Pool *pool); - void create_impl(Storage *storage, uint32_t storage_node_id, - DoubleArrayImpl *src_impl); - void open_impl(Storage *storage, uint32_t storage_node_id, Pool *pool); - - void defrag(DoubleArrayImpl *src_impl, uint64_t src, uint64_t dest); - - bool replace_key(int64_t key_id, KeyArg src_key, KeyArg dest_key); - - bool find_leaf(KeyArg key, Node **leaf_node, uint64_t *leaf_key_pos); - bool insert_leaf(KeyArg key, Node *node, uint64_t key_pos, Node **leaf_node); - - Node *insert_node(Node *node, uint64_t label); - Node *separate(Node *node, uint64_t labels[2]); - - void resolve(Node *node, uint64_t label); - void migrate_nodes(Node *node, uint64_t dest_offset, - const uint64_t *labels, uint64_t num_labels); - - uint64_t find_offset(const uint64_t *labels, uint64_t num_labels); - - Node *reserve_node(uint64_t node_id); - Block *reserve_block(uint64_t block_id); - - void update_block_level(uint64_t block_id, Block *block, uint64_t level); - void set_block_level(uint64_t block_id, Block *block, uint64_t level); - void unset_block_level(uint64_t block_id, Block *block); -}; - -DoubleArrayImpl::DoubleArrayImpl() - : storage_(nullptr), - storage_node_id_(STORAGE_INVALID_NODE_ID), - header_(nullptr), - nodes_(), - siblings_(), - blocks_(), - pool_(nullptr) {} - -DoubleArrayImpl::~DoubleArrayImpl() {} - -DoubleArrayImpl *DoubleArrayImpl::create(Storage *storage, - uint32_t storage_node_id, - Pool *pool) { - std::unique_ptr<DoubleArrayImpl> impl(new (std::nothrow) DoubleArrayImpl); - if (!impl) { - GRNXX_ERROR() << "new grnxx::map::DoubleArrayImpl failed"; - throw MemoryError(); - } - impl->create_impl(storage, storage_node_id, pool); - return impl.release(); -} - -DoubleArrayImpl *DoubleArrayImpl::create(Storage *storage, - uint32_t storage_node_id, - DoubleArrayImpl *src_impl) { - std::unique_ptr<DoubleArrayImpl> impl(new (std::nothrow) DoubleArrayImpl); - if (!impl) { - GRNXX_ERROR() << "new grnxx::map::DoubleArrayImpl failed"; - throw MemoryError(); - } - impl->create_impl(storage, storage_node_id, src_impl); - return impl.release(); -} - -DoubleArrayImpl *DoubleArrayImpl::open(Storage *storage, - uint32_t storage_node_id, - Pool *pool) { - std::unique_ptr<DoubleArrayImpl> impl(new (std::nothrow) DoubleArrayImpl); - if (!impl) { - GRNXX_ERROR() << "new grnxx::map::DoubleArrayImpl failed"; - throw MemoryError(); - } - impl->open_impl(storage, storage_node_id, pool); - return impl.release(); -} - -bool DoubleArrayImpl::get(int64_t key_id, Key *key) { - if ((key_id < MAP_MIN_KEY_ID) || (key_id > max_key_id())) { - // Out of range. - return false; - } - if (key) { - return pool_->get(key_id, key); - } - return pool_->get_bit(key_id); -} - -bool DoubleArrayImpl::unset(int64_t key_id) { - if ((key_id < MAP_MIN_KEY_ID) || (key_id > max_key_id())) { - // Out of range. - return false; - } - Key key; - if (!pool_->get(key_id, &key)) { - // Not found. - return false; - } - return remove(key); -} - -bool DoubleArrayImpl::reset(int64_t key_id, KeyArg dest_key) { - if ((key_id < MAP_MIN_KEY_ID) || (key_id > max_key_id())) { - // Out of range. - return false; - } - Key src_key; - if (!pool_->get(key_id, &src_key)) { - // Not found. - return false; - } - return replace(src_key, dest_key); -} - -bool DoubleArrayImpl::find(KeyArg key, int64_t *key_id) { - uint64_t node_id = ROOT_NODE_ID; - Node node = nodes_->get(node_id); - uint64_t key_pos; - for (key_pos = 0; key_pos < key.size(); ++key_pos) { - if (node.is_leaf()) { - // Found. - break; - } - node_id = node.offset() ^ key[key_pos]; - node = nodes_->get(node_id); - if (node.label() != key[key_pos]) { - // Not found. - return false; - } - } - if (!node.is_leaf()) { - if (node.child() != TERMINAL_LABEL) { - // Not found. - return false; - } - node_id = node.offset() ^ TERMINAL_LABEL; - node = nodes_->get(node_id); - if (!node.is_leaf()) { - // Not found. - return false; - } - } - Key stored_key; - if (!pool_->get(node.key_id(), &stored_key)) { - // Not found. - return false; - } - if (key.except_prefix(key_pos) != stored_key.except_prefix(key_pos)) { - // Not found. - return false; - } - if (key_id) { - *key_id = node.key_id(); - } - return true; -} - -bool DoubleArrayImpl::add(KeyArg key, int64_t *key_id) { - Node *node; - uint64_t key_pos; - find_leaf(key, &node, &key_pos); - if (!insert_leaf(key, node, key_pos, &node)) { - if (key_id) { - *key_id = node->key_id(); - } - return false; - } - const int64_t next_key_id = pool_->add(key); - node->set_key_id(next_key_id); - if (key_id) { - *key_id = next_key_id; - } - return true; -} - -bool DoubleArrayImpl::remove(KeyArg key) { - Node *node; - uint64_t key_pos; - if (!find_leaf(key, &node, &key_pos)) { - // Not found. - return false; - } - Key stored_key; - if (!pool_->get(node->key_id(), &stored_key)) { - // Not found. - return false; - } - if (key.except_prefix(key_pos) != stored_key.except_prefix(key_pos)) { - // Not found. - return false; - } - pool_->unset(node->key_id()); - node->set_offset(INVALID_OFFSET); - return true; -} - -bool DoubleArrayImpl::replace(KeyArg src_key, KeyArg dest_key, - int64_t *key_id) { - int64_t src_key_id; - if (!find(src_key, &src_key_id)) { - // Not found. - return false; - } - if (!replace_key(src_key_id, src_key, dest_key)) { - // Found. - return false; - } - if (key_id) { - *key_id = src_key_id; - } - return true; -} - -bool DoubleArrayImpl::find_longest_prefix_match(KeyArg query, - int64_t *key_id, Key *key) { - bool found = false; - uint64_t node_id = ROOT_NODE_ID; - Node node = nodes_->get(node_id); - uint64_t query_pos; - for (query_pos = 0; query_pos < query.size(); ++query_pos) { - if (node.is_leaf()) { - Key stored_key; - if (pool_->get(node.key_id(), &stored_key)) { - if ((stored_key.size() <= query.size()) && - (stored_key.except_prefix(query_pos) == - query.prefix(stored_key.size()).except_prefix(query_pos))) { - if (key_id) { - *key_id = node.key_id(); - } - if (key) { - *key = stored_key; - } - found = true; - } - } - return found; - } - - if (node.child() == TERMINAL_LABEL) { - Node leaf_node = nodes_->get(node.offset() ^ TERMINAL_LABEL); - if (leaf_node.is_leaf()) { - if (pool_->get(leaf_node.key_id(), key)) { - if (key_id) { - *key_id = leaf_node.key_id(); - } - found = true; - } - } - } - - node_id = node.offset() ^ query[query_pos]; - node = nodes_->get(node_id); - if (node.label() != query[query_pos]) { - return found; - } - } - - if (node.is_leaf()) { - Key stored_key; - if (pool_->get(node.key_id(), &stored_key)) { - if (stored_key.size() <= query.size()) { - if (key_id) { - *key_id = node.key_id(); - } - if (key) { - *key = stored_key; - } - found = true; - } - } - } else if (node.child() == TERMINAL_LABEL) { - node = nodes_->get(node.offset() ^ TERMINAL_LABEL); - if (pool_->get(node.key_id(), key)) { - if (key_id) { - *key_id = node.key_id(); - } - found = true; - } - } - return found; -} - -void DoubleArrayImpl::create_impl(Storage *storage, uint32_t storage_node_id, - Pool *pool) { - storage_ = storage; - StorageNode storage_node = - storage->create_node(storage_node_id, sizeof(Header)); - storage_node_id_ = storage_node.id(); - try { - header_ = static_cast<Header *>(storage_node.body()); - *header_ = Header(); - pool_ = pool; - nodes_.reset(NodeArray::create(storage, storage_node_id_, - NODE_ARRAY_SIZE)); - siblings_.reset(SiblingArray::create(storage, storage_node_id_, - SIBLING_ARRAY_SIZE)); - blocks_.reset(BlockArray::create(storage, storage_node_id_, - BLOCK_ARRAY_SIZE)); - header_->nodes_storage_node_id = nodes_->storage_node_id(); - header_->siblings_storage_node_id = siblings_->storage_node_id(); - header_->blocks_storage_node_id = blocks_->storage_node_id(); - Node * const root_node = reserve_node(ROOT_NODE_ID); - root_node[INVALID_OFFSET - ROOT_NODE_ID].set_is_origin(true); - } catch (...) { - storage->unlink_node(storage_node_id_); - throw; - } -} - -void DoubleArrayImpl::create_impl(Storage *storage, uint32_t storage_node_id, - DoubleArrayImpl *src_impl) { - create_impl(storage, storage_node_id, src_impl->pool_); - try { - // Build a double-array from "src_impl". - defrag(src_impl, ROOT_NODE_ID, ROOT_NODE_ID); - } catch (...) { - storage->unlink_node(storage_node_id_); - throw; - } -} - -void DoubleArrayImpl::open_impl(Storage *storage, uint32_t storage_node_id, - Pool *pool) { - storage_ = storage; - storage_node_id_ = storage_node_id; - StorageNode storage_node = storage->open_node(storage_node_id_); - if (storage_node.size() < sizeof(Header)) { - GRNXX_ERROR() << "invalid format: size = " << storage_node.size() - << ", header_size = " << sizeof(Header); - throw LogicError(); - } - header_ = static_cast<Header *>(storage_node.body()); - pool_ = pool; - nodes_.reset(NodeArray::open(storage, header_->nodes_storage_node_id)); - siblings_.reset( - SiblingArray::open(storage, header_->siblings_storage_node_id)); - blocks_.reset(BlockArray::open(storage, header_->blocks_storage_node_id)); -} - -bool DoubleArrayImpl::replace_key(int64_t key_id, KeyArg src_key, - KeyArg dest_key) { - Node *dest_node; - uint64_t key_pos; - find_leaf(dest_key, &dest_node, &key_pos); - if (!insert_leaf(dest_key, dest_node, key_pos, &dest_node)) { - return false; - } - Node *src_node; - if (!find_leaf(src_key, &src_node, &key_pos)) { - // Critical error. - GRNXX_ERROR() << "not found: src_key = " << src_key; - throw LogicError(); - } - pool_->reset(key_id, dest_key); - dest_node->set_key_id(key_id); - src_node->set_offset(INVALID_OFFSET); - return true; -} - -void DoubleArrayImpl::defrag(DoubleArrayImpl *src_impl, uint64_t src_node_id, - uint64_t dest_node_id) { - const Node src_node = src_impl->nodes_->get(src_node_id); - Node &dest_node = nodes_->get_value(dest_node_id); - if (src_node.is_leaf()) { - dest_node.set_key_id(src_node.key_id()); - return; - } - - const uint64_t src_offset = src_node.offset(); - uint64_t dest_offset; - { - uint64_t labels[MAX_LABEL + 1]; - uint64_t num_labels = 0; - uint64_t label = src_node.child(); - while (label != INVALID_LABEL) { - const uint64_t child_node_id = src_offset ^ label; - const Node child_node = src_impl->nodes_->get(child_node_id); - if (child_node.is_leaf() || (child_node.child() != INVALID_LABEL)) { - labels[num_labels++] = label; - } - if (child_node.has_sibling()) { - label = src_impl->siblings_->get(child_node_id); - } else { - label = INVALID_LABEL; - } - } - if (num_labels == 0) { - return; - } - - dest_offset = find_offset(labels, num_labels); - for (uint64_t i = 0; i < num_labels; ++i) { - const uint64_t child_node_id = dest_offset ^ labels[i]; - reserve_node(child_node_id); - Node &child_node = nodes_->get_value(child_node_id); - child_node.set_label(labels[i]); - if ((i + 1) < num_labels) { - child_node.set_has_sibling(); - siblings_->set(child_node_id, labels[i + 1]); - } - } - - nodes_->get_value(dest_offset).set_is_origin(true); - dest_node.set_offset(dest_offset); - dest_node.set_child(labels[0]); - } - - uint16_t label = dest_node.child(); - while (label != INVALID_LABEL) { - const uint64_t next_src_node_id = src_offset ^ label; - const uint64_t next_dest_node_id = dest_offset ^ label; - defrag(src_impl, next_src_node_id, next_dest_node_id); - label = nodes_->get_value(next_dest_node_id).has_sibling() ? - siblings_->get(next_dest_node_id) : INVALID_LABEL; - } -} - -bool DoubleArrayImpl::find_leaf(KeyArg key, Node **leaf_node, - uint64_t *leaf_key_pos) { - Node *node = &nodes_->get_value(ROOT_NODE_ID); - uint64_t key_pos; - for (key_pos = 0; key_pos < key.size(); ++key_pos) { - if (node->is_leaf()) { - // Found. - *leaf_node = node; - *leaf_key_pos = key_pos; - return true; - } - const uint64_t child_node_id = node->offset() ^ key[key_pos]; - Node * const child_node = &nodes_->get_value(child_node_id); - if (child_node->label() != key[key_pos]) { - // Not found. - *leaf_node = node; - *leaf_key_pos = key_pos; - return false; - } - node = child_node; - } - *leaf_node = node; - *leaf_key_pos = key_pos; - if (node->is_leaf()) { - // Found. - return true; - } - if (node->child() != TERMINAL_LABEL) { - // Not found. - return false; - } - const uint64_t node_id = node->offset() ^ TERMINAL_LABEL; - node = &nodes_->get_value(node_id); - *leaf_node = node; - return node->is_leaf(); -} - -bool DoubleArrayImpl::insert_leaf(KeyArg key, Node *node, - uint64_t key_pos, Node **leaf_node) { - if (node->is_leaf()) { - Key stored_key; - if (!pool_->get(node->key_id(), &stored_key)) { - GRNXX_ERROR() << "not found: key = " << key << ", key_pos = " << key_pos; - throw LogicError(); - } - uint64_t i = key_pos; - while ((i < key.size()) && (i < stored_key.size())) { - if (key[i] != stored_key[i]) { - break; - } - ++i; - } - if ((i == key.size()) && (i == stored_key.size())) { - return false; - } - while (key_pos < i) { - node = insert_node(node, key[key_pos]); - ++key_pos; - } - uint64_t labels[2]; - labels[0] = (key_pos < stored_key.size()) ? - stored_key[key_pos] : TERMINAL_LABEL; - labels[1] = (key_pos < key.size()) ? key[key_pos] : TERMINAL_LABEL; - *leaf_node = separate(node, labels); - return true; - } else if (node->label() == TERMINAL_LABEL) { - *leaf_node = node; - return true; - } else { - const uint64_t label = (key_pos < key.size()) ? - key[key_pos] : TERMINAL_LABEL; - resolve(node, label); - *leaf_node = insert_node(node, label); - return true; - } -} - -Node *DoubleArrayImpl::insert_node(Node *node, uint64_t label) { - uint64_t offset = node->offset(); - if (node->is_leaf() || (offset == INVALID_OFFSET)) { - offset = find_offset(&label, 1); - } - const uint64_t next_node_id = offset ^ label; - uint8_t *next_sibling = &siblings_->get_value(next_node_id); - Node * const next_node = reserve_node(next_node_id); - next_node->set_label(label); - if (node->is_leaf()) { - next_node[offset - next_node_id].set_is_origin(true); - next_node->set_key_id(node->key_id()); - } else if (node->offset() == INVALID_OFFSET) { - next_node[offset - next_node_id].set_is_origin(true); - } - node->set_offset(offset); - const uint64_t child_label = node->child(); - if (child_label == INVALID_LABEL) { - node->set_child(label); - } else if ((label == TERMINAL_LABEL) || - ((child_label != TERMINAL_LABEL) && (label < child_label))) { - // The child node becomes the first child. - *next_sibling = child_label; - next_node->set_has_sibling(); - node->set_child(label); - } else { - uint64_t prev_node_id = offset ^ child_label; - Node *prev_node = &next_node[prev_node_id - next_node_id]; - uint8_t *prev_sibling = &next_sibling[prev_node_id - next_node_id]; - uint64_t sibling_label = prev_node->has_sibling() ? - *prev_sibling : INVALID_LABEL; - while (label > sibling_label) { - prev_node_id = offset ^ sibling_label; - prev_node = &next_node[prev_node_id - next_node_id]; - prev_sibling = &next_sibling[prev_node_id - next_node_id]; - sibling_label = prev_node->has_sibling() ? - *prev_sibling : INVALID_LABEL; - } - *next_sibling = *prev_sibling; - *prev_sibling = label; - if (prev_node->has_sibling()) { - next_node->set_has_sibling(); - } - prev_node->set_has_sibling(); - } - return next_node; -} - -Node *DoubleArrayImpl::separate(Node *node, uint64_t labels[2]) { - const uint64_t offset = find_offset(labels, 2); - uint64_t node_ids[2] = { offset ^ labels[0], offset ^ labels[1] }; - Node *nodes[2]; - nodes[0] = reserve_node(node_ids[0]); - nodes[1] = reserve_node(node_ids[1]); - uint8_t * const sibling_block = - &siblings_->get_value(offset & ~(BLOCK_SIZE - 1)); - nodes[0]->set_label(labels[0]); - nodes[0]->set_key_id(node->key_id()); - nodes[1]->set_label(labels[1]); - nodes[0][offset - node_ids[0]].set_is_origin(true); - node->set_offset(offset); - if ((labels[0] == TERMINAL_LABEL) || - ((labels[1] != TERMINAL_LABEL) && (labels[0] < labels[1]))) { - sibling_block[node_ids[0] % BLOCK_SIZE] = static_cast<uint8_t>(labels[1]); - nodes[0]->set_has_sibling(); - node->set_child(labels[0]); - } else { - sibling_block[node_ids[1] % BLOCK_SIZE] = static_cast<uint8_t>(labels[0]); - nodes[1]->set_has_sibling(); - node->set_child(labels[1]); - } - return nodes[1]; -} - -void DoubleArrayImpl::resolve(Node *node, uint64_t label) { - uint64_t offset = node->offset(); - if (offset == INVALID_OFFSET) { - return; - } - uint64_t dest_node_id = offset ^ label; - Node * const dest_node = &nodes_->get_value(dest_node_id); - if (dest_node->is_phantom()) { - return; - } - Node * const node_block = dest_node - (dest_node_id % BLOCK_SIZE); - uint8_t * const sibling_block = - &siblings_->get_value(dest_node_id & ~(BLOCK_SIZE - 1)); - uint64_t labels[MAX_LABEL + 1]; - uint64_t num_labels = 0; - uint64_t child_label = node->child(); - while (child_label != INVALID_LABEL) { - labels[num_labels++] = child_label; - const uint64_t child_node_id = offset ^ child_label; - if (node_block[child_node_id % BLOCK_SIZE].has_sibling()) { - child_label = sibling_block[child_node_id % BLOCK_SIZE]; - } else { - child_label = INVALID_LABEL; - } - } - labels[num_labels] = label; - offset = find_offset(labels, num_labels + 1); - migrate_nodes(node, offset, labels, num_labels); -} - -void DoubleArrayImpl::migrate_nodes(Node *node, uint64_t dest_offset, - const uint64_t *labels, - uint64_t num_labels) { - const uint64_t src_offset = node->offset(); - Node * const src_node_block = - &nodes_->get_value(src_offset & ~(BLOCK_SIZE - 1)); - uint8_t * const src_sibling_block = - &siblings_->get_value(src_offset & ~(BLOCK_SIZE - 1)); - Node * const dest_node_block = - &nodes_->get_value(dest_offset & ~(BLOCK_SIZE - 1)); - uint8_t * const dest_sibling_block = - &siblings_->get_value(dest_offset & ~(BLOCK_SIZE - 1)); - for (uint64_t i = 0; i < num_labels; ++i) { - const uint64_t src_node_id = src_offset ^ labels[i]; - Node * const src_node = &src_node_block[src_node_id % BLOCK_SIZE]; - uint8_t * const src_sibling = &src_sibling_block[src_node_id % BLOCK_SIZE]; - const uint64_t dest_node_id = dest_offset ^ labels[i]; - Node * const dest_node = reserve_node(dest_node_id); - uint8_t * const dest_sibling = - &dest_sibling_block[dest_node_id % BLOCK_SIZE]; - Node dummy_node = *src_node; - dummy_node.set_is_origin(dest_node->is_origin()); - *dest_node = dummy_node; - *dest_sibling = *src_sibling; - } - header_->num_zombies += num_labels; - dest_node_block[dest_offset % BLOCK_SIZE].set_is_origin(true); - node->set_offset(dest_offset); -} - -uint64_t DoubleArrayImpl::find_offset(const uint64_t *labels, - uint64_t num_labels) { - // Blocks are tested in descending order of level. - // Generally, a lower level contains more phantom nodes. - uint64_t level = bit_scan_reverse(num_labels) + 1; - level = (level < BLOCK_MAX_LEVEL) ? (BLOCK_MAX_LEVEL - level) : 0; - uint64_t block_count = 0; - do { - uint64_t latest_block_id = header_->latest_blocks[level]; - if (latest_block_id == BLOCK_INVALID_ID) { - // This level group is skipped because it is empty. - continue; - } - uint64_t block_id = latest_block_id; - do { - Block * const block = &blocks_->get_value(block_id); - Node * const node_block = &nodes_->get_value(block_id * BLOCK_SIZE); - const uint64_t first_phantom_node_id = block->first_phantom(); - uint64_t node_id = first_phantom_node_id; - do { - const uint64_t offset = node_id ^ labels[0]; - if (!node_block[offset].is_origin()) { - uint64_t i; - for (i = 1; i < num_labels; ++i) { - if (!node_block[offset ^ labels[i]].is_phantom()) { - break; - } - } - if (i >= num_labels) { - // Found. - return (block_id * BLOCK_SIZE) | offset; - } - } - node_id = node_block[node_id].next(); - } while (node_id != first_phantom_node_id); - - Block * const prev_block = block; - const uint64_t prev_block_id = block_id; - const uint64_t next_block_id = block->next(); - block_id = next_block_id; - - // A block level is updated if this function fails many times. - prev_block->set_failure_count(prev_block->failure_count() + 1); - if (prev_block->failure_count() >= BLOCK_MAX_FAILURE_COUNT) { - update_block_level(prev_block_id, prev_block, level + 1); - if (next_block_id == latest_block_id) { - // All the blocks are tested. - break; - } else { - latest_block_id = header_->latest_blocks[level]; - continue; - } - } - } while ((++block_count < BLOCK_MAX_COUNT) && - (block_id != latest_block_id)); - } while ((block_count < BLOCK_MAX_COUNT) && (level-- != 0)); - // Use a new block. - return (header_->num_blocks * BLOCK_SIZE) ^ labels[0]; -} - -Node *DoubleArrayImpl::reserve_node(uint64_t node_id) { - const uint64_t block_id = node_id / BLOCK_SIZE; - Block *block; - if (node_id >= (header_->num_blocks * BLOCK_SIZE)) { - block = reserve_block(block_id); - } else { - block = &blocks_->get_value(block_id); - } - Node * const node = &nodes_->get_value(node_id); - Node * const node_block = node - (node_id % BLOCK_SIZE); - Node * const next_node = &node_block[node->next()]; - Node * const prev_node = &node_block[node->prev()]; - if ((node_id % BLOCK_SIZE) == block->first_phantom()) { - block->set_first_phantom(node->next()); - } - prev_node->set_next(node->next()); - next_node->set_prev(node->prev()); - if (block->level() != BLOCK_MAX_LEVEL) { - const uint64_t threshold = - 1ULL << ((BLOCK_MAX_LEVEL - block->level() - 1) * 2); - if (block->num_phantoms() == threshold) { - update_block_level(block_id, block, block->level() + 1); - } - } - block->set_num_phantoms(block->num_phantoms() - 1); - node->unset_is_phantom(); - --header_->num_phantoms; - return node; -} - -Block *DoubleArrayImpl::reserve_block(uint64_t block_id) { - if (block_id >= blocks_->size()) { - GRNXX_ERROR() << "too many blocks: block_id = " << block_id - << ", max_block_id = " << (blocks_->size() - 1); - throw LogicError(); - } - Block * const block = &blocks_->get_value(block_id); - Node * const node = &nodes_->get_value(block_id * BLOCK_SIZE); - *block = Block::empty_block(); - for (uint64_t i = 0; i < BLOCK_SIZE; ++i) { - node[i] = Node::phantom_node(i + 1, i - 1); - } - // The level of a new block is 0. - set_block_level(block_id, block, 0); - header_->num_blocks = block_id + 1; - header_->num_phantoms += BLOCK_SIZE; - return block; -} - -void DoubleArrayImpl::update_block_level(uint64_t block_id, Block *block, - uint64_t level) { - // FIXME: If set_block_level() fails, the block gets lost. - unset_block_level(block_id, block); - set_block_level(block_id, block, level); -} - -void DoubleArrayImpl::set_block_level(uint64_t block_id, Block *block, - uint64_t level) { - if (header_->latest_blocks[level] == BLOCK_INVALID_ID) { - // The block becomes the only one member of the level group. - block->set_next(block_id); - block->set_prev(block_id); - header_->latest_blocks[level] = block_id; - } else { - // The block is appended to the level group. - const uint64_t next_block_id = header_->latest_blocks[level]; - Block * const next_block = &blocks_->get_value(next_block_id); - const uint64_t prev_block_id = next_block->prev(); - Block * const prev_block = &blocks_->get_value(prev_block_id); - block->set_next(next_block_id); - block->set_prev(prev_block_id); - prev_block->set_next(block_id); - next_block->set_prev(block_id); - } - block->set_level(level); - block->set_failure_count(0); -} - -void DoubleArrayImpl::unset_block_level(uint64_t block_id, Block *block) { - const uint64_t level = block->level(); - const uint64_t next_block_id = block->next(); - const uint64_t prev_block_id = block->prev(); - if (next_block_id == prev_block_id) { - // The level group becomes empty. - header_->latest_blocks[level] = BLOCK_INVALID_ID; - } else { - Block * const next_block = &blocks_->get_value(next_block_id); - Block * const prev_block = &blocks_->get_value(prev_block_id); - prev_block->set_next(next_block_id); - next_block->set_prev(prev_block_id); - if (block_id == header_->latest_blocks[level]) { - // The next block becomes the latest block of the level group. - header_->latest_blocks[level] = next_block_id; - } - } -} - -struct DoubleArrayHeader { - CommonHeader common_header; - uint64_t pool_id; - uint64_t impl_id; - uint32_t pool_storage_node_id; - uint32_t impl_storage_node_id; - Mutex mutex; - - // Initialize the member variables. - DoubleArrayHeader(); - - // Return true iff the header seems to be correct. - explicit operator bool() const; -}; - -DoubleArrayHeader::DoubleArrayHeader() - : common_header(FORMAT_STRING, MAP_DOUBLE_ARRAY), - pool_id(0), - impl_id(0), - pool_storage_node_id(STORAGE_INVALID_NODE_ID), - impl_storage_node_id(STORAGE_INVALID_NODE_ID), - mutex() {} - -DoubleArrayHeader::operator bool() const { - return common_header.format() == FORMAT_STRING; -} - -template <typename T> -Map<T> *DoubleArray<T>::create(Storage *, uint32_t, const MapOptions &) { - GRNXX_ERROR() << "unsupported type"; - throw LogicError(); -} - -template <typename T> -Map<T> *DoubleArray<T>::open(Storage *, uint32_t) { - GRNXX_ERROR() << "unsupported type"; - throw LogicError(); -} - -template class DoubleArray<int8_t>; -template class DoubleArray<uint8_t>; -template class DoubleArray<int16_t>; -template class DoubleArray<uint16_t>; -template class DoubleArray<int32_t>; -template class DoubleArray<uint32_t>; -template class DoubleArray<int64_t>; -template class DoubleArray<uint64_t>; -template class DoubleArray<double>; -template class DoubleArray<GeoPoint>; - -DoubleArray<Bytes>::DoubleArray() - : storage_(nullptr), - storage_node_id_(STORAGE_INVALID_NODE_ID), - header_(nullptr), - pool_(), - impl_(), - queue_(), - pool_id_(0), - impl_id_(0), - clock_() {} - -DoubleArray<Bytes>::~DoubleArray() {} - -DoubleArray<Bytes> *DoubleArray<Bytes>::create(Storage *storage, - uint32_t storage_node_id, - const MapOptions &options) { - std::unique_ptr<DoubleArray> map(new (std::nothrow) DoubleArray); - if (!map) { - GRNXX_ERROR() << "new grnxx::map::DoubleArray failed"; - throw MemoryError(); - } - map->create_map(storage, storage_node_id, options); - return map.release(); -} - -DoubleArray<Bytes> *DoubleArray<Bytes>::open(Storage *storage, - uint32_t storage_node_id) { - std::unique_ptr<DoubleArray> map(new (std::nothrow) DoubleArray); - if (!map) { - GRNXX_ERROR() << "new grnxx::map::DoubleArray failed"; - throw MemoryError(); - } - map->open_map(storage, storage_node_id); - return map.release(); -} - -uint32_t DoubleArray<Bytes>::storage_node_id() const { - return storage_node_id_; -} - -MapType DoubleArray<Bytes>::type() const { - return MAP_DOUBLE_ARRAY; -} - -int64_t DoubleArray<Bytes>::max_key_id() { - refresh_if_possible(); - return impl_->max_key_id(); -} - -uint64_t DoubleArray<Bytes>::num_keys() { - refresh_if_possible(); - return impl_->num_keys(); -} - -bool DoubleArray<Bytes>::get(int64_t key_id, Key *key) { - refresh_if_possible(); - return impl_->get(key_id, key); -} - -bool DoubleArray<Bytes>::unset(int64_t key_id) { - refresh_if_possible(); - return impl_->unset(key_id); -} - -bool DoubleArray<Bytes>::reset(int64_t key_id, KeyArg dest_key) { - refresh_if_possible(); - return impl_->reset(key_id, dest_key); -} - -bool DoubleArray<Bytes>::find(KeyArg key, int64_t *key_id) { - refresh_if_possible(); - return impl_->find(key, key_id); -} - -bool DoubleArray<Bytes>::add(KeyArg key, int64_t *key_id) { - refresh_if_possible(); - return impl_->add(key, key_id); -} - -bool DoubleArray<Bytes>::remove(KeyArg key) { - refresh_if_possible(); - return impl_->remove(key); -} - -bool DoubleArray<Bytes>::replace(KeyArg src_key, KeyArg dest_key, - int64_t *key_id) { - refresh_if_possible(); - return impl_->replace(src_key, dest_key, key_id); -} - -void DoubleArray<Bytes>::defrag() { - refresh_if_possible(); - if (max_key_id() < MAP_MIN_KEY_ID) { - // Nothing to do. - return; - } - pool_->defrag(); - std::unique_ptr<Impl> new_impl( - Impl::create(storage_, storage_node_id_, impl_.get())); - { - // Validate a new impl. - Lock lock(&header_->mutex); - header_->impl_storage_node_id = new_impl->storage_node_id(); - ++header_->impl_id; - impl_.swap(new_impl); - impl_id_ = header_->impl_id; - } - Impl::unlink(storage_, new_impl->storage_node_id()); - try { - queue_.push(QueueEntry{ nullptr, std::move(new_impl), clock_.now() }); - } catch (const std::exception &exception) { - GRNXX_ERROR() << "std::queue::push() failed"; - throw StandardError(exception); - } -} - -void DoubleArray<Bytes>::sweep(Duration lifetime) { - const Time threshold = clock_.now() - lifetime; - while (!queue_.empty()) { - QueueEntry &queue_entry = queue_.front(); - if (queue_entry.time <= threshold) { - queue_.pop(); - } - } -} - -void DoubleArray<Bytes>::truncate() { - refresh_if_possible(); - if (max_key_id() < MAP_MIN_KEY_ID) { - // Nothing to do. - return; - } - std::unique_ptr<Pool> new_pool(Pool::create(storage_, storage_node_id_)); - std::unique_ptr<Impl> new_impl; - try { - new_impl.reset(Impl::create(storage_, storage_node_id_, new_pool.get())); - } catch (...) { - Pool::unlink(storage_, new_pool->storage_node_id()); - throw; - } - { - // Validate a new impl and a new pool. - Lock lock(&header_->mutex); - header_->pool_storage_node_id = new_pool->storage_node_id(); - header_->impl_storage_node_id = new_impl->storage_node_id(); - ++header_->pool_id; - ++header_->impl_id; - pool_.swap(new_pool); - impl_.swap(new_impl); - pool_id_ = header_->pool_id; - impl_id_ = header_->impl_id; - } - Pool::unlink(storage_, new_pool->storage_node_id()); - Impl::unlink(storage_, new_impl->storage_node_id()); - try { - queue_.push(QueueEntry{ std::move(new_pool), std::move(new_impl), - clock_.now() }); - } catch (const std::exception &exception) { - GRNXX_ERROR() << "std::queue::push() failed"; - throw StandardError(exception); - } -} - -bool DoubleArray<Bytes>::find_longest_prefix_match(KeyArg query, - int64_t *key_id, - Key *key) { - refresh_if_possible(); - return impl_->find_longest_prefix_match(query, key_id, key); -} - -//MapCursor<Bytes> *DoubleArray<Bytes>::create_cursor( -// MapCursorAllKeys<Bytes> query, const MapCursorOptions &options) { -// // TODO -// return nullptr; -//} - -//MapCursor<Bytes> *DoubleArray<Bytes>::create_cursor( -// const MapCursorKeyIDRange<Bytes> &query, const MapCursorOptions &options) { -// // TODO -// return nullptr; -//} - -//MapCursor<Bytes> *DoubleArray<Bytes>::create_cursor( -// const MapCursorKeyRange<Bytes> &query, const MapCursorOptions &options) { -// // TODO -// return nullptr; -//} - -void DoubleArray<Bytes>::create_map(Storage *storage, uint32_t storage_node_id, - const MapOptions &) { - storage_ = storage; - StorageNode header_node = - storage->create_node(storage_node_id, sizeof(Header)); - storage_node_id_ = header_node.id(); - try { - header_ = static_cast<Header *>(header_node.body()); - *header_ = Header(); - pool_.reset(Pool::create(storage, storage_node_id_)); - impl_.reset(Impl::create(storage, storage_node_id_, pool_.get())); - header_->pool_storage_node_id = pool_->storage_node_id(); - header_->impl_storage_node_id = impl_->storage_node_id(); - pool_id_ = ++header_->pool_id; - impl_id_ = ++header_->impl_id; - } catch (...) { - storage->unlink_node(storage_node_id_); - throw; - } -} - -void DoubleArray<Bytes>::open_map(Storage *storage, uint32_t storage_node_id) { - storage_ = storage; - storage_node_id_ = storage_node_id; - StorageNode header_node = storage->open_node(storage_node_id_); - if (header_node.size() < sizeof(Header)) { - GRNXX_ERROR() << "invalid format: size = " << header_node.size() - << ", header_size = " << sizeof(Header); - throw LogicError(); - } - header_ = static_cast<Header *>(header_node.body()); - if (!*header_) { - GRNXX_ERROR() << "wrong format: expected = " << FORMAT_STRING - << ", actual = " << header_->common_header.format(); - throw LogicError(); - } -} - -void DoubleArray<Bytes>::refresh_if_possible() { - if (impl_id_ != header_->impl_id) { - refresh(); - } -} - -void DoubleArray<Bytes>::refresh() { - Lock lock(&header_->mutex); - if (pool_id_ != header_->pool_id) { - refresh_pool(); - } - if (impl_id_ != header_->impl_id) { - refresh_impl(); - } -} - -void DoubleArray<Bytes>::refresh_pool() { - std::unique_ptr<Pool> new_pool( - Pool::open(storage_, header_->pool_storage_node_id)); - pool_.swap(new_pool); - pool_id_ = header_->pool_id; - try { - queue_.push(QueueEntry{ std::move(new_pool), nullptr, clock_.now() }); - } catch (const std::exception &exception) { - GRNXX_ERROR() << "std::queue::push() failed"; - throw StandardError(exception); - } -} - -void DoubleArray<Bytes>::refresh_impl() { - std::unique_ptr<Impl> new_impl( - Impl::open(storage_, header_->impl_storage_node_id, pool_.get())); - impl_.swap(new_impl); - impl_id_ = header_->impl_id; - try { - queue_.push(QueueEntry{ nullptr, std::move(new_impl), clock_.now() }); - } catch (const std::exception &exception) { - GRNXX_ERROR() << "std::queue::push() failed"; - throw StandardError(exception); - } -} - -} // namespace map -} // namespace grnxx Deleted: lib/grnxx/map/double_array.hpp (+0 -137) 100644 =================================================================== --- lib/grnxx/map/double_array.hpp 2013-08-23 10:46:34 +0900 (3fb028e) +++ /dev/null @@ -1,137 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_MAP_DOUBLE_ARRAY_HPP -#define GRNXX_MAP_DOUBLE_ARRAY_HPP - -#include "grnxx/features.hpp" - -#include <memory> -#include <queue> - -#include "grnxx/bytes.hpp" -#include "grnxx/duration.hpp" -#include "grnxx/map.hpp" -#include "grnxx/map_cursor.hpp" -#include "grnxx/map_cursor_query.hpp" -#include "grnxx/periodic_clock.hpp" -#include "grnxx/time.hpp" -#include "grnxx/types.hpp" - -namespace grnxx { - -class Storage; - -namespace map { - -template <typename T> class Pool; - -class DoubleArrayImpl; - -struct DoubleArrayHeader; - -template <typename T> -class DoubleArray { - public: - static Map<T> *create(Storage *storage, uint32_t storage_node_id, - const MapOptions &options = MapOptions()); - static Map<T> *open(Storage *storage, uint32_t storage_node_id); -}; - -template <> -class DoubleArray<Bytes> : public Map<Bytes> { - using Header = DoubleArrayHeader; - using Impl = DoubleArrayImpl; - using Pool = map::Pool<Bytes>; - - struct QueueEntry { - std::unique_ptr<Pool> pool; - std::unique_ptr<Impl> impl; - Time time; - }; - - public: - using Key = typename Map<Bytes>::Key; - using KeyArg = typename Map<Bytes>::KeyArg; - using Cursor = typename Map<Bytes>::Cursor; - - DoubleArray(); - ~DoubleArray(); - - static DoubleArray *create(Storage *storage, uint32_t storage_node_id, - const MapOptions &options = MapOptions()); - static DoubleArray *open(Storage *storage, uint32_t storage_node_id); - - uint32_t storage_node_id() const; - MapType type() const; - - int64_t max_key_id(); - uint64_t num_keys(); - - bool get(int64_t key_id, Key *key = nullptr); - bool unset(int64_t key_id); - bool reset(int64_t key_id, KeyArg dest_key); - - bool find(KeyArg key, int64_t *key_id = nullptr); - bool add(KeyArg key, int64_t *key_id = nullptr); - bool remove(KeyArg key); - bool replace(KeyArg src_key, KeyArg dest_key, int64_t *key_id = nullptr); - - void defrag(); - void sweep(Duration lifetime); - - void truncate(); - - bool find_longest_prefix_match(KeyArg query, - int64_t *key_id = nullptr, - Key *key = nullptr); - -// Cursor *create_cursor( -// MapCursorAllKeys<Bytes> query, -// const MapCursorOptions &options = MapCursorOptions()); -// Cursor *create_cursor( -// const MapCursorKeyIDRange<Bytes> &query, -// const MapCursorOptions &options = MapCursorOptions()); -// Cursor *create_cursor( -// const MapCursorKeyRange<Bytes> &query, -// const MapCursorOptions &options = MapCursorOptions()); - - private: - Storage *storage_; - uint32_t storage_node_id_; - Header *header_; - std::unique_ptr<Pool> pool_; - std::unique_ptr<Impl> impl_; - std::queue<QueueEntry> queue_; - uint64_t pool_id_; - uint64_t impl_id_; - PeriodicClock clock_; - - void create_map(Storage *storage, uint32_t storage_node_id, - const MapOptions &options); - void open_map(Storage *storage, uint32_t storage_node_id); - - inline void refresh_if_possible(); - void refresh(); - void refresh_pool(); - void refresh_impl(); -}; - -} // namespace map -} // namespace grnxx - -#endif // GRNXX_MAP_DOUBLE_ARRAY_HPP Deleted: lib/grnxx/map/hash.hpp (+0 -133) 100644 =================================================================== --- lib/grnxx/map/hash.hpp 2013-08-23 10:46:34 +0900 (23475ff) +++ /dev/null @@ -1,133 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_MAP_HASH_HPP -#define GRNXX_MAP_HASH_HPP - -#include "grnxx/features.hpp" - -#include "grnxx/bytes.hpp" -#include "grnxx/geo_point.hpp" -#include "grnxx/traits.hpp" -#include "grnxx/types.hpp" - -namespace grnxx { -namespace map { - -// Calculate a hash value. -template <typename T> -struct Hash; - -// Use Murmur3's 64-bit finalizer for integers. -template <> -struct Hash<uint64_t> { - uint64_t operator()(uint64_t key) const { - uint64_t hash = key; - hash ^= hash >> 33; - hash *= 0xFF51AFD7ED558CCDULL; - hash ^= hash >> 33; - hash *= 0xC4CEB9FE1A85EC53ULL; - hash ^= hash >> 33; - return hash; - } -}; - -template <> -struct Hash<int64_t> { - uint64_t operator()(int64_t key) const { - return Hash<uint64_t>()(key); - } -}; - -template <> -struct Hash<uint32_t> { - uint64_t operator()(uint32_t key) const { - return Hash<uint64_t>()(key); - } -}; - -template <> -struct Hash<int32_t> { - uint64_t operator()(int32_t key) const { - return Hash<uint32_t>()(key); - } -}; - -template <> -struct Hash<uint16_t> { - uint64_t operator()(uint16_t key) const { - return Hash<uint64_t>()(key); - } -}; - -template <> -struct Hash<int16_t> { - uint64_t operator()(int16_t key) const { - return Hash<uint16_t>()(key); - } -}; - -template <> -struct Hash<uint8_t> { - uint64_t operator()(uint8_t key) const { - return Hash<uint64_t>()(key); - } -}; - -template <> -struct Hash<int8_t> { - uint64_t operator()(int8_t key) const { - return Hash<uint8_t>()(key); - } -}; - -// Murmur3's 64-bit finalizer. -template <> -struct Hash<double> { - using KeyArg = typename Traits<double>::ArgumentType; - uint64_t operator()(KeyArg key) const { - return Hash<uint64_t>()(reinterpret_cast<const uint64_t &>(key)); - } -}; - -// Murmur3's 64-bit finalizer. -template <> -struct Hash<GeoPoint> { - using KeyArg = typename Traits<GeoPoint>::ArgumentType; - uint64_t operator()(KeyArg key) const { - return Hash<uint64_t>()(key.value()); - } -}; - -// 64-bit FNV-1a. -template <> -struct Hash<Bytes> { - using KeyArg = typename Traits<Bytes>::ArgumentType; - uint64_t operator()(KeyArg key) const { - uint64_t hash = 0xCBF29CE484222325ULL; - for (uint64_t i = 0; i < key.size(); ++i) { - hash ^= key[i]; - hash *= 0x100000001B3ULL; - } - return hash; - } -}; - -} // namespace map -} // namespace grnxx - -#endif // GRNXX_MAP_HASH_HPP Deleted: lib/grnxx/map/hash_table.cpp (+0 -847) 100644 =================================================================== --- lib/grnxx/map/hash_table.cpp 2013-08-23 10:46:34 +0900 (7d236e7) +++ /dev/null @@ -1,847 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/map/hash_table.hpp" - -#include <new> - -#include "grnxx/bytes.hpp" -#include "grnxx/exception.hpp" -#include "grnxx/geo_point.hpp" -#include "grnxx/intrinsic.hpp" -#include "grnxx/lock.hpp" -#include "grnxx/logger.hpp" -#include "grnxx/map/common_header.hpp" -#include "grnxx/map/hash.hpp" -#include "grnxx/map/helper.hpp" -#include "grnxx/map/pool.hpp" -#include "grnxx/mutex.hpp" -#include "grnxx/storage.hpp" - -namespace grnxx { -namespace map { -namespace { - -constexpr char FORMAT_STRING[] = "grnxx::map::HashTable"; - -constexpr uint64_t MIN_TABLE_SIZE = 64; -constexpr uint64_t MAX_TABLE_SIZE = 1ULL << 41; - -struct ImplHeader { - uint64_t num_entries; - uint64_t table_size; - uint32_t table_storage_node_id; - - ImplHeader(); -}; - -ImplHeader::ImplHeader() - : num_entries(0), - table_size(0), - table_storage_node_id(STORAGE_INVALID_NODE_ID) {} - -class TableEntry { - static constexpr uint64_t IS_UNUSED_FLAG = 1ULL << 40; - static constexpr uint64_t IS_REMOVED_FLAG = 1ULL << 41; - static constexpr uint8_t MEMO_SHIFT = 42; - static constexpr uint64_t KEY_ID_MASK = (1ULL << 40) - 1; - - public: - // Create an unused entry. - static TableEntry unused_entry() { - return TableEntry(IS_UNUSED_FLAG); - } - - // Return true iff this entry is not used. - bool is_unused() const { - return value_ & IS_UNUSED_FLAG; - } - // Return true iff this entry is removed. - bool is_removed() const { - return value_ & IS_REMOVED_FLAG; - } - // Return true iff this entry and "hash_value" have the same memo. - bool test_hash_value(uint64_t hash_value) const { - return ((value_ ^ hash_value) >> MEMO_SHIFT) == 0; - } - // Return a stored key ID. - int64_t key_id() const { - return value_ & KEY_ID_MASK; - } - - // Set a key ID and a memo, which is extracted from "hash_value". - void set(int64_t key_id, uint64_t hash_value) { - value_ = key_id | (hash_value & (~0ULL << MEMO_SHIFT)); - } - // Remove this entry. - void remove() { - value_ |= IS_REMOVED_FLAG; - } - - private: - uint64_t value_; - - explicit TableEntry(uint64_t value) : value_(value) {} -}; - -struct TableSizeError {}; - -} // namespace - -template <typename T> -class HashTableImpl { - using Header = ImplHeader; - using Pool = map::Pool<T>; - - public: - using Key = typename Map<T>::Key; - using KeyArg = typename Map<T>::KeyArg; - using Cursor = typename Map<T>::Cursor; - - HashTableImpl(); - ~HashTableImpl(); - - static HashTableImpl *create(Storage *storage, uint32_t storage_node_id, - Pool *pool); - static HashTableImpl *open(Storage *storage, uint32_t storage_node_id, - Pool *pool); - - static void unlink(Storage *storage, uint32_t storage_node_id) { - storage->unlink_node(storage_node_id); - } - - uint32_t storage_node_id() const { - return storage_node_id_; - } - - int64_t max_key_id() { - return pool_->max_key_id(); - } - uint64_t num_keys() { - return pool_->num_keys(); - } - - bool get(int64_t key_id, Key *key = nullptr); - bool unset(int64_t key_id); - bool reset(int64_t key_id, KeyArg dest_key); - - bool find(KeyArg key, int64_t *key_id = nullptr); - bool add(KeyArg key, int64_t *key_id = nullptr); - bool remove(KeyArg key); - bool replace(KeyArg src_key, KeyArg dest_key, int64_t *key_id = nullptr); - - void defrag(); - - void truncate(); - - private: - Storage *storage_; - uint32_t storage_node_id_; - Header *header_; - Pool *pool_; - TableEntry *table_; - uint64_t id_mask_; - - void create_impl(Storage *storage, uint32_t storage_node_id, Pool *pool); - void open_impl(Storage *storage, uint32_t storage_node_id, Pool *pool); - - // Search a hash table for a key ID. - // On success, return a pointer to a matched entry. - // On failure, return nullptr. - TableEntry *find_key_id(int64_t key_id); - // Search a hash table for a key. - // On success, assign a pointer to a matched entry to "*entry" and return - // true. - // On failure, assign a pointer to the first unused or removed entry to - // "*entry" and return false. - bool find_key(KeyArg key, uint64_t hash_value, TableEntry **entry); - - // Build a hash table. - void build_table(); - - // Move to the next entry. - uint64_t rehash(uint64_t hash) const { - return hash + 1; - } - - // Return the table size threshold. - uint64_t table_size_threshold() const { - return ((header_->table_size + (header_->table_size / 4)) / 2); - } -}; - -template <typename T> -HashTableImpl<T>::HashTableImpl() - : storage_(nullptr), - storage_node_id_(STORAGE_INVALID_NODE_ID), - header_(nullptr), - pool_(nullptr), - table_(nullptr), - id_mask_(0) {} - -template <typename T> -HashTableImpl<T>::~HashTableImpl() {} - -template <typename T> -HashTableImpl<T> *HashTableImpl<T>::create(Storage *storage, - uint32_t storage_node_id, - Pool *pool) { - std::unique_ptr<HashTableImpl> map(new (std::nothrow) HashTableImpl); - if (!map) { - GRNXX_ERROR() << "new grnxx::map::HashTable failed"; - throw MemoryError(); - } - map->create_impl(storage, storage_node_id, pool); - return map.release(); -} - -template <typename T> -HashTableImpl<T> *HashTableImpl<T>::open(Storage *storage, - uint32_t storage_node_id, - Pool *pool) { - std::unique_ptr<HashTableImpl> map(new (std::nothrow) HashTableImpl); - if (!map) { - GRNXX_ERROR() << "new grnxx::map::HashTable failed"; - throw MemoryError(); - } - map->open_impl(storage, storage_node_id, pool); - return map.release(); -} - -template <typename T> -bool HashTableImpl<T>::get(int64_t key_id, Key *key) { - if ((key_id < MAP_MIN_KEY_ID) || (key_id > max_key_id())) { - // Out of range. - return false; - } - if (key) { - return pool_->get(key_id, key); - } - return pool_->get_bit(key_id); -} - -template <typename T> -bool HashTableImpl<T>::unset(int64_t key_id) { - if ((key_id < MAP_MIN_KEY_ID) || (key_id > max_key_id())) { - // Out of range. - return false; - } - TableEntry * const entry = find_key_id(key_id); - if (!entry) { - // Not found. - return false; - } - pool_->unset(key_id); - entry->remove(); - return true; -} - -template <typename T> -bool HashTableImpl<T>::reset(int64_t key_id, KeyArg dest_key) { - if ((key_id < MAP_MIN_KEY_ID) || (key_id > max_key_id())) { - // Out of range. - return false; - } - TableEntry * const src_entry = find_key_id(key_id); - if (!src_entry) { - // Not found. - return false; - } - const Key dest_normalized_key = Helper<T>::normalize(dest_key); - const uint64_t dest_hash_value = Hash<T>()(dest_normalized_key); - TableEntry *dest_entry; - if (find_key(dest_normalized_key, dest_hash_value, &dest_entry)) { - // Found. - return false; - } - // Throw an exception if the filling rate of the current table is greater - // than 62.5%. - if (header_->num_entries > table_size_threshold()) { - throw TableSizeError(); - } - pool_->reset(key_id, dest_normalized_key); - if (dest_entry->is_unused()) { - ++header_->num_entries; - } - dest_entry->set(key_id, dest_hash_value); - src_entry->remove(); - return true; -} - -template <typename T> -bool HashTableImpl<T>::find(KeyArg key, int64_t *key_id) { - const Key normalized_key = Helper<T>::normalize(key); - const uint64_t hash_value = Hash<T>()(normalized_key); - for (uint64_t id = hash_value; ; ) { - const TableEntry entry = table_[id & id_mask_]; - if (entry.is_unused()) { - // Not found. - return false; - } else if (!entry.is_removed()) { - if (entry.test_hash_value(hash_value)) { - Key stored_key = pool_->get_key(entry.key_id()); - if (Helper<T>::equal_to(stored_key, normalized_key)) { - // Found. - if (key_id) { - *key_id = entry.key_id(); - } - return true; - } - } - } - id = rehash(id); - if (((id ^ hash_value) & id_mask_) == 0) { - // Critical error. - GRNXX_ERROR() << "endless loop"; - throw LogicError(); - } - } -} - -template <typename T> -bool HashTableImpl<T>::add(KeyArg key, int64_t *key_id) { - // Throw an exception if the filling rate of the current table is greater - // than 62.5%. - if (header_->num_entries > table_size_threshold()) { - throw TableSizeError(); - } - const Key normalized_key = Helper<T>::normalize(key); - const uint64_t hash_value = Hash<T>()(normalized_key); - TableEntry *entry; - if (find_key(normalized_key, hash_value, &entry)) { - // Found. - if (key_id) { - *key_id = entry->key_id(); - } - return false; - } - int64_t next_key_id = pool_->add(normalized_key); - if (entry->is_unused()) { - ++header_->num_entries; - } - entry->set(next_key_id, hash_value); - if (key_id) { - *key_id = next_key_id; - } - return true; -} - -template <typename T> -bool HashTableImpl<T>::remove(KeyArg key) { - const Key normalized_key = Helper<T>::normalize(key); - const uint64_t hash_value = Hash<T>()(normalized_key); - TableEntry *entry; - if (!find_key(normalized_key, hash_value, &entry)) { - // Not found. - return false; - } - pool_->unset(entry->key_id()); - entry->remove(); - return true; -} - -template <typename T> -bool HashTableImpl<T>::replace(KeyArg src_key, KeyArg dest_key, - int64_t *key_id) { - const Key src_normalized_key = Helper<T>::normalize(src_key); - const uint64_t src_hash_value = Hash<T>()(src_normalized_key); - TableEntry *src_entry; - if (!find_key(src_normalized_key, src_hash_value, &src_entry)) { - // Not found. - return false; - } - const Key dest_normalized_key = Helper<T>::normalize(dest_key); - const uint64_t dest_hash_value = Hash<T>()(dest_normalized_key); - TableEntry *dest_entry; - if (find_key(dest_normalized_key, dest_hash_value, &dest_entry)) { - // Found. - return false; - } - // Throw an exception if the filling rate of the current table is greater - // than 62.5%. - if (header_->num_entries > table_size_threshold()) { - throw TableSizeError(); - } - pool_->reset(src_entry->key_id(), dest_normalized_key); - if (dest_entry->is_unused()) { - ++header_->num_entries; - } - dest_entry->set(src_entry->key_id(), dest_hash_value); - src_entry->remove(); - if (key_id) { - *key_id = dest_entry->key_id(); - } - return true; -} - -template <typename T> -void HashTableImpl<T>::create_impl(Storage *storage, uint32_t storage_node_id, - Pool *pool) { - storage_ = storage; - StorageNode header_node = - storage->create_node(storage_node_id, sizeof(Header)); - storage_node_id_ = header_node.id(); - try { - header_ = static_cast<Header *>(header_node.body()); - *header_ = Header(); - pool_ = pool; - build_table(); - } catch (...) { - storage->unlink_node(storage_node_id_); - throw; - } -} - -template <typename T> -void HashTableImpl<T>::open_impl(Storage *storage, uint32_t storage_node_id, - Pool *pool) { - storage_ = storage; - StorageNode header_node = storage->open_node(storage_node_id); - if (header_node.size() < sizeof(Header)) { - GRNXX_ERROR() << "invalid format: size = " << header_node.size() - << ", header_size = " << sizeof(Header); - throw LogicError(); - } - storage_node_id_ = storage_node_id; - header_ = static_cast<Header *>(header_node.body()); - pool_ = pool; - StorageNode table_node = storage->open_node(header_->table_storage_node_id); - table_ = static_cast<TableEntry *>(table_node.body()); - id_mask_ = header_->table_size - 1; -} - -template <typename T> -TableEntry *HashTableImpl<T>::find_key_id(int64_t key_id) { - Key stored_key; - if (!pool_->get(key_id, &stored_key)) { - // Not found. - return nullptr; - } - const uint64_t hash_value = Hash<T>()(stored_key); - for (uint64_t id = hash_value; ; ) { - TableEntry &entry = table_[id & id_mask_]; - if (entry.key_id() == key_id) { - // Found. - return &entry; - } - id = rehash(id); - if (((id ^ hash_value) & id_mask_) == 0) { - // Critical error. - GRNXX_ERROR() << "endless loop"; - throw LogicError(); - } - } -} - -template <typename T> -bool HashTableImpl<T>::find_key(KeyArg key, uint64_t hash_value, - TableEntry **entry) { - *entry = nullptr; - for (uint64_t id = hash_value; ; ) { - TableEntry &this_entry = table_[id & id_mask_]; - if (this_entry.is_unused()) { - // Not found. - if (!*entry) { - *entry = &this_entry; - } - return false; - } else if (this_entry.is_removed()) { - // Save the first removed entry. - if (!*entry) { - *entry = &this_entry; - } - } else if (this_entry.test_hash_value(hash_value)) { - Key stored_key = pool_->get_key(this_entry.key_id()); - if (Helper<T>::equal_to(stored_key, key)) { - // Found. - *entry = &this_entry; - return true; - } - } - id = rehash(id); - if (((id ^ hash_value) & id_mask_) == 0) { - // Critical error. - GRNXX_ERROR() << "endless loop"; - throw LogicError(); - } - } -} - -template <typename T> -void HashTableImpl<T>::build_table() { - // Create a new table. - uint64_t new_size = pool_->num_keys() * 2; - if (new_size < MIN_TABLE_SIZE) { - new_size = MIN_TABLE_SIZE; - } else if (new_size > MAX_TABLE_SIZE) { - new_size = MAX_TABLE_SIZE; - } - new_size = 2ULL << bit_scan_reverse(new_size - 1); - StorageNode table_node = - storage_->create_node(storage_node_id_, sizeof(TableEntry) * new_size); - table_ = static_cast<TableEntry *>(table_node.body()); - id_mask_ = new_size - 1; - for (uint64_t i = 0; i < new_size; ++i) { - table_[i] = TableEntry::unused_entry(); - } - // Add entries associated with keys in a pool. - const uint64_t new_id_mask = new_size - 1; - const int64_t max_key_id = pool_->max_key_id(); - for (int64_t key_id = MAP_MIN_KEY_ID; key_id <= max_key_id; ++key_id) { - Key stored_key; - if (!pool_->get(key_id, &stored_key)) { - continue; - } - const uint64_t hash_value = Hash<T>()(stored_key); - for (uint64_t id = hash_value; ; id = rehash(id)) { - TableEntry &entry = table_[id & new_id_mask]; - if (entry.is_unused()) { - entry.set(key_id, hash_value); - break; - } - } - ++header_->num_entries; - } - header_->table_size = new_size; - header_->table_storage_node_id = table_node.id(); -} - -struct HashTableHeader { - CommonHeader common_header; - uint64_t pool_id; - uint64_t impl_id; - uint32_t pool_storage_node_id; - uint32_t impl_storage_node_id; - Mutex mutex; - - // Initialize the member variables. - HashTableHeader(); - - // Return true iff the header seems to be correct. - explicit operator bool() const; -}; - -HashTableHeader::HashTableHeader() - : common_header(FORMAT_STRING, MAP_HASH_TABLE), - pool_id(0), - impl_id(0), - pool_storage_node_id(STORAGE_INVALID_NODE_ID), - impl_storage_node_id(STORAGE_INVALID_NODE_ID), - mutex() {} - -HashTableHeader::operator bool() const { - return common_header.format() == FORMAT_STRING; -} - -template <typename T> -HashTable<T>::HashTable() - : storage_(nullptr), - storage_node_id_(STORAGE_INVALID_NODE_ID), - header_(nullptr), - pool_(), - impl_(), - queue_(), - pool_id_(0), - impl_id_(0), - clock_() {} - -template <typename T> -HashTable<T>::~HashTable() {} - -template <typename T> -HashTable<T> *HashTable<T>::create(Storage *storage, uint32_t storage_node_id, - const MapOptions &options) { - std::unique_ptr<HashTable> map(new (std::nothrow) HashTable); - if (!map) { - GRNXX_ERROR() << "new grnxx::map::HashTable failed"; - throw MemoryError(); - } - map->create_map(storage, storage_node_id, options); - return map.release(); -} - -template <typename T> -HashTable<T> *HashTable<T>::open(Storage *storage, uint32_t storage_node_id) { - std::unique_ptr<HashTable> map(new (std::nothrow) HashTable); - if (!map) { - GRNXX_ERROR() << "new grnxx::map::HashTable failed"; - throw MemoryError(); - } - map->open_map(storage, storage_node_id); - return map.release(); -} - -template <typename T> -uint32_t HashTable<T>::storage_node_id() const { - return storage_node_id_; -} - -template <typename T> -MapType HashTable<T>::type() const { - return MAP_HASH_TABLE; -} - -template <typename T> -int64_t HashTable<T>::max_key_id() { - refresh_if_possible(); - return impl_->max_key_id(); -} - -template <typename T> -uint64_t HashTable<T>::num_keys() { - refresh_if_possible(); - return impl_->num_keys(); -} - -template <typename T> -bool HashTable<T>::get(int64_t key_id, Key *key) { - refresh_if_possible(); - return impl_->get(key_id, key); -} - -template <typename T> -bool HashTable<T>::unset(int64_t key_id) { - refresh_if_possible(); - return impl_->unset(key_id); -} - -template <typename T> -bool HashTable<T>::reset(int64_t key_id, KeyArg dest_key) { - refresh_if_possible(); - try { - return impl_->reset(key_id, dest_key); - } catch (TableSizeError) { - rebuild_table(); - return impl_->reset(key_id, dest_key); - } -} - -template <typename T> -bool HashTable<T>::find(KeyArg key, int64_t *key_id) { - refresh_if_possible(); - return impl_->find(key, key_id); -} - -template <typename T> -bool HashTable<T>::add(KeyArg key, int64_t *key_id) { - refresh_if_possible(); - try { - return impl_->add(key, key_id); - } catch (TableSizeError) { - rebuild_table(); - return impl_->add(key, key_id); - } -} - -template <typename T> -bool HashTable<T>::remove(KeyArg key) { - refresh_if_possible(); - return impl_->remove(key); -} - -template <typename T> -bool HashTable<T>::replace(KeyArg src_key, KeyArg dest_key, int64_t *key_id) { - refresh_if_possible(); - try { - return impl_->replace(src_key, dest_key, key_id); - } catch (TableSizeError) { - rebuild_table(); - return impl_->replace(src_key, dest_key, key_id); - } -} - -template <typename T> -void HashTable<T>::rebuild_table() { - std::unique_ptr<Impl> new_impl( - Impl::create(storage_, storage_node_id_, pool_.get())); - { - // Validate a new impl. - Lock lock(&header_->mutex); - header_->impl_storage_node_id = new_impl->storage_node_id(); - ++header_->impl_id; - impl_.swap(new_impl); - impl_id_ = header_->impl_id; - } - Impl::unlink(storage_, new_impl->storage_node_id()); - try { - queue_.push(QueueEntry{ nullptr, std::move(new_impl), clock_.now() }); - } catch (const std::exception &exception) { - GRNXX_ERROR() << "std::queue::push() failed"; - throw StandardError(exception); - } -} - -template <typename T> -void HashTable<T>::defrag() { - refresh_if_possible(); - if (max_key_id() < MAP_MIN_KEY_ID) { - // Nothing to do. - return; - } - pool_->defrag(); - rebuild_table(); -} - -template <typename T> -void HashTable<T>::sweep(Duration lifetime) { - const Time threshold = clock_.now() - lifetime; - while (!queue_.empty()) { - QueueEntry &queue_entry = queue_.front(); - if (queue_entry.time <= threshold) { - queue_.pop(); - } - } -} - -template <typename T> -void HashTable<T>::truncate() { - refresh_if_possible(); - if (max_key_id() < MAP_MIN_KEY_ID) { - // Nothing to do. - return; - } - std::unique_ptr<Pool> new_pool(Pool::create(storage_, storage_node_id_)); - std::unique_ptr<Impl> new_impl; - try { - new_impl.reset(Impl::create(storage_, storage_node_id_, new_pool.get())); - } catch (...) { - Pool::unlink(storage_, new_pool->storage_node_id()); - throw; - } - { - // Validate a new impl and a new pool. - Lock lock(&header_->mutex); - header_->pool_storage_node_id = new_pool->storage_node_id(); - header_->impl_storage_node_id = new_impl->storage_node_id(); - ++header_->pool_id; - ++header_->impl_id; - pool_.swap(new_pool); - impl_.swap(new_impl); - pool_id_ = header_->pool_id; - impl_id_ = header_->impl_id; - } - Pool::unlink(storage_, new_pool->storage_node_id()); - Impl::unlink(storage_, new_impl->storage_node_id()); - try { - queue_.push(QueueEntry{ std::move(new_pool), std::move(new_impl), - clock_.now() }); - } catch (const std::exception &exception) { - GRNXX_ERROR() << "std::queue::push() failed"; - throw StandardError(exception); - } -} - -template <typename T> -void HashTable<T>::create_map(Storage *storage, uint32_t storage_node_id, - const MapOptions &) { - storage_ = storage; - StorageNode header_node = - storage->create_node(storage_node_id, sizeof(Header)); - storage_node_id_ = header_node.id(); - try { - header_ = static_cast<Header *>(header_node.body()); - *header_ = Header(); - pool_.reset(Pool::create(storage, storage_node_id_)); - impl_.reset(Impl::create(storage, storage_node_id_, pool_.get())); - header_->pool_storage_node_id = pool_->storage_node_id(); - header_->impl_storage_node_id = impl_->storage_node_id(); - pool_id_ = ++header_->pool_id; - impl_id_ = ++header_->impl_id; - } catch (...) { - storage->unlink_node(storage_node_id_); - throw; - } -} - -template <typename T> -void HashTable<T>::open_map(Storage *storage, uint32_t storage_node_id) { - storage_ = storage; - StorageNode header_node = storage->open_node(storage_node_id); - if (header_node.size() < sizeof(Header)) { - GRNXX_ERROR() << "invalid format: size = " << header_node.size() - << ", header_size = " << sizeof(Header); - throw LogicError(); - } - storage_node_id_ = storage_node_id; - header_ = static_cast<Header *>(header_node.body()); - if (!*header_) { - GRNXX_ERROR() << "wrong format: expected = " << FORMAT_STRING - << ", actual = " << header_->common_header.format(); - throw LogicError(); - } -} - -template <typename T> -void HashTable<T>::refresh_if_possible() { - if (impl_id_ != header_->impl_id) { - refresh(); - } -} - -template <typename T> -void HashTable<T>::refresh() { - Lock lock(&header_->mutex); - if (pool_id_ != header_->pool_id) { - refresh_pool(); - } - if (impl_id_ != header_->impl_id) { - refresh_impl(); - } -} - -template <typename T> -void HashTable<T>::refresh_pool() { - std::unique_ptr<Pool> new_pool( - Pool::open(storage_, header_->pool_storage_node_id)); - pool_.swap(new_pool); - pool_id_ = header_->pool_id; - try { - queue_.push(QueueEntry{ std::move(new_pool), nullptr, clock_.now() }); - } catch (const std::exception &exception) { - GRNXX_ERROR() << "std::queue::push() failed"; - throw StandardError(exception); - } -} - -template <typename T> -void HashTable<T>::refresh_impl() { - std::unique_ptr<Impl> new_impl( - Impl::open(storage_, header_->impl_storage_node_id, pool_.get())); - impl_.swap(new_impl); - impl_id_ = header_->impl_id; - try { - queue_.push(QueueEntry{ nullptr, std::move(new_impl), clock_.now() }); - } catch (const std::exception &exception) { - GRNXX_ERROR() << "std::queue::push() failed"; - throw StandardError(exception); - } -} - -template class HashTable<int8_t>; -template class HashTable<uint8_t>; -template class HashTable<int16_t>; -template class HashTable<uint16_t>; -template class HashTable<int32_t>; -template class HashTable<uint32_t>; -template class HashTable<int64_t>; -template class HashTable<uint64_t>; -template class HashTable<double>; -template class HashTable<GeoPoint>; -template class HashTable<Bytes>; - -} // namespace map -} // namespace grnxx Deleted: lib/grnxx/map/hash_table.hpp (+0 -114) 100644 =================================================================== --- lib/grnxx/map/hash_table.hpp 2013-08-23 10:46:34 +0900 (fe51f69) +++ /dev/null @@ -1,114 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_MAP_HASH_TABLE_HPP -#define GRNXX_MAP_HASH_TABLE_HPP - -#include "grnxx/features.hpp" - -#include <memory> -#include <queue> - -#include "grnxx/duration.hpp" -#include "grnxx/map.hpp" -#include "grnxx/periodic_clock.hpp" -#include "grnxx/time.hpp" -#include "grnxx/types.hpp" - -namespace grnxx { - -class Storage; - -namespace map { - -template <typename T> class Pool; - -template <typename T> class HashTableImpl; - -struct HashTableHeader; - -template <typename T> -class HashTable : public Map<T> { - using Header = HashTableHeader; - using Pool = map::Pool<T>; - using Impl = HashTableImpl<T>; - - struct QueueEntry { - std::unique_ptr<Pool> pool; - std::unique_ptr<Impl> impl; - Time time; - }; - - public: - using Key = typename Map<T>::Key; - using KeyArg = typename Map<T>::KeyArg; - using Cursor = typename Map<T>::Cursor; - - HashTable(); - ~HashTable(); - - static HashTable *create(Storage *storage, uint32_t storage_node_id, - const MapOptions &options = MapOptions()); - static HashTable *open(Storage *storage, uint32_t storage_node_id); - - uint32_t storage_node_id() const; - MapType type() const; - - int64_t max_key_id(); - uint64_t num_keys(); - - bool get(int64_t key_id, Key *key = nullptr); - bool unset(int64_t key_id); - bool reset(int64_t key_id, KeyArg dest_key); - - bool find(KeyArg key, int64_t *key_id = nullptr); - bool add(KeyArg key, int64_t *key_id = nullptr); - bool remove(KeyArg key); - bool replace(KeyArg src_key, KeyArg dest_key, int64_t *key_id = nullptr); - - void defrag(); - void sweep(Duration lifetime); - - void truncate(); - - private: - Storage *storage_; - uint32_t storage_node_id_; - Header *header_; - std::unique_ptr<Pool> pool_; - std::unique_ptr<Impl> impl_; - std::queue<QueueEntry> queue_; - uint64_t pool_id_; - uint64_t impl_id_; - PeriodicClock clock_; - - void create_map(Storage *storage, uint32_t storage_node_id, - const MapOptions &options); - void open_map(Storage *storage, uint32_t storage_node_id); - - void rebuild_table(); - - inline void refresh_if_possible(); - void refresh(); - void refresh_pool(); - void refresh_impl(); -}; - -} // namespace map -} // namespace grnxx - -#endif // GRNXX_MAP_HASH_TABLE_HPP Deleted: lib/grnxx/map/header.hpp (+0 -33) 100644 =================================================================== --- lib/grnxx/map/header.hpp 2013-08-23 10:46:34 +0900 (375fd05) +++ /dev/null @@ -1,33 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_MAP_HEADER_HPP -#define GRNXX_MAP_HEADER_HPP - -#include "grnxx/map.hpp" - -namespace grnxx { -namespace map { - -struct Header { - MapType type; -}; - -} // namespace map -} // namespace grnxx - -#endif // GRNXX_MAP_HEADER_HPP Deleted: lib/grnxx/map/helper.hpp (+0 -106) 100644 =================================================================== --- lib/grnxx/map/helper.hpp 2013-08-23 10:46:34 +0900 (8144d4c) +++ /dev/null @@ -1,106 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_MAP_HELPER_HPP -#define GRNXX_MAP_HELPER_HPP - -#include "grnxx/features.hpp" - -#include <cmath> -#include <cstring> -#include <limits> -#include <type_traits> - -#include "grnxx/array.hpp" -#include "grnxx/bytes.hpp" -#include "grnxx/traits.hpp" - -namespace grnxx { -namespace map { - -// Normalize a key. -template <typename T, - bool IS_FLOATING_POINT = std::is_floating_point<T>::value> -struct NormalizeHelper; -// Do nothing if "T" is not a floating point type. -template <typename T> -struct NormalizeHelper<T, false> { - using Key = typename Traits<T>::Type; - using KeyArg = typename Traits<T>::ArgumentType; - - // Return "key" as is. - static Key normalize(KeyArg key) { - return key; - } -}; -// Normalize a floating point number. -template <typename T> -struct NormalizeHelper<T, true> { - using Key = typename Traits<T>::Type; - using KeyArg = typename Traits<T>::ArgumentType; - - // Return the normalized NaN iff "key" is a NaN. - // Return +0.0 iff "key" is +/-0.0. - // Return "key" as is otherwise. - static Key normalize(KeyArg key) { - return std::isnan(key) ? std::numeric_limits<Key>::quiet_NaN() : - (key != 0.0 ? key : 0.0); - } -}; - -// Compare keys. -template <typename T, - bool IS_FLOATING_POINT = std::is_floating_point<T>::value> -struct EqualToHelper; -// Compare keys with operator==() if "T" is not a floating point type. -template <typename T> -struct EqualToHelper<T, false> { - using Key = typename Traits<T>::Type; - using KeyArg = typename Traits<T>::ArgumentType; - - static bool equal_to(KeyArg lhs, KeyArg rhs) { - return lhs == rhs; - } -}; -// Compare keys as sequences of bytes. -template <typename T> -struct EqualToHelper<T, true> { - using Key = typename Traits<T>::Type; - using KeyArg = typename Traits<T>::ArgumentType; - - static bool equal_to(KeyArg lhs, KeyArg rhs) { - return std::memcmp(&lhs, &rhs, sizeof(Key)) == 0; - } -}; - -template <typename T> -struct Helper { - using Key = typename Traits<T>::Type; - using KeyArg = typename Traits<T>::ArgumentType; - - static Key normalize(KeyArg key) { - return NormalizeHelper<T>::normalize(key); - } - static bool equal_to(KeyArg lhs, KeyArg rhs) { - return EqualToHelper<T>::equal_to(lhs, rhs); - } -}; - -} // namespace map -} // namespace grnxx - -#endif // GRNXX_MAP_HELPER_HPP Deleted: lib/grnxx/map/key_pool.cpp (+0 -428) 100644 =================================================================== --- lib/grnxx/map/key_pool.cpp 2013-08-23 10:46:34 +0900 (54624ca) +++ /dev/null @@ -1,428 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/map/key_pool.hpp" - -#include "grnxx/common_header.hpp" -#include "grnxx/exception.hpp" -#include "grnxx/geo_point.hpp" -#include "grnxx/intrinsic.hpp" -#include "grnxx/logger.hpp" -#include "grnxx/map.hpp" -#include "grnxx/storage.hpp" - -namespace grnxx { -namespace map { -namespace { - -constexpr char FORMAT_STRING[] = "grnxx::map::KeyPool"; - -constexpr int64_t MIN_KEY_ID = MAP_MIN_KEY_ID; -constexpr int64_t MAX_KEY_ID = MAP_MAX_KEY_ID; - -constexpr uint64_t INVALID_UNIT_ID = ~0ULL; -constexpr uint64_t INVALID_ENTRY_ID = (1ULL << 63) - 1; - -} // namespace - -struct KeyPoolHeader { - grnxx::CommonHeader common_header; - int64_t max_key_id; - uint64_t num_keys; - // For other than Bytes. - uint64_t latest_available_unit_id; - uint32_t keys_storage_node_id; - uint32_t bits_storage_node_id; - uint32_t links_storage_node_id; - // For Bytes. - uint64_t latest_free_entry_id; - uint32_t pool_storage_node_id; - uint32_t entries_storage_node_id; - - // Initialize the member variables. - KeyPoolHeader(); - - // Return true iff the header seems to be correct. - explicit operator bool() const; -}; - -KeyPoolHeader::KeyPoolHeader() - : common_header(FORMAT_STRING), - max_key_id(MIN_KEY_ID - 1), - num_keys(0), - latest_available_unit_id(INVALID_UNIT_ID), - keys_storage_node_id(STORAGE_INVALID_NODE_ID), - bits_storage_node_id(STORAGE_INVALID_NODE_ID), - links_storage_node_id(STORAGE_INVALID_NODE_ID), - latest_free_entry_id(INVALID_ENTRY_ID), - pool_storage_node_id(STORAGE_INVALID_NODE_ID), - entries_storage_node_id(STORAGE_INVALID_NODE_ID) {} - -KeyPoolHeader::operator bool() const { - return common_header.format() == FORMAT_STRING; -} - -template <typename T> -KeyPool<T>::KeyPool() - : storage_(nullptr), - storage_node_id_(STORAGE_INVALID_NODE_ID), - header_(nullptr), - max_key_id_(nullptr), - num_keys_(nullptr), - keys_(), - bits_(), - links_() {} - -template <typename T> -KeyPool<T>::~KeyPool() {} - -template <typename T> -KeyPool<T> *KeyPool<T>::create(Storage *storage, uint32_t storage_node_id) { - if (!storage) { - GRNXX_ERROR() << "invalid argument: storage == nullptr"; - throw LogicError(); - } - std::unique_ptr<KeyPool> pool(new (std::nothrow) KeyPool); - if (!pool) { - GRNXX_ERROR() << "new grnxx::map::KeyPool failed"; - throw MemoryError(); - } - pool->create_pool(storage, storage_node_id); - return pool.release(); -} - -template <typename T> -KeyPool<T> *KeyPool<T>::open(Storage *storage, uint32_t storage_node_id) { - if (!storage) { - GRNXX_ERROR() << "invalid argument: storage == nullptr"; - throw LogicError(); - } - std::unique_ptr<KeyPool> pool(new (std::nothrow) KeyPool); - if (!pool) { - GRNXX_ERROR() << "new grnxx::map::KeyPool failed"; - throw MemoryError(); - } - pool->open_pool(storage, storage_node_id); - return pool.release(); -} - -template <typename T> -void KeyPool<T>::unset(int64_t key_id) { - // Prepare to update "bits_" and "links_". - const uint64_t unit_id = key_id / UNIT_SIZE; - const uint64_t unit_bit = 1ULL << (key_id % UNIT_SIZE); - BitArrayUnit * const unit = &bits_->get_unit(unit_id); - if ((*unit & unit_bit) == 0) { - GRNXX_ERROR() << "not found: key_id = " << key_id; - throw LogicError(); - } - // Set "link" if this operation creates the first 0 bit in the unit. - Link *link = nullptr; - if (*unit == ~BitArrayUnit(0)) { - link = &links_->get_value(unit_id); - } - *unit &= ~unit_bit; - if (link) { - if (header_->latest_available_unit_id != INVALID_UNIT_ID) { - // "*link" points to the next unit. - *link = static_cast<Link>(header_->latest_available_unit_id); - } else { - // "*link" points to itself because there are no more units. - *link = static_cast<Link>(unit_id); - } - header_->latest_available_unit_id = *link; - } - --header_->num_keys; -} - -template <typename T> -void KeyPool<T>::reset(int64_t key_id, KeyArg dest_key) { - if (!get_bit(key_id)) { - GRNXX_ERROR() << "not found: key_id = " << key_id; - throw LogicError(); - } - keys_->set(key_id, dest_key); -} - -template <typename T> -int64_t KeyPool<T>::add(KeyArg key) { - // Find an unused key ID. - const bool is_new_unit = header_->latest_available_unit_id == INVALID_UNIT_ID; - uint64_t unit_id; - if (is_new_unit) { - if (header_->max_key_id == MAX_KEY_ID) { - GRNXX_ERROR() << "too many keys: key_id = " << (header_->max_key_id + 1) - << ", max_key_id = " << MAX_KEY_ID; - throw LogicError(); - } - unit_id = (header_->max_key_id + 1) / UNIT_SIZE; - } else { - unit_id = header_->latest_available_unit_id; - } - BitArrayUnit * const unit = &bits_->get_unit(unit_id); - uint8_t unit_bit_id; - uint64_t unit_bit; - const Link *link = nullptr; - if (is_new_unit) { - // "links_[unit_id]" points to itself because there are no more units. - links_->set(unit_id, unit_id); - *unit = 0; - unit_bit_id = 0; - unit_bit = 1; - header_->latest_available_unit_id = unit_id; - } else { - unit_bit_id = bit_scan_forward(~*unit); - unit_bit = 1ULL << unit_bit_id; - if ((*unit | unit_bit) == ~BitArrayUnit(0)) { - // The unit must be removed from "links_" because it becomes full. - link = &links_->get_value(header_->latest_available_unit_id); - } - } - const int64_t next_key_id = (unit_id * UNIT_SIZE) + unit_bit_id; - keys_->set(next_key_id, key); - if (link) { - if (*link != unit_id) { - // Move to the next unit. - header_->latest_available_unit_id = *link; - } else { - // There are no more units. - header_->latest_available_unit_id = INVALID_UNIT_ID; - } - } - *unit |= unit_bit; - if (next_key_id > header_->max_key_id) { - header_->max_key_id = next_key_id; - } - ++header_->num_keys; - return next_key_id; -} - -template <typename T> -void KeyPool<T>::defrag(double) { - // Nothing to do. -} - -template <typename T> -void KeyPool<T>::truncate() { - header_->max_key_id = MIN_KEY_ID - 1; - header_->num_keys = 0; - header_->latest_available_unit_id = INVALID_UNIT_ID; -} - -template <typename T> -void KeyPool<T>::create_pool(Storage *storage, uint32_t storage_node_id) { - storage_ = storage; - StorageNode storage_node = - storage->create_node(storage_node_id, sizeof(Header)); - storage_node_id_ = storage_node.id(); - try { - header_ = static_cast<Header *>(storage_node.body()); - *header_ = Header(); - max_key_id_ = &header_->max_key_id; - num_keys_ = &header_->num_keys; - keys_.reset(KeyArray::create(storage, storage_node_id_, - KeyPoolHelper<T>::KEY_ARRAY_SIZE)); - bits_.reset(BitArray::create(storage, storage_node_id_, - KeyPoolHelper<T>::BIT_ARRAY_SIZE)); - links_.reset(LinkArray::create(storage, storage_node_id_, - KeyPoolHelper<T>::LINK_ARRAY_SIZE)); - header_->keys_storage_node_id = keys_->storage_node_id(); - header_->bits_storage_node_id = bits_->storage_node_id(); - header_->links_storage_node_id = links_->storage_node_id(); - } catch (...) { - storage->unlink_node(storage_node_id_); - throw; - } -} - -template <typename T> -void KeyPool<T>::open_pool(Storage *storage, uint32_t storage_node_id) { - storage_ = storage; - StorageNode storage_node = storage->open_node(storage_node_id); - storage_node_id_ = storage_node.id(); - header_ = static_cast<Header *>(storage_node.body()); - if (!*header_) { - GRNXX_ERROR() << "wrong format: expected = " << FORMAT_STRING - << ", actual = " << header_->common_header.format(); - throw LogicError(); - } - max_key_id_ = &header_->max_key_id; - num_keys_ = &header_->num_keys; - keys_.reset(KeyArray::open(storage, header_->keys_storage_node_id)); - bits_.reset(BitArray::open(storage, header_->bits_storage_node_id)); - links_.reset(LinkArray::open(storage, header_->links_storage_node_id)); -} - -template class KeyPool<int8_t>; -template class KeyPool<uint8_t>; -template class KeyPool<int16_t>; -template class KeyPool<uint16_t>; -template class KeyPool<int32_t>; -template class KeyPool<uint32_t>; -template class KeyPool<int64_t>; -template class KeyPool<uint64_t>; -template class KeyPool<double>; -template class KeyPool<GeoPoint>; - -KeyPool<Bytes>::KeyPool() - : storage_(nullptr), - storage_node_id_(STORAGE_INVALID_NODE_ID), - header_(nullptr), - max_key_id_(nullptr), - num_keys_(nullptr), - pool_(), - entries_() {} - -KeyPool<Bytes>::~KeyPool() {} - -KeyPool<Bytes> *KeyPool<Bytes>::create(Storage *storage, - uint32_t storage_node_id) { - if (!storage) { - GRNXX_ERROR() << "invalid argument: storage == nullptr"; - throw LogicError(); - } - std::unique_ptr<KeyPool> pool(new (std::nothrow) KeyPool); - if (!pool) { - GRNXX_ERROR() << "new grnxx::map::KeyPool failed"; - throw MemoryError(); - } - pool->create_pool(storage, storage_node_id); - return pool.release(); -} - -KeyPool<Bytes> *KeyPool<Bytes>::open(Storage *storage, - uint32_t storage_node_id) { - if (!storage) { - GRNXX_ERROR() << "invalid argument: storage == nullptr"; - throw LogicError(); - } - std::unique_ptr<KeyPool> pool(new (std::nothrow) KeyPool); - if (!pool) { - GRNXX_ERROR() << "new grnxx::map::KeyPool failed"; - throw MemoryError(); - } - pool->open_pool(storage, storage_node_id); - return pool.release(); -} - -void KeyPool<Bytes>::unset(int64_t key_id) { - Entry &entry = entries_->get_value(key_id); - if (!entry) { - GRNXX_ERROR() << "not found: key_id = " << key_id; - throw LogicError(); - } - pool_->unset(entry.bytes_id()); - entry.set_next_free_entry_id(header_->latest_free_entry_id); - header_->latest_free_entry_id = key_id; - --header_->num_keys; -} - -void KeyPool<Bytes>::reset(int64_t key_id, KeyArg dest_key) { - Entry &entry = entries_->get_value(key_id); - if (!entry) { - GRNXX_ERROR() << "not found: key_id = " << key_id; - throw LogicError(); - } - const uint64_t src_bytes_id = entry.bytes_id(); - entry.set_bytes_id(pool_->add(dest_key)); - pool_->unset(src_bytes_id); -} - -int64_t KeyPool<Bytes>::add(KeyArg key) { - uint64_t entry_id; - if (header_->latest_free_entry_id != INVALID_ENTRY_ID) { - entry_id = header_->latest_free_entry_id; - } else { - entry_id = header_->max_key_id + 1; - } - Entry &entry = entries_->get_value(entry_id); - const uint64_t bytes_id = pool_->add(key); - if (header_->latest_free_entry_id != INVALID_ENTRY_ID) { - header_->latest_free_entry_id = entry.next_free_entry_id(); - } - entry.set_bytes_id(bytes_id); - if (static_cast<int64_t>(entry_id) > header_->max_key_id) { - header_->max_key_id = entry_id; - } - ++header_->num_keys; - return entry_id; -} - -void KeyPool<Bytes>::defrag(double usage_rate_threshold) { - const uint64_t page_size_in_use_threshold = - uint64_t(pool_->page_size() * usage_rate_threshold); - for (int64_t key_id = MIN_KEY_ID; key_id <= header_->max_key_id; ++key_id) { - Entry &entry = entries_->get_value(key_id); - if (entry) { - // Reallocate a key if it belongs to a page whose usage rate is less than - // "usage_rate_threshold". - const uint64_t bytes_id = entry.bytes_id(); - const uint64_t page_id = bytes_id / pool_->page_size(); - if (pool_->get_page_size_in_use(page_id) < page_size_in_use_threshold) { - entry.set_bytes_id(pool_->add(pool_->get(bytes_id))); - pool_->unset(bytes_id); - } - } - } -} - -void KeyPool<Bytes>::truncate() { - header_->max_key_id = MIN_KEY_ID - 1; - header_->num_keys = 0; - header_->latest_free_entry_id = INVALID_ENTRY_ID; - pool_->truncate(); -} - -void KeyPool<Bytes>::create_pool(Storage *storage, uint32_t storage_node_id) { - storage_ = storage; - StorageNode storage_node = - storage->create_node(storage_node_id, sizeof(Header)); - storage_node_id_ = storage_node.id(); - try { - header_ = static_cast<Header *>(storage_node.body()); - *header_ = Header(); - max_key_id_ = &header_->max_key_id; - num_keys_ = &header_->num_keys; - pool_.reset(BytesPool::create(storage, storage_node_id_)); - entries_.reset(EntryArray::create(storage, storage_node_id_, - ENTRY_ARRAY_SIZE)); - header_->pool_storage_node_id = pool_->storage_node_id(); - header_->entries_storage_node_id = entries_->storage_node_id(); - } catch (...) { - storage->unlink_node(storage_node_id_); - throw; - } -} - -void KeyPool<Bytes>::open_pool(Storage *storage, uint32_t storage_node_id) { - storage_ = storage; - StorageNode storage_node = storage->open_node(storage_node_id); - storage_node_id_ = storage_node.id(); - header_ = static_cast<Header *>(storage_node.body()); - if (!*header_) { - GRNXX_ERROR() << "wrong format: expected = " << FORMAT_STRING - << ", actual = " << header_->common_header.format(); - throw LogicError(); - } - max_key_id_ = &header_->max_key_id; - num_keys_ = &header_->num_keys; - pool_.reset(BytesPool::open(storage, header_->pool_storage_node_id)); - entries_.reset(EntryArray::open(storage, header_->entries_storage_node_id)); -} - -} // namespace map -} // namespace grnxx Deleted: lib/grnxx/map/key_pool.hpp (+0 -307) 100644 =================================================================== --- lib/grnxx/map/key_pool.hpp 2013-08-23 10:46:34 +0900 (9a62887) +++ /dev/null @@ -1,307 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_MAP_KEY_POOL_HPP -#define GRNXX_MAP_KEY_POOL_HPP - -#include "grnxx/features.hpp" - -#include <memory> - -#include "grnxx/array.hpp" -#include "grnxx/bytes.hpp" -#include "grnxx/map/bytes_pool.hpp" -#include "grnxx/traits.hpp" -#include "grnxx/types.hpp" - -namespace grnxx { - -class Storage; - -namespace map { - -class BytesPool; - -struct KeyPoolHeader; - -// Change the size of arrays based on "T". -// Note that the size of link array is N/64 where N is the size of KeyArray. -template <typename T, size_t T_SIZE = sizeof(T)> -struct KeyPoolHelper; - -// Map<T> has at most 2^40 different keys. -template <typename T, size_t T_SIZE> -struct KeyPoolHelper { - using KeyArray = Array<T, (1 << 16), (1 << 12)>; - using BitArray = Array<bool, (1 << 18), (1 << 11)>; - using Link = uint64_t; - using LinkArray = Array<Link, (1 << 14), (1 << 10)>; - - static constexpr uint64_t KEY_ARRAY_SIZE = 1ULL << 40; - static constexpr uint64_t BIT_ARRAY_SIZE = 1ULL << 40; - static constexpr uint64_t LINK_ARRAY_SIZE = 1ULL << 34; -}; - -// Map<T> has at most 2^8 different keys. -template <typename T> -struct KeyPoolHelper<T, 1> { - using KeyArray = Array<T>; - using BitArray = Array<bool>; - using Link = uint8_t; - using LinkArray = Array<Link>; - - static constexpr uint64_t KEY_ARRAY_SIZE = 1ULL << 8; - static constexpr uint64_t BIT_ARRAY_SIZE = 1ULL << 8; - static constexpr uint64_t LINK_ARRAY_SIZE = 1ULL << 2; -}; - -// Map<T> has at most 2^16 different keys. -template <typename T> -struct KeyPoolHelper<T, 2> { - using KeyArray = Array<T>; - using BitArray = Array<bool>; - using Link = uint16_t; - using LinkArray = Array<Link>; - - static constexpr uint64_t KEY_ARRAY_SIZE = 1ULL << 16; - static constexpr uint64_t BIT_ARRAY_SIZE = 1ULL << 16; - static constexpr uint64_t LINK_ARRAY_SIZE = 1ULL << 10; -}; - -// Map<T> has at most 2^32 different keys. -template <typename T> -struct KeyPoolHelper<T, 4> { - using KeyArray = Array<T, (1 << 18)>; - using BitArray = Array<bool, (1 << 20)>; - using Link = uint32_t; - using LinkArray = Array<Link, (1 << 15)>; - - static constexpr uint64_t KEY_ARRAY_SIZE = 1ULL << 32; - static constexpr uint64_t BIT_ARRAY_SIZE = 1ULL << 32; - static constexpr uint64_t LINK_ARRAY_SIZE = 1ULL << 26; -}; - -template <typename T> -class KeyPool { - using Header = KeyPoolHeader; - using KeyArray = typename KeyPoolHelper<T>::KeyArray; - using BitArray = typename KeyPoolHelper<T>::BitArray; - using BitArrayUnit = typename BitArray::Unit; - using Link = typename KeyPoolHelper<T>::Link; - using LinkArray = typename KeyPoolHelper<T>::LinkArray; - - static constexpr uint64_t UNIT_SIZE = sizeof(BitArrayUnit) * 8; - - public: - using Key = typename Traits<T>::Type; - using KeyArg = typename Traits<T>::ArgumentType; - - KeyPool(); - ~KeyPool(); - - // Create a pool. - static KeyPool *create(Storage *storage, uint32_t storage_node_id); - // Open a pool. - static KeyPool *open(Storage *storage, uint32_t storage_node_id); - - // Return the storage node ID. - uint32_t storage_node_id() const { - return storage_node_id_; - } - - // Return the maximum key ID ever used. - // The return value can be a negative value iff the map is empty. - int64_t max_key_id() const { - return *max_key_id_; - } - // Return the number of keys. - uint64_t num_keys() const { - return *num_keys_; - } - - // Get a key associated with "key_id" and return true iff it exists. - // Assign the found key to "*key" iff "key" != nullptr. - bool get(int64_t key_id, Key *key) { - if (!get_bit(key_id)) { - return false; - } - if (key) { - *key = get_key(key_id); - } - return true; - } - // Get a key associated with "key_id" without check. - Key get_key(int64_t key_id) { - return keys_->get(key_id); - } - // Return true iff "key_id" is valid. - bool get_bit(int64_t key_id) { - return bits_->get(key_id); - } - // Remove a key associated with "key_id". - void unset(int64_t key_id); - // Replace a key associated with "key_id" with "dest_key". - void reset(int64_t key_id, KeyArg dest_key); - - // Add "key" and return its ID. - int64_t add(KeyArg key); - - // Defrag a pool. - void defrag(double usage_rate_threshold); - - // Remove all the keys. - void truncate(); - - private: - Storage *storage_; - uint32_t storage_node_id_; - Header *header_; - const int64_t *max_key_id_; - const uint64_t *num_keys_; - std::unique_ptr<KeyArray> keys_; - std::unique_ptr<BitArray> bits_; - std::unique_ptr<LinkArray> links_; - - // Create a pool. - void create_pool(Storage *storage, uint32_t storage_node_id); - // Open a pool. - void open_pool(Storage *storage, uint32_t storage_node_id); -}; - -class KeyPoolEntry { - static constexpr uint64_t IS_VALID_FLAG = 1ULL << 63; - - public: - KeyPoolEntry() = default; - - // Return true iff the entry is valid. - explicit operator bool() const { - return value_ & IS_VALID_FLAG; - } - - // Return the ID of the associated byte sequence. - uint64_t bytes_id() const { - return value_ & ~IS_VALID_FLAG; - } - // Return the ID of the next invalid entry. - uint64_t next_free_entry_id() const { - return value_; - } - - // Set the ID of the associated byte sequence. - void set_bytes_id(uint64_t bytes_id) { - value_ = IS_VALID_FLAG | bytes_id; - } - // Set the ID of the next free entry. - void set_next_free_entry_id(uint64_t next_free_entry_id) { - value_ = next_free_entry_id; - } - - private: - uint64_t value_; - - explicit KeyPoolEntry(uint64_t value) : value_(value) {} -}; - -template <> -class KeyPool<Bytes> { - using Header = KeyPoolHeader; - using Entry = KeyPoolEntry; - using EntryArray = Array<Entry, (1 << 16), (1 << 12)>; - - static constexpr uint64_t ENTRY_ARRAY_SIZE = 1ULL << 40; - - public: - using Key = typename Traits<Bytes>::Type; - using KeyArg = typename Traits<Bytes>::ArgumentType; - - KeyPool(); - ~KeyPool(); - - // Create a pool. - static KeyPool *create(Storage *storage, uint32_t storage_node_id); - // Open a pool. - static KeyPool *open(Storage *storage, uint32_t storage_node_id); - - // Return the storage node ID. - uint32_t storage_node_id() const { - return storage_node_id_; - } - - // Return the maximum key ID ever used. - // The return value can be a negative value iff the map is empty. - int64_t max_key_id() const { - return *max_key_id_; - } - // Return the number of keys. - uint64_t num_keys() const { - return *num_keys_; - } - - // Get a key associated with "key_id" and return true iff it exists. - // Assign the found key to "*key" iff "key" != nullptr. - bool get(int64_t key_id, Key *key) { - const Entry entry = entries_->get(key_id); - if (!entry) { - return false; - } - if (key) { - *key = pool_->get(entry.bytes_id()); - } - return true; - } - // Get a key associated with "key_id" without check. - Key get_key(int64_t key_id) { - return pool_->get(entries_->get(key_id).bytes_id()); - } - // Return true iff "key_id" is valid. - bool get_bit(int64_t key_id) { - return bool(entries_->get(key_id)); - } - // Remove a key associated with "key_id". - void unset(int64_t key_id); - // Replace a key associated with "key_id" with "dest_key". - void reset(int64_t key_id, KeyArg dest_key); - - // Add "key" and return its ID. - int64_t add(KeyArg key); - - // Defrag a pool. - void defrag(double usage_rate_threshold); - - // Remove all the keys. - void truncate(); - - private: - Storage *storage_; - uint32_t storage_node_id_; - Header *header_; - const int64_t *max_key_id_; - const uint64_t *num_keys_; - std::unique_ptr<BytesPool> pool_; - std::unique_ptr<EntryArray> entries_; - - // Create a pool. - void create_pool(Storage *storage, uint32_t storage_node_id); - // Open a pool. - void open_pool(Storage *storage, uint32_t storage_node_id); -}; - -} // namespace map -} // namespace grnxx - -#endif // GRNXX_MAP_KEY_POOL_HPP Deleted: lib/grnxx/map/patricia.cpp (+0 -1771) 100644 =================================================================== --- lib/grnxx/map/patricia.cpp 2013-08-23 10:46:34 +0900 (815409c) +++ /dev/null @@ -1,1771 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/map/patricia.hpp" - -#include <new> - -#include "grnxx/bytes.hpp" -#include "grnxx/exception.hpp" -#include "grnxx/geo_point.hpp" -#include "grnxx/lock.hpp" -#include "grnxx/logger.hpp" -#include "grnxx/map/common_header.hpp" -#include "grnxx/map/hash.hpp" -#include "grnxx/map/helper.hpp" -#include "grnxx/map/key_pool.hpp" -#include "grnxx/mutex.hpp" -#include "grnxx/storage.hpp" - -namespace grnxx { -namespace map { -namespace { - -constexpr char FORMAT_STRING[] = "grnxx::map::Patricia"; - -constexpr uint64_t ROOT_NODE_ID = 0; -constexpr uint64_t DUMMY_NODE_ID = ROOT_NODE_ID + 1; - -constexpr uint64_t NODE_ARRAY_SIZE = 1ULL << 41; -constexpr uint64_t CACHE_SIZE = 1ULL << 19; - -enum NodeStatus : uint64_t { - NODE_DEAD = 0, - NODE_LEAF = 1, - NODE_BRANCH = 2, - NODE_TERMINAL = 3 -}; - -} // namespace - -struct PatriciaHeader { - CommonHeader common_header; - MapType map_type; - uint64_t next_node_id; - uint64_t nodes_id; - uint32_t nodes_storage_node_id; - uint32_t pool_storage_node_id; - uint32_t cache_storage_node_id; - Mutex mutex; - - // Initialize the member variables. - PatriciaHeader(); - - // Return true iff the header seems to be correct. - explicit operator bool() const; -}; - -PatriciaHeader::PatriciaHeader() - : common_header(FORMAT_STRING, MAP_PATRICIA), - next_node_id(2), - nodes_id(0), - nodes_storage_node_id(STORAGE_INVALID_NODE_ID), - pool_storage_node_id(STORAGE_INVALID_NODE_ID), - cache_storage_node_id(STORAGE_INVALID_NODE_ID), - mutex() {} - -PatriciaHeader::operator bool() const { - return common_header.format() == FORMAT_STRING; -} - -// The internal structure of PatriciaNode is as follows: -// - Common -// 62-63 ( 2): status (DEAD, LEAF, BRANCH, TERMINAL) -// - Leaf: LEAF -// 0-39 (40): key_id -// 40-61 (22): reserved -// - Branch or Terminal: BRANCH || TERMINAL -// 16-57 (42): offset -// 58-61 ( 4): reserved -// - Branch: BRANCH -// 0-15 (16): bit_pos -// - Terminal: TERMINAL -// 0-15 (16): bit_size -// where 0 is the LSB and 63 is the MSB. -class PatriciaNode { - static constexpr uint64_t STATUS_MASK = (1ULL << 2) - 1; - static constexpr uint8_t STATUS_SHIFT = 62; - - static constexpr uint64_t KEY_ID_MASK = (1ULL << 40) - 1; - static constexpr uint8_t KEY_ID_SHIFT = 0; - - static constexpr uint64_t OFFSET_MASK = (1ULL << 42) - 1; - static constexpr uint8_t OFFSET_SHIFT = 16; - - static constexpr uint64_t BIT_POS_MASK = (1ULL << 16) - 1; - static constexpr uint8_t BIT_POS_SHIFT = 0; - - static constexpr uint64_t BIT_SIZE_MASK = (1ULL << 16) - 1; - static constexpr uint8_t BIT_SIZE_SHIFT = 0; - - public: - PatriciaNode() = default; - - // Create a node that has neither descendants nor an associated key. - static PatriciaNode dead_node() { - return PatriciaNode(NODE_DEAD << STATUS_SHIFT); - } - // Create a node that has an associated key that is identified by "key_id". - static PatriciaNode leaf_node(int64_t key_id) { - return PatriciaNode((NODE_LEAF << STATUS_SHIFT) | - ((key_id & KEY_ID_MASK) << KEY_ID_SHIFT)); - } - // Create a node that works as a 0/1 branch. - // If key["bit_pos"] == 0, the next node ID is "offset". - // Otherwise, the next node ID is "offset" + 1. - static PatriciaNode branch_node(uint64_t bit_pos, uint64_t offset) { - return PatriciaNode((NODE_BRANCH << STATUS_SHIFT) | - ((bit_pos & BIT_POS_MASK) << BIT_POS_SHIFT) | - ((offset & OFFSET_MASK) << OFFSET_SHIFT)); - } - // Create a node that works as a short/long branch. - // If key_size <= "bit_size", the next node ID is "offset". - // Otherwise, the next node ID is "offset" + 1. - static PatriciaNode terminal_node(uint64_t bit_size, uint64_t offset) { - return PatriciaNode((NODE_TERMINAL << STATUS_SHIFT) | - ((bit_size & BIT_SIZE_MASK) << BIT_SIZE_SHIFT) | - ((offset & OFFSET_MASK) << OFFSET_SHIFT)); - } - - // Return the node status. - uint64_t status() const { - return (value_ >> STATUS_SHIFT) & STATUS_MASK; - } - // Return the associated key ID. - int64_t key_id() const { - return (value_ >> KEY_ID_SHIFT) & KEY_ID_MASK; - } - // Return the offset to the next nodes. - uint64_t offset() const { - return (value_ >> OFFSET_SHIFT) & OFFSET_MASK; - } - // Return the position of the branch. - uint64_t bit_pos() const { - return (value_ >> BIT_POS_SHIFT) & BIT_POS_MASK; - } - // Return the branch condition. - uint64_t bit_size() const { - return (value_ >> BIT_SIZE_SHIFT) & BIT_SIZE_MASK; - } - - private: - uint64_t value_; - - explicit PatriciaNode(uint64_t value) : value_(value) {} -}; - -class PatriciaCacheEntry { - public: - // Create an unused entry. - static PatriciaCacheEntry invalid_entry() { - return PatriciaCacheEntry(0); - } - - // Return true iff this entry is not empty. - explicit operator bool() { - return value_ & IS_VALID_FLAG; - } - - // Return true iff this entry and "hash_value" have the same memo. - bool test_hash_value(uint64_t hash_value) const { - return ((value_ ^ hash_value) >> MEMO_SHIFT) == 0; - } - // Return a stored key ID. - int64_t key_id() const { - return value_ & KEY_ID_MASK; - } - - // Set a key ID and a memo, which is extracted from "hash_value". - void set(int64_t key_id, uint64_t hash_value) { - value_ = IS_VALID_FLAG | key_id | (hash_value & (~0ULL << MEMO_SHIFT)); - } - - private: - uint64_t value_; - - explicit PatriciaCacheEntry(uint64_t value) : value_(value) {} - - static constexpr uint64_t IS_VALID_FLAG = 1ULL << 40; - static constexpr uint8_t MEMO_SHIFT = 41; - static constexpr uint64_t KEY_ID_MASK = (1ULL << 40) - 1; -}; - -template <typename T> -Patricia<T>::Patricia() - : storage_(nullptr), - storage_node_id_(STORAGE_INVALID_NODE_ID), - header_(nullptr), - nodes_(), - old_nodes_(), - pool_(), - cache_(), - nodes_id_(0) {} - -template <typename T> -Patricia<T>::~Patricia() {} - -template <typename T> -Patricia<T> *Patricia<T>::create(Storage *storage, - uint32_t storage_node_id, - const MapOptions &options) { - std::unique_ptr<Patricia> map(new (std::nothrow) Patricia); - if (!map) { - GRNXX_ERROR() << "new grnxx::map::Patricia failed"; - throw MemoryError(); - } - map->create_map(storage, storage_node_id, options); - return map.release(); -} - -template <typename T> -Patricia<T> *Patricia<T>::open(Storage *storage, - uint32_t storage_node_id) { - std::unique_ptr<Patricia> map(new (std::nothrow) Patricia); - if (!map) { - GRNXX_ERROR() << "new grnxx::map::Patricia failed"; - throw MemoryError(); - } - map->open_map(storage, storage_node_id); - return map.release(); -} - -template <typename T> -uint32_t Patricia<T>::storage_node_id() const { - return storage_node_id_; -} - -template <typename T> -MapType Patricia<T>::type() const { - return MAP_PATRICIA; -} - -template <typename T> -int64_t Patricia<T>::max_key_id() { - return pool_->max_key_id(); -} - -template <typename T> -uint64_t Patricia<T>::num_keys() { - return pool_->num_keys(); -} - -template <typename T> -bool Patricia<T>::get(int64_t key_id, Key *key) { - if ((key_id < MAP_MIN_KEY_ID) || (key_id > pool_->max_key_id())) { - // Out of range. - return false; - } - return pool_->get(key_id, key); -} - -template <typename T> -bool Patricia<T>::unset(int64_t key_id) { - refresh_nodes(); - Key key; - if (!get(key_id, &key)) { - // Not found. - return false; - } - // The root node must not be dead because the above get() has succeeded. - uint64_t node_id = ROOT_NODE_ID; - Node *prev_node = nullptr; - for ( ; ; ) { - Node * const node = &nodes_->get_value(node_id); - if (node->status() == NODE_LEAF) { - if (node->key_id() != key_id) { - // Not found. - return false; - } - pool_->unset(key_id); - if (prev_node) { - Node * const sibling_node = node + (node_id ^ 1) - node_id; - *prev_node = *sibling_node; - } else { - *node = Node::dead_node(); - } - return true; - } - prev_node = node; - node_id = node->offset() + get_ith_bit(key, node->bit_pos()); - } -} - -template <typename T> -bool Patricia<T>::reset(int64_t key_id, KeyArg dest_key) { - refresh_nodes(); - // Find the source key. - Key src_key; - if (!get(key_id, &src_key)) { - // Not found. - return false; - } - // The root node must not be dead because the above get() has succeeded. - uint64_t node_id = ROOT_NODE_ID; - Node *src_node; - Node *src_prev_node = nullptr; - Node *src_sibling_node = nullptr; - for ( ; ; ) { - src_node = &nodes_->get_value(node_id); - if (src_node->status() == NODE_LEAF) { - if (src_node->key_id() != key_id) { - // Not found. - return false; - } - if (src_prev_node) { - src_sibling_node = src_node + (node_id ^ 1) - node_id; - } - break; - } - src_prev_node = src_node; - node_id = src_node->offset() + get_ith_bit(src_key, src_node->bit_pos()); - } - // Add the destination key. - const Key dest_normalized_key = Helper<T>::normalize(dest_key); - node_id = ROOT_NODE_ID; - Node *history[(sizeof(Key) * 8) + 1]; - int depth = -1; - for ( ; ; ) { - Node * const node = &nodes_->get_value(node_id); - history[++depth] = node; - if (node->status() == NODE_LEAF) { - break; - } - node_id = node->offset() + - get_ith_bit(dest_normalized_key, node->bit_pos()); - } - // Count the number of the common prefix bits. - Key stored_key = pool_->get_key(history[depth]->key_id()); - const uint64_t count = - count_common_prefix_bits(dest_normalized_key, stored_key); - if (count == (sizeof(Key) * 8)) { - // Found. - return false; - } - // Find the branching point in "history". - while (depth > 0) { - if (history[depth - 1]->bit_pos() < count) { - break; - } - --depth; - } - Node * const dest_prev_node = history[depth]; - Node * const next_nodes = &nodes_->get_value(header_->next_node_id); - pool_->reset(key_id, dest_normalized_key); - Node *dest_node; - Node *dest_sibling_node; - if (get_ith_bit(dest_normalized_key, count)) { - dest_node = &next_nodes[1]; - dest_sibling_node = &next_nodes[0]; - } else { - dest_node = &next_nodes[0]; - dest_sibling_node = &next_nodes[1]; - } - if (dest_prev_node == src_prev_node) { - src_prev_node = dest_sibling_node; - } else if (dest_prev_node == src_node) { - src_sibling_node = dest_node; - src_prev_node = dest_prev_node; - } - *dest_sibling_node = *dest_prev_node; - *dest_node = Node::leaf_node(key_id); - *dest_prev_node = Node::branch_node(count, header_->next_node_id); - *src_prev_node = *src_sibling_node; - header_->next_node_id += 2; - return true; -} - -template <typename T> -bool Patricia<T>::find(KeyArg key, int64_t *key_id) { - refresh_nodes(); - const Key normalized_key = Helper<T>::normalize(key); - uint64_t node_id = ROOT_NODE_ID; - Node node = nodes_->get(node_id); - if (node.status() == NODE_DEAD) { - // Not found. - return false; - } - for ( ; ; ) { - if (node.status() == NODE_LEAF) { - Key stored_key = pool_->get_key(node.key_id()); - if (!Helper<T>::equal_to(normalized_key, stored_key)) { - // Not found. - return false; - } - if (key_id) { - *key_id = node.key_id(); - } - return true; - } - node_id = node.offset() + get_ith_bit(normalized_key, node.bit_pos()); - node = nodes_->get(node_id); - } -} - -template <typename T> -bool Patricia<T>::add(KeyArg key, int64_t *key_id) { - refresh_nodes(); - const Key normalized_key = Helper<T>::normalize(key); - const uint64_t hash_value = Hash<Key>()(normalized_key); - CacheEntry &cache = cache_->get_value(hash_value & (cache_->size() - 1)); - if (cache && cache.test_hash_value(hash_value)) { - Key cached_key; - if (pool_->get(cache.key_id(), &cached_key)) { - if (key == cached_key) { - if (key_id) { - *key_id = cache.key_id(); - } - return false; - } - } - } - uint64_t node_id = ROOT_NODE_ID; - Node *node = &nodes_->get_value(node_id); - if (node->status() == NODE_DEAD) { - // The patricia is empty. - int64_t next_key_id = pool_->add(normalized_key); - *node = Node::leaf_node(next_key_id); - if (key_id) { - *key_id = next_key_id; - } - cache.set(next_key_id, hash_value); - return true; - } - Node *history[(sizeof(Key) * 8) + 1]; - int depth = 0; - history[0] = node; - while (node->status() != NODE_LEAF) { - node_id = node->offset() + get_ith_bit(normalized_key, node->bit_pos()); - node = &nodes_->get_value(node_id); - history[++depth] = node; - } - // Count the number of the common prefix bits. - Key stored_key = pool_->get_key(node->key_id()); - const uint64_t count = count_common_prefix_bits(normalized_key, stored_key); - if (count == (sizeof(Key) * 8)) { - // Found. - if (key_id) { - *key_id = node->key_id(); - } - cache.set(node->key_id(), hash_value); - return false; - } - // Find the branching point in "history". - while (depth > 0) { - if (history[depth - 1]->bit_pos() < count) { - break; - } - --depth; - } - node = history[depth]; - Node * const next_nodes = &nodes_->get_value(header_->next_node_id); - int64_t next_key_id = pool_->add(normalized_key); - if (get_ith_bit(normalized_key, count)) { - next_nodes[0] = *node; - next_nodes[1] = Node::leaf_node(next_key_id); - } else { - next_nodes[0] = Node::leaf_node(next_key_id); - next_nodes[1] = *node; - } - *node = Node::branch_node(count, header_->next_node_id); - header_->next_node_id += 2; - if (key_id) { - *key_id = next_key_id; - } - cache.set(next_key_id, hash_value); - return true; -} - -template <typename T> -bool Patricia<T>::remove(KeyArg key) { - refresh_nodes(); - const Key normalized_key = Helper<T>::normalize(key); - uint64_t node_id = ROOT_NODE_ID; - Node *node = &nodes_->get_value(node_id); - if (node->status() == NODE_DEAD) { - // Not found. - return false; - } - Node *prev_node = nullptr; - for ( ; ; ) { - if (node->status() == NODE_LEAF) { - Key stored_key = pool_->get_key(node->key_id()); - if (!Helper<T>::equal_to(normalized_key, stored_key)) { - // Not found. - return false; - } - pool_->unset(node->key_id()); - if (prev_node) { - Node * const sibling_node = node + (node_id ^ 1) - node_id; - *prev_node = *sibling_node; - } else { - *node = Node::dead_node(); - } - return true; - } - prev_node = node; - node_id = node->offset() + get_ith_bit(normalized_key, node->bit_pos()); - node = &nodes_->get_value(node_id); - } -} - -template <typename T> -bool Patricia<T>::replace(KeyArg src_key, KeyArg dest_key, int64_t *key_id) { - refresh_nodes(); - const Key src_normalized_key = Helper<T>::normalize(src_key); - uint64_t node_id = ROOT_NODE_ID; - Node *src_node = &nodes_->get_value(node_id); - if (src_node->status() == NODE_DEAD) { - // Not found. - return false; - } - int64_t src_key_id; - Node *src_prev_node = nullptr; - Node *src_sibling_node = nullptr; - for ( ; ; ) { - if (src_node->status() == NODE_LEAF) { - src_key_id = src_node->key_id(); - Key stored_key = pool_->get_key(src_key_id); - if (!Helper<T>::equal_to(src_normalized_key, stored_key)) { - // Not found. - return false; - } - if (src_prev_node) { - src_sibling_node = src_node + (node_id ^ 1) - node_id; - } - break; - } - src_prev_node = src_node; - node_id = src_node->offset() + - get_ith_bit(src_normalized_key, src_node->bit_pos()); - src_node = &nodes_->get_value(node_id); - } - // Add the destination key. - const Key dest_normalized_key = Helper<T>::normalize(dest_key); - node_id = ROOT_NODE_ID; - Node *history[(sizeof(Key) * 8) + 1]; - int depth = -1; - for ( ; ; ) { - Node * const node = &nodes_->get_value(node_id); - history[++depth] = node; - if (node->status() == NODE_LEAF) { - break; - } - node_id = node->offset() + - get_ith_bit(dest_normalized_key, node->bit_pos()); - } - // Count the number of the common prefix bits. - Key stored_key = pool_->get_key(history[depth]->key_id()); - const uint64_t count = - count_common_prefix_bits(dest_normalized_key, stored_key); - if (count == (sizeof(Key) * 8)) { - // Found. - return false; - } - // Find the branching point in "history". - while (depth > 0) { - if (history[depth - 1]->bit_pos() < count) { - break; - } - --depth; - } - Node * const dest_prev_node = history[depth]; - Node * const next_nodes = &nodes_->get_value(header_->next_node_id); - pool_->reset(src_key_id, dest_normalized_key); - Node *dest_node; - Node *dest_sibling_node; - if (get_ith_bit(dest_normalized_key, count)) { - dest_node = &next_nodes[1]; - dest_sibling_node = &next_nodes[0]; - } else { - dest_node = &next_nodes[0]; - dest_sibling_node = &next_nodes[1]; - } - if (dest_prev_node == src_prev_node) { - src_prev_node = dest_sibling_node; - } else if (dest_prev_node == src_node) { - src_sibling_node = dest_node; - src_prev_node = dest_prev_node; - } - *dest_sibling_node = *dest_prev_node; - *dest_node = Node::leaf_node(src_key_id); - *dest_prev_node = Node::branch_node(count, header_->next_node_id); - *src_prev_node = *src_sibling_node; - header_->next_node_id += 2; - if (key_id) { - *key_id = src_key_id; - } - return true; -} - -template <typename T> -void Patricia<T>::defrag() { - refresh_nodes(); - if (max_key_id() == MAP_MIN_KEY_ID) { - // Nothing to do. - return; - } - defrag_nodes(); - pool_->defrag(0.5); -} - -template <typename T> -void Patricia<T>::truncate() { - refresh_nodes(); - if (max_key_id() == MAP_MIN_KEY_ID) { - // Nothing to do. - return; - } - std::unique_ptr<NodeArray> new_nodes( - NodeArray::create(storage_, storage_node_id_, NODE_ARRAY_SIZE)); - try { - new_nodes->set(ROOT_NODE_ID, Node::dead_node()); - new_nodes->set(DUMMY_NODE_ID, Node::dead_node()); - for (uint64_t i = 0; i < CACHE_SIZE; ++i) { - cache_->set(i, CacheEntry::invalid_entry()); - } - pool_->truncate(); - } catch (...) { - NodeArray::unlink(storage_, new_nodes->storage_node_id()); - throw; - } - { - // Validate a new nodes. - Lock lock(&header_->mutex); - header_->nodes_storage_node_id = new_nodes->storage_node_id(); - header_->next_node_id = 2; - ++header_->nodes_id; - old_nodes_.swap(new_nodes); - nodes_.swap(old_nodes_); - nodes_id_ = header_->nodes_id; - } - NodeArray::unlink(storage_, old_nodes_->storage_node_id()); -} - -template <typename T> -void Patricia<T>::create_map(Storage *storage, uint32_t storage_node_id, - const MapOptions &) { - storage_ = storage; - StorageNode storage_node = - storage->create_node(storage_node_id, sizeof(Header)); - storage_node_id_ = storage_node.id(); - try { - header_ = static_cast<Header *>(storage_node.body()); - *header_ = Header(); - nodes_.reset(NodeArray::create(storage, storage_node_id_, NODE_ARRAY_SIZE)); - pool_.reset(KeyPool<T>::create(storage, storage_node_id_)); - cache_.reset(Cache::create(storage, storage_node_id_, - CACHE_SIZE, CacheEntry::invalid_entry())); - header_->nodes_storage_node_id = nodes_->storage_node_id(); - header_->pool_storage_node_id = pool_->storage_node_id(); - header_->cache_storage_node_id = cache_->storage_node_id(); - nodes_->set(ROOT_NODE_ID, Node::dead_node()); - nodes_->set(DUMMY_NODE_ID, Node::dead_node()); - } catch (...) { - storage->unlink_node(storage_node_id_); - throw; - } -} - -template <typename T> -void Patricia<T>::open_map(Storage *storage, uint32_t storage_node_id) { - storage_ = storage; - StorageNode storage_node = storage->open_node(storage_node_id); - if (storage_node.size() < sizeof(Header)) { - GRNXX_ERROR() << "invalid format: size = " << storage_node.size() - << ", header_size = " << sizeof(Header); - throw LogicError(); - } - storage_node_id_ = storage_node_id; - header_ = static_cast<Header *>(storage_node.body()); - if (!*header_) { - GRNXX_ERROR() << "wrong format: expected = " << FORMAT_STRING - << ", actual = " << header_->common_header.format(); - throw LogicError(); - } - Lock lock(&header_->mutex); - nodes_.reset(NodeArray::open(storage, header_->nodes_storage_node_id)); - pool_.reset(KeyPool<T>::open(storage, header_->pool_storage_node_id)); - cache_.reset(Cache::open(storage, header_->cache_storage_node_id)); - nodes_id_ = header_->nodes_id; -} - -template <typename T> -void Patricia<T>::defrag_nodes() { - // Create a new nodes. - std::unique_ptr<NodeArray> new_nodes( - NodeArray::create(storage_, storage_node_id_, NODE_ARRAY_SIZE)); - uint64_t next_node_id = 2; - try { - next_node_id = rearrange_nodes(ROOT_NODE_ID, ROOT_NODE_ID, - next_node_id, new_nodes.get()); - next_node_id = rearrange_nodes(DUMMY_NODE_ID, DUMMY_NODE_ID, - next_node_id, new_nodes.get()); - } catch (...) { - NodeArray::unlink(storage_, new_nodes->storage_node_id()); - throw; - } - { - // Validate a new nodes. - Lock lock(&header_->mutex); - header_->nodes_storage_node_id = new_nodes->storage_node_id(); - header_->next_node_id = next_node_id; - ++header_->nodes_id; - old_nodes_.swap(new_nodes); - nodes_.swap(old_nodes_); - nodes_id_ = header_->nodes_id; - } - NodeArray::unlink(storage_, old_nodes_->storage_node_id()); -} - -template <typename T> -uint64_t Patricia<T>::rearrange_nodes(uint64_t src_node_id, - uint64_t dest_node_id, - uint64_t next_node_id, - NodeArray *dest_nodes) { - const Node src_node = nodes_->get(src_node_id); - Node &dest_node = dest_nodes->get_value(dest_node_id); - switch (src_node.status()) { - case NODE_DEAD: - case NODE_LEAF: { - dest_node = src_node; - return next_node_id; - } - case NODE_BRANCH: { - dest_node = Node::branch_node(src_node.bit_pos(), next_node_id); - break; - } - case NODE_TERMINAL: { - dest_node = Node::terminal_node(src_node.bit_size(), next_node_id); - break; - } - } - src_node_id = src_node.offset(); - dest_node_id = next_node_id; - next_node_id += 2; - next_node_id = rearrange_nodes(src_node_id, dest_node_id, - next_node_id, dest_nodes); - next_node_id = rearrange_nodes(src_node_id + 1, dest_node_id + 1, - next_node_id, dest_nodes); - return next_node_id; -} - -template <typename T> -void Patricia<T>::refresh_nodes() { - if (nodes_id_ != header_->nodes_id) { - Lock lock(&header_->mutex); - if (nodes_id_ != header_->nodes_id) { - std::unique_ptr<NodeArray> new_nodes( - NodeArray::open(storage_, header_->nodes_storage_node_id)); - old_nodes_.swap(new_nodes); - nodes_.swap(old_nodes_); - nodes_id_ = header_->nodes_id; - } - } -} - -template <typename T> -uint64_t Patricia<T>::get_ith_bit(KeyArg key, uint64_t bit_pos) { - return (key >> ((sizeof(Key) * 8) - 1 - bit_pos)) & 1; -} - -template <> -uint64_t Patricia<double>::get_ith_bit(KeyArg key, uint64_t bit_pos) { - constexpr uint64_t MASK[2] = { 1ULL << 63, ~0ULL }; - uint64_t x = *reinterpret_cast<const uint64_t *>(&key); - x ^= MASK[x >> 63]; - return (x >> ((sizeof(Key) * 8) - 1 - bit_pos)) & 1; -} - -template <> -uint64_t Patricia<GeoPoint>::get_ith_bit(KeyArg key, uint64_t bit_pos) { - const uint32_t x = reinterpret_cast<const uint32_t *>(&key)[bit_pos & 1]; - return (x >> (31 - (bit_pos >> 1))) & 1; -} - -template <typename T> -uint64_t Patricia<T>::count_common_prefix_bits(KeyArg lhs, KeyArg rhs) { - if (lhs == rhs) { - return sizeof(Key) * 8; - } - return (sizeof(Key) * 8) - 1 - bit_scan_reverse(static_cast<Key>(lhs ^ rhs)); -} - -template <> -uint64_t Patricia<double>::count_common_prefix_bits(KeyArg lhs, KeyArg rhs) { - const uint64_t x = *reinterpret_cast<const uint64_t *>(&lhs); - const uint64_t y = *reinterpret_cast<const uint64_t *>(&rhs); - if (x == y) { - return sizeof(Key) * 8; - } - return (sizeof(Key) * 8) - 1 - bit_scan_reverse(x ^ y); -} - -template <> -uint64_t Patricia<GeoPoint>::count_common_prefix_bits(KeyArg lhs, KeyArg rhs) { - if (lhs == rhs) { - return sizeof(GeoPoint) * 8; - } - const GeoPoint x = GeoPoint(lhs.value() ^ rhs.value()); - const uint32_t latitude = x.latitude(); - const uint32_t longitude = x.longitude(); - const uint8_t y = bit_scan_reverse(latitude | longitude); - return ((31 - y) << 1) + 1 - (latitude >> y); -} - -template class Patricia<int8_t>; -template class Patricia<uint8_t>; -template class Patricia<int16_t>; -template class Patricia<uint16_t>; -template class Patricia<int32_t>; -template class Patricia<uint32_t>; -template class Patricia<int64_t>; -template class Patricia<uint64_t>; -template class Patricia<double>; -template class Patricia<GeoPoint>; - -Patricia<Bytes>::Patricia() - : storage_(nullptr), - storage_node_id_(STORAGE_INVALID_NODE_ID), - header_(nullptr), - nodes_(), - old_nodes_(), - pool_(), - cache_(), - nodes_id_(0) {} - -Patricia<Bytes>::~Patricia() {} - -Patricia<Bytes> *Patricia<Bytes>::create(Storage *storage, - uint32_t storage_node_id, - const MapOptions &options) { - std::unique_ptr<Patricia> map(new (std::nothrow) Patricia); - if (!map) { - GRNXX_ERROR() << "new grnxx::map::Patricia failed"; - throw MemoryError(); - } - map->create_map(storage, storage_node_id, options); - return map.release(); -} - -Patricia<Bytes> *Patricia<Bytes>::open(Storage *storage, - uint32_t storage_node_id) { - std::unique_ptr<Patricia> map(new (std::nothrow) Patricia); - if (!map) { - GRNXX_ERROR() << "new grnxx::map::Patricia failed"; - throw MemoryError(); - } - map->open_map(storage, storage_node_id); - return map.release(); -} - -uint32_t Patricia<Bytes>::storage_node_id() const { - return storage_node_id_; -} - -MapType Patricia<Bytes>::type() const { - return MAP_PATRICIA; -} - -int64_t Patricia<Bytes>::max_key_id() { - return pool_->max_key_id(); -} - -uint64_t Patricia<Bytes>::num_keys() { - return pool_->num_keys(); -} - -bool Patricia<Bytes>::get(int64_t key_id, Key *key) { - if ((key_id < MAP_MIN_KEY_ID) || (key_id > pool_->max_key_id())) { - // Out of range. - return false; - } - return pool_->get(key_id, key); -} - -bool Patricia<Bytes>::unset(int64_t key_id) { - refresh_nodes(); - Key key; - if (!get(key_id, &key)) { - // Not found. - return false; - } - const uint64_t bit_size = key.size() * 8; - uint64_t node_id = ROOT_NODE_ID; - Node *prev_node = nullptr; - for ( ; ; ) { - Node * const node = &nodes_->get_value(node_id); - switch (node->status()) { - case NODE_LEAF: { - if (node->key_id() != key_id) { - // Not found. - return false; - } - pool_->unset(key_id); - if (prev_node) { - Node * const sibling_node = node + (node_id ^ 1) - node_id; - *prev_node = *sibling_node; - } else { - *node = Node::dead_node(); - } - return true; - } - case NODE_BRANCH: { - if (node->bit_pos() >= bit_size) { - // Not found. - return false; - } - node_id = node->offset() + get_ith_bit(key, node->bit_pos()); - break; - } - case NODE_TERMINAL: { - if (node->bit_size() > bit_size) { - // Not found. - return false; - } - node_id = node->offset() + (node->bit_size() < bit_size); - break; - } - } - prev_node = node; - } -} - -bool Patricia<Bytes>::reset(int64_t key_id, KeyArg dest_key) { - refresh_nodes(); - // Find the source key. - Key src_key; - if (!get(key_id, &src_key)) { - // Not found. - return false; - } - const uint64_t src_bit_size = src_key.size() * 8; - uint64_t src_node_id = ROOT_NODE_ID; - Node *src_node; - Node *src_prev_node = nullptr; - Node *src_sibling_node = nullptr; - for ( ; ; ) { - src_node = &nodes_->get_value(src_node_id); - if (src_node->status() == NODE_LEAF) { - if (src_node->key_id() != key_id) { - // Not found. - return false; - } - if (src_prev_node) { - src_sibling_node = src_node + (src_node_id ^ 1) - src_node_id; - } - break; - } else if (src_node->status() == NODE_BRANCH) { - if (src_node->bit_pos() >= src_bit_size) { - // Not found. - return false; - } - src_node_id = src_node->offset() + - get_ith_bit(src_key, src_node->bit_pos()); - } else if (src_node->status() == NODE_TERMINAL) { - if (src_node->bit_size() > src_bit_size) { - // Not found. - return false; - } - src_node_id = src_node->offset() + - (src_node->bit_size() < src_bit_size); - } - src_prev_node = src_node; - } - if (header_->next_node_id >= NODE_ARRAY_SIZE) { - defrag_nodes(); - } - // Add the destination key. - constexpr std::size_t HISTORY_SIZE = 8; - uint64_t dest_node_id = ROOT_NODE_ID; - const uint64_t dest_bit_size = dest_key.size() * 8; - Node *history[HISTORY_SIZE]; - int depth = -1; - for ( ; ; ) { - Node *node = &nodes_->get_value(dest_node_id); - history[++depth % HISTORY_SIZE] = node; - if (node->status() == NODE_LEAF) { - break; - } else if (node->status() == NODE_BRANCH) { - if (node->bit_pos() >= dest_bit_size) { - break; - } - dest_node_id = node->offset() + get_ith_bit(dest_key, node->bit_pos()); - } else { - if (node->bit_size() >= dest_bit_size) { - break; - } - dest_node_id = node->offset() + 1; - } - } - // Find a leaf node. - Node *leaf_node = history[depth % HISTORY_SIZE]; - while (leaf_node->status() != NODE_LEAF) { - leaf_node = &nodes_->get_value(leaf_node->offset()); - } - // Count the number of the common prefix bits. - Key stored_key = pool_->get_key(leaf_node->key_id()); - const uint64_t min_size = (dest_key.size() < stored_key.size()) ? - dest_key.size() : stored_key.size(); - uint64_t count; - for (count = 0; count < min_size; ++count) { - if (dest_key[count] != stored_key[count]) { - break; - } - } - if (count == min_size) { - if (dest_key.size() == stored_key.size()) { - // Found. - return false; - } - Node * const dest_prev_node = history[depth % HISTORY_SIZE]; - Node * const next_nodes = &nodes_->get_value(header_->next_node_id); - pool_->reset(key_id, dest_key); - Node *dest_node; - Node *dest_sibling_node; - if (count == dest_key.size()) { - // "dest_key" is a prefix of "stored_key". - dest_node = &next_nodes[0]; - dest_sibling_node = &next_nodes[1]; - } else { - // "stored_key" is a prefix of "dest_key". - dest_node = &next_nodes[1]; - dest_sibling_node = &next_nodes[0]; - } - if (dest_prev_node == src_prev_node) { - src_prev_node = dest_sibling_node; - } else if (dest_prev_node == src_node) { - src_sibling_node = dest_node; - src_prev_node = dest_prev_node; - } - *dest_sibling_node = *dest_prev_node; - *dest_node = Node::leaf_node(key_id); - *dest_prev_node = Node::terminal_node(count * 8, header_->next_node_id); - *src_prev_node = *src_sibling_node; - header_->next_node_id += 2; - return true; - } - count = (count * 8) + 7 - - bit_scan_reverse(dest_key[count] ^ stored_key[count]); - // Find the branching point in "history". - int min_depth = (depth < 8) ? 0 : depth - 7; - while (--depth >= min_depth) { - Node * const node = history[depth % HISTORY_SIZE]; - if (node->status() == NODE_BRANCH) { - if (node->bit_pos() < count) { - break; - } - } else if (node->bit_size() < count) { - break; - } - } - Node *dest_prev_node; - if (depth >= min_depth) { - // The branching point exists in "history". - dest_prev_node = history[(depth + 1) % HISTORY_SIZE]; - } else { - // Find the branching point with the naive method. - dest_node_id = ROOT_NODE_ID; - for ( ; ; ) { - dest_prev_node = &nodes_->get_value(dest_node_id); - if (dest_prev_node->status() == NODE_LEAF) { - break; - } else if (dest_prev_node->status() == NODE_BRANCH) { - if (dest_prev_node->bit_pos() >= count) { - break; - } - dest_node_id = dest_prev_node->offset() + - get_ith_bit(dest_key, dest_prev_node->bit_pos()); - } else { - if (dest_prev_node->bit_size() > count) { - break; - } - dest_node_id = dest_prev_node->offset() + 1; - } - } - } - Node * const next_nodes = &nodes_->get_value(header_->next_node_id); - pool_->reset(key_id, dest_key); - Node *dest_node; - Node *dest_sibling_node; - if (get_ith_bit(dest_key, count)) { - dest_node = &next_nodes[1]; - dest_sibling_node = &next_nodes[0]; - } else { - dest_node = &next_nodes[0]; - dest_sibling_node = &next_nodes[1]; - } - if (dest_prev_node == src_prev_node) { - src_prev_node = dest_sibling_node; - } else if (dest_prev_node == src_node) { - src_sibling_node = dest_node; - src_prev_node = dest_prev_node; - } - *dest_sibling_node = *dest_prev_node; - *dest_node = Node::leaf_node(key_id); - *dest_prev_node = Node::branch_node(count, header_->next_node_id); - *src_prev_node = *src_sibling_node; - header_->next_node_id += 2; - return true; -} - -bool Patricia<Bytes>::find(KeyArg key, int64_t *key_id) { - refresh_nodes(); - NodeArray * const nodes = nodes_.get(); - const uint64_t bit_size = key.size() * 8; - uint64_t node_id = ROOT_NODE_ID; - Node node = nodes->get(node_id); - if (node.status() == NODE_DEAD) { - // Not found. - return false; - } - for ( ; ; ) { - switch (node.status()) { - case NODE_LEAF: { - Key stored_key = pool_->get_key(node.key_id()); - if (key != stored_key) { - // Not found. - return false; - } - if (key_id) { - *key_id = node.key_id(); - } - return true; - } - case NODE_BRANCH: { - if (node.bit_pos() >= bit_size) { - // Not found. - return false; - } - node_id = node.offset() + get_ith_bit(key, node.bit_pos()); - break; - } - case NODE_TERMINAL: { - if (node.bit_size() > bit_size) { - // Not found. - return false; - } - node_id = node.offset() + (node.bit_size() < bit_size); - break; - } - } - node = nodes->get(node_id); - } -} - -bool Patricia<Bytes>::add(KeyArg key, int64_t *key_id) { - refresh_nodes(); - const uint64_t hash_value = Hash<Key>()(key); - CacheEntry &cache = cache_->get_value(hash_value & (cache_->size() - 1)); - if (cache && cache.test_hash_value(hash_value)) { - Key cached_key; - if (pool_->get(cache.key_id(), &cached_key)) { - if (key == cached_key) { - if (key_id) { - *key_id = cache.key_id(); - } - return false; - } - } - } - if (header_->next_node_id >= NODE_ARRAY_SIZE) { - defrag_nodes(); - } - uint64_t node_id = ROOT_NODE_ID; - Node *node = &nodes_->get_value(node_id); - if (node->status() == NODE_DEAD) { - // The patricia is empty. - int64_t next_key_id = pool_->add(key); - *node = Node::leaf_node(next_key_id); - if (key_id) { - *key_id = next_key_id; - } - cache.set(next_key_id, hash_value); - return true; - } - const uint64_t bit_size = key.size() * 8; - constexpr std::size_t HISTORY_SIZE = 8; - Node *history[HISTORY_SIZE]; - int depth = 0; - history[0] = node; - while (node->status() != NODE_LEAF) { - if (node->status() == NODE_BRANCH) { - if (node->bit_pos() >= bit_size) { - break; - } - node_id = node->offset() + get_ith_bit(key, node->bit_pos()); - } else { - if (node->bit_size() >= bit_size) { - break; - } - node_id = node->offset() + 1; - } - node = &nodes_->get_value(node_id); - history[++depth % HISTORY_SIZE] = node; - } - // Find a leaf node. - while (node->status() != NODE_LEAF) { - node_id = node->offset(); - node = &nodes_->get_value(node_id); - } - // Count the number of the common prefix bits. - Key stored_key = pool_->get_key(node->key_id()); - const uint64_t min_size = - (key.size() < stored_key.size()) ? key.size() : stored_key.size(); - uint64_t count; - for (count = 0; count < min_size; ++count) { - if (key[count] != stored_key[count]) { - break; - } - } - if (count == min_size) { - if (key.size() == stored_key.size()) { - // Found. - if (key_id) { - *key_id = node->key_id(); - } - cache.set(node->key_id(), hash_value); - return false; - } - node = history[depth % HISTORY_SIZE]; - Node * const next_nodes = &nodes_->get_value(header_->next_node_id); - int64_t next_key_id = pool_->add(key); - if (count == key.size()) { - // "key" is a prefix of "stored_key". - next_nodes[0] = Node::leaf_node(next_key_id); - next_nodes[1] = *node; - } else { - // "stored_key" is a prefix of "key". - next_nodes[0] = *node; - next_nodes[1] = Node::leaf_node(next_key_id); - } - *node = Node::terminal_node(count * 8, header_->next_node_id); - header_->next_node_id += 2; - if (key_id) { - *key_id = next_key_id; - } - cache.set(next_key_id, hash_value); - return true; - } - count = (count * 8) + 7 - bit_scan_reverse(key[count] ^ stored_key[count]); - // Find the branching point in "history". - int min_depth = (depth < 8) ? 0 : depth - 7; - while (--depth >= min_depth) { - node = history[depth % HISTORY_SIZE]; - if (node->status() == NODE_BRANCH) { - if (node->bit_pos() < count) { - break; - } - } else if (node->bit_size() <= count) { - break; - } - } - if (depth >= min_depth) { - // The branching point exists in "history". - node = history[(depth + 1) % HISTORY_SIZE]; - } else { - // Find the branching point with the naive method. - node_id = ROOT_NODE_ID; - for ( ; ; ) { - node = &nodes_->get_value(node_id); - if (node->status() == NODE_LEAF) { - break; - } else if (node->status() == NODE_BRANCH) { - if (node->bit_pos() >= count) { - break; - } - node_id = node->offset() + get_ith_bit(key, node->bit_pos()); - } else { - if (node->bit_size() > count) { - break; - } - node_id = node->offset() + 1; - } - } - } - Node * const next_nodes = &nodes_->get_value(header_->next_node_id); - int64_t next_key_id = pool_->add(key); - if (get_ith_bit(key, count)) { - next_nodes[0] = *node; - next_nodes[1] = Node::leaf_node(next_key_id); - } else { - next_nodes[0] = Node::leaf_node(next_key_id); - next_nodes[1] = *node; - } - *node = Node::branch_node(count, header_->next_node_id); - header_->next_node_id += 2; - if (key_id) { - *key_id = next_key_id; - } - cache.set(next_key_id, hash_value); - return true; -} - -bool Patricia<Bytes>::remove(KeyArg key) { - refresh_nodes(); - const uint64_t bit_size = key.size() * 8; - uint64_t node_id = ROOT_NODE_ID; - Node *node = &nodes_->get_value(node_id); - if (node->status() == NODE_DEAD) { - // Not found. - return false; - } - Node *prev_node = nullptr; - for ( ; ; ) { - switch (node->status()) { - case NODE_LEAF: { - Key stored_key = pool_->get_key(node->key_id()); - if (stored_key != key) { - // Not found. - return false; - } - pool_->unset(node->key_id()); - if (prev_node) { - Node * const sibling_node = node + (node_id ^ 1) - node_id; - *prev_node = *sibling_node; - } else { - *node = Node::dead_node(); - } - return true; - } - case NODE_BRANCH: { - if (node->bit_pos() >= bit_size) { - // Not found. - return false; - } - node_id = node->offset() + get_ith_bit(key, node->bit_pos()); - break; - } - case NODE_TERMINAL: { - if (node->bit_size() > bit_size) { - // Not found. - return false; - } - node_id = node->offset() + (node->bit_size() < bit_size); - break; - } - } - prev_node = node; - node = &nodes_->get_value(node_id); - } -} - -bool Patricia<Bytes>::replace(KeyArg src_key, KeyArg dest_key, - int64_t *key_id) { - refresh_nodes(); - // Find the source key. - const uint64_t src_bit_size = src_key.size() * 8; - int64_t src_key_id; - uint64_t src_node_id = ROOT_NODE_ID; - Node *src_node = &nodes_->get_value(src_node_id); - if (src_node->status() == NODE_DEAD) { - // Not found. - return false; - } - Node *src_prev_node = nullptr; - Node *src_sibling_node = nullptr; - for ( ; ; ) { - if (src_node->status() == NODE_LEAF) { - src_key_id = src_node->key_id(); - Key stored_key = pool_->get_key(src_key_id); - if (stored_key != src_key) { - // Not found. - return false; - } - if (key_id) { - *key_id = src_key_id; - } - if (src_prev_node) { - src_sibling_node = src_node + (src_node_id ^ 1) - src_node_id; - } - break; - } else if (src_node->status() == NODE_BRANCH) { - if (src_node->bit_pos() >= src_bit_size) { - // Not found. - return false; - } - src_node_id = src_node->offset() + - get_ith_bit(src_key, src_node->bit_pos()); - } else if (src_node->status() == NODE_TERMINAL) { - if (src_node->bit_size() > src_bit_size) { - // Not found. - return false; - } - src_node_id = src_node->offset() + - (src_node->bit_size() < src_bit_size); - } - src_prev_node = src_node; - src_node = &nodes_->get_value(src_node_id); - } - if (header_->next_node_id >= NODE_ARRAY_SIZE) { - defrag_nodes(); - } - // Add the destination key. - constexpr std::size_t HISTORY_SIZE = 8; - uint64_t dest_node_id = ROOT_NODE_ID; - const uint64_t dest_bit_size = dest_key.size() * 8; - Node *history[HISTORY_SIZE]; - int depth = -1; - for ( ; ; ) { - Node *node = &nodes_->get_value(dest_node_id); - history[++depth % HISTORY_SIZE] = node; - if (node->status() == NODE_LEAF) { - break; - } else if (node->status() == NODE_BRANCH) { - if (node->bit_pos() >= dest_bit_size) { - break; - } - dest_node_id = node->offset() + get_ith_bit(dest_key, node->bit_pos()); - } else { - if (node->bit_size() >= dest_bit_size) { - break; - } - dest_node_id = node->offset() + 1; - } - } - // Find a leaf node. - Node *leaf_node = history[depth % HISTORY_SIZE]; - while (leaf_node->status() != NODE_LEAF) { - leaf_node = &nodes_->get_value(leaf_node->offset()); - } - // Count the number of the common prefix bits. - Key stored_key = pool_->get_key(leaf_node->key_id()); - const uint64_t min_size = (dest_key.size() < stored_key.size()) ? - dest_key.size() : stored_key.size(); - uint64_t count; - for (count = 0; count < min_size; ++count) { - if (dest_key[count] != stored_key[count]) { - break; - } - } - if (count == min_size) { - if (dest_key.size() == stored_key.size()) { - // Found. - return false; - } - Node * const dest_prev_node = history[depth % HISTORY_SIZE]; - Node * const next_nodes = &nodes_->get_value(header_->next_node_id); - pool_->reset(src_key_id, dest_key); - Node *dest_node; - Node *dest_sibling_node; - if (count == dest_key.size()) { - // "dest_key" is a prefix of "stored_key". - dest_node = &next_nodes[0]; - dest_sibling_node = &next_nodes[1]; - } else { - // "stored_key" is a prefix of "dest_key". - dest_node = &next_nodes[1]; - dest_sibling_node = &next_nodes[0]; - } - if (dest_prev_node == src_prev_node) { - src_prev_node = dest_sibling_node; - } else if (dest_prev_node == src_node) { - src_sibling_node = dest_node; - src_prev_node = dest_prev_node; - } - *dest_sibling_node = *dest_prev_node; - *dest_node = Node::leaf_node(src_key_id); - *dest_prev_node = Node::terminal_node(count * 8, header_->next_node_id); - *src_prev_node = *src_sibling_node; - header_->next_node_id += 2; - return true; - } - count = (count * 8) + 7 - - bit_scan_reverse(dest_key[count] ^ stored_key[count]); - // Find the branching point in "history". - int min_depth = (depth < 8) ? 0 : depth - 7; - while (--depth >= min_depth) { - Node * const node = history[depth % HISTORY_SIZE]; - if (node->status() == NODE_BRANCH) { - if (node->bit_pos() < count) { - break; - } - } else if (node->bit_size() < count) { - break; - } - } - Node *dest_prev_node; - if (depth >= min_depth) { - // The branching point exists in "history". - dest_prev_node = history[(depth + 1) % HISTORY_SIZE]; - } else { - // Find the branching point with the naive method. - dest_node_id = ROOT_NODE_ID; - for ( ; ; ) { - dest_prev_node = &nodes_->get_value(dest_node_id); - if (dest_prev_node->status() == NODE_LEAF) { - break; - } else if (dest_prev_node->status() == NODE_BRANCH) { - if (dest_prev_node->bit_pos() >= count) { - break; - } - dest_node_id = dest_prev_node->offset() + - get_ith_bit(dest_key, dest_prev_node->bit_pos()); - } else { - if (dest_prev_node->bit_size() > count) { - break; - } - dest_node_id = dest_prev_node->offset() + 1; - } - } - } - Node * const next_nodes = &nodes_->get_value(header_->next_node_id); - pool_->reset(src_key_id, dest_key); - Node *dest_node; - Node *dest_sibling_node; - if (get_ith_bit(dest_key, count)) { - dest_node = &next_nodes[1]; - dest_sibling_node = &next_nodes[0]; - } else { - dest_node = &next_nodes[0]; - dest_sibling_node = &next_nodes[1]; - } - if (dest_prev_node == src_prev_node) { - src_prev_node = dest_sibling_node; - } else if (dest_prev_node == src_node) { - src_sibling_node = dest_node; - src_prev_node = dest_prev_node; - } - *dest_sibling_node = *dest_prev_node; - *dest_node = Node::leaf_node(src_key_id); - *dest_prev_node = Node::branch_node(count, header_->next_node_id); - *src_prev_node = *src_sibling_node; - header_->next_node_id += 2; - return true; -} - -bool Patricia<Bytes>::find_longest_prefix_match(KeyArg query, int64_t *key_id, - Key *key) { - refresh_nodes(); - NodeArray * const nodes = nodes_.get(); - const uint64_t bit_size = query.size() * 8; - bool found = false; - uint64_t node_id = ROOT_NODE_ID; - for ( ; ; ) { - Node node = nodes->get(node_id); - switch (node.status()) { - case NODE_DEAD: { - // Not found. - return found; - } - case NODE_LEAF: { - Key stored_key = pool_->get_key(node.key_id()); - if (query.starts_with(stored_key)) { - if (key_id) { - *key_id = node.key_id(); - } - if (key) { - *key = stored_key; - } - found = true; - } - return found; - } - case NODE_BRANCH: { - if (node.bit_pos() >= bit_size) { - return found; - } - node_id = node.offset() + get_ith_bit(query, node.bit_pos()); - break; - } - case NODE_TERMINAL: { - if (node.bit_size() > bit_size) { - return found; - } else if (node.bit_size() < bit_size) { - Node leaf_node = nodes->get(node.offset()); - Key stored_key = pool_->get_key(leaf_node.key_id()); - if (query.starts_with(stored_key)) { - if (key_id) { - *key_id = leaf_node.key_id(); - } - if (key) { - *key = stored_key; - } - found = true; - } - } - node_id = node.offset() + (node.bit_size() < bit_size); - break; - } - } - } -} - -void Patricia<Bytes>::defrag() { - refresh_nodes(); - if (max_key_id() == MAP_MIN_KEY_ID) { - // Nothing to do. - return; - } - defrag_nodes(); - pool_->defrag(0.5); -} - -void Patricia<Bytes>::truncate() { - refresh_nodes(); - if (max_key_id() == MAP_MIN_KEY_ID) { - // Nothing to do. - return; - } - std::unique_ptr<NodeArray> new_nodes( - NodeArray::create(storage_, storage_node_id_, NODE_ARRAY_SIZE)); - try { - new_nodes->set(ROOT_NODE_ID, Node::dead_node()); - new_nodes->set(DUMMY_NODE_ID, Node::dead_node()); - for (uint64_t i = 0; i < CACHE_SIZE; ++i) { - cache_->set(i, CacheEntry::invalid_entry()); - } - pool_->truncate(); - } catch (...) { - NodeArray::unlink(storage_, new_nodes->storage_node_id()); - throw; - } - { - // Validate a new nodes. - Lock lock(&header_->mutex); - header_->nodes_storage_node_id = new_nodes->storage_node_id(); - header_->next_node_id = 2; - ++header_->nodes_id; - old_nodes_.swap(new_nodes); - nodes_.swap(old_nodes_); - nodes_id_ = header_->nodes_id; - } - NodeArray::unlink(storage_, old_nodes_->storage_node_id()); -} - -void Patricia<Bytes>::create_map(Storage *storage, uint32_t storage_node_id, - const MapOptions &) { - storage_ = storage; - StorageNode storage_node = - storage->create_node(storage_node_id, sizeof(Header)); - storage_node_id_ = storage_node.id(); - try { - header_ = static_cast<Header *>(storage_node.body()); - *header_ = Header(); - nodes_.reset(NodeArray::create(storage, storage_node_id_, NODE_ARRAY_SIZE)); - pool_.reset(KeyPool<Bytes>::create(storage, storage_node_id_)); - cache_.reset(Cache::create(storage, storage_node_id_, - CACHE_SIZE, CacheEntry::invalid_entry())); - header_->nodes_storage_node_id = nodes_->storage_node_id(); - header_->pool_storage_node_id = pool_->storage_node_id(); - header_->cache_storage_node_id = cache_->storage_node_id(); - nodes_->set(ROOT_NODE_ID, Node::dead_node()); - nodes_->set(DUMMY_NODE_ID, Node::dead_node()); - } catch (...) { - storage->unlink_node(storage_node_id_); - throw; - } -} - -void Patricia<Bytes>::open_map(Storage *storage, uint32_t storage_node_id) { - storage_ = storage; - StorageNode storage_node = storage->open_node(storage_node_id); - if (storage_node.size() < sizeof(Header)) { - GRNXX_ERROR() << "invalid format: size = " << storage_node.size() - << ", header_size = " << sizeof(Header); - throw LogicError(); - } - storage_node_id_ = storage_node_id; - header_ = static_cast<Header *>(storage_node.body()); - if (!*header_) { - GRNXX_ERROR() << "wrong format: expected = " << FORMAT_STRING - << ", actual = " << header_->common_header.format(); - throw LogicError(); - } - Lock lock(&header_->mutex); - nodes_.reset(NodeArray::open(storage, header_->nodes_storage_node_id)); - pool_.reset(KeyPool<Bytes>::open(storage, header_->pool_storage_node_id)); - cache_.reset(Cache::open(storage, header_->cache_storage_node_id)); - nodes_id_ = header_->nodes_id; -} - -void Patricia<Bytes>::defrag_nodes() { - // Create a new nodes. - std::unique_ptr<NodeArray> new_nodes( - NodeArray::create(storage_, storage_node_id_, NODE_ARRAY_SIZE)); - uint64_t next_node_id = 2; - try { - next_node_id = rearrange_nodes(ROOT_NODE_ID, ROOT_NODE_ID, - next_node_id, new_nodes.get()); - next_node_id = rearrange_nodes(DUMMY_NODE_ID, DUMMY_NODE_ID, - next_node_id, new_nodes.get()); - } catch (...) { - NodeArray::unlink(storage_, new_nodes->storage_node_id()); - throw; - } - { - // Validate a new nodes. - Lock lock(&header_->mutex); - header_->nodes_storage_node_id = new_nodes->storage_node_id(); - header_->next_node_id = next_node_id; - ++header_->nodes_id; - old_nodes_.swap(new_nodes); - nodes_.swap(old_nodes_); - nodes_id_ = header_->nodes_id; - } - NodeArray::unlink(storage_, old_nodes_->storage_node_id()); -} - -uint64_t Patricia<Bytes>::rearrange_nodes(uint64_t src_node_id, - uint64_t dest_node_id, - uint64_t next_node_id, - NodeArray *dest_nodes) { - const Node src_node = nodes_->get(src_node_id); - Node &dest_node = dest_nodes->get_value(dest_node_id); - switch (src_node.status()) { - case NODE_DEAD: - case NODE_LEAF: { - dest_node = src_node; - return next_node_id; - } - case NODE_BRANCH: { - dest_node = Node::branch_node(src_node.bit_pos(), next_node_id); - break; - } - case NODE_TERMINAL: { - dest_node = Node::terminal_node(src_node.bit_size(), next_node_id); - break; - } - } - src_node_id = src_node.offset(); - dest_node_id = next_node_id; - next_node_id += 2; - next_node_id = rearrange_nodes(src_node_id, dest_node_id, - next_node_id, dest_nodes); - next_node_id = rearrange_nodes(src_node_id + 1, dest_node_id + 1, - next_node_id, dest_nodes); - return next_node_id; -} - -void Patricia<Bytes>::refresh_nodes() { - if (nodes_id_ != header_->nodes_id) { - Lock lock(&header_->mutex); - if (nodes_id_ != header_->nodes_id) { - std::unique_ptr<NodeArray> new_nodes( - NodeArray::open(storage_, header_->nodes_storage_node_id)); - old_nodes_.swap(new_nodes); - nodes_.swap(old_nodes_); - nodes_id_ = header_->nodes_id; - } - } -} - -uint64_t Patricia<Bytes>::get_ith_bit(KeyArg key, uint64_t bit_pos) { - return (key[bit_pos / 8] >> (7 - (bit_pos % 8))) & 1; -} - -} // namespace map -} // namespace grnxx Deleted: lib/grnxx/map/patricia.hpp (+0 -179) 100644 =================================================================== --- lib/grnxx/map/patricia.hpp 2013-08-23 10:46:34 +0900 (9e08d5a) +++ /dev/null @@ -1,179 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_MAP_PATRICIA_HPP -#define GRNXX_MAP_PATRICIA_HPP - -#include "grnxx/features.hpp" - -#include <memory> - -#include "grnxx/array.hpp" -#include "grnxx/bytes.hpp" -#include "grnxx/map.hpp" -#include "grnxx/types.hpp" - -namespace grnxx { - -class Storage; - -namespace map { - -template <typename T> class KeyPool; - -struct PatriciaHeader; -class PatriciaNode; -class PatriciaCacheEntry; - -template <typename T> -class Patricia : public Map<T> { - using Header = PatriciaHeader; - using Node = PatriciaNode; - using NodeArray = Array<Node, 65536, 8192>; - using CacheEntry = PatriciaCacheEntry; - using Cache = Array<CacheEntry>; - - public: - using Key = typename Map<T>::Key; - using KeyArg = typename Map<T>::KeyArg; - using Cursor = typename Map<T>::Cursor; - - Patricia(); - ~Patricia(); - - static Patricia *create(Storage *storage, uint32_t storage_node_id, - const MapOptions &options = MapOptions()); - static Patricia *open(Storage *storage, uint32_t storage_node_id); - - uint32_t storage_node_id() const; - MapType type() const; - - int64_t max_key_id(); - uint64_t num_keys(); - - bool get(int64_t key_id, Key *key = nullptr); - bool unset(int64_t key_id); - bool reset(int64_t key_id, KeyArg dest_key); - - bool find(KeyArg key, int64_t *key_id = nullptr); - bool add(KeyArg key, int64_t *key_id = nullptr); - bool remove(KeyArg key); - bool replace(KeyArg src_key, KeyArg dest_key, int64_t *key_id = nullptr); - - void defrag(); - - void truncate(); - - private: - Storage *storage_; - uint32_t storage_node_id_; - Header *header_; - std::unique_ptr<NodeArray> nodes_; - std::unique_ptr<NodeArray> old_nodes_; - std::unique_ptr<KeyPool<T>> pool_; - std::unique_ptr<Cache> cache_; - uint64_t nodes_id_; - - void create_map(Storage *storage, uint32_t storage_node_id, - const MapOptions &options); - void open_map(Storage *storage, uint32_t storage_node_id); - - // Resize "nodes_" and "cache_". - void defrag_nodes(); - // Recursively arrange nodes. - uint64_t rearrange_nodes(uint64_t src_node_id, uint64_t dest_node_id, - uint64_t next_node_id, NodeArray *dest_nodes); - - // Refresh "nodes_" and "cache_" if new ones are available. - void refresh_nodes(); - - static uint64_t get_ith_bit(KeyArg key, uint64_t bit_pos); - static uint64_t count_common_prefix_bits(KeyArg lhs, KeyArg rhs); -}; - -template <> -class Patricia<Bytes> : public Map<Bytes> { - using Header = PatriciaHeader; - using Node = PatriciaNode; - using NodeArray = Array<Node, 65536, 8192>; - using CacheEntry = PatriciaCacheEntry; - using Cache = Array<CacheEntry>; - - public: - using Key = typename Map<Bytes>::Key; - using KeyArg = typename Map<Bytes>::KeyArg; - using Cursor = typename Map<Bytes>::Cursor; - - Patricia(); - ~Patricia(); - - static Patricia *create(Storage *storage, uint32_t storage_node_id, - const MapOptions &options = MapOptions()); - static Patricia *open(Storage *storage, uint32_t storage_node_id); - - uint32_t storage_node_id() const; - MapType type() const; - - int64_t max_key_id(); - uint64_t num_keys(); - - bool get(int64_t key_id, Key *key = nullptr); - bool unset(int64_t key_id); - bool reset(int64_t key_id, KeyArg dest_key); - - bool find(KeyArg key, int64_t *key_id = nullptr); - bool add(KeyArg key, int64_t *key_id = nullptr); - bool remove(KeyArg key); - bool replace(KeyArg src_key, KeyArg dest_key, int64_t *key_id = nullptr); - - bool find_longest_prefix_match(KeyArg query, int64_t *key_id = nullptr, - Key *key = nullptr); - - void defrag(); - - void truncate(); - - private: - Storage *storage_; - uint32_t storage_node_id_; - Header *header_; - std::unique_ptr<NodeArray> nodes_; - std::unique_ptr<NodeArray> old_nodes_; - std::unique_ptr<KeyPool<Bytes>> pool_; - std::unique_ptr<Cache> cache_; - uint64_t nodes_id_; - - void create_map(Storage *storage, uint32_t storage_node_id, - const MapOptions &options); - void open_map(Storage *storage, uint32_t storage_node_id); - - // Resize "nodes_" and "cache_". - void defrag_nodes(); - // Recursively arrange nodes. - uint64_t rearrange_nodes(uint64_t src_node_id, uint64_t dest_node_id, - uint64_t next_node_id, NodeArray *dest_nodes); - - // Refresh "nodes_" and "cache_" if new ones are available. - void refresh_nodes(); - - static uint64_t get_ith_bit(KeyArg key, uint64_t bit_pos); -}; - -} // namespace map -} // namespace grnxx - -#endif // GRNXX_MAP_PATRICIA_HPP Deleted: lib/grnxx/map/pool.cpp (+0 -830) 100644 =================================================================== --- lib/grnxx/map/pool.cpp 2013-08-23 10:46:34 +0900 (fa0ae37) +++ /dev/null @@ -1,830 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/map/pool.hpp" - -#include <cstring> -#include <exception> -#include <limits> - -#include "grnxx/exception.hpp" -#include "grnxx/geo_point.hpp" -#include "grnxx/intrinsic.hpp" -#include "grnxx/lock.hpp" -#include "grnxx/logger.hpp" -#include "grnxx/map.hpp" -#include "grnxx/storage.hpp" - -namespace grnxx { -namespace map { -namespace { - -constexpr uint64_t INVALID_UNIT_ID = std::numeric_limits<uint64_t>::max(); - -} // namespace - -template <typename T> -PoolHeader<T>::PoolHeader() - : max_key_id(-1), - num_keys(0), - size(0), - latest_available_unit_id(INVALID_UNIT_ID), - page_storage_node_id(STORAGE_INVALID_NODE_ID), - mutex() {} - -template <typename T> -Pool<T>::Pool() - : storage_(nullptr), - storage_node_id_(STORAGE_INVALID_NODE_ID), - header_(nullptr), - pages_(), - table_(nullptr), - size_(0), - queue_(), - clock_() {} - -template <typename T> -Pool<T>::~Pool() {} - -template <typename T> -Pool<T> *Pool<T>::create(Storage *storage, uint32_t storage_node_id) { - if (!storage) { - GRNXX_ERROR() << "invalid argument: storage == nullptr"; - throw LogicError(); - } - std::unique_ptr<Pool> pool(new (std::nothrow) Pool); - if (!pool) { - GRNXX_ERROR() << "new grnxx::map::Pool failed"; - throw MemoryError(); - } - pool->create_pool(storage, storage_node_id); - return pool.release(); -} - -template <typename T> -Pool<T> *Pool<T>::open(Storage *storage, uint32_t storage_node_id) { - if (!storage) { - GRNXX_ERROR() << "invalid argument: storage == nullptr"; - throw LogicError(); - } - std::unique_ptr<Pool> pool(new (std::nothrow) Pool); - if (!pool) { - GRNXX_ERROR() << "new grnxx::map::Pool failed"; - throw MemoryError(); - } - pool->open_pool(storage, storage_node_id); - return pool.release(); -} - -template <typename T> -void Pool<T>::unlink(Storage *storage, uint32_t storage_node_id) { - std::unique_ptr<Pool> pool(Pool::open(storage, storage_node_id)); - storage->unlink_node(storage_node_id); -} - -template <typename T> -void Pool<T>::unset(int64_t key_id) { - refresh_if_possible(); - void * const page = get_page(key_id / PAGE_SIZE); - const uint64_t local_key_id = key_id % PAGE_SIZE; - const uint64_t unit_id = local_key_id / UNIT_SIZE; - const uint64_t validity_bit = 1ULL << (local_key_id % UNIT_SIZE); - Unit * const unit = static_cast<Unit *>(page) - unit_id - 1; - if (~unit->validity_bits & validity_bit) { - GRNXX_ERROR() << "not found: key_id = " << key_id; - throw LogicError(); - } - if (unit->validity_bits == ~uint64_t(0)) { - unit->next_available_unit_id = header_->latest_available_unit_id; - header_->latest_available_unit_id = unit_id; - } - unit->validity_bits &= ~validity_bit; - --header_->num_keys; -} - -template <typename T> -void Pool<T>::reset(int64_t key_id, KeyArg dest_key) { - refresh_if_possible(); - void * const page = get_page(key_id / PAGE_SIZE); - const uint64_t local_key_id = key_id % PAGE_SIZE; - const Unit * const unit = - static_cast<const Unit *>(page) - (local_key_id / UNIT_SIZE) - 1; - if (~unit->validity_bits & (1ULL << (local_key_id % UNIT_SIZE))) { - GRNXX_ERROR() << "not found: key_id = " << key_id; - throw LogicError(); - } - static_cast<T *>(page)[local_key_id] = dest_key; -} - -template <typename T> -int64_t Pool<T>::add(KeyArg key) { - refresh_if_possible(); - if (header_->latest_available_unit_id == INVALID_UNIT_ID) { - // Use a new unit. - const int64_t next_key_id = header_->max_key_id + 1; - if (next_key_id > MAX_KEY_ID) { - GRNXX_ERROR() << "pool is full: next_key_id = " << next_key_id - << ", max_key_id = " << MAX_KEY_ID; - throw LogicError(); - } - reserve_key_id(next_key_id); - void * const page = get_page(next_key_id / PAGE_SIZE); - const uint64_t local_key_id = next_key_id % PAGE_SIZE; - Unit * const unit = - static_cast<Unit *>(page) - (local_key_id / UNIT_SIZE) - 1; - unit->validity_bits = 1; - unit->next_available_unit_id = INVALID_UNIT_ID; - header_->latest_available_unit_id = next_key_id / UNIT_SIZE; - static_cast<T *>(page)[local_key_id] = key; - header_->max_key_id = next_key_id; - ++header_->num_keys; - return next_key_id; - } else { - // Use an existing unit. - const uint64_t unit_id = header_->latest_available_unit_id; - void * const page = get_page(unit_id * UNIT_SIZE / PAGE_SIZE); - Unit * const unit = - static_cast<Unit *>(page) - (unit_id % (PAGE_SIZE / UNIT_SIZE)) - 1; - const uint8_t validity_bit_id = bit_scan_forward(~unit->validity_bits); - const int64_t next_key_id = (unit_id * UNIT_SIZE) + validity_bit_id; - if (next_key_id > MAX_KEY_ID) { - GRNXX_ERROR() << "pool is full: next_key_id = " << next_key_id - << ", max_key_id = " << MAX_KEY_ID; - throw LogicError(); - } - unit->validity_bits |= 1ULL << validity_bit_id; - if (unit->validity_bits == ~uint64_t(0)) { - header_->latest_available_unit_id = unit->next_available_unit_id; - } - static_cast<T *>(page)[next_key_id % PAGE_SIZE] = key; - if (next_key_id > header_->max_key_id) { - header_->max_key_id = next_key_id; - } - ++header_->num_keys; - return next_key_id; - } -} - -template <typename T> -void Pool<T>::defrag() { - refresh_if_possible(); - // Nothing to do. -} - -template <typename T> -void Pool<T>::sweep(Duration lifetime) { - const Time threshold = clock_.now() - lifetime; - while (!queue_.empty()) { - QueueEntry &queue_entry = queue_.front(); - if (queue_entry.time <= threshold) { - queue_.pop(); - } - } -} - -template <typename T> -void Pool<T>::create_pool(Storage *storage, uint32_t storage_node_id) { - storage_ = storage; - StorageNode header_node = - storage->create_node(storage_node_id, sizeof(Header)); - storage_node_id_ = header_node.id(); - try { - header_ = static_cast<Header *>(header_node.body()); - *header_ = Header(); - } catch (...) { - storage->unlink_node(storage_node_id_); - throw; - } -} - -template <typename T> -void Pool<T>::open_pool(Storage *storage, uint32_t storage_node_id) { - storage_ = storage; - StorageNode header_node = storage->open_node(storage_node_id); - storage_node_id_ = header_node.id(); - header_ = static_cast<Header *>(header_node.body()); -} - -template <typename T> -void *Pool<T>::open_page(uint64_t page_id) { - if (page_id >= (header_->size / PAGE_SIZE)) { - GRNXX_ERROR() << "invalid argument: page_id = " << page_id - << ", table_size = " << (header_->size / PAGE_SIZE); - throw LogicError(); - } - if (!pages_[page_id]) { - Lock lock(&header_->mutex); - if (!pages_[page_id]) { - // Open an existing full-size page. - // Note that a small-size page is opened in refresh_page(). - if (table_[page_id] == STORAGE_INVALID_NODE_ID) { - GRNXX_ERROR() << "not found: page_id = " << page_id; - throw LogicError(); - } - StorageNode page_node = storage_->open_node(table_[page_id]); - pages_[page_id] = - static_cast<Unit *>(page_node.body()) + (PAGE_SIZE / UNIT_SIZE); - } - } - return pages_[page_id]; -} - -template <typename T> -void Pool<T>::reserve_key_id(int64_t key_id) { - if (static_cast<uint64_t>(key_id) >= header_->size) { - expand(); - } - const uint64_t page_id = key_id / PAGE_SIZE; - if (!pages_[page_id]) { - // Note that "pages_[0]" is not nullptr if there is a small-size page - // because it is opened in refresh_page(). - if (table_[page_id] == STORAGE_INVALID_NODE_ID) { - Lock lock(&header_->mutex); - if (table_[page_id] == STORAGE_INVALID_NODE_ID) { - // Create a full-size page. - // Note that a small-size page is created in expand_page(). - const uint64_t page_node_size = - (sizeof(Unit) * (PAGE_SIZE / UNIT_SIZE)) + (sizeof(T) * PAGE_SIZE); - StorageNode page_node = - storage_->create_node(storage_node_id_, page_node_size); - table_[page_id] = page_node.id(); - } - } - } -} - -template <typename T> -void Pool<T>::expand() { - Lock lock(&header_->mutex); - if (size_ < PAGE_SIZE) { - // Create a small-size page or the first full-size page. - expand_page(); - refresh_page(); - } else { - // Create a table. - expand_table(); - refresh_table(); - } -} - -template <typename T> -void Pool<T>::expand_page() { - const uint64_t new_size = (size_ == 0) ? MIN_PAGE_SIZE : (size_ * 2); - const uint64_t page_node_size = - (sizeof(Unit) * (new_size / UNIT_SIZE)) + (sizeof(T) * new_size); - StorageNode page_node = - storage_->create_node(storage_node_id_, page_node_size); - if (size_ != 0) { - // Copy data from the current page and unlink it. - std::memcpy(static_cast<Unit *>(page_node.body()) + (size_ / UNIT_SIZE), - static_cast<Unit *>(pages_[0]) - (size_ / UNIT_SIZE), - page_node_size / 2); - try { - storage_->unlink_node(header_->page_storage_node_id); - } catch (...) { - storage_->unlink_node(page_node.id()); - throw; - } - } - header_->page_storage_node_id = page_node.id(); - header_->size = new_size; -} - -template <typename T> -void Pool<T>::expand_table() { - const uint64_t old_table_size = - (size_ <= PAGE_SIZE) ? 0 : (size_ / PAGE_SIZE); - const uint64_t new_table_size = - (old_table_size == 0) ? MIN_TABLE_SIZE : (old_table_size * 2); - const uint64_t new_size = new_table_size * PAGE_SIZE; - StorageNode table_node = storage_->create_node( - storage_node_id_, sizeof(uint32_t) * new_table_size); - uint32_t * const new_table = static_cast<uint32_t *>(table_node.body()); - uint64_t i; - if (old_table_size == 0) { - new_table[0] = header_->page_storage_node_id; - i = 1; - } else { - for (i = 0; i < old_table_size; ++i) { - new_table[i] = table_[i]; - } - } - for ( ; i < new_table_size; ++i) { - new_table[i] = STORAGE_INVALID_NODE_ID; - } - header_->table_storage_node_id = table_node.id(); - header_->size = new_size; -} - -template <typename T> -void Pool<T>::refresh() { - Lock lock(&header_->mutex); - if (size_ != header_->size) { - if (header_->size <= PAGE_SIZE) { - // Reopen a page because it is old. - refresh_page(); - } else { - // Reopen a table because it is old. - refresh_table(); - } - size_ = header_->size; - } -} - -template <typename T> -void Pool<T>::refresh_page() { - StorageNode page_node = - storage_->open_node(header_->page_storage_node_id); - if (!pages_) { - std::unique_ptr<void *[]> new_pages(new (std::nothrow) void *[1]); - if (!new_pages) { - GRNXX_ERROR() << "new void *[] failed: size = " << 1; - throw MemoryError(); - } - new_pages[0] = - static_cast<Unit *>(page_node.body()) + (header_->size / UNIT_SIZE); - pages_.swap(new_pages); - } else { - pages_[0] = - static_cast<Unit *>(page_node.body()) + (header_->size / UNIT_SIZE); - } -} - -template <typename T> -void Pool<T>::refresh_table() { - StorageNode table_node = - storage_->open_node(header_->table_storage_node_id); - uint32_t * const new_table = static_cast<uint32_t *>(table_node.body()); - const uint64_t new_table_size = header_->size / PAGE_SIZE; - std::unique_ptr<void *[]> new_pages( - new (std::nothrow) void *[new_table_size]); - if (!new_pages) { - GRNXX_ERROR() << "new void *[] failed: size = " << new_table_size; - throw MemoryError(); - } - // Initialize a new cache table. - const uint64_t old_table_size = size_ / PAGE_SIZE; - uint64_t i = 0; - for ( ; i < old_table_size; ++i) { - new_pages[i] = pages_[i]; - } - for ( ; i < new_table_size; ++i) { - new_pages[i] = nullptr; - } - pages_.swap(new_pages); - // Keep an old cache table because another thread may read it. - if (new_pages) { - try { - queue_.push(QueueEntry{ std::move(new_pages), clock_.now() }); - } catch (const std::exception &exception) { - GRNXX_ERROR() << "std::queue::push() failed"; - throw StandardError(exception); - } - } - table_ = new_table; -} - -template class Pool<int8_t>; -template class Pool<int16_t>; -template class Pool<int32_t>; -template class Pool<int64_t>; -template class Pool<uint8_t>; -template class Pool<uint16_t>; -template class Pool<uint32_t>; -template class Pool<uint64_t>; -template class Pool<double>; -template class Pool<GeoPoint>; - -namespace { - -constexpr uint32_t MAX_PAGE_ID = std::numeric_limits<uint32_t>::max() - 1; -constexpr uint32_t INVALID_PAGE_ID = MAX_PAGE_ID + 1; - -} // namespace - -PoolHeader<Bytes>::PoolHeader() - : size(0), - next_offset(0), - page_storage_node_id(STORAGE_INVALID_NODE_ID), - index_pool_storage_node_id(STORAGE_INVALID_NODE_ID), - mutex() {} - -PoolTableEntry::PoolTableEntry() - : page_storage_node_id(STORAGE_INVALID_NODE_ID), - size_in_use(0) {} - -Pool<Bytes>::Pool() - : storage_(nullptr), - storage_node_id_(STORAGE_INVALID_NODE_ID), - header_(nullptr), - index_pool_(), - pages_(), - table_(nullptr), - size_(0), - queue_(), - clock_() {} - -Pool<Bytes>::~Pool() {} - -Pool<Bytes> *Pool<Bytes>::create(Storage *storage, uint32_t storage_node_id) { - if (!storage) { - GRNXX_ERROR() << "invalid argument: storage == nullptr"; - throw LogicError(); - } - std::unique_ptr<Pool> pool(new (std::nothrow) Pool); - if (!pool) { - GRNXX_ERROR() << "new grnxx::map::Pool failed"; - throw MemoryError(); - } - pool->create_pool(storage, storage_node_id); - return pool.release(); -} - -Pool<Bytes> *Pool<Bytes>::open(Storage *storage, uint32_t storage_node_id) { - if (!storage) { - GRNXX_ERROR() << "invalid argument: storage == nullptr"; - throw LogicError(); - } - std::unique_ptr<Pool> pool(new (std::nothrow) Pool); - if (!pool) { - GRNXX_ERROR() << "new grnxx::map::Pool failed"; - throw MemoryError(); - } - pool->open_pool(storage, storage_node_id); - return pool.release(); -} - -void Pool<Bytes>::unlink(Storage *storage, uint32_t storage_node_id) { - std::unique_ptr<Pool> pool(Pool::open(storage, storage_node_id)); - storage->unlink_node(storage_node_id); -} - -void Pool<Bytes>::unset(int64_t key_id) { - uint64_t bytes_id; - if (!index_pool_->get(key_id, &bytes_id)) { - GRNXX_ERROR() << "not found: key_id = " << key_id; - throw LogicError(); - } - refresh_if_possible(); - index_pool_->unset(key_id); - unset_bytes(bytes_id); -} - -void Pool<Bytes>::reset(int64_t key_id, KeyArg dest_key) { - uint64_t src_bytes_id; - if (!index_pool_->get(key_id, &src_bytes_id)) { - GRNXX_ERROR() << "not found: key_id = " << key_id; - throw LogicError(); - } - refresh_if_possible(); - const uint64_t dest_bytes_id = add_bytes(dest_key); - index_pool_->reset(key_id, dest_bytes_id); - unset_bytes(src_bytes_id); -} - -int64_t Pool<Bytes>::add(KeyArg key) { - refresh_if_possible(); - const uint64_t bytes_id = add_bytes(key); - try { - const int64_t key_id = index_pool_->add(bytes_id); - return key_id; - } catch (...) { - unset_bytes(bytes_id); - throw; - } -} - -void Pool<Bytes>::defrag() { - index_pool_->defrag(); - refresh_if_possible(); - if (header_->size <= PAGE_SIZE) { - // Nothing to do. - return; - } - // Keys in the active page should not be moved. - const uint64_t offset_threshold = - header_->next_offset - (header_->next_offset % PAGE_SIZE); - // Keys in low-usage-rate pages should be moved. - const uint32_t size_in_use_threshold = - static_cast<uint32_t>(PAGE_SIZE * USAGE_RATE_THRESHOLD); - const int64_t max_key_id = index_pool_->max_key_id(); - uint32_t prev_page_id = INVALID_PAGE_ID; - uint8_t *page = nullptr; - for (int64_t key_id = MIN_KEY_ID; key_id <= max_key_id; ++key_id) { - // FIXME: "index_pool_->get/reset()" can be the bottleneck. - uint64_t bytes_id; - if (!index_pool_->get(key_id, &bytes_id)) { - continue; - } - const uint64_t offset = get_offset(bytes_id); - if (offset >= offset_threshold) { - continue; - } - const uint32_t page_id = static_cast<uint32_t>(offset / PAGE_SIZE); - if (page_id != prev_page_id) { - if (table_[page_id].size_in_use >= size_in_use_threshold) { - page = nullptr; - } else { - page = get_page(page_id); - } - prev_page_id = page_id; - } - if (!page) { - continue; - } - const uint32_t bytes_size = get_size(bytes_id); - const Bytes bytes(page + (offset % PAGE_SIZE), bytes_size); - const uint64_t new_bytes_id = add_bytes(bytes); - index_pool_->reset(key_id, new_bytes_id); - table_[page_id].size_in_use -= bytes_size; - if (table_[page_id].size_in_use == 0) { - // Unlink a page if this operation makes it empty. - storage_->unlink_node(table_[page_id].page_storage_node_id); - } - } -} - -void Pool<Bytes>::sweep(Duration lifetime) { - const Time threshold = clock_.now() - lifetime; - while (!queue_.empty()) { - QueueEntry &queue_entry = queue_.front(); - if (queue_entry.time <= threshold) { - queue_.pop(); - } - } -} - -void Pool<Bytes>::create_pool(Storage *storage, uint32_t storage_node_id) { - storage_ = storage; - const uint64_t header_node_size = sizeof(Header) + sizeof(TableEntry); - StorageNode header_node = - storage->create_node(storage_node_id, header_node_size); - storage_node_id_ = header_node.id(); - try { - header_ = static_cast<Header *>(header_node.body()); - *header_ = Header(); - index_pool_.reset(IndexPool::create(storage_, storage_node_id_)); - header_->index_pool_storage_node_id = index_pool_->storage_node_id(); - table_ = reinterpret_cast<TableEntry *>(header_ + 1); - *table_ = TableEntry(); - } catch (...) { - storage->unlink_node(storage_node_id_); - throw; - } -} - -void Pool<Bytes>::open_pool(Storage *storage, uint32_t storage_node_id) { - storage_ = storage; - StorageNode storage_node = storage->open_node(storage_node_id); - storage_node_id_ = storage_node.id(); - header_ = static_cast<Header *>(storage_node.body()); - index_pool_.reset(IndexPool::open(storage_, - header_->index_pool_storage_node_id)); - table_ = reinterpret_cast<TableEntry *>(header_ + 1); -} - -void Pool<Bytes>::unset_bytes(uint64_t bytes_id) { - if (bytes_id == EMPTY_BYTES_ID) { - // Nothing to do. - return; - } - const uint64_t bytes_offset = get_offset(bytes_id); - const uint32_t bytes_size = get_size(bytes_id); - if ((bytes_offset + bytes_size) > header_->next_offset) { - GRNXX_ERROR() << "invalid argument: bytes_offset = " << bytes_offset - << ", bytes_size = " << bytes_size - << ", next_offset = " << header_->next_offset; - throw LogicError(); - } - const uint32_t page_id = static_cast<uint32_t>(bytes_offset / PAGE_SIZE); - TableEntry * const table_entry = &table_[page_id]; - if (bytes_size > table_entry->size_in_use) { - GRNXX_ERROR() << "invalid argument: bytes_size = " << bytes_size - << ", size_in_use = " << table_entry->size_in_use; - throw LogicError(); - } - table_entry->size_in_use -= bytes_size; - if ((table_entry->size_in_use == 0) && - (page_id != (header_->next_offset / PAGE_SIZE))) { - // Unlink a page if this operation makes it empty. - storage_->unlink_node(table_entry->page_storage_node_id); - } -} - -uint64_t Pool<Bytes>::add_bytes(KeyArg bytes) { - const uint32_t bytes_size = static_cast<uint32_t>(bytes.size()); - if (bytes_size > MAX_KEY_SIZE) { - GRNXX_ERROR() << "invalid argument: key_size = " << bytes_size - << ", max_key_size = " << MAX_KEY_SIZE; - throw LogicError(); - } - if (bytes_size == 0) { - return EMPTY_BYTES_ID; - } - const uint64_t bytes_offset = reserve_space(bytes_size); - const uint32_t page_id = static_cast<uint32_t>(bytes_offset / PAGE_SIZE); - uint8_t * const page = get_page(page_id); - std::memcpy(page + (bytes_offset % PAGE_SIZE), bytes.data(), bytes_size); - TableEntry * const table_entry = &table_[page_id]; - table_entry->size_in_use += bytes_size; - return get_bytes_id(bytes_offset, bytes_size); -} - -uint8_t *Pool<Bytes>::open_page(uint32_t page_id) { - if (page_id >= (header_->size / PAGE_SIZE)) { - GRNXX_ERROR() << "invalid argument: page_id = " << page_id - << ", table_size = " << (header_->size / PAGE_SIZE); - throw LogicError(); - } - if (!pages_[page_id]) { - Lock lock(&header_->mutex); - if (!pages_[page_id]) { - // Open an existing full-size page. - // Note that a small-size page is opened in refresh_page(). - if (table_[page_id].page_storage_node_id == STORAGE_INVALID_NODE_ID) { - GRNXX_ERROR() << "not found: page_id = " << page_id; - throw LogicError(); - } - StorageNode page_node = - storage_->open_node(table_[page_id].page_storage_node_id); - pages_[page_id] = static_cast<uint8_t *>(page_node.body()); - } - } - return pages_[page_id]; -} - -uint64_t Pool<Bytes>::reserve_space(uint32_t size) { - uint64_t offset = header_->next_offset; - const uint32_t page_size = static_cast<uint32_t>( - (header_->size < PAGE_SIZE) ? header_->size : PAGE_SIZE); - const uint32_t page_size_left = static_cast<uint32_t>( - ((offset % PAGE_SIZE) == 0) ? 0 : (page_size - (offset % PAGE_SIZE))); - if (size <= page_size_left) { - header_->next_offset += size; - return offset; - } - if ((header_->next_offset + size) > header_->size) { - expand(size); - } - if (page_size == PAGE_SIZE) { - offset += page_size_left; - } - const uint32_t page_id = static_cast<uint32_t>(offset / PAGE_SIZE); - if (page_id > 0) { - if ((table_[page_id - 1].size_in_use == 0) && (page_size_left != 0)) { - // Unlink an empty page if it is fixed. - storage_->unlink_node(table_[page_id - 1].page_storage_node_id); - } - } - if (!pages_[page_id]) { - // Note that "pages_[0]" is not nullptr if there is a small-size page - // because it is opened in refresh_page(). - if (table_[page_id].page_storage_node_id == STORAGE_INVALID_NODE_ID) { - Lock lock(&header_->mutex); - if (table_[page_id].page_storage_node_id == STORAGE_INVALID_NODE_ID) { - // Create a full-size page. - // Note that a small-size page is created in expand_page(). - StorageNode page_node = - storage_->create_node(storage_node_id_, PAGE_SIZE); - table_[page_id].page_storage_node_id = page_node.id(); - } - } - } - header_->next_offset = offset + size; - return offset; -} - -void Pool<Bytes>::expand(uint32_t additional_size) { - Lock lock(&header_->mutex); - if (size_ < PAGE_SIZE) { - // Create a small-size page or the first full-size page. - expand_page(additional_size); - refresh_page(); - } else { - // Create a table. - expand_table(additional_size); - refresh_table(); - } -} - -void Pool<Bytes>::expand_page(uint32_t additional_size) { - const uint64_t min_size = size_ + additional_size; - uint64_t new_size = (size_ == 0) ? MIN_PAGE_SIZE : (size_ * 2); - while (new_size < min_size) { - new_size *= 2; - } - StorageNode page_node = storage_->create_node(storage_node_id_, new_size); - if (size_ != 0) { - // Copy data from the current page and unlink it. - std::memcpy(page_node.body(), pages_[0], size_); - try { - storage_->unlink_node(header_->page_storage_node_id); - } catch (...) { - storage_->unlink_node(page_node.id()); - throw; - } - } - table_[0].page_storage_node_id = page_node.id(); - header_->page_storage_node_id = page_node.id(); - header_->size = new_size; -} - -void Pool<Bytes>::expand_table(uint32_t) { - const uint64_t old_table_size = size_ / PAGE_SIZE; - const uint64_t new_table_size = (old_table_size < MIN_TABLE_SIZE) ? - MIN_TABLE_SIZE : (old_table_size * 2); - const uint64_t new_size = new_table_size * PAGE_SIZE; - StorageNode table_node = storage_->create_node( - storage_node_id_, sizeof(TableEntry) * new_table_size); - TableEntry * const new_table = static_cast<TableEntry *>(table_node.body()); - uint64_t i = 0; - for ( ; i < old_table_size; ++i) { - new_table[i] = table_[i]; - } - for ( ; i < new_table_size; ++i) { - new_table[i] = TableEntry(); - } - header_->table_storage_node_id = table_node.id(); - header_->size = new_size; -} - -void Pool<Bytes>::refresh() { - if (size_ != header_->size) { - Lock lock(&header_->mutex); - if (header_->size <= PAGE_SIZE) { - // Reopen a page because it is old. - refresh_page(); - } else { - // Reopen a table because it is old. - refresh_table(); - } - size_ = header_->size; - } -} - -void Pool<Bytes>::refresh_page() { - StorageNode page_node = - storage_->open_node(header_->page_storage_node_id); - if (!pages_) { - std::unique_ptr<uint8_t *[]> new_pages(new (std::nothrow) uint8_t *[1]); - if (!new_pages) { - GRNXX_ERROR() << "new uint8_t *[] failed: size = " << 1; - throw MemoryError(); - } - new_pages[0] = static_cast<uint8_t *>(page_node.body()); - pages_.swap(new_pages); - } else { - pages_[0] = static_cast<uint8_t *>(page_node.body()); - } -} - -void Pool<Bytes>::refresh_table() { - StorageNode table_node = - storage_->open_node(header_->table_storage_node_id); - TableEntry * const new_table = - static_cast<TableEntry *>(table_node.body()); - const uint64_t new_table_size = header_->size / PAGE_SIZE; - std::unique_ptr<uint8_t *[]> new_pages( - new (std::nothrow) uint8_t *[new_table_size]); - if (!new_pages) { - GRNXX_ERROR() << "new uint8_t *[] failed: size = " << new_table_size; - throw MemoryError(); - } - // Initialize a new cache table. - const uint64_t old_table_size = size_ / PAGE_SIZE; - uint64_t i = 0; - for ( ; i < old_table_size; ++i) { - new_pages[i] = pages_[i]; - } - for ( ; i < new_table_size; ++i) { - new_pages[i] = nullptr; - } - pages_.swap(new_pages); - // Keep an old cache table because another thread may read it. - if (new_pages) { - try { - queue_.push(QueueEntry{ std::move(new_pages), clock_.now() }); - } catch (const std::exception &exception) { - GRNXX_ERROR() << "std::queue::push() failed"; - throw StandardError(exception); - } - } - table_ = new_table; -} - -} // namespace map -} // namespace grnxx Deleted: lib/grnxx/map/pool.hpp (+0 -344) 100644 =================================================================== --- lib/grnxx/map/pool.hpp 2013-08-23 10:46:34 +0900 (fb06ea5) +++ /dev/null @@ -1,344 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_MAP_POOL_HPP -#define GRNXX_MAP_POOL_HPP - -#include "grnxx/features.hpp" - -#include <memory> -#include <queue> - -#include "grnxx/bytes.hpp" -#include "grnxx/duration.hpp" -#include "grnxx/mutex.hpp" -#include "grnxx/periodic_clock.hpp" -#include "grnxx/time.hpp" -#include "grnxx/traits.hpp" -#include "grnxx/types.hpp" - -namespace grnxx { - -class Storage; - -namespace map { - -// The minimum key ID. -constexpr int64_t POOL_MIN_KEY_ID = 0; -// The maximum key ID. -constexpr int64_t POOL_MAX_KEY_ID = (1LL << 40) - 2; - -template <typename T> -struct PoolHeader { - int64_t max_key_id; - uint64_t num_keys; - uint64_t size; - uint64_t latest_available_unit_id; - union { - uint32_t page_storage_node_id; - uint32_t table_storage_node_id; - }; - Mutex mutex; - - PoolHeader(); -}; - -struct PoolUnit { - uint64_t validity_bits; - uint64_t next_available_unit_id; -}; - -template <typename T> -struct PoolQueueEntry { - std::unique_ptr<void *[]> page; - Time time; -}; - -template <typename T> -class Pool { - using Header = PoolHeader<T>; - using Unit = PoolUnit; - using QueueEntry = PoolQueueEntry<T>; - - static constexpr int64_t MIN_KEY_ID = POOL_MIN_KEY_ID; - static constexpr int64_t MAX_KEY_ID = POOL_MAX_KEY_ID; - - static constexpr uint64_t UNIT_SIZE = 64; - static constexpr uint64_t PAGE_SIZE = 1ULL << 16; - - static constexpr uint64_t MIN_PAGE_SIZE = UNIT_SIZE; - static constexpr uint64_t MIN_TABLE_SIZE = 1ULL << 10; - - public: - using Key = typename Traits<T>::Type; - using KeyArg = typename Traits<T>::ArgumentType; - - Pool(); - ~Pool(); - - static Pool *create(Storage *storage, uint32_t storage_node_id); - static Pool *open(Storage *storage, uint32_t storage_node_id); - - static void unlink(Storage *storage, uint32_t storage_node_id); - - uint32_t storage_node_id() const { - return storage_node_id_; - } - - static constexpr int64_t min_key_id() { - return MIN_KEY_ID; - } - int64_t max_key_id() const { - return header_->max_key_id; - } - uint64_t num_keys() const { - return header_->num_keys; - } - - bool get(int64_t key_id, Key *key) { - refresh_if_possible(); - const void * const page = get_page(key_id / PAGE_SIZE); - const uint64_t local_key_id = key_id % PAGE_SIZE; - const Unit * const unit = - static_cast<const Unit *>(page) - (local_key_id / UNIT_SIZE) - 1; - if (~unit->validity_bits & (1ULL << (local_key_id % UNIT_SIZE))) { - // Not found. - return false; - } - *key = static_cast<const T *>(page)[local_key_id]; - return true; - } - - Key get_key(int64_t key_id) { - refresh_if_possible(); - const void * const page = get_page(key_id / PAGE_SIZE); - return static_cast<const T *>(page)[key_id % PAGE_SIZE]; - } - - bool get_bit(int64_t key_id) { - refresh_if_possible(); - const void * const page = get_page(key_id / PAGE_SIZE); - const uint64_t local_key_id = key_id % PAGE_SIZE; - const Unit * const unit = - static_cast<const Unit *>(page) - (local_key_id / UNIT_SIZE) - 1; - return unit->validity_bits & (1ULL << (local_key_id % UNIT_SIZE)); - } - - void unset(int64_t key_id); - void reset(int64_t key_id, KeyArg dest_key); - - int64_t add(KeyArg key); - - void defrag(); - void sweep(Duration lifetime); - - private: - Storage *storage_; - uint32_t storage_node_id_; - Header *header_; - std::unique_ptr<void *[]> pages_; - uint32_t *table_; - uint64_t size_; - std::queue<QueueEntry> queue_; - PeriodicClock clock_; - - void create_pool(Storage *storage, uint32_t storage_node_id); - void open_pool(Storage *storage, uint32_t storage_node_id); - - void *get_page(uint64_t page_id) { - return pages_[page_id] ? pages_[page_id] : open_page(page_id); - } - void *open_page(uint64_t page_id); - - void reserve_key_id(int64_t key_id); - - void expand(); - void expand_page(); - void expand_table(); - - void refresh_if_possible() { - if (size_ != header_->size) { - refresh(); - } - } - void refresh(); - void refresh_page(); - void refresh_table(); -}; - -template <> -struct PoolHeader<Bytes> { - uint64_t size; - uint64_t next_offset; - union { - uint32_t page_storage_node_id; - uint32_t table_storage_node_id; - }; - uint32_t index_pool_storage_node_id; - Mutex mutex; - - PoolHeader(); -}; - -struct PoolTableEntry { - uint32_t page_storage_node_id; - uint32_t size_in_use; - - PoolTableEntry(); -}; - -template <> -struct PoolQueueEntry<Bytes> { - std::unique_ptr<uint8_t *[]> page; - Time time; -}; - -template <> -class Pool<Bytes> { - using Header = PoolHeader<Bytes>; - using IndexPool = Pool<uint64_t>; - using TableEntry = PoolTableEntry; - using QueueEntry = PoolQueueEntry<Bytes>; - - static constexpr int64_t MIN_KEY_ID = POOL_MIN_KEY_ID; - static constexpr int64_t MAX_KEY_ID = POOL_MAX_KEY_ID; - static constexpr uint64_t MAX_KEY_SIZE = 4096; - - static constexpr uint64_t PAGE_SIZE = 1ULL << 20; - - static constexpr uint64_t MIN_PAGE_SIZE = 64; - static constexpr uint64_t MIN_TABLE_SIZE = 1ULL << 10; - - static constexpr uint64_t BYTES_ID_SIZE_MASK = (1ULL << 13) - 1; - - static constexpr uint64_t EMPTY_BYTES_ID = 0; - - static constexpr double USAGE_RATE_THRESHOLD = 0.5; - - public: - using Key = typename Traits<Bytes>::Type; - using KeyArg = typename Traits<Bytes>::ArgumentType; - - Pool(); - ~Pool(); - - static Pool *create(Storage *storage, uint32_t storage_node_id); - static Pool *open(Storage *storage, uint32_t storage_node_id); - - static void unlink(Storage *storage, uint32_t storage_node_id); - - uint32_t storage_node_id() const { - return storage_node_id_; - } - - static constexpr int64_t min_key_id() { - return IndexPool::min_key_id(); - } - int64_t max_key_id() const { - return index_pool_->max_key_id(); - } - uint64_t num_keys() const { - return index_pool_->num_keys(); - } - - bool get(int64_t key_id, Key *key) { - uint64_t bytes_id; - if (!index_pool_->get(key_id, &bytes_id)) { - // Not found. - return false; - } - *key = get_bytes(bytes_id); - return true; - } - - Key get_key(int64_t key_id) { - return get_bytes(index_pool_->get_key(key_id)); - } - - bool get_bit(int64_t key_id) { - return index_pool_->get_bit(key_id); - } - - void unset(int64_t key_id); - void reset(int64_t key_id, KeyArg dest_key); - - int64_t add(KeyArg key); - - void defrag(); - void sweep(Duration lifetime); - - private: - Storage *storage_; - uint32_t storage_node_id_; - Header *header_; - std::unique_ptr<IndexPool> index_pool_; - std::unique_ptr<uint8_t *[]> pages_; - TableEntry *table_; - uint64_t size_; - std::queue<QueueEntry> queue_; - PeriodicClock clock_; - - void create_pool(Storage *storage, uint32_t storage_node_id); - void open_pool(Storage *storage, uint32_t storage_node_id); - - Key get_bytes(uint64_t bytes_id) { - if (bytes_id == EMPTY_BYTES_ID) { - return Bytes("", 0); - } - refresh_if_possible(); - const uint64_t offset = get_offset(bytes_id); - const uint32_t page_id = static_cast<uint32_t>(offset / PAGE_SIZE); - return Bytes(get_page(page_id) + (offset % PAGE_SIZE), get_size(bytes_id)); - } - void unset_bytes(uint64_t bytes_id); - uint64_t add_bytes(KeyArg bytes); - - uint8_t *get_page(uint32_t page_id) { - return pages_[page_id] ? pages_[page_id] : open_page(page_id); - } - uint8_t *open_page(uint32_t page_id); - - uint64_t reserve_space(uint32_t size); - - static uint64_t get_bytes_id(uint64_t offset, uint32_t size) { - return (offset * (BYTES_ID_SIZE_MASK + 1)) | size; - } - static uint64_t get_offset(uint64_t bytes_id) { - return bytes_id / (BYTES_ID_SIZE_MASK + 1); - } - static uint32_t get_size(uint64_t bytes_id) { - return static_cast<uint32_t>(bytes_id & BYTES_ID_SIZE_MASK); - } - - void expand(uint32_t additional_size); - void expand_page(uint32_t additional_size); - void expand_table(uint32_t additional_size); - - void refresh_if_possible() { - if (size_ != header_->size) { - refresh(); - } - } - void refresh(); - void refresh_page(); - void refresh_table(); -}; - -} // namespace map -} // namespace grnxx - -#endif // GRNXX_MAP_POOL_HPP Deleted: lib/grnxx/map/scanner_impl.cpp (+0 -75) 100644 =================================================================== --- lib/grnxx/map/scanner_impl.cpp 2013-08-23 10:46:34 +0900 (8c09113) +++ /dev/null @@ -1,75 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/map/scanner_impl.hpp" - -#include <memory> -#include <new> - -#include "grnxx/bytes.hpp" -#include "grnxx/charset.hpp" -#include "grnxx/exception.hpp" -#include "grnxx/logger.hpp" -#include "grnxx/map.hpp" - -namespace grnxx { -namespace map { - -template <typename T> -ScannerImpl<T>::ScannerImpl() : map_(), query_(), charset_() {} - -template <typename T> -ScannerImpl<T>::~ScannerImpl() {} - -template <typename T> -ScannerImpl<T> *ScannerImpl<T>::create(Map<T> *map, KeyArg query, - const Charset *charset) { - std::unique_ptr<ScannerImpl> scanner(new (std::nothrow) ScannerImpl); - if (!scanner) { - GRNXX_ERROR() << "new grnxx::map::ScannerImpl failed"; - throw MemoryError(); - } - scanner->map_ = map; - scanner->query_ = query; - scanner->charset_ = charset; - return scanner.release(); -} - -template <typename T> -bool ScannerImpl<T>::next() { - this->offset_ += this->size_; - while (this->offset_ < query_.size()) { - const T rest = query_.except_prefix(this->offset_); - if (map_->find_longest_prefix_match(rest, &this->key_id_, &this->key_)) { - this->size_ = this->key_.size(); - return true; - } - // Move to the next character. - if (charset_) { - this->offset_ += charset_->get_char_size(rest); - } else { - ++this->offset_; - } - } - this->size_ = 0; - return false; -} - -template class ScannerImpl<Bytes>; - -} // namespace map -} // namespace grnxx Deleted: lib/grnxx/map/scanner_impl.hpp (+0 -55) 100644 =================================================================== --- lib/grnxx/map/scanner_impl.hpp 2013-08-23 10:46:34 +0900 (3d23ce2) +++ /dev/null @@ -1,55 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_MAP_SCANNER_IMPL_HPP -#define GRNXX_MAP_SCANNER_IMPL_HPP - -#include "grnxx/features.hpp" - -#include "grnxx/map_scanner.hpp" - -namespace grnxx { - -class Charset; -template <typename T> class Map; - -namespace map { - -template <typename T> -class ScannerImpl : public MapScanner<T> { - public: - using Key = typename MapScanner<T>::Key; - using KeyArg = typename MapScanner<T>::KeyArg; - - ScannerImpl(); - ~ScannerImpl(); - - static ScannerImpl *create(Map<T> *map, KeyArg query, - const Charset *charset); - - bool next(); - - protected: - Map<T> *map_; - Key query_; - const Charset *charset_; -}; - -} // namespace map -} // namespace grnxx - -#endif // GRNXX_MAP_SCANNER_IMPL_HPP Deleted: lib/grnxx/map_cursor.cpp (+0 -81) 100644 =================================================================== --- lib/grnxx/map_cursor.cpp 2013-08-23 10:46:34 +0900 (9e9e284) +++ /dev/null @@ -1,81 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/map_cursor.hpp" - -#include <limits> - -#include "grnxx/bytes.hpp" -#include "grnxx/exception.hpp" -#include "grnxx/geo_point.hpp" -#include "grnxx/logger.hpp" -#include "grnxx/map.hpp" -#include "grnxx/string_builder.hpp" - -namespace grnxx { - -#define GRNXX_FLAGS_WRITE(flag) do { \ - if (flags & flag) { \ - if (!is_first) { \ - builder << " | "; \ - } \ - builder << #flag; \ - is_first = false; \ - } \ -} while (false) - -StringBuilder &operator<<(StringBuilder &builder, MapCursorFlags flags) { - bool is_first = true; - GRNXX_FLAGS_WRITE(MAP_CURSOR_ORDER_BY_ID); - GRNXX_FLAGS_WRITE(MAP_CURSOR_ORDER_BY_KEY); - GRNXX_FLAGS_WRITE(MAP_CURSOR_REVERSE_ORDER); - if (is_first) { - builder << "MAP_CURSOR_DEFAULT"; - } - return builder; -} - -MapCursorOptions::MapCursorOptions() - : flags(MAP_CURSOR_DEFAULT), - offset(0), - limit(std::numeric_limits<uint64_t>::max()) {} - -template <typename T> -MapCursor<T>::MapCursor() : key_id_(MAP_INVALID_KEY_ID), key_() {} - -template <typename T> -MapCursor<T>::~MapCursor() {} - -template <typename T> -bool MapCursor<T>::remove() { - GRNXX_ERROR() << "invalid operation"; - throw LogicError(); -} - -template class MapCursor<int8_t>; -template class MapCursor<uint8_t>; -template class MapCursor<int16_t>; -template class MapCursor<uint16_t>; -template class MapCursor<int32_t>; -template class MapCursor<uint32_t>; -template class MapCursor<int64_t>; -template class MapCursor<uint64_t>; -template class MapCursor<double>; -template class MapCursor<GeoPoint>; -template class MapCursor<Bytes>; - -} // namespace grnxx Deleted: lib/grnxx/map_cursor.hpp (+0 -91) 100644 =================================================================== --- lib/grnxx/map_cursor.hpp 2013-08-23 10:46:34 +0900 (9297eba) +++ /dev/null @@ -1,91 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_MAP_CURSOR_HPP -#define GRNXX_MAP_CURSOR_HPP - -#include "grnxx/features.hpp" - -#include "grnxx/flags_impl.hpp" -#include "grnxx/traits.hpp" -#include "grnxx/types.hpp" - -namespace grnxx { - -class StringBuilder; - -template <typename T> class Map; - -// TODO: How to implement NEAR cursor. -struct MapCursorFlagsIdentifier; -using MapCursorFlags = FlagsImpl<MapCursorFlagsIdentifier>; - -// Use the default settings. -constexpr MapCursorFlags MAP_CURSOR_DEFAULT = - MapCursorFlags::define(0x00); -// Sort keys by ID. -constexpr MapCursorFlags MAP_CURSOR_ORDER_BY_ID = - MapCursorFlags::define(0x01); -// Sort keys by key. -constexpr MapCursorFlags MAP_CURSOR_ORDER_BY_KEY = - MapCursorFlags::define(0x02); -// Access keys in reverse order. -constexpr MapCursorFlags MAP_CURSOR_REVERSE_ORDER = - MapCursorFlags::define(0x10); - -StringBuilder &operator<<(StringBuilder &builder, MapCursorFlags flags); - -struct MapCursorOptions { - MapCursorFlags flags; - uint64_t offset; - uint64_t limit; - - // Initialize the members. - MapCursorOptions(); -}; - -template <typename T> -class MapCursor { - public: - using Key = typename Traits<T>::Type; - using KeyArg = typename Traits<T>::ArgumentType; - - MapCursor(); - virtual ~MapCursor(); - - // Move the cursor to the next key and return true on success. - virtual bool next() = 0; - // Remove the current key and return true on success. - virtual bool remove(); - - // Return the ID of the current key. - int64_t key_id() const { - return key_id_; - } - // Return the current key. - const Key &key() const { - return key_; - } - - protected: - int64_t key_id_; - Key key_; -}; - -} // namespace grnxx - -#endif // GRNXX_MAP_CURSOR_HPP Deleted: lib/grnxx/map_cursor_query.hpp (+0 -326) 100644 =================================================================== --- lib/grnxx/map_cursor_query.hpp 2013-08-23 10:46:34 +0900 (9ebe771) +++ /dev/null @@ -1,326 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_MAP_CURSOR_QUERY_HPP -#define GRNXX_MAP_CURSOR_QUERY_HPP - -#include "grnxx/features.hpp" - -#include "grnxx/flags_impl.hpp" -#include "grnxx/types.hpp" - -namespace grnxx { - -// MapCursorAllKeys. - -template <typename T> struct MapCursorAllKeys {}; - -// MapCursorKeyID - -template <typename T> struct MapCursorKeyID {}; - -struct MapCursorKeyIDFlagsIdentifier; -using MapCursorKeyIDFlags = FlagsImpl<MapCursorKeyIDFlagsIdentifier>; - -constexpr MapCursorKeyIDFlags MAP_CURSOR_KEY_ID_LESS = - MapCursorKeyIDFlags::define(0x01); -constexpr MapCursorKeyIDFlags MAP_CURSOR_KEY_ID_LESS_EQUAL = - MapCursorKeyIDFlags::define(0x02); -constexpr MapCursorKeyIDFlags MAP_CURSOR_KEY_ID_GREATER = - MapCursorKeyIDFlags::define(0x04); -constexpr MapCursorKeyIDFlags MAP_CURSOR_KEY_ID_GREATER_EQUAL = - MapCursorKeyIDFlags::define(0x08); - -template <typename T> -struct MapCursorKeyIDRange { - MapCursorKeyIDFlags flags; - int64_t min; - int64_t max; -}; - -template <typename T> -struct MapCursorKeyIDLess { - int64_t max; - constexpr MapCursorKeyIDFlags flags() const { - return MAP_CURSOR_KEY_ID_LESS; - } - operator MapCursorKeyIDRange<T>() const { - return MapCursorKeyIDRange<T>{ flags(), 0, max }; - } -}; - -template <typename T> -struct MapCursorKeyIDLessEqual { - int64_t max; - constexpr MapCursorKeyIDFlags flags() const { - return MAP_CURSOR_KEY_ID_LESS_EQUAL; - } - operator MapCursorKeyIDRange<T>() const { - return MapCursorKeyIDRange<T>{ flags(), 0, max }; - }; -}; - -template <typename T> -struct MapCursorKeyIDGreater { - int64_t min; - constexpr MapCursorKeyIDFlags flags() const { - return MAP_CURSOR_KEY_ID_GREATER; - } - operator MapCursorKeyIDRange<T>() const { - return MapCursorKeyIDRange<T>{ flags(), min, 0 }; - } -}; - -template <typename T> -struct MapCursorKeyIDGreaterEqual { - int64_t min; - constexpr MapCursorKeyIDFlags flags() const { - return MAP_CURSOR_KEY_ID_GREATER_EQUAL; - } - operator MapCursorKeyIDRange<T>() const { - return MapCursorKeyIDRange<T>{ flags(), min, 0 }; - } -}; - -template <typename T> -MapCursorKeyIDLess<T> operator<(MapCursorKeyID<T>, int64_t max) { - return MapCursorKeyIDLess<T>{ max }; -} -template <typename T> -MapCursorKeyIDLessEqual<T> operator<=(MapCursorKeyID<T>, int64_t max) { - return MapCursorKeyIDLessEqual<T>{ max }; -} -template <typename T> -MapCursorKeyIDGreater<T> operator>(MapCursorKeyID<T>, int64_t min) { - return MapCursorKeyIDGreater<T>{ min }; -} -template <typename T> -MapCursorKeyIDGreaterEqual<T> operator>=(MapCursorKeyID<T>, int64_t min) { - return MapCursorKeyIDGreaterEqual<T>{ min }; -} - -template <typename T> -MapCursorKeyIDGreater<T> operator<(int64_t min, MapCursorKeyID<T>) { - return MapCursorKeyIDGreater<T>{ min }; -} -template <typename T> -MapCursorKeyIDGreaterEqual<T> operator<=(int64_t min, MapCursorKeyID<T>) { - return MapCursorKeyIDGreaterEqual<T>{ min }; -} -template <typename T> -MapCursorKeyIDLess<T> operator>(int64_t max, MapCursorKeyID<T>) { - return MapCursorKeyIDLess<T>{ max }; -} -template <typename T> -MapCursorKeyIDLessEqual<T> operator>=(int64_t max, MapCursorKeyID<T>) { - return MapCursorKeyIDLessEqual<T>{ max }; -} - -template <typename T> -MapCursorKeyIDRange<T> operator&&(MapCursorKeyIDLess<T> less, - MapCursorKeyIDGreater<T> greater) { - return MapCursorKeyIDRange<T>{ less.flags() | greater.flags(), - greater.min, less.max }; -} -template <typename T> -MapCursorKeyIDRange<T> operator&&(MapCursorKeyIDLess<T> less, - MapCursorKeyIDGreaterEqual<T> greater) { - return MapCursorKeyIDRange<T>{ less.flags() | greater.flags(), - greater.min, less.max }; -} -template <typename T> -MapCursorKeyIDRange<T> operator&&(MapCursorKeyIDLessEqual<T> less, - MapCursorKeyIDGreater<T> greater) { - return MapCursorKeyIDRange<T>{ less.flags() | greater.flags(), - greater.min, less.max }; -} -template <typename T> -MapCursorKeyIDRange<T> operator&&(MapCursorKeyIDLessEqual<T> less, - MapCursorKeyIDGreaterEqual<T> greater) { - return MapCursorKeyIDRange<T>{ less.flags() | greater.flags(), - greater.min, less.max }; -} -template <typename T> -MapCursorKeyIDRange<T> operator&&(MapCursorKeyIDGreater<T> greater, - MapCursorKeyIDLess<T> less) { - return less && greater; -} -template <typename T> -MapCursorKeyIDRange<T> operator&&(MapCursorKeyIDGreater<T> greater, - MapCursorKeyIDLessEqual<T> less) { - return less && greater; -} -template <typename T> -MapCursorKeyIDRange<T> operator&&(MapCursorKeyIDGreaterEqual<T> greater, - MapCursorKeyIDLess<T> less) { - return less && greater; -} -template <typename T> -MapCursorKeyIDRange<T> operator&&(MapCursorKeyIDGreaterEqual<T> greater, - MapCursorKeyIDLessEqual<T> less) { - return less && greater; -} - -// MapCursorKey - -template <typename T> struct MapCursorKey {}; - -struct MapCursorKeyFlagsIdentifier; -using MapCursorKeyFlags = FlagsImpl<MapCursorKeyFlagsIdentifier>; - -constexpr MapCursorKeyFlags MAP_CURSOR_KEY_LESS = - MapCursorKeyFlags::define(0x01); -constexpr MapCursorKeyFlags MAP_CURSOR_KEY_LESS_EQUAL = - MapCursorKeyFlags::define(0x02); -constexpr MapCursorKeyFlags MAP_CURSOR_KEY_GREATER = - MapCursorKeyFlags::define(0x04); -constexpr MapCursorKeyFlags MAP_CURSOR_KEY_GREATER_EQUAL = - MapCursorKeyFlags::define(0x08); - -template <typename T> -struct MapCursorKeyRange { - MapCursorKeyFlags flags; - T min; - T max; -}; - -template <typename T> -struct MapCursorKeyLess { - T max; - constexpr MapCursorKeyFlags flags() const { - return MAP_CURSOR_KEY_LESS; - } - operator MapCursorKeyRange<T>() const { - return MapCursorKeyRange<T>{ flags(), T(), max }; - } -}; - -template <typename T> -struct MapCursorKeyLessEqual { - T max; - constexpr MapCursorKeyFlags flags() const { - return MAP_CURSOR_KEY_LESS_EQUAL; - } - operator MapCursorKeyRange<T>() const { - return MapCursorKeyRange<T>{ flags(), T(), max }; - } -}; - -template <typename T> -struct MapCursorKeyGreater { - T min; - constexpr MapCursorKeyFlags flags() const { - return MAP_CURSOR_KEY_GREATER; - } - operator MapCursorKeyRange<T>() const { - return MapCursorKeyRange<T>{ flags(), min, T() }; - } -}; - -template <typename T> -struct MapCursorKeyGreaterEqual { - T min; - constexpr MapCursorKeyFlags flags() const { - return MAP_CURSOR_KEY_GREATER_EQUAL; - } - operator MapCursorKeyRange<T>() const { - return MapCursorKeyRange<T>{ flags(), min, T() }; - } -}; - -template <typename T> -MapCursorKeyLess<T> operator<(MapCursorKey<T>, T max) { - return MapCursorKeyLess<T>{ max }; -} -template <typename T> -MapCursorKeyLessEqual<T> operator<=(MapCursorKey<T>, T max) { - return MapCursorKeyLessEqual<T>{ max }; -} -template <typename T> -MapCursorKeyGreater<T> operator>(MapCursorKey<T>, T min) { - return MapCursorKeyGreater<T>{ min }; -} -template <typename T> -MapCursorKeyGreaterEqual<T> operator>=(MapCursorKey<T>, T min) { - return MapCursorKeyGreaterEqual<T>{ min }; -} - -template <typename T> -MapCursorKeyGreater<T> operator<(T min, MapCursorKey<T>) { - return MapCursorKeyGreater<T>{ min }; -} -template <typename T> -MapCursorKeyGreaterEqual<T> operator<=(T min, MapCursorKey<T>) { - return MapCursorKeyGreaterEqual<T>{ min }; -} -template <typename T> -MapCursorKeyLess<T> operator>(T max, MapCursorKey<T>) { - return MapCursorKeyLess<T>{ max }; -} -template <typename T> -MapCursorKeyLessEqual<T> operator>=(T max, MapCursorKey<T>) { - return MapCursorKeyLessEqual<T>{ max }; -} - -template <typename T> -MapCursorKeyRange<T> operator&&(MapCursorKeyLess<T> less, - MapCursorKeyGreater<T> greater) { - return MapCursorKeyRange<T>{ less.flags() | greater.flags(), - greater.min, less.max }; -} -template <typename T> -MapCursorKeyRange<T> operator&&(MapCursorKeyLess<T> less, - MapCursorKeyGreaterEqual<T> greater) { - return MapCursorKeyRange<T>{ less.flags() | greater.flags(), - greater.min, less.max }; -} -template <typename T> -MapCursorKeyRange<T> operator&&(MapCursorKeyLessEqual<T> less, - MapCursorKeyGreater<T> greater) { - return MapCursorKeyRange<T>{ less.flags() | greater.flags(), - greater.min, less.max }; -} -template <typename T> -MapCursorKeyRange<T> operator&&(MapCursorKeyLessEqual<T> less, - MapCursorKeyGreaterEqual<T> greater) { - return MapCursorKeyRange<T>{ less.flags() | greater.flags(), - greater.min, less.max }; -} -template <typename T> -MapCursorKeyRange<T> operator&&(MapCursorKeyGreater<T> greater, - MapCursorKeyLess<T> less) { - return less && greater; -} -template <typename T> -MapCursorKeyRange<T> operator&&(MapCursorKeyGreater<T> greater, - MapCursorKeyLessEqual<T> less) { - return less && greater; -} -template <typename T> -MapCursorKeyRange<T> operator&&(MapCursorKeyGreaterEqual<T> greater, - MapCursorKeyLess<T> less) { - return less && greater; -} -template <typename T> -MapCursorKeyRange<T> operator&&(MapCursorKeyGreaterEqual<T> greater, - MapCursorKeyLessEqual<T> less) { - return less && greater; -} - -} // namespace grnxx - -#endif // GRNXX_MAP_CURSOR_QUERY_HPP Deleted: lib/grnxx/map_scanner.cpp (+0 -37) 100644 =================================================================== --- lib/grnxx/map_scanner.cpp 2013-08-23 10:46:34 +0900 (8814983) +++ /dev/null @@ -1,37 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/map_scanner.hpp" - -#include "grnxx/bytes.hpp" -#include "grnxx/map.hpp" - -namespace grnxx { - -template <typename T> -MapScanner<T>::MapScanner() - : offset_(0), - size_(0), - key_id_(MAP_INVALID_KEY_ID), - key_() {} - -template <typename T> -MapScanner<T>::~MapScanner() {} - -template class MapScanner<Bytes>; - -} // namespace grnxx Deleted: lib/grnxx/map_scanner.hpp (+0 -70) 100644 =================================================================== --- lib/grnxx/map_scanner.hpp 2013-08-23 10:46:34 +0900 (b28af1c) +++ /dev/null @@ -1,70 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_MAP_SCANNER_HPP -#define GRNXX_MAP_SCANNER_HPP - -#include "grnxx/features.hpp" - -#include "grnxx/flags_impl.hpp" -#include "grnxx/traits.hpp" -#include "grnxx/types.hpp" - -namespace grnxx { - -class Charset; -class Storage; - -template <typename T> -class MapScanner { - public: - using Key = typename Traits<T>::Type; - using KeyArg = typename Traits<T>::ArgumentType; - - MapScanner(); - virtual ~MapScanner(); - - // Find the next key from the rest of the query and return true on success. - virtual bool next() = 0; - - // Return the start position of the found key. - uint64_t offset() const { - return offset_; - } - // Return the size of the found key. - uint64_t size() const { - return size_; - } - // Return the ID of the found key. - int64_t key_id() const { - return key_id_; - } - // Return the found key. - const Key &key() const { - return key_; - } - - protected: - uint64_t offset_; - uint64_t size_; - int64_t key_id_; - Key key_; -}; - -} // namespace grnxx - -#endif // GRNXX_MAP_SCANNER_HPP Deleted: lib/grnxx/mutex.cpp (+0 -92) 100644 =================================================================== --- lib/grnxx/mutex.cpp 2013-08-23 10:46:34 +0900 (ac8b575) +++ /dev/null @@ -1,92 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/mutex.hpp" - -#include "grnxx/string_builder.hpp" -#include "grnxx/thread.hpp" -#include "grnxx/stopwatch.hpp" - -namespace grnxx { -namespace { - -constexpr int MUTEX_SPIN_COUNT = 100; -constexpr int MUTEX_CONTEXT_SWITCH_COUNT = 100; -constexpr Duration MUTEX_SLEEP_DURATION = Duration::milliseconds(10); - -} // namespace - -void Mutex::lock_without_timeout() { - for (int i = 0; i < MUTEX_SPIN_COUNT; ++i) { - if (try_lock()) { - return; - } - } - for (int i = 0; i < MUTEX_CONTEXT_SWITCH_COUNT; ++i) { - if (try_lock()) { - return; - } - Thread::yield(); - } - while (!try_lock()) { - Thread::sleep_for(MUTEX_SLEEP_DURATION); - } -} - -bool Mutex::lock_with_timeout(Duration timeout) { - if (timeout <= Duration(0)) { - return false; - } - for (int i = 0; i < MUTEX_SPIN_COUNT; ++i) { - if (try_lock()) { - return true; - } - } - Stopwatch stopwatch(true); - for (int i = 0; i < MUTEX_CONTEXT_SWITCH_COUNT; ++i) { - if (stopwatch.elapsed() >= timeout) { - return false; - } - if (try_lock()) { - return true; - } - Thread::yield(); - } - while (stopwatch.elapsed() < timeout) { - if (try_lock()) { - return true; - } - Thread::sleep_for(MUTEX_SLEEP_DURATION); - } - return false; -} - -StringBuilder &Mutex::write_to(StringBuilder &builder) const { - switch (status_) { - case MUTEX_UNLOCKED: { - return builder << "unlocked"; - } - case MUTEX_LOCKED: { - return builder << "locked"; - } - default: { - return builder << "n/a"; - } - } -} - -} // namespace grnxx Deleted: lib/grnxx/mutex.hpp (+0 -84) 100644 =================================================================== --- lib/grnxx/mutex.hpp 2013-08-23 10:46:34 +0900 (f1d267c) +++ /dev/null @@ -1,84 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_MUTEX_HPP -#define GRNXX_MUTEX_HPP - -#include "grnxx/features.hpp" - -#include "grnxx/intrinsic.hpp" -#include "grnxx/duration.hpp" -#include "grnxx/types.hpp" - -namespace grnxx { - -class StringBuilder; - -enum MutexStatus : uint32_t { - MUTEX_UNLOCKED = 0, - MUTEX_LOCKED = 1 -}; - -class Mutex { - public: - constexpr Mutex() : status_(MUTEX_UNLOCKED) {} - - void lock() { - if (!try_lock()) { - lock_without_timeout(); - } - } - bool lock(Duration timeout) { - if (try_lock()) { - return true; - } - return lock_with_timeout(timeout); - } - bool try_lock() { - if (locked()) { - return false; - } - return atomic_compare_and_swap(MUTEX_UNLOCKED, MUTEX_LOCKED, &status_); - } - bool unlock() { - if (!locked()) { - return false; - } - status_ = MUTEX_UNLOCKED; - return true; - } - - bool locked() const { - return status_ != MUTEX_UNLOCKED; - } - - StringBuilder &write_to(StringBuilder &builder) const; - - private: - volatile MutexStatus status_; - - void lock_without_timeout(); - bool lock_with_timeout(Duration timeout); -}; - -inline StringBuilder &operator<<(StringBuilder &builder, const Mutex &mutex) { - return mutex.write_to(builder); -} - -} // namespace grnxx - -#endif // GRNXX_MUTEX_HPP Deleted: lib/grnxx/os.cpp (+0 -92) 100644 =================================================================== --- lib/grnxx/os.cpp 2013-08-23 10:46:34 +0900 (75db2d2) +++ /dev/null @@ -1,92 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/os.hpp" - -#include <cerrno> -#include <cstdlib> -#include <cstring> -#include <memory> -#include <new> - -#include "grnxx/errno.hpp" -#include "grnxx/exception.hpp" -#include "grnxx/lock.hpp" -#include "grnxx/logger.hpp" - -namespace grnxx { - -uint64_t OS::get_page_size() { -#if defined(GRNXX_WINDOWS) || !defined(_SC_PAGESIZE) - static const uint64_t page_size = 4096; -#else // defined(GRNXX_WINDOWS) || !defined(_SC_PAGESIZE) - static const uint64_t page_size = ::sysconf(_SC_PAGESIZE); -#endif // defined(GRNXX_WINDOWS) || !defined(_SC_PAGESIZE) - return page_size; -} - -char *OS::get_environment_variable(const char *name) { - if (!name) { - GRNXX_ERROR() << "invalid argument: name = nullptr"; - throw LogicError(); - } - static Mutex mutex; - Lock lock(&mutex); -#ifdef GRNXX_MSC - char *value; - size_t value_size; - errno_t error; - error = ::_dupenv_s(&value, &value_size, name); - if (error != 0) { - const Errno error_code(error); - GRNXX_ERROR() << "failed to get environment variable: name = " << name - << ": '::_dupenv_s' " << error_code; - throw SystemError(error_code); - } - if (!value) { - // No match. - return nullptr; - } - char * const result = new (std::nothrow) char[value_size + 1]; - if (!result) { - GRNXX_ERROR() << "new char[] failed: size = " << (value_size + 1); - std::free(value); - throw MemoryError(); - } - std::memcpy(result, value, value_size); - result[value_size] = '\0'; - std::free(value); - return result; -#else // GRNXX_MSC - char * const value = std::getenv(name); - if (!value) { - // No match. - return nullptr; - } - const size_t value_size = std::strlen(value); - char * const result = new (std::nothrow) char[value_size + 1]; - if (!result) { - GRNXX_ERROR() << "new char[] failed: size = " << (value_size + 1); - throw MemoryError(); - } - std::memcpy(result, value, value_size); - result[value_size] = '\0'; - return result; -#endif // GRNXX_MSC -} - -} // namespace grnxx Deleted: lib/grnxx/os.hpp (+0 -39) 100644 =================================================================== --- lib/grnxx/os.hpp 2013-08-23 10:46:34 +0900 (9d7ecd5) +++ /dev/null @@ -1,39 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_OS_HPP -#define GRNXX_OS_HPP - -#include "grnxx/features.hpp" - -#include "grnxx/types.hpp" - -namespace grnxx { - -class OS { - public: - // Get the page size. - static uint64_t get_page_size(); - - // Return an environment variable, or nullptr if "name" does not exist. - // The returned string must be freed with delete[]. - static char *get_environment_variable(const char *name); -}; - -} // namespace grnxx - -#endif // GRNXX_OS_HPP Deleted: lib/grnxx/periodic_clock.cpp (+0 -81) 100644 =================================================================== --- lib/grnxx/periodic_clock.cpp 2013-08-23 10:46:34 +0900 (2f10d49) +++ /dev/null @@ -1,81 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/periodic_clock.hpp" - -#include <memory> - -#include "grnxx/intrinsic.hpp" -#include "grnxx/lock.hpp" -#include "grnxx/logger.hpp" -#include "grnxx/mutex.hpp" -#include "grnxx/thread.hpp" - -namespace grnxx { -namespace { - -// Accuracy of the periodic clock. Note that a short sleep may lead to a -// busy-wait loop, which exhausts CPU resources. -constexpr Duration UPDATE_INTERVAL = Duration::milliseconds(100); - -// The number of PeriodicClock objects. -volatile uint32_t ref_count = 0; -// The current thread ID. -volatile uint32_t thread_id = 0; -Mutex mutex; - -} // namespace - -Time PeriodicClock::now_ = Time::min(); - -PeriodicClock::PeriodicClock() { - Lock lock(&mutex); - if (++ref_count == 1) try { - // Start an internal thread that updates "now_" periodically. - std::unique_ptr<grnxx::Thread> thread(grnxx::Thread::create(routine)); - thread->detach(); - // Immediately update "now_". - now_ = SystemClock::now(); - } catch (...) { - GRNXX_WARNING() << "failed to create thread for PeriodicClock"; - } -} - -PeriodicClock::~PeriodicClock() { - Lock lock(&mutex); - if (--ref_count == 0) { - now_ = Time::min(); - // Increment "thread_id" so that an internal thread will stop. - atomic_fetch_and_add(1, &thread_id); - } -} - -void PeriodicClock::routine() { - // Increment "thread_id" to generate the ID of this thread. - const uint64_t this_thread_id = atomic_fetch_and_add(1, &thread_id) + 1; - // This thread terminates if there are no PeriodicClock objects or another - // thread is running. - while ((ref_count != 0) && (this_thread_id == thread_id)) { - Thread::sleep_for(UPDATE_INTERVAL); - Lock lock(&mutex); - if ((ref_count != 0) && (this_thread_id == thread_id)) { - now_ = SystemClock::now(); - } - } -} - -} // namespace grnxx Deleted: lib/grnxx/periodic_clock.hpp (+0 -51) 100644 =================================================================== --- lib/grnxx/periodic_clock.hpp 2013-08-23 10:46:34 +0900 (074fdf1) +++ /dev/null @@ -1,51 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_PERIODIC_CLOCK_HPP -#define GRNXX_PERIODIC_CLOCK_HPP - -#include "grnxx/features.hpp" - -#include "grnxx/system_clock.hpp" -#include "grnxx/time.hpp" - -namespace grnxx { - -class PeriodicClock { - public: - // Increment an internal reference count. - // Start a thread for updating "now_" when the reference count becomes 1. - PeriodicClock(); - // Decrement an internal reference count. - // Stop a thread for updating "now_" when the reference count becomes 0. - ~PeriodicClock(); - - // Return the current time. - static Time now() { - return (now_ == Time::min()) ? SystemClock::now() : now_; - } - - private: - static Time now_; - - // Update "now_" periodically. - static void routine(); -}; - -} // namespace grnxx - -#endif // GRNXX_PERIODIC_CLOCK_HPP Deleted: lib/grnxx/stopwatch.cpp (+0 -66) 100644 =================================================================== --- lib/grnxx/stopwatch.cpp 2013-08-23 10:46:34 +0900 (db8927a) +++ /dev/null @@ -1,66 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/stopwatch.hpp" - -#include <chrono> - -namespace grnxx { -namespace { - -int64_t now() { - return std::chrono::duration_cast<std::chrono::microseconds>( - std::chrono::steady_clock::now().time_since_epoch()).count(); -} - -} // namespace - -Stopwatch::Stopwatch(bool is_running) - : elapsed_(0), - start_count_(is_running ? now() : 0), - is_running_(is_running) {} - -void Stopwatch::start() { - if (!is_running_) { - start_count_ = now(); - is_running_ = true; - } -} - -void Stopwatch::stop() { - if (is_running_) { - elapsed_ += Duration(now() - start_count_); - is_running_ = false; - } -} - -void Stopwatch::reset() { - if (is_running_) { - start_count_ = now(); - } - elapsed_ = Duration(0); -} - -Duration Stopwatch::elapsed() const { - if (is_running_) { - return elapsed_ + Duration(now() - start_count_); - } else { - return elapsed_; - } -} - -} // namespace grnxx Deleted: lib/grnxx/stopwatch.hpp (+0 -57) 100644 =================================================================== --- lib/grnxx/stopwatch.hpp 2013-08-23 10:46:34 +0900 (5933bee) +++ /dev/null @@ -1,57 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_STOPWATCH_HPP -#define GRNXX_STOPWATCH_HPP - -#include "grnxx/features.hpp" - -#include "grnxx/duration.hpp" - -namespace grnxx { - -// To measure the amount of time elapsed. -class Stopwatch { - public: - // Initialize a stopwatch, which is started if "is_running" == true. - explicit Stopwatch(bool is_running = false); - - // Return true iff the stopwatch is running. - bool is_running() const { - return is_running_; - } - - // Start measurement. - void start(); - // Stop measurement. - void stop(); - - // Clear the elapsed time. - void reset(); - - // Get the current elapsed time. - Duration elapsed() const; - - private: - Duration elapsed_; - int64_t start_count_; - bool is_running_; -}; - -} // namespace grnxx - -#endif // GRNXX_STOPWATCH_HPP Deleted: lib/grnxx/storage.cpp (+0 -165) 100644 =================================================================== --- lib/grnxx/storage.cpp 2013-08-23 10:46:34 +0900 (07daccf) +++ /dev/null @@ -1,165 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/storage.hpp" - -#include "grnxx/storage/node_header.hpp" -#include "grnxx/storage/storage_impl.hpp" -#include "grnxx/string_builder.hpp" - -namespace grnxx { -namespace { - -// 1GB-8EB (default: 1TB). -constexpr uint64_t MAX_FILE_SIZE_LOWER_LIMIT = 1ULL << 30; -constexpr uint64_t MAX_FILE_SIZE_UPPER_LIMIT = 1ULL << 63; -constexpr uint64_t MAX_FILE_SIZE_DEFAULT = 1ULL << 40; -// 1-1000 (default: 1000). -constexpr uint16_t MAX_NUM_FILES_LOWER_LIMIT = 1; -constexpr uint16_t MAX_NUM_FILES_UPPER_LIMIT = 1000; -constexpr uint16_t MAX_NUM_FILES_DEFAULT = MAX_NUM_FILES_UPPER_LIMIT; -// 0-max_file_size bytes (default: 4KB). -constexpr uint64_t ROOT_SIZE_DEFAULT = 1ULL << 12; - -} // namespace - -#define GRNXX_FLAGS_WRITE(flag) do { \ - if (flags & flag) { \ - if (!is_first) { \ - builder << " | "; \ - } \ - builder << #flag; \ - is_first = false; \ - } \ -} while (false) - -StringBuilder &operator<<(StringBuilder &builder, StorageFlags flags) { - bool is_first = true; - GRNXX_FLAGS_WRITE(STORAGE_ANONYMOUS); - GRNXX_FLAGS_WRITE(STORAGE_HUGE_TLB); - GRNXX_FLAGS_WRITE(STORAGE_READ_ONLY); - GRNXX_FLAGS_WRITE(STORAGE_TEMPORARY); - if (is_first) { - builder << "STORAGE_DEFAULT"; - } - return builder; -} - -#define GRNXX_STATUS_CASE(status) \ - case status: { \ - return builder << #status; \ - } - -StringBuilder &operator<<(StringBuilder &builder, StorageNodeStatus status) { - switch (status) { - GRNXX_STATUS_CASE(STORAGE_NODE_PHANTOM) - GRNXX_STATUS_CASE(STORAGE_NODE_ACTIVE) - GRNXX_STATUS_CASE(STORAGE_NODE_UNLINKED) - GRNXX_STATUS_CASE(STORAGE_NODE_IDLE) - default: { - return builder << "n/a"; - } - } -} - -StorageOptions::StorageOptions() - : max_file_size(MAX_FILE_SIZE_DEFAULT), - max_num_files(MAX_NUM_FILES_DEFAULT), - root_size(ROOT_SIZE_DEFAULT) {} - -StorageOptions::operator bool() const { - if ((max_file_size < MAX_FILE_SIZE_LOWER_LIMIT) || - (max_file_size > MAX_FILE_SIZE_UPPER_LIMIT)) { - return false; - } - if ((max_num_files < MAX_NUM_FILES_LOWER_LIMIT) || - (max_num_files > MAX_NUM_FILES_UPPER_LIMIT)) { - return false; - } - if (root_size > max_file_size) { - return false; - } - return true; -} - -StringBuilder &operator<<(StringBuilder &builder, - const StorageOptions &options) { - if (!builder) { - return builder; - } - return builder << "{ max_num_files = " << options.max_num_files - << ", max_file_size = " << options.max_file_size - << ", root_size = " << options.root_size << " }"; -} - -uint32_t StorageNode::id() const { - return header_->id; -} - -StorageNodeStatus StorageNode::status() const { - return header_->status; -} - -uint16_t StorageNode::chunk_id() const { - return header_->chunk_id; -} - -uint64_t StorageNode::offset() const { - return header_->offset; -} - -uint64_t StorageNode::size() const { - return header_->size; -} - -Time StorageNode::modified_time() const { - return header_->modified_time; -} - -void *StorageNode::user_data() const { - return header_->user_data; -} - -Storage::Storage() {} -Storage::~Storage() {} - -Storage *Storage::create(const char *path, - StorageFlags flags, - const StorageOptions &options) { - return storage::StorageImpl::create(path, flags, options); -} - -Storage *Storage::open(const char *path, - StorageFlags flags) { - return storage::StorageImpl::open(path, flags); -} - -Storage *Storage::open_or_create(const char *path, - StorageFlags flags, - const StorageOptions &options) { - return storage::StorageImpl::open_or_create(path, flags, options); -} - -bool Storage::exists(const char *path) { - return storage::StorageImpl::exists(path); -} - -void Storage::unlink(const char *path) { - storage::StorageImpl::unlink(path); -} - -} // namespace grnxx Deleted: lib/grnxx/storage.hpp (+0 -191) 100644 =================================================================== --- lib/grnxx/storage.hpp 2013-08-23 10:46:34 +0900 (1efdca9) +++ /dev/null @@ -1,191 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_STORAGE_HPP -#define GRNXX_STORAGE_HPP - -#include "grnxx/features.hpp" - -#include <limits> - -#include "grnxx/duration.hpp" -#include "grnxx/flags_impl.hpp" -#include "grnxx/time.hpp" -#include "grnxx/types.hpp" - -namespace grnxx { -namespace storage { - -struct NodeHeader; - -} // namespace storage - -class Storage; -using StorageFlags = FlagsImpl<Storage>; - -// Use the default settings. -constexpr StorageFlags STORAGE_DEFAULT = StorageFlags::define(0x00); -// Create an anonymous storage. -// This flag is implicitly enabled if "path" == nullptr and "flags" does not -// contain STORAGE_TEMPORARY. -constexpr StorageFlags STORAGE_ANONYMOUS = StorageFlags::define(0x01); -// Use huge pages if available, or use regular pages. -constexpr StorageFlags STORAGE_HUGE_TLB = StorageFlags::define(0x02); -// Open a storage in read-only mode. -// If not specified, a storage is opened in read-write mode. -constexpr StorageFlags STORAGE_READ_ONLY = StorageFlags::define(0x04); -// Create a file-backed temporary storage. -constexpr StorageFlags STORAGE_TEMPORARY = StorageFlags::define(0x08); - -StringBuilder &operator<<(StringBuilder &builder, StorageFlags flags); - -enum StorageNodeStatus : uint8_t { - // A node without body. - STORAGE_NODE_PHANTOM = 0, - // An active node. - STORAGE_NODE_ACTIVE = 1, - // An unlinked node. - STORAGE_NODE_UNLINKED = 2, - // An unused node. - STORAGE_NODE_IDLE = 3 -}; - -StringBuilder &operator<<(StringBuilder &builder, StorageNodeStatus status); - -constexpr uint32_t STORAGE_ROOT_NODE_ID = 0; -constexpr uint32_t STORAGE_INVALID_NODE_ID = - std::numeric_limits<uint32_t>::max(); - -struct StorageOptions { - // The maximum size of each file. - uint64_t max_file_size; - // The maximum number of files. - uint16_t max_num_files; - // The size of the root node. - uint64_t root_size; - - // Initialize the members with the default parameters. - StorageOptions(); - - // Return true iff the options are valid. - explicit operator bool() const; -}; - -StringBuilder &operator<<(StringBuilder &builder, - const StorageOptions &options); - -class StorageNode { - public: - StorageNode() : header_(nullptr), body_(nullptr) {} - StorageNode(storage::NodeHeader *header, void *body) - : header_(header), - body_(body) {} - - // Return true iff the node is valid. - explicit operator bool() const { - return header_ != nullptr; - } - - // Return the ID. - uint32_t id() const; - // Return the status. - StorageNodeStatus status() const; - // Return the ID of the chunk to which the node belongs. - uint16_t chunk_id() const; - // Return the offset in chunk. - uint64_t offset() const; - // Return the body size. - uint64_t size() const; - // Return the last modified time. - Time modified_time() const; - // Return the address to the user data (8 bytes) in the header. - void *user_data() const; - // Return the address to the body. - void *body() const { - return body_; - } - - private: - // The address to the node header. - storage::NodeHeader *header_; - // The address to the node body. - void *body_; -}; - -class Storage { - public: - Storage(); - virtual ~Storage(); - - // Create a storage. - // STORAGE_ANONYMOUS is implicitly enabled if "path" == nullptr and "flags" - // does not contain STORAGE_TEMPORARY. - // Available flags are STORAGE_HUGE_TLB and STORAGE_TEMPORARY. - static Storage *create(const char *path, - StorageFlags flags = STORAGE_DEFAULT, - const StorageOptions &options = StorageOptions()); - // Open a storage. - // Available flags are STORAGE_HUGE_TLB and STORAGE_READ_ONLY. - static Storage *open(const char *path, - StorageFlags flags = STORAGE_DEFAULT); - // Open or create a storage. - // The available flags is STORAGE_HUGE_TLB. - static Storage *open_or_create( - const char *path, StorageFlags flags = STORAGE_DEFAULT, - const StorageOptions &options = StorageOptions()); - - // Return true iff "path" refers to a valid storage. - static bool exists(const char *path); - // Remove a storage. - static void unlink(const char *path); - - // Create a node of at least "size" bytes under the specified parent node. - virtual StorageNode create_node(uint32_t parent_node_id, uint64_t size) = 0; - // Open a node. - virtual StorageNode open_node(uint32_t node_id) = 0; - - // Unlink a node and return true on success. - // The unlinked node and its descendants will be removed by sweep(). - virtual void unlink_node(uint32_t node_id) = 0; - - // Sweep unlinked nodes whose modified time < (now - lifetime). - virtual void sweep(Duration lifetime) = 0; - - // Return the storage path. - // Note that an anonymous or temporary storage may return nullptr. - virtual const char *path() const = 0; - // Return the activated flags. - virtual StorageFlags flags() const = 0; - // Return the maximum size of each file. - virtual uint64_t max_file_size() const = 0; - // Return the maximum number of files. - virtual uint16_t max_num_files() const = 0; - // Return the number of active or unlinked nodes. - virtual uint32_t num_nodes() const = 0; - // Return the number of chunks for node body. - virtual uint16_t num_chunks() const = 0; - // Return the total usage of body chunks (including unlinked nodes). - virtual uint64_t body_usage() const = 0; - // Return the total size of body chunks. - virtual uint64_t body_size() const = 0; - // Return the total size. - virtual uint64_t total_size() const = 0; -}; - -} // namespace grnxx - -#endif // GRNXX_STORAGE_HPP Deleted: lib/grnxx/storage/Makefile.am (+0 -30) 100644 =================================================================== --- lib/grnxx/storage/Makefile.am 2013-08-23 10:46:34 +0900 (937f1a9) +++ /dev/null @@ -1,30 +0,0 @@ -noinst_LTLIBRARIES = libgrnxx_storage.la - -libgrnxx_storage_la_LDFLAGS = @AM_LTLDFLAGS@ - -libgrnxx_storage_la_SOURCES = \ - chunk.cpp \ - chunk-posix.cpp \ - chunk-windows.cpp \ - chunk_index.cpp \ - file.cpp \ - file-posix.cpp \ - file-windows.cpp \ - header.cpp \ - node_header.cpp \ - path.cpp \ - storage_impl.cpp - -libgrnxx_storage_includedir = ${includedir}/grnxx/storage -libgrnxx_storage_include_HEADERS = \ - chunk.hpp \ - chunk-posix.hpp \ - chunk-windows.hpp \ - chunk_index.hpp \ - file.hpp \ - file-posix.hpp \ - file-windows.hpp \ - header.hpp \ - node_header.hpp \ - path.hpp \ - storage_impl.hpp Deleted: lib/grnxx/storage/chunk-posix.cpp (+0 -188) 100644 =================================================================== --- lib/grnxx/storage/chunk-posix.cpp 2013-08-23 10:46:34 +0900 (b54c83b) +++ /dev/null @@ -1,188 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/storage/chunk-posix.hpp" - -#ifndef GRNXX_WINDOWS - -#include <sys/mman.h> - -#include <cerrno> -#include <limits> -#include <memory> -#include <new> - -#include "grnxx/errno.hpp" -#include "grnxx/exception.hpp" -#include "grnxx/logger.hpp" -#include "grnxx/storage/file.hpp" - -#ifndef MAP_ANONYMOUS -# ifdef MAP_ANON -# define MAP_ANONYMOUS MAP_ANON -# endif // MAP_ANON -#endif // MAP_ANONYMOUS - -namespace grnxx { -namespace storage { - -ChunkImpl::ChunkImpl() - : flags_(CHUNK_DEFAULT), - address_(MAP_FAILED), - size_(0) {} - -ChunkImpl::~ChunkImpl() { - if (address_ != MAP_FAILED) { - if (::munmap(address_, static_cast<size_t>(size_)) != 0) { - Errno errno_copy(errno); - GRNXX_WARNING() << "failed to unmap chunk: " - << "call = ::munmap, errno = " << errno_copy; - } - } -} - -ChunkImpl *ChunkImpl::create(File *file, uint64_t offset, uint64_t size, - ChunkFlags flags) { - std::unique_ptr<ChunkImpl> chunk(new (std::nothrow) ChunkImpl); - if (!chunk) { - GRNXX_ERROR() << "new grnxx::storage::FileImpl failed"; - throw MemoryError(); - } - if (file) { - chunk->create_file_backed_chunk(file, offset, size, flags); - } else { - chunk->create_anonymous_chunk(size, flags); - } - return chunk.release(); -} - -void ChunkImpl::sync(uint64_t offset, uint64_t size) { - if ((flags_ & CHUNK_ANONYMOUS) || (flags_ & CHUNK_READ_ONLY)) { - GRNXX_ERROR() << "invalid operation: flags = " << flags_; - throw LogicError(); - } - if ((offset > size_) || (size > size_) || (size > (size_ - offset))) { - GRNXX_ERROR() << "invalid argument: offset = " << offset - << ", size = " << size << ", chunk_size = " << size_; - throw LogicError(); - } - if (size == 0) { - size = size_ - offset; - } - if (size > std::numeric_limits<size_t>::max()) { - GRNXX_ERROR() << "invalid argument: size = " << size; - throw LogicError(); - } - if (size > 0) { - if (::msync(static_cast<char *>(address_) + offset, size, MS_SYNC) != 0) { - Errno errno_copy(errno); - GRNXX_ERROR() << "failed to sync chunk: offset = " << offset - << ", size = " << size - << ", call = ::msync, errno = " << errno_copy; - throw SystemError(errno_copy); - } - } -} - -ChunkFlags ChunkImpl::flags() const { - return flags_; -} - -void *ChunkImpl::address() const { - return address_; -} - -uint64_t ChunkImpl::size() const { - return size_; -} - -void ChunkImpl::create_file_backed_chunk(File *file, uint64_t offset, - uint64_t size, ChunkFlags flags) { - const uint64_t file_size = file->get_size(); - if ((offset >= file_size) || (size > file_size) || - (size > (file_size - offset))) { - GRNXX_ERROR() << "invalid argument: offset = " << offset - << ", size = " << size << ", file_size = " << file_size; - throw LogicError(); - } - if (size == 0) { - size = file_size - offset; - } - if ((offset > static_cast<uint64_t>(std::numeric_limits<off_t>::max())) || - (size > std::numeric_limits<size_t>::max())) { - GRNXX_ERROR() << "invalid argument: offset = " << offset - << ", size = " << size; - throw LogicError(); - } - if (file->flags() & FILE_READ_ONLY) { - flags_ |= CHUNK_READ_ONLY; - } - size_ = size; - int protection_flags = PROT_READ | PROT_WRITE; - if (flags_ & CHUNK_READ_ONLY) { - flags_ |= CHUNK_READ_ONLY; - protection_flags = PROT_READ; - } - const int mmap_flags = MAP_SHARED; - address_ = ::mmap(nullptr, size, protection_flags, mmap_flags, - *static_cast<const int *>(file->handle()), offset); - if (address_ == MAP_FAILED) { - Errno errno_copy(errno); - GRNXX_ERROR() << "failed to map file-backed chunk: " - << "file_path = " << file->path() - << ", file_size = " << file_size - << ", offset = " << offset << ", size = " << size - << ", flags = " << flags - << ", call = ::mmap, errno = " << errno_copy; - throw SystemError(errno_copy); - } -} - -void ChunkImpl::create_anonymous_chunk(uint64_t size, ChunkFlags flags) { - if ((size == 0) || (size > std::numeric_limits<size_t>::max())) { - GRNXX_ERROR() << "invalid argument: size = " << size; - throw LogicError(); - } - flags_ = CHUNK_ANONYMOUS; - size_ = size; - const int protection_flags = PROT_READ | PROT_WRITE; - const int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS; -#ifdef MAP_HUGETLB - if (flags & CHUNK_HUGE_TLB) { - address_ = ::mmap(nullptr, size, protection_flags, - mmap_flags | MAP_HUGETLB, -1, 0); - if (address_ != MAP_FAILED) { - flags_ |= CHUNK_HUGE_TLB; - } - } -#endif // MAP_HUGETLB - if (address_ == MAP_FAILED) { - address_ = ::mmap(nullptr, size, protection_flags, mmap_flags, -1, 0); - if (address_ == MAP_FAILED) { - Errno errno_copy(errno); - GRNXX_ERROR() << "failed to map anonymous chunk: size = " << size - << ", flags = " << flags - << ", call = ::mmap, errno = " << errno_copy; - throw SystemError(errno_copy); - } - } -} - -} // namespace storage -} // namespace grnxx - -#endif // GRNXX_WINDOWS Deleted: lib/grnxx/storage/chunk-posix.hpp (+0 -59) 100644 =================================================================== --- lib/grnxx/storage/chunk-posix.hpp 2013-08-23 10:46:34 +0900 (659bc7a) +++ /dev/null @@ -1,59 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_STORAGE_CHUNK_POSIX_HPP -#define GRNXX_STORAGE_CHUNK_POSIX_HPP - -#include "grnxx/features.hpp" - -#ifndef GRNXX_WINDOWS - -#include "grnxx/storage/chunk.hpp" - -namespace grnxx { -namespace storage { - -class ChunkImpl : public Chunk { - public: - ChunkImpl(); - ~ChunkImpl(); - - static ChunkImpl *create(File *file, uint64_t offset, uint64_t size, - ChunkFlags flags); - - void sync(uint64_t offset, uint64_t size); - - ChunkFlags flags() const; - void *address() const; - uint64_t size() const; - - private: - ChunkFlags flags_; - void *address_; - uint64_t size_; - - void create_file_backed_chunk(File *file, uint64_t offset, uint64_t size, - ChunkFlags flags); - void create_anonymous_chunk(uint64_t size, ChunkFlags flags); -}; - -} // namespace storage -} // namespace grnxx - -#endif // GRNXX_WINDOWS - -#endif // GRNXX_STORAGE_CHUNK_POSIX_HPP Deleted: lib/grnxx/storage/chunk-windows.cpp (+0 -181) 100644 =================================================================== --- lib/grnxx/storage/chunk-windows.cpp 2013-08-23 10:46:34 +0900 (8e912f9) +++ /dev/null @@ -1,181 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/storage/chunk-windows.hpp" - -#ifdef GRNXX_WINDOWS - -#include <limits> -#include <memory> -#include <new> - -#include "grnxx/errno.hpp" -#include "grnxx/exception.hpp" -#include "grnxx/logger.hpp" -#include "grnxx/storage/file.hpp" - -namespace grnxx { -namespace storage { - -ChunkImpl::ChunkImpl() - : flags_(CHUNK_DEFAULT), - handle_(nullptr), - address_(nullptr), - size_(0) {} - -ChunkImpl::~ChunkImpl() { - if (address_) { - if (!::UnmapViewOfFile(address_)) { - Errno errno_copy(::GetLastError()); - GRNXX_ERROR() << "failed to unmap chunk: " - << "call = ::UnmapViewOfFile, errno = " << errno_copy; - } - } - if (handle_) { - if (!::CloseHandle(handle_)) { - Errno errno_copy(::GetLastError()); - GRNXX_ERROR() << "failed to close file mapping: " - << "call = ::CloseHandle, errno = " << errno_copy; - } - } -} - -ChunkImpl *ChunkImpl::create(File *file, uint64_t offset, uint64_t size, - ChunkFlags flags) { - std::unique_ptr<ChunkImpl> chunk(new (std::nothrow) ChunkImpl); - if (!chunk) { - GRNXX_ERROR() << "new grnxx::storage::FileImpl failed"; - throw MemoryError(); - } - if (file) { - chunk->create_file_backed_chunk(file, offset, size, flags); - } else { - chunk->create_anonymous_chunk(size, flags); - } - return chunk.release(); -} - -void ChunkImpl::sync(uint64_t offset, uint64_t size) { - if ((flags_ & CHUNK_ANONYMOUS) || (flags_ & CHUNK_READ_ONLY)) { - GRNXX_ERROR() << "invalid operation: flags = " << flags_; - throw LogicError(); - } - if ((offset > size_) || (size > size_) || (size > (size_ - offset))) { - GRNXX_ERROR() << "invalid argument: offset = " << offset - << ", size = " << size << ", chunk_size = " << size_; - throw LogicError(); - } - if (size > std::numeric_limits<SIZE_T>::max()) { - GRNXX_ERROR() << "invalid argument: size = " << size; - throw LogicError(); - } - if (!::FlushViewOfFile(static_cast<char *>(address_) + offset, size)) { - Errno errno_copy(::GetLastError()); - GRNXX_ERROR() << "failed to sync chunk: offset = " << offset - << ", size = " << size - << ", call = FlushViewOfFile;, errno = " << errno_copy; - throw SystemError(errno_copy); - } -} - -void ChunkImpl::create_file_backed_chunk(File *file, uint64_t offset, - uint64_t size, ChunkFlags flags) { - uint64_t file_size = file->get_size(); - if ((offset >= file_size) || (size > file_size) || - (size > (file_size - offset))) { - GRNXX_ERROR() << "invalid argument: offset = " << offset - << ", size = " << size << ", file_size = " << file_size; - throw LogicError(); - } - if (size == 0) { - size = file_size - offset; - } - if (size > std::numeric_limits<SIZE_T>::max()) { - GRNXX_ERROR() << "invalid argument: size = " << size; - throw LogicError(); - } - if (file->flags() & FILE_READ_ONLY) { - flags_ |= CHUNK_READ_ONLY; - } - size_ = size; - int protection_mode = PAGE_READWRITE; - DWORD desired_access = FILE_MAP_WRITE; - if (flags_ & CHUNK_READ_ONLY) { - protection_mode = PAGE_READONLY; - desired_access = FILE_MAP_READ; - } - const DWORD size_high = static_cast<DWORD>((offset + size) >> 32); - const DWORD size_low = static_cast<DWORD>(offset + size); - handle_ = ::CreateFileMapping(*static_cast<const HANDLE *>(file->handle()), - nullptr, protection_mode, size_high, size_low, - nullptr); - if (!handle_) { - Errno errno_copy(::GetLastError()); - GRNXX_ERROR() << "failed to create file mapping: " - << "file_path = " << file->path() - << ", file_size = " << file_size << ", offset = " << offset - << ", size = " << size << ", flags = " << flags - << ", call = ::CreateFileMapping, errno = " << errno_copy; - throw SystemError(errno_copy); - } - const DWORD offset_high = static_cast<DWORD>(offset >> 32); - const DWORD offset_low = static_cast<DWORD>(offset); - address_ = ::MapViewOfFile(handle_, desired_access, offset_high, offset_low, - static_cast<SIZE_T>(size)); - if (!address_) { - Errno errno_copy(::GetLastError()); - GRNXX_ERROR() << "failed to map chunk: " - << "file_path = " << file->path() - << ", file_size = " << file_size << ", offset = " << offset - << ", size = " << size << ", flags = " << flags - << ", call = ::MapViewOfFile, errno = " << errno_copy; - throw SystemError(errno_copy); - } -} - -void ChunkImpl::create_anonymous_chunk(uint64_t size, ChunkFlags flags) { - if (size == 0) { - GRNXX_ERROR() << "invalid argument: size = " << size; - throw LogicError(); - } - flags_ = CHUNK_ANONYMOUS; - size_ = size; - const DWORD size_high = static_cast<DWORD>(size >> 32); - const DWORD size_low = static_cast<DWORD>(size); - handle_ = ::CreateFileMapping(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, - size_high, size_low, nullptr); - if (!handle_) { - Errno errno_copy(::GetLastError()); - GRNXX_ERROR() << "failed to create anonymous file mapping: " - << "size = " << size << ", flags = " << flags - << ", call = ::CreateFileMapping, errno = " << errno_copy; - throw SystemError(errno_copy); - } - address_ = ::MapViewOfFile(handle_, FILE_MAP_WRITE, 0, 0, 0); - if (!address_) { - Errno errno_copy(::GetLastError()); - GRNXX_ERROR() << "failed to map anonymous chunk: " - << "size = " << size << ", flags = " << flags - << ", call = ::MapViewOfFile, errno = " << errno_copy; - throw SystemError(errno_copy); - } -} - -} // namespace storage -} // namespace grnxx - -#endif // GRNXX_WINDOWS Deleted: lib/grnxx/storage/chunk-windows.hpp (+0 -67) 100644 =================================================================== --- lib/grnxx/storage/chunk-windows.hpp 2013-08-23 10:46:34 +0900 (a6460ba) +++ /dev/null @@ -1,67 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_STORAGE_CHUNK_WINDOWS_HPP -#define GRNXX_STORAGE_CHUNK_WINDOWS_HPP - -#include "grnxx/features.hpp" - -#ifdef GRNXX_WINDOWS - -#include <windows.h> - -#include "grnxx/storage/chunk.hpp" - -// FILE_READ_ONLY is defined as a macro in windows.h. -#ifdef FILE_READ_ONLY -# undef FILE_READ_ONLY -#endif // FILE_READ_ONLY - -namespace grnxx { -namespace storage { - -class ChunkImpl : public Chunk { - public: - ChunkImpl(); - ~ChunkImpl(); - - static ChunkImpl *create(File *file, uint64_t offset, uint64_t size, - ChunkFlags flags); - - void sync(uint64_t offset, uint64_t size); - - ChunkFlags flags() const; - void *address() const; - uint64_t size() const; - - private: - ChunkFlags flags_; - HANDLE handle_; - void *address_; - uint64_t size_; - - void create_file_backed_chunk(File *file, uint64_t offset, uint64_t size, - ChunkFlags flags); - void create_anonymous_chunk(uint64_t size, ChunkFlags flags); -}; - -} // namespace storage -} // namespace grnxx - -#endif // GRNXX_WINDOWS - -#endif // GRNXX_STORAGE_CHUNK_WINDOWS_HPP Deleted: lib/grnxx/storage/chunk.cpp (+0 -57) 100644 =================================================================== --- lib/grnxx/storage/chunk.cpp 2013-08-23 10:46:34 +0900 (40c3331) +++ /dev/null @@ -1,57 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/storage/chunk.hpp" - -#include "grnxx/storage/chunk-posix.hpp" -#include "grnxx/storage/chunk-windows.hpp" -#include "grnxx/string_builder.hpp" - -namespace grnxx { -namespace storage { - -#define GRNXX_FLAGS_WRITE(flag) do { \ - if (flags & flag) { \ - if (!is_first) { \ - builder << " | "; \ - } \ - builder << #flag; \ - is_first = false; \ - } \ -} while (false) - -StringBuilder &operator<<(StringBuilder &builder, ChunkFlags flags) { - bool is_first = true; - GRNXX_FLAGS_WRITE(CHUNK_ANONYMOUS); - GRNXX_FLAGS_WRITE(CHUNK_HUGE_TLB); - GRNXX_FLAGS_WRITE(CHUNK_READ_ONLY); - if (is_first) { - builder << "CHUNK_DEFAULT"; - } - return builder; -} - -Chunk::Chunk() {} -Chunk::~Chunk() {} - -Chunk *Chunk::create(File *file, uint64_t offset, uint64_t size, - ChunkFlags flags) { - return ChunkImpl::create(file, offset, size, flags); -} - -} // namespace storage -} // namespace grnxx Deleted: lib/grnxx/storage/chunk.hpp (+0 -75) 100644 =================================================================== --- lib/grnxx/storage/chunk.hpp 2013-08-23 10:46:34 +0900 (c852ed0) +++ /dev/null @@ -1,75 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_STORAGE_CHUNK_HPP -#define GRNXX_STORAGE_CHUNK_HPP - -#include "grnxx/features.hpp" - -#include "grnxx/flags_impl.hpp" -#include "grnxx/types.hpp" - -namespace grnxx { - -class StringBuilder; - -namespace storage { - -class File; - -class Chunk; -using ChunkFlags = FlagsImpl<Chunk>; - -// Use the default settings. -constexpr ChunkFlags CHUNK_DEFAULT = ChunkFlags::define(0x00); -// Create an anonymous memory mapping. -// This flag is implicitly enabled if "file" == nullptr. -constexpr ChunkFlags CHUNK_ANONYMOUS = ChunkFlags::define(0x01); -// Use huge pages if available, or use regular pages. -constexpr ChunkFlags CHUNK_HUGE_TLB = ChunkFlags::define(0x02); -// Create a read-only memory mapping. -// This flag is implicitly enabled if "file" is read-only. -constexpr ChunkFlags CHUNK_READ_ONLY = ChunkFlags::define(0x04); - -StringBuilder &operator<<(StringBuilder &builder, ChunkFlags flags); - -class Chunk { - public: - Chunk(); - virtual ~Chunk(); - - // Create a file-backed memory mapping on "file" if "file" != nullptr, or - // create an anonymous memory mapping. - // The available flag is CHUNK_HUGE_TLB. - static Chunk *create(File *file, uint64_t offset = 0, uint64_t size = 0, - ChunkFlags flags = CHUNK_DEFAULT); - - // Flush modified pages. - virtual void sync(uint64_t offset = 0, uint64_t size = 0) = 0; - - // Return the enabled flags. - virtual ChunkFlags flags() const = 0; - // Return the starting address. - virtual void *address() const = 0; - // Return the size. - virtual uint64_t size() const = 0; -}; - -} // namespace storage -} // namespace grnxx - -#endif // GRNXX_STORAGE_CHUNK_HPP Deleted: lib/grnxx/storage/chunk_index.cpp (+0 -34) 100644 =================================================================== --- lib/grnxx/storage/chunk_index.cpp 2013-08-23 10:46:34 +0900 (e7c4369) +++ /dev/null @@ -1,34 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/storage/chunk_index.hpp" - -namespace grnxx { -namespace storage { - -ChunkIndex::ChunkIndex(uint16_t id, ChunkIndexType type) - : id(id), - type(type), - reserved_0(0), - file_id(0), - reserved_1(0), - offset(0), - size(0), - reserved_2(0) {} - -} // namespace storage -} // namespace grnxx Deleted: lib/grnxx/storage/chunk_index.hpp (+0 -60) 100644 =================================================================== --- lib/grnxx/storage/chunk_index.hpp 2013-08-23 10:46:34 +0900 (744496d) +++ /dev/null @@ -1,60 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_STORAGE_CHUNK_INDEX_HPP -#define GRNXX_STORAGE_CHUNK_INDEX_HPP - -#include "grnxx/features.hpp" - -#include "grnxx/types.hpp" - -namespace grnxx { -namespace storage { - -constexpr size_t CHUNK_INDEX_SIZE = 32; - -enum ChunkIndexType : uint8_t { - HEADER_CHUNK = 0, - REGULAR_BODY_CHUNK = 1, - SMALL_BODY_CHUNK = 2 -}; - -struct ChunkIndex { - // The chunk ID. - uint16_t id; - // The chunk type. - ChunkIndexType type; - uint8_t reserved_0; - // The ID of the file to which the chunk belongs. - uint16_t file_id; - uint16_t reserved_1; - // The offset in file. - uint64_t offset; - // The chunk size. - uint64_t size; - uint64_t reserved_2; - - ChunkIndex(uint16_t id, ChunkIndexType type); -}; - -static_assert(sizeof(ChunkIndex) == CHUNK_INDEX_SIZE, - "sizeof(ChunkIndex) != CHUNK_INDEX_SIZE"); - -} // namespace storage -} // namespace grnxx - -#endif // GRNXX_STORAGE_CHUNK_INDEX_HPP Deleted: lib/grnxx/storage/file-posix.cpp (+0 -310) 100644 =================================================================== --- lib/grnxx/storage/file-posix.cpp 2013-08-23 10:46:34 +0900 (db3fb5e) +++ /dev/null @@ -1,310 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/storage/file-posix.hpp" - -#ifndef GRNXX_WINDOWS - -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/file.h> -#include <fcntl.h> -#include <unistd.h> - -#include <cerrno> -#include <limits> -#include <new> - -#include "grnxx/errno.hpp" -#include "grnxx/exception.hpp" -#include "grnxx/logger.hpp" -#include "grnxx/storage/path.hpp" - -namespace grnxx { -namespace storage { -namespace { - -constexpr int UNIQUE_PATH_GENERATION_TRIAL_COUNT = 10; - -} // namespace - -FileImpl::FileImpl() - : File(), - path_(), - flags_(FILE_DEFAULT), - fd_(-1), - locked_(false) {} - -FileImpl::~FileImpl() { - if (fd_ != -1) { - if (locked_) { - unlock(); - } - if (::close(fd_) != 0) { - Errno errno_copy(errno); - GRNXX_WARNING() << "failed to close file: path = " << path_.get() - << ", call = ::close, errno = " << errno_copy; - } - } -} - -FileImpl *FileImpl::create(const char *path, FileFlags flags) { - std::unique_ptr<FileImpl> file(new (std::nothrow) FileImpl); - if (!file) { - GRNXX_ERROR() << "new grnxx::storage::FileImpl failed"; - throw MemoryError(); - } - if (path && (~flags & FILE_TEMPORARY)) { - file->create_persistent_file(path, flags); - } else { - file->create_temporary_file(path, flags); - } - return file.release(); -} - -FileImpl *FileImpl::open(const char *path, FileFlags flags) { - if (!path) { - GRNXX_ERROR() << "invalid argument: path = nullptr"; - throw LogicError(); - } - std::unique_ptr<FileImpl> file(new (std::nothrow) FileImpl); - if (!file) { - GRNXX_ERROR() << "new grnxx::storage::FileImpl failed"; - throw MemoryError(); - } - file->open_file(path, flags); - return file.release(); -} - -FileImpl *FileImpl::open_or_create(const char *path, FileFlags flags) { - if (!path) { - GRNXX_ERROR() << "invalid argument: path = nullptr"; - throw LogicError(); - } - std::unique_ptr<FileImpl> file(new (std::nothrow) FileImpl); - if (!file) { - GRNXX_ERROR() << "new grnxx::storage::FileImpl failed"; - throw MemoryError(); - } - file->open_or_create_file(path, flags); - return file.release(); -} - -bool FileImpl::exists(const char *path) { - if (!path) { - GRNXX_ERROR() << "invalid argument: path = nullptr"; - throw LogicError(); - } - struct stat stat; - if (::stat(path, &stat) != 0) { - if (errno != ENOENT) { - Errno errno_copy(errno); - GRNXX_WARNING() << "failed to get file information: " - << "call = ::stat, errno = " << errno_copy; - } - return false; - } - return S_ISREG(stat.st_mode); -} - -void FileImpl::unlink(const char *path) { - if (!path) { - GRNXX_ERROR() << "invalid argument: path = nullptr"; - throw LogicError(); - } - if (::unlink(path) != 0) { - Errno errno_copy(errno); - GRNXX_ERROR() << "failed to unlink file: path = " << path - << ", call = ::unlink, errno = " << errno_copy; - throw SystemError(errno_copy); - } -} - -bool FileImpl::lock(FileLockFlags lock_flags) { - if (locked_) { - GRNXX_ERROR() << "already locked: path = " << path_.get(); - throw LogicError(); - } - FileLockFlags lock_type = - lock_flags & (FILE_LOCK_SHARED | FILE_LOCK_EXCLUSIVE); - if (!lock_type || (lock_type == (FILE_LOCK_SHARED | FILE_LOCK_EXCLUSIVE))) { - GRNXX_ERROR() << "invalid argument: lock_flags == " << lock_flags; - throw LogicError(); - } - int operation = 0; - if (lock_flags & FILE_LOCK_SHARED) { - operation |= LOCK_SH; - } - if (lock_flags & FILE_LOCK_EXCLUSIVE) { - operation |= LOCK_EX; - } - if (lock_flags & FILE_LOCK_NONBLOCKING) { - operation |= LOCK_NB; - } - if (::flock(fd_, operation) != 0) { - if (errno == EWOULDBLOCK) { - return false; - } - Errno errno_copy(errno); - GRNXX_ERROR() << "failed to lock file: path = " << path_.get() - << ", lock_flags = " << lock_flags - << ", call = ::flock, errno = " << Errno(errno_copy); - throw SystemError(errno_copy); - } - locked_ = true; - return true; -} - -void FileImpl::unlock() { - if (!locked_) { - GRNXX_WARNING() << "unlocked: path = " << path_.get(); - throw LogicError(); - } - if (::flock(fd_, LOCK_UN) != 0) { - Errno errno_copy(errno); - GRNXX_ERROR() << "failed to unlock file: path = " << path_.get() - << ", call = ::flock, errno = " << errno_copy; - throw SystemError(errno_copy); - } - locked_ = false; -} - -void FileImpl::sync() { - if (::fsync(fd_) != 0) { - Errno errno_copy(errno); - GRNXX_ERROR() << "failed to sync file: path = " << path_.get() - << ", call = ::fsync, errno = " << errno_copy; - throw SystemError(errno_copy); - } -} - -void FileImpl::resize(uint64_t size) { - if (flags_ & FILE_READ_ONLY) { - GRNXX_ERROR() << "invalid operation: flags = " << flags_; - throw LogicError(); - } - if (size > static_cast<uint64_t>(std::numeric_limits<off_t>::max())) { - GRNXX_ERROR() << "invalid argument: size = " << size; - throw LogicError(); - } - if (::ftruncate(fd_, size) != 0) { - Errno errno_copy(errno); - GRNXX_ERROR() << "failed to resize file: path = " << path_.get() - << ", size = " << size - << ", call = ::ftruncate, errno = " << errno_copy; - throw SystemError(errno_copy); - } -} - -uint64_t FileImpl::get_size() { - struct stat stat; - if (::fstat(fd_, &stat) != 0) { - Errno errno_copy(errno); - GRNXX_ERROR() << "failed to stat file: path = " << path_.get() - << ", call = ::fstat, errno = " << errno_copy; - throw SystemError(errno_copy); - } - return stat.st_size; -} - -const char *FileImpl::path() const { - return path_.get(); -} - -FileFlags FileImpl::flags() const { - return flags_; -} - -const void *FileImpl::handle() const { - return &fd_; -} - -void FileImpl::create_persistent_file(const char *path, FileFlags flags) { - if (!path) { - GRNXX_ERROR() << "invalid argument: path = nullptr"; - throw LogicError(); - } - path_.reset(Path::clone_path(path)); - fd_ = ::open(path, O_RDWR | O_CREAT | O_EXCL, 0644); - if (fd_ == -1) { - Errno errno_copy(errno); - GRNXX_ERROR() << "failed to create file: path = " << path - << ", flags = " << flags - << ", call = ::open, errno = " << errno_copy; - throw SystemError(errno_copy); - } -} - -void FileImpl::create_temporary_file(const char *path, FileFlags flags) { - flags_ = FILE_TEMPORARY; - int posix_flags = O_RDWR | O_CREAT | O_EXCL | O_NOCTTY; -#ifdef O_NOATIME - posix_flags |= O_NOATIME; -#endif // O_NOATIME -#ifdef O_NOFOLLOW - posix_flags |= O_NOFOLLOW; -#endif // O_NOFOLLOW - Errno errno_copy; - for (int i = 0; i < UNIQUE_PATH_GENERATION_TRIAL_COUNT; ++i) { - path_.reset(Path::unique_path(path)); - fd_ = ::open(path_.get(), posix_flags, 0600); - if (fd_ != -1) { - unlink(path_.get()); - return; - } - errno_copy = Errno(errno); - GRNXX_WARNING() << "failed to create file: path = " << path_.get() - << ", call = ::open, errno = " << errno_copy; - } - GRNXX_ERROR() << "failed to create temporary file: " - << "path = " << path << ", flags = " << flags; - throw SystemError(errno_copy); -} - -void FileImpl::open_file(const char *path, FileFlags flags) { - path_.reset(Path::clone_path(path)); - int posix_flags = O_RDWR; - if (flags & FILE_READ_ONLY) { - posix_flags = O_RDONLY; - flags_ |= FILE_READ_ONLY; - } - fd_ = ::open(path, posix_flags); - if (fd_ == -1) { - Errno errno_copy(errno); - GRNXX_ERROR() << "failed to open file: path = " << path - << ", flags = " << flags - << ", call = ::open, errno = " << errno_copy; - throw SystemError(errno_copy); - } -} - -void FileImpl::open_or_create_file(const char *path, FileFlags flags) { - path_.reset(Path::clone_path(path)); - fd_ = ::open(path, O_RDWR | O_CREAT, 0644); - if (fd_ == -1) { - Errno errno_copy(errno); - GRNXX_ERROR() << "failed to open file: path = " << path - << ", flags = " << flags - << ", call = ::open, errno = " << errno_copy; - throw SystemError(errno_copy); - } -} - -} // namespace storage -} // namespace grnxx - -#endif // GRNXX_WINDOWS Deleted: lib/grnxx/storage/file-posix.hpp (+0 -73) 100644 =================================================================== --- lib/grnxx/storage/file-posix.hpp 2013-08-23 10:46:34 +0900 (72740e1) +++ /dev/null @@ -1,73 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_STORAGE_FILE_POSIX_HPP -#define GRNXX_STORAGE_FILE_POSIX_HPP - -#include "grnxx/features.hpp" - -#ifndef GRNXX_WINDOWS - -#include <memory> - -#include "grnxx/storage/file.hpp" - -namespace grnxx { -namespace storage { - -class FileImpl : public File { - public: - FileImpl(); - ~FileImpl(); - - static FileImpl *create(const char *path, FileFlags flags); - static FileImpl *open(const char *path, FileFlags flags); - static FileImpl *open_or_create(const char *path, FileFlags flags); - - static bool exists(const char *path); - static void unlink(const char *path); - - bool lock(FileLockFlags lock_flags); - void unlock(); - - void sync(); - - void resize(uint64_t size); - uint64_t get_size(); - - const char *path() const; - FileFlags flags() const; - const void *handle() const; - - private: - std::unique_ptr<char[]> path_; - FileFlags flags_; - int fd_; - bool locked_; - - void create_persistent_file(const char *path, FileFlags flags); - void create_temporary_file(const char *path_prefix, FileFlags flags); - void open_file(const char *path, FileFlags flags); - void open_or_create_file(const char *path, FileFlags flags); -}; - -} // namespace storage -} // namespace grnxx - -#endif // GRNXX_WINDOWS - -#endif // GRNXX_STORAGE_FILE_POSIX_HPP Deleted: lib/grnxx/storage/file-windows.cpp (+0 -343) 100644 =================================================================== --- lib/grnxx/storage/file-windows.cpp 2013-08-23 10:46:34 +0900 (1ba3f77) +++ /dev/null @@ -1,343 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/storage/file-windows.hpp" - -#ifdef GRNXX_WINDOWS - -#include <sys/types.h> -#include <sys/stat.h> -#include <io.h> - -#include <cerrno> -#include <limits> -#include <new> - -#include "grnxx/errno.hpp" -#include "grnxx/exception.hpp" -#include "grnxx/logger.hpp" -#include "grnxx/storage/path.hpp" - -namespace grnxx { -namespace storage { -namespace { - -constexpr int UNIQUE_PATH_GENERATION_TRIAL_COUNT = 10; - -} // namespace - -FileImpl::FileImpl() - : File(), - path_(), - flags_(FILE_DEFAULT), - handle_(INVALID_HANDLE_VALUE), - locked_(false) {} - -FileImpl::~FileImpl() { - if (handle_ != INVALID_HANDLE_VALUE) { - if (locked_) { - unlock(); - } - if (!::CloseHandle(handle_)) { - Errno errno_copy(::GetLastError()); - GRNXX_WARNING() << "failed to close file: file = " << *this - << ", call = ::CloseHandle, errno = " << errno_copy; - } - } -} - - -FileImpl *FileImpl::create(const char *path, FileFlags flags) { - std::unique_ptr<FileImpl> file(new (std::nothrow) FileImpl); - if (!file) { - GRNXX_ERROR() << "new grnxx::storage::FileImpl failed"; - throw MemoryError(); - } - if (path && (~flags & FILE_TEMPORARY)) { - file->create_persistent_file(path, flags); - } else { - file->create_temporary_file(path, flags); - } - return file.release(); -} - -FileImpl *FileImpl::open(const char *path, FileFlags flags) { - if (!path) { - GRNXX_ERROR() << "invalid argument: path = nullptr"; - throw LogicError(); - } - std::unique_ptr<FileImpl> file(new (std::nothrow) FileImpl); - if (!file) { - GRNXX_ERROR() << "new grnxx::storage::FileImpl failed"; - throw MemoryError(); - } - file->open_file(path, flags); - return file.release(); -} - -FileImpl *FileImpl::open_or_create(const char *path, FileFlags flags) { - if (!path) { - GRNXX_ERROR() << "invalid argument: path = nullptr"; - throw LogicError(); - } - std::unique_ptr<FileImpl> file(new (std::nothrow) FileImpl); - if (!file) { - GRNXX_ERROR() << "new grnxx::storage::FileImpl failed"; - throw MemoryError(); - } - file->open_or_create_file(path, flags); - return file.release(); -} - -bool FileImpl::exists(const char *path) { - if (!path) { - GRNXX_ERROR() << "invalid argument: path = nullptr"; - throw LogicError(); - } - struct _stat stat; - if (::_stat(path, &stat) != 0) { - if (errno != ENOENT) { - Errno errno_copy(errno); - GRNXX_WARNING() << "failed to get file information: " - << "call = ::_stat, errno = " << errno_copy; - } - return false; - } - return stat.st_mode & _S_IFREG; -} - -void FileImpl::unlink(const char *path) { - if (!path) { - GRNXX_ERROR() << "invalid argument: path = nullptr"; - throw LogicError(); - } - if (!::DeleteFile(path)) { - Errno errno_copy(::GetLastError()); - GRNXX_ERROR() << "failed to unlink file: path = " << path - << ", call = ::DeleteFile, errno = " << errno_copy; - throw SystemError(errno_copy); - } -} - -bool FileImpl::lock(FileLockMode mode) { - if (locked_) { - GRNXX_ERROR() << "already locked: path = " << path_.get(); - throw LogicError(); - } - FileLockFlags lock_type = - lock_flags & (FILE_LOCK_SHARED | FILE_LOCK_EXCLUSIVE); - if (!lock_type || (lock_type == (FILE_LOCK_SHARED | FILE_LOCK_EXCLUSIVE))) { - GRNXX_ERROR() << "invalid argument: lock_flags == " << lock_flags; - throw LogicError(); - } - DWORD flags = LOCKFILE_FAIL_IMMEDIATELY; - if (lock_flags & FILE_LOCK_SHARED) { - // Nothing to do. - } - if (lock_flags & FILE_LOCK_EXCLUSIVE) { - flags |= LOCKFILE_EXCLUSIVE_LOCK; - } - if (lock_flags & FILE_LOCK_NONBLOCKING) { - flags |= LOCKFILE_FAIL_IMMEDIATELY; - } - - OVERLAPPED overlapped; - overlapped.Offset = 0; - overlapped.OffsetHigh = 0x80000000U; - if (!::LockFileEx(handle_, flags, 0, 0, 0x80000000U, &overlapped)) { - const DWORD last_error = ::GetLastError(); - if (last_error == ERROR_LOCK_FAILED) { - // The file is locked by others. - return false; - } - Errno errno_copy(last_error); - GRNXX_ERROR() << "failed to lock file: path = " << path_.get() - << ", mode = " << mode - << ", call = ::LockFileEx, errno = " << errno_copy; - throw SystemError(errno_copy); - } - locked_ = true; - return true; -} - -void FileImpl::unlock() { - if (!locked_) { - GRNXX_WARNING() << "unlocked: path = " << path_.get(); - throw LogicError(); - } - OVERLAPPED overlapped; - overlapped.Offset = 0; - overlapped.OffsetHigh = 0x80000000U; - if (!::UnlockFileEx(handle_, 0, 0, 0x80000000U, &overlapped)) { - Errno errno_copy(::GetLastError()); - GRNXX_ERROR() << "failed to unlock file: path = " << path_.get() - << ", call = ::UnlockFileEx, errno = " << errno_copy; - throw SystemError(errno_copy); - } - locked_ = false; -} - -void FileImpl::sync() { - if (!::FlushFileBuffers(handle_)) { - Errno errno_copy(::GetLastError()); - GRNXX_ERROR() << "failed to sync file: path = " << path_.get() - << ", call = ::FlushFileBuffers, errno = " << errno_copy; - throw SystemError(errno_copy); - } -} - -void FileImpl::resize(uint64_t size) { - if (flags_ & FILE_READ_ONLY) { - GRNXX_ERROR() << "invalid operation: flags = " << flags_; - throw LogicError(); - } - if (size > static_cast<uint64_t>(std::numeric_limits<LONGLONG>::max())) { - GRNXX_ERROR() << "invalid argument: size = " << size; - throw LogicError(); - } - LARGE_INTEGER request; - request.QuadPart = size; - if (!::SetFilePointerEx(handle_, request, nullptr, FILE_BEGIN)) { - Errno errno_copy(::GetLastError()); - GRNXX_ERROR() << "failed to seek file: path = " << path_.get() - << ", offset = " << offset << ", whence = " << whence - << ", call = ::SetFilePointerEx, errno = " << errno_copy; - throw SystemError(errno_copy); - } - if (!::SetEndOfFile(handle_)) { - Errno errno_copy(::GetLastError()); - GRNXX_ERROR() << "failed to resize file: path = " << path_.get() - << ", size = " << size - << ", call = ::SetEndOfFile, errno = " << errno_copy; - throw SystemError(errno_copy); - } -} - -uint64_t FileImpl::get_size() { - LARGE_INTEGER file_size; - if (!::GetFileSizeEx(handle_, &file_size)) { - Errno errno_copy(::GetLastError()); - GRNXX_ERROR() << "failed to get file size: path = " << path_.get() - << ": '::GetFileSizeEx' " << Errno(::GetLastError()); - throw SystemError(errno_copy); - } - return file_size.QuadPart; -} - -const char *FileImpl::path() const { - return path_.get(); -} - -FileFlags FileImpl::flags() const { - return flags_; -} - -const void *FileImpl::handle() const { - return &handle_; -} - -void FileImpl::create_persistent_file(const char *path, FileFlags flags) { - if (!path) { - GRNXX_ERROR() << "invalid argument: path = nullptr"; - throw LogicError(); - } - path_.reset(Path::clone_path(path)); - const DWORD desired_access = GENERIC_READ | GENERIC_WRITE; - const DWORD share_mode = - FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE; - const DWORD creation_disposition = CREATE_NEW; - const DWORD flags_and_attributes = FILE_ATTRIBUTE_NORMAL; - handle_ = ::CreateFileA(path, desired_access, share_mode, nullptr, - creation_disposition, flags_and_attributes, nullptr); - if (handle_ == INVALID_HANDLE_VALUE) { - Errno errno_copy(::GetLastError()); - GRNXX_ERROR() << "failed to open file: path = " << path - << ", flags = " << flags - << ", call = ::CreateFileA, errno = " << errno_copy; - throw SystemError(errno_copy); - } -} - -void FileImpl::create_temporary_file(const char *path, FileFlags flags) { - flags_ = FILE_TEMPORARY; - const DWORD desired_access = GENERIC_READ | GENERIC_WRITE; - const DWORD share_mode = FILE_SHARE_DELETE; - const DWORD creation_disposition = CREATE_NEW; - const DWORD flags_and_attributes = FILE_ATTRIBUTE_TEMPORARY | - FILE_FLAG_DELETE_ON_CLOSE; - Errno errno_copy; - for (int i = 0; i < UNIQUE_PATH_GENERATION_TRIAL_COUNT; ++i) { - path_.reset(Path::unique_path(path)); - handle_ = ::CreateFileA(path_.get(), desired_access, - share_mode, nullptr, creation_disposition, - flags_and_attributes, nullptr); - if (handle_ != INVALID_HANDLE_VALUE) { - return; - } - errno_copy = Errno(::GetLastError()); - GRNXX_WARNING() << "failed to create file: path = " << path_.get() - << ", call = ::CreateFileA, errno = " << errno_copy; - } - GRNXX_ERROR() << "failed to create temporary file: " - << "path = " << path << ", flags = " << flags; - throw SystemError(errno_copy); -} - -void FileImpl::open_file(const char *path, FileFlags flags) { - path_.reset(Path::clone_path(path)); - DWORD desired_access = GENERIC_READ | GENERIC_WRITE; - if (flags_ & FILE_READ_ONLY) { - flags_ |= FILE_READ_ONLY; - desired_access = GENERIC_READ; - } - const DWORD share_mode = - FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE; - const DWORD creation_disposition = OPEN_EXISTING; - const DWORD flags_and_attributes = FILE_ATTRIBUTE_NORMAL; - handle_ = ::CreateFileA(path, desired_access, share_mode, nullptr, - creation_disposition, flags_and_attributes, nullptr); - if (handle_ == INVALID_HANDLE_VALUE) { - Errno errno_copy(::GetLastError()); - GRNXX_ERROR() << "failed to open file: path = " << path - << ", flags = " << flags - << ", call = ::CreateFileA, errno = " << errno_copy; - throw SystemError(errno_copy); - } -} - -void FileImpl::open_or_create_file(const char *path, FileFlags flags) { - path_.reset(Path::clone_path(path)); - const DWORD desired_access = GENERIC_READ | GENERIC_WRITE; - const DWORD share_mode = - FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE; - const DWORD creation_disposition = OPEN_ALWAYS; - const DWORD flags_and_attributes = FILE_ATTRIBUTE_NORMAL; - handle_ = ::CreateFileA(path, desired_access, share_mode, nullptr, - creation_disposition, flags_and_attributes, nullptr); - if (handle_ == INVALID_HANDLE_VALUE) { - Errno errno_copy(::GetLastError()); - GRNXX_ERROR() << "failed to open file: path = " << path - << ", flags = " << flags - << ", call = ::CreateFileA, errno = " << errno_copy; - throw SystemError(errno_copy); - } -} - -} // namespace storage -} // namespace grnxx - -#endif // GRNXX_WINDOWS Deleted: lib/grnxx/storage/file-windows.hpp (+0 -81) 100644 =================================================================== --- lib/grnxx/storage/file-windows.hpp 2013-08-23 10:46:34 +0900 (9dc527e) +++ /dev/null @@ -1,81 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_STORAGE_FILE_WINDOWS_HPP -#define GRNXX_STORAGE_FILE_WINDOWS_HPP - -#include "grnxx/features.hpp" - -#ifdef GRNXX_WINDOWS - -#include <windows.h> - -#include <memory> - -#include "grnxx/storage/file.hpp" - -// FILE_READ_ONLY is defined as a macro in windows.h. -#ifdef FILE_READ_ONLY -# undef FILE_READ_ONLY -#endif // FILE_READ_ONLY - -namespace grnxx { -namespace storage { - -class FileImpl : public File { - public: - FileImpl(); - ~FileImpl(); - - static FileImpl *create(const char *path, FileFlags flags); - static FileImpl *open(const char *path, FileFlags flags); - static FileImpl *open_or_create(const char *path, FileFlags flags); - - static bool exists(const char *path); - static void unlink(const char *path); - - bool lock(FileLockFlags lock_flags); - void unlock(); - - void sync(); - - void resize(uint64_t size); - uint64_t get_size(); - - const char *path() const; - FileFlags flags() const; - const void *handle() const; - - private: - std::unique_ptr<char[]> path_; - FileFlags flags_; - HANDLE handle_; - int fd_; - bool locked_; - - void create_persistent_file(const char *path, FileFlags flags); - void create_temporary_file(const char *path_prefix, FileFlags flags); - void open_file(const char *path, FileFlags flags); - void open_or_create_file(const char *path, FileFlags flags); -}; - -} // namespace storage -} // namespace grnxx - -#endif // GRNXX_WINDOWS - -#endif // GRNXX_STORAGE_FILE_WINDOWS_HPP Deleted: lib/grnxx/storage/file.cpp (+0 -82) 100644 =================================================================== --- lib/grnxx/storage/file.cpp 2013-08-23 10:46:34 +0900 (8bb3370) +++ /dev/null @@ -1,82 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/storage/file.hpp" - -#include "grnxx/storage/file-posix.hpp" -#include "grnxx/storage/file-windows.hpp" -#include "grnxx/string_builder.hpp" - -namespace grnxx { -namespace storage { - -#define GRNXX_FLAGS_WRITE(flag) do { \ - if (flags & flag) { \ - if (!is_first) { \ - builder << " | "; \ - } \ - builder << #flag; \ - is_first = false; \ - } \ -} while (false) - -StringBuilder &operator<<(StringBuilder &builder, FileFlags flags) { - bool is_first = true; - GRNXX_FLAGS_WRITE(FILE_READ_ONLY); - GRNXX_FLAGS_WRITE(FILE_TEMPORARY); - if (is_first) { - builder << "FILE_DEFAULT"; - } - return builder; -} - -StringBuilder &operator<<(StringBuilder &builder, FileLockFlags flags) { - bool is_first = true; - GRNXX_FLAGS_WRITE(FILE_LOCK_SHARED); - GRNXX_FLAGS_WRITE(FILE_LOCK_EXCLUSIVE); - GRNXX_FLAGS_WRITE(FILE_LOCK_NONBLOCKING); - if (is_first) { - builder << "0"; - } - return builder; -} - -File::File() {} -File::~File() {} - -File *File::create(const char *path, FileFlags flags) { - return FileImpl::create(path, flags); -} - -File *File::open(const char *path, FileFlags flags) { - return FileImpl::open(path, flags); -} - -File *File::open_or_create(const char *path, FileFlags flags) { - return FileImpl::open_or_create(path, flags); -} - -bool File::exists(const char *path) { - return FileImpl::exists(path); -} - -void File::unlink(const char *path) { - FileImpl::unlink(path); -} - -} // namespace storage -} // namespace grnxx Deleted: lib/grnxx/storage/file.hpp (+0 -107) 100644 =================================================================== --- lib/grnxx/storage/file.hpp 2013-08-23 10:46:34 +0900 (5cabce4) +++ /dev/null @@ -1,107 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_STORAGE_FILE_HPP -#define GRNXX_STORAGE_FILE_HPP - -#include "grnxx/features.hpp" - -#include "grnxx/flags_impl.hpp" -#include "grnxx/types.hpp" - -namespace grnxx { - -class StringBuilder; - -namespace storage { - -class File; -using FileFlags = FlagsImpl<File>; - -// Use the default settings. -constexpr FileFlags FILE_DEFAULT = FileFlags::define(0x00); -// Open a file in read-only mode. -constexpr FileFlags FILE_READ_ONLY = FileFlags::define(0x01); -// Create a temporary file. -// This flag is implicitly enabled if "path" == nullptr. -constexpr FileFlags FILE_TEMPORARY = FileFlags::define(0x02); - -StringBuilder &operator<<(StringBuilder &builder, FileFlags flags); - -class FileLock; -using FileLockFlags = FlagsImpl<FileLock>; - -// Apply an exclusive advisory lock. -constexpr FileLockFlags FILE_LOCK_SHARED = FileLockFlags::define(0x01); -// Apply a shared advisory lock. -constexpr FileLockFlags FILE_LOCK_EXCLUSIVE = FileLockFlags::define(0x02); -// Immediately return the result when the file is locked. -constexpr FileLockFlags FILE_LOCK_NONBLOCKING = FileLockFlags::define(0x04); - -StringBuilder &operator<<(StringBuilder &builder, FileLockFlags flags); - -class File { - public: - File(); - virtual ~File(); - - // Create a file. - // FILE_TEMPORARY is implicitly enabled if "path" == nullptr. - // The available flag is FILE_TEMPORARY. - static File *create(const char *path, - FileFlags flags = FILE_DEFAULT); - // Open a file. - // The available flag is FILE_READ_ONLY. - static File *open(const char *path, - FileFlags flags = FILE_DEFAULT); - // Open or create a file. - // There are no available flags. - static File *open_or_create(const char *path, - FileFlags flags = FILE_DEFAULT); - - // Return true iff "path" refers to a regular file. - static bool exists(const char *path); - // Unlink a file. - static void unlink(const char *path); - - // Try to lock a file and return true on success. - // Note that the file is accessible even if it is locked (advisory). - virtual bool lock(FileLockFlags lock_flags) = 0; - // Unlock a file. - virtual void unlock() = 0; - - // Flush modified pages. - virtual void sync() = 0; - - // Extend or truncate a file to "size" bytes. - // Note that the contents of the extended part are undefined. - virtual void resize(uint64_t size) = 0; - // Return the file size. - virtual uint64_t get_size() = 0; - - // Return the file path. - virtual const char *path() const = 0; - // Return the activated flags. - virtual FileFlags flags() const = 0; - // Return a pointer to the file handle - virtual const void *handle() const = 0; -}; - -} // namespace storage -} // namespace grnxx - -#endif // GRNXX_STORAGE_FILE_HPP Deleted: lib/grnxx/storage/header.cpp (+0 -67) 100644 =================================================================== --- lib/grnxx/storage/header.cpp 2013-08-23 10:46:34 +0900 (44011f0) +++ /dev/null @@ -1,67 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/storage/header.hpp" - -#include <cstring> - -#include "grnxx/grnxx.hpp" -#include "grnxx/storage.hpp" - -namespace grnxx { -namespace storage { -namespace { - -constexpr char FORMAT_STRING[] = "grnxx::Storage"; - -} // namespace - -Header::Header() - : common_header(), - max_file_size(0), - max_num_files(0), - num_body_chunks(0), - num_small_body_chunks(0), - reserved_0(0), - num_nodes(0), - num_active_or_unlinked_nodes(0), - max_num_nodes(0), - reserved_1(0), - body_usage(0), - body_size(0), - total_size(0), - latest_phantom_node_id(STORAGE_INVALID_NODE_ID), - latest_unlinked_node_id(STORAGE_INVALID_NODE_ID), - oldest_idle_node_ids(), - data_mutex(), - file_mutex(), - reserved_2{} { - for (size_t i = 0; i < NUM_IDLE_NODE_LISTS; ++i) { - oldest_idle_node_ids[i] = STORAGE_INVALID_NODE_ID; - } -} - -Header::operator bool() const { - return common_header.format() == FORMAT_STRING; -} - -void Header::validate() { - common_header = CommonHeader(FORMAT_STRING); -} - -} // namespace storage -} // namespace grnxx Deleted: lib/grnxx/storage/header.hpp (+0 -92) 100644 =================================================================== --- lib/grnxx/storage/header.hpp 2013-08-23 10:46:34 +0900 (087a1aa) +++ /dev/null @@ -1,92 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_STORAGE_HEADER_HPP -#define GRNXX_STORAGE_HEADER_HPP - -#include "grnxx/features.hpp" - -#include "grnxx/common_header.hpp" -#include "grnxx/mutex.hpp" -#include "grnxx/types.hpp" - -namespace grnxx { -namespace storage { - -// The number of bytes allocated to a header. -// sizeof(Header) must not be greater than this value. -constexpr size_t HEADER_SIZE = 512; - -constexpr size_t NUM_IDLE_NODE_LISTS = 64; - -struct Header { - // The file format and the grnxx version. - CommonHeader common_header; - // The maximum size of each file. - uint64_t max_file_size; - // The maximum number of files. - uint16_t max_num_files; - // The number of body chunks. - uint16_t num_body_chunks; - // The number of small body chunks. - uint16_t num_small_body_chunks; - uint16_t reserved_0; - // The number of nodes. - uint32_t num_nodes; - // The number of active or unlinked nodes. - uint32_t num_active_or_unlinked_nodes; - // The upper limit of the number of nodes. - // This value is extended when a node header chunk is added. - uint32_t max_num_nodes; - uint32_t reserved_1; - // The total usage of body chunks. - uint64_t body_usage; - // The total size of body chunks. - uint64_t body_size; - // The total size including headers. - uint64_t total_size; - // The ID of the latest phantom node. - // STORAGE_INVALID_NODE_ID indicates that there are no phantom nodes. - uint32_t latest_phantom_node_id; - // The ID of the latest unlinked node. - // STORAGE_INVALID_NODE_ID indicates that there are no unlinked nodes. - uint32_t latest_unlinked_node_id; - // The IDs of the oldest idle nodes. - // STORAGE_INVALID_NODE_ID indicates that the idle node list is empty. - uint32_t oldest_idle_node_ids[NUM_IDLE_NODE_LISTS]; - // A mutex object for exclusively updating data. - Mutex data_mutex; - // A mutex object for exclusively update files. - Mutex file_mutex; - uint8_t reserved_2[88]; - - // Initialize the members except "common_header". - Header(); - - // Return true iff the header seems to be correct. - explicit operator bool() const; - - // Initialize "common_header". - void validate(); -}; - -static_assert(sizeof(Header) == HEADER_SIZE, "sizeof(Header) != HEADER_SIZE"); - -} // namespace storage -} // namespace grnxx - -#endif // GRNXX_STORAGE_HEADER_HPP Deleted: lib/grnxx/storage/node_header.cpp (+0 -40) 100644 =================================================================== --- lib/grnxx/storage/node_header.cpp 2013-08-23 10:46:34 +0900 (468d40c) +++ /dev/null @@ -1,40 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/storage/node_header.hpp" - -namespace grnxx { -namespace storage { - -NodeHeader::NodeHeader(uint32_t id) - : id(id), - status(STORAGE_NODE_PHANTOM), - reserved_0(0), - chunk_id(0), - offset(0), - size(0), - next_node_id(STORAGE_INVALID_NODE_ID), - prev_node_id(STORAGE_INVALID_NODE_ID), - from_node_id(STORAGE_INVALID_NODE_ID), - reserved_1(0), - next_phantom_node_id(STORAGE_INVALID_NODE_ID), - sibling_node_id(STORAGE_INVALID_NODE_ID), - modified_time(0), - user_data{} {} - -} // namespace storage -} // namespace grnxx Deleted: lib/grnxx/storage/node_header.hpp (+0 -105) 100644 =================================================================== --- lib/grnxx/storage/node_header.hpp 2013-08-23 10:46:34 +0900 (90d3e0f) +++ /dev/null @@ -1,105 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_STORAGE_NODE_HEADER_HPP -#define GRNXX_STORAGE_NODE_HEADER_HPP - -#include "grnxx/features.hpp" - -#include "grnxx/storage.hpp" -#include "grnxx/time.hpp" -#include "grnxx/types.hpp" - -namespace grnxx { -namespace storage { - -constexpr size_t NODE_HEADER_SIZE = 64; - -struct NodeHeader { - // The node ID. - uint32_t id; - // The node status. - StorageNodeStatus status; - uint8_t reserved_0; - // (Non-phantom) - // The ID of the chunk to which the node belongs. - uint16_t chunk_id; - // (Non-phantom) - // The offset in chunk. - uint64_t offset; - // (Non-phantom) - // The body size. - uint64_t size; - // (Non-phantom) - // The ID of the next node in chunk. - // STORAGE_INVALID_NODE_ID indicates that the node is the last node in chunk. - uint32_t next_node_id; - // (Non-phantom) - // The ID of the previous node in chunk. - // STORAGE_INVALID_NODE_ID indicates that the node is the first node in chunk. - uint32_t prev_node_id; - // (Active) - // The ID of the from node. - // STORAGE_INVALID_NODE_ID indicates that the node is the root node. - uint32_t from_node_id; - uint32_t reserved_1; - union { - // (Phantom) - // The ID of the next phantom node. - uint32_t next_phantom_node_id; - // (Active or unlinked) - // The ID of the latest child node. - // STORAGE_INVALID_NODE_ID indicates that the node has no children. - uint32_t child_node_id; - // (Idle) - // The ID of the next idle node. - // id == next_idle_node_id indicates that the node is the only member of - // an idle node list. - uint32_t next_idle_node_id; - }; - union { - // (Active) - // The ID of the next sibling node. - // STORAGE_INVALID_NODE_ID indicates that the node has no elder siblings. - uint32_t sibling_node_id; - // (Unlinked) - // The ID of the next unlinked node. - // STORAGE_INVALID_NODE_ID indicates that the node is the last unlinked - // node. - uint32_t next_unlinked_node_id; - // (Idle) - // The ID of the previous idle node. - // id == prev_idle_node_id indicates that the node is the only member of - // an idle node list. - uint32_t prev_idle_node_id; - }; - // The last modified time. - Time modified_time; - // User data. - uint8_t user_data[8]; - - // Initialize the members. - explicit NodeHeader(uint32_t id); -}; - -static_assert(sizeof(NodeHeader) == NODE_HEADER_SIZE, - "sizeof(NodeHeader) != NODE_HEADER_SIZE"); - -} // namespace storage -} // namespace grnxx - -#endif // GRNXX_STORAGE_NODE_HEADER_HPP Deleted: lib/grnxx/storage/path.cpp (+0 -165) 100644 =================================================================== --- lib/grnxx/storage/path.cpp 2013-08-23 10:46:34 +0900 (73d9cd4) +++ /dev/null @@ -1,165 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/storage/path.hpp" - -#ifdef GRNXX_WINDOWS -# include <stdlib.h> -#else // GRNXX_WINDOWS -# include <unistd.h> -#endif // GRNXX_WINDOWS - -#include <cerrno> -#include <cstring> -#include <new> -#include <random> - -#include "grnxx/errno.hpp" -#include "grnxx/exception.hpp" -#include "grnxx/logger.hpp" -#include "grnxx/string_builder.hpp" - -namespace grnxx { -namespace storage { -namespace { - -constexpr size_t MAX_PATH_LENGTH = 1023; - -} // namespace - -char *Path::full_path(const char *path) { - if (!path) { - path = ""; - } - char full_path[MAX_PATH_LENGTH + 1]; - size_t full_path_length = 0; -#ifdef GRNXX_WINDOWS - if (!::_fullpath(full_path, path, sizeof(full_path))) { - const Errno error_code(errno); - GRNXX_ERROR() << "failed to generate full path: path = " << path - << ", call = ::_fullpath, errno = " << error_code; - throw SystemError(error_code); - } - full_path_length = std::strlen(full_path); -#else // GRNXX_WINDOWS - if (path[0] != '/') { - if (!::getcwd(full_path, sizeof(full_path))) { - const Errno error_code(errno); - GRNXX_ERROR() << "failed to get current working directory: " - << "call = ::getcwd, errno = " << error_code; - throw SystemError(error_code); - } - full_path_length = std::strlen(full_path); - full_path[full_path_length++] = '/'; - } - - const size_t path_length = std::strlen(path); - if ((full_path_length + path_length) >= sizeof(full_path)) { - GRNXX_ERROR() << "failed to generate full path: path = " << path - << ": too long"; - throw LogicError(); - } - std::memcpy(full_path + full_path_length, path, path_length); - full_path_length += path_length; - full_path[full_path_length] = '\0'; - - size_t src = 0; - size_t dest = 0; - while (full_path[src] != '\0') { - if (full_path[src] == '/') { - if (full_path[src + 1] == '\0') { - full_path[dest++] = full_path[src++]; - break; - } else if (full_path[src + 1] == '/') { - ++src; - continue; - } else if (full_path[src + 1] == '.') { - if ((full_path[src + 2] == '/') || (full_path[src + 2] == '\0')) { - src += 2; - continue; - } else if (full_path[src + 2] == '.') { - if ((full_path[src + 3] == '/') || (full_path[src + 3] == '\0')) { - if (dest > 0) { - do { - --dest; - } while (full_path[dest] != '/'); - } - src += 3; - continue; - } - } - } - } - full_path[dest++] = full_path[src++]; - } - if (dest == 0) { - full_path[0] = '/'; - full_path_length = 1; - } else { - full_path_length = dest; - } -#endif // GRNXX_WINDOWS - char * const buf = new (std::nothrow) char[full_path_length + 1]; - if (!buf) { - GRNXX_ERROR() << "new char[" << (full_path_length + 1) << "] failed"; - throw MemoryError(); - } - std::memcpy(buf, full_path, full_path_length); - buf[full_path_length] = '\0'; - return buf; -} - -char *Path::unique_path(const char *prefix) { - if (!prefix) { - prefix = ""; - } - constexpr size_t SUFFIX_LENGTH = 8; - const size_t prefix_length = std::strlen(prefix); - const size_t path_size = prefix_length + SUFFIX_LENGTH + 2; - char * const path(new (std::nothrow) char[path_size]); - if (!path) { - GRNXX_ERROR() << "new char[] failed: path_size = " << path_size; - throw MemoryError(); - } - std::memcpy(path, prefix, prefix_length); - path[prefix_length] = '_'; - std::random_device random; - for (size_t i = 0; i < SUFFIX_LENGTH; ++i) { - const int value = static_cast<int>(random() % 36); - path[prefix_length + 1 + i] = - (value < 10) ? ('0' + value) : ('A' + value - 10); - } - path[prefix_length + 1 + SUFFIX_LENGTH] = '\0'; - return path; -} - -char *Path::clone_path(const char *path) { - if (!path) { - path = ""; - } - const size_t size = std::strlen(path) + 1; - char * const path_clone = new (std::nothrow) char[size]; - if (!path_clone) { - GRNXX_ERROR() << "new char[] failed: size = " << size; - throw MemoryError(); - } - std::memcpy(path_clone, path, size); - return path_clone; -} - -} // namespace storage -} // namespace grnxx Deleted: lib/grnxx/storage/path.hpp (+0 -46) 100644 =================================================================== --- lib/grnxx/storage/path.hpp 2013-08-23 10:46:34 +0900 (92d6435) +++ /dev/null @@ -1,46 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_STORAGE_PATH_HPP -#define GRNXX_STORAGE_PATH_HPP - -#include "grnxx/features.hpp" - -namespace grnxx { -namespace storage { - -class Path { - public: - // Generate a full path from "path" and return an allocated buffer which - // must be freed with delete[]. - static char *full_path(const char *path); - - // Generate an almost unique path by adding a random suffix and return an - // allocated buffer which must be freed with delete[]. - // For example, when "prefix" == "temp", the result is "temp_XXXXXXXX", - // where X indicates a random character ('0'-'9' or 'A'-'Z'). - static char *unique_path(const char *prefix); - - // Create a clone of "path" and return an allocated buffer which must be - // freed with delete[]. - static char *clone_path(const char *path); -}; - -} // namespace storage -} // namespace grnxx - -#endif // GRNXX_STORAGE_PATH_HPP Deleted: lib/grnxx/storage/storage_impl.cpp (+0 -997) 100644 =================================================================== --- lib/grnxx/storage/storage_impl.cpp 2013-08-23 10:46:34 +0900 (a1ac2f9) +++ /dev/null @@ -1,997 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/storage/storage_impl.hpp" - -#include <cstdio> -#include <cstring> -#include <new> -#include <utility> - -#include "grnxx/bytes.hpp" -#include "grnxx/exception.hpp" -#include "grnxx/intrinsic.hpp" -#include "grnxx/lock.hpp" -#include "grnxx/logger.hpp" -#include "grnxx/storage/chunk.hpp" -#include "grnxx/storage/chunk_index.hpp" -#include "grnxx/storage/file.hpp" -#include "grnxx/storage/header.hpp" -#include "grnxx/storage/node_header.hpp" -#include "grnxx/storage/path.hpp" - -namespace grnxx { -namespace storage { -namespace { - -// The size of chunk must be a multiple of CHUNK_UNIT_SIZE (64KB). -constexpr uint64_t CHUNK_UNIT_SIZE = 1 << 16; -// The size of regular node must be a multiple of REGULAR_NODE_UNIT_SIZE (4KB). -constexpr uint64_t REGULAR_NODE_UNIT_SIZE = 1 << 12; -// The size of small node must be a multiple of SMALL_NODE_UNIT_SIZE (64 bytes). -constexpr uint64_t SMALL_NODE_UNIT_SIZE = 1 << 6; -// A node larger than NODE_SIZE_THRESHOLD (2KB) is a regular node. -constexpr uint64_t NODE_SIZE_THRESHOLD = 1 << 11; - -// The chunk size for Header and ChunkIndexes. -constexpr uint64_t ROOT_CHUNK_SIZE = CHUNK_UNIT_SIZE; -// The size allocated to ChunkIndexes. -constexpr uint64_t ROOT_INDEX_SIZE = ROOT_CHUNK_SIZE - HEADER_SIZE; - -// The number of NodeHeaders in the minimum header chunk. -constexpr uint32_t HEADER_CHUNK_MIN_SIZE = CHUNK_UNIT_SIZE / NODE_HEADER_SIZE; - -// The maximum node ID. -constexpr uint32_t MAX_NODE_ID = - STORAGE_INVALID_NODE_ID - HEADER_CHUNK_MIN_SIZE; - -// The maximum number of chunks for NodeHeaders. -constexpr uint16_t MAX_NUM_HEADER_CHUNKS = 32; -// The maximum number of chunks for node bodies. -constexpr uint16_t MAX_NUM_BODY_CHUNKS = - (ROOT_INDEX_SIZE / CHUNK_INDEX_SIZE) - MAX_NUM_HEADER_CHUNKS; - -static_assert(MAX_NUM_BODY_CHUNKS >= 2000, "MAX_NUM_BODY_CHUNKS < 2000"); - -// The minimum size of regular body chunks. -constexpr uint64_t REGULAR_BODY_CHUNK_MIN_SIZE = 1 << 21; -// The ratio of the next regular body chunk size to the storage total size. -constexpr double REGULAR_BODY_CHUNK_SIZE_RATIO = 1.0 / 64; -// The size of the minimum small body chunk. -constexpr uint64_t SMALL_BODY_CHUNK_MIN_SIZE = CHUNK_UNIT_SIZE; - -} // namespace - -StorageImpl::StorageImpl() - : Storage(), - path_(), - flags_(STORAGE_DEFAULT), - header_(nullptr), - header_chunk_indexes_(nullptr), - body_chunk_indexes_(nullptr), - files_(), - root_chunk_(), - header_chunks_(), - body_chunks_(), - mutex_(), - clock_() {} - -StorageImpl::~StorageImpl() {} - -StorageImpl *StorageImpl::create(const char *path, StorageFlags flags, - const StorageOptions &options) { - if (!options) { - GRNXX_ERROR() << "invalid argument: options = " << options; - throw LogicError(); - } - std::unique_ptr<StorageImpl> storage(new (std::nothrow) StorageImpl); - if (!storage) { - GRNXX_ERROR() << "new grnxx::storage::StorageImpl failed"; - throw MemoryError(); - } - if (path || (flags & STORAGE_TEMPORARY)) { - storage->create_file_backed_storage(path, flags, options); - } else { - storage->create_anonymous_storage(flags, options); - } - return storage.release(); -} - -StorageImpl *StorageImpl::open(const char *path, StorageFlags flags) { - if (!path) { - GRNXX_ERROR() << "invalid argument: path = nullptr"; - throw LogicError(); - } - std::unique_ptr<StorageImpl> storage(new (std::nothrow) StorageImpl); - if (!storage) { - GRNXX_ERROR() << "new grnxx::storage::StorageImpl failed"; - throw MemoryError(); - } - storage->open_storage(path, flags); - return storage.release(); -} - -StorageImpl *StorageImpl::open_or_create(const char *path, StorageFlags flags, - const StorageOptions &options) { - if (!path) { - GRNXX_ERROR() << "invalid argument: path = nullptr"; - throw LogicError(); - } - if (!options) { - GRNXX_ERROR() << "invalid argument: options = " << options; - throw LogicError(); - } - std::unique_ptr<StorageImpl> storage(new (std::nothrow) StorageImpl); - if (!storage) { - GRNXX_ERROR() << "new grnxx::storage::StorageImpl failed"; - throw MemoryError(); - } - storage->open_or_create_storage(path, flags, options); - return storage.release(); -} - -bool StorageImpl::exists(const char *path) { - if (!path) { - GRNXX_ERROR() << "invalid argument: path = nullptr"; - throw LogicError(); - } - if (!File::exists(path)) { - return false; - } - std::unique_ptr<Storage> storage(open(path, STORAGE_READ_ONLY)); - return true; -} - -void StorageImpl::unlink(const char *path) { - if (!path) { - GRNXX_ERROR() << "invalid argument: path = nullptr"; - throw LogicError(); - } - std::unique_ptr<StorageImpl> storage(open(path, STORAGE_READ_ONLY)); - storage->unlink_storage(); -} - -StorageNode StorageImpl::create_node(uint32_t parent_node_id, uint64_t size) { - if (flags_ & STORAGE_READ_ONLY) { - GRNXX_ERROR() << "invalid operation: flags = " << flags_; - throw LogicError(); - } - Lock data_lock(&header_->data_mutex); - if (parent_node_id >= header_->num_nodes) { - GRNXX_ERROR() << "invalid argument: parent_node_id = " << parent_node_id - << ", num_nodes = " << header_->num_nodes; - throw LogicError(); - } else if (size > header_->max_file_size) { - GRNXX_ERROR() << "invalid argument: size = " << size - << ", max_file_size = " << header_->max_file_size; - throw LogicError(); - } - NodeHeader * const parent_node_header = get_node_header(parent_node_id); - if ((parent_node_header->status != STORAGE_NODE_ACTIVE) && - (parent_node_header->status != STORAGE_NODE_UNLINKED)) { - GRNXX_ERROR() << "invalid argument: status = " - << parent_node_header->status; - throw LogicError(); - } - NodeHeader *child_node_header = nullptr; - if (parent_node_header->child_node_id != STORAGE_INVALID_NODE_ID) { - child_node_header = get_node_header(parent_node_header->child_node_id); - } - NodeHeader * const node_header = create_active_node(size); - node_header->sibling_node_id = parent_node_header->child_node_id; - node_header->from_node_id = parent_node_id; - parent_node_header->child_node_id = node_header->id; - if (child_node_header) { - child_node_header->from_node_id = node_header->id; - } - void * const body = get_node_body(node_header); - return StorageNode(node_header, body); -} - -StorageNode StorageImpl::open_node(uint32_t node_id) { - NodeHeader * const node_header = get_node_header(node_id); - if ((node_header->status != STORAGE_NODE_ACTIVE) && - (node_header->status != STORAGE_NODE_UNLINKED)) { - GRNXX_ERROR() << "invalid argument: status = " << node_header->status; - throw LogicError(); - } - void * const body = get_node_body(node_header); - return StorageNode(node_header, body); -} - -void StorageImpl::unlink_node(uint32_t node_id) { - if (flags_ & STORAGE_READ_ONLY) { - GRNXX_ERROR() << "invalid operation: flags = " << flags_; - throw LogicError(); - } - Lock data_lock(&header_->data_mutex); - if ((node_id == STORAGE_ROOT_NODE_ID) || (node_id >= header_->num_nodes)) { - GRNXX_ERROR() << "invalid argument: node_id = " << node_id - << ", num_nodes = " << header_->num_nodes; - throw LogicError(); - } - NodeHeader * const node_header = get_node_header(node_id); - if (node_header->status != STORAGE_NODE_ACTIVE) { - GRNXX_ERROR() << "invalid status: expected = " << STORAGE_NODE_ACTIVE - << ", actual = " << node_header->status; - throw LogicError(); - } - NodeHeader * const from_node_header = - get_node_header(node_header->from_node_id); - if (node_id == from_node_header->child_node_id) { - from_node_header->child_node_id = node_header->sibling_node_id; - } else if (node_id == from_node_header->sibling_node_id) { - from_node_header->sibling_node_id = node_header->sibling_node_id; - } else { - // This error must not occur. - GRNXX_ERROR() << "broken link: node_id = " << node_id - << ", from_node_id = " << from_node_header->id - << ", child_node_id = " << from_node_header->child_node_id - << ", sibling_node_id = " - << from_node_header->sibling_node_id; - throw LogicError(); - } - if (node_header->sibling_node_id != STORAGE_INVALID_NODE_ID) { - NodeHeader * const sibling_node_header = - get_node_header(node_header->sibling_node_id); - sibling_node_header->from_node_id = node_header->from_node_id; - } - NodeHeader *latest_node_header = nullptr; - if (header_->latest_unlinked_node_id != STORAGE_INVALID_NODE_ID) { - latest_node_header = get_node_header(header_->latest_unlinked_node_id); - } - node_header->status = STORAGE_NODE_UNLINKED; - if (latest_node_header) { - node_header->next_unlinked_node_id = - latest_node_header->next_unlinked_node_id; - latest_node_header->next_unlinked_node_id = node_id; - } else { - node_header->next_unlinked_node_id = node_id; - } - header_->latest_unlinked_node_id = node_id; - node_header->modified_time = clock_.now(); -} - -void StorageImpl::sweep(Duration lifetime) { - if (flags_ & STORAGE_READ_ONLY) { - GRNXX_ERROR() << "invalid operation: flags = " << flags_; - throw LogicError(); - } - Lock data_lock(&header_->data_mutex); - if (header_->latest_unlinked_node_id == STORAGE_INVALID_NODE_ID) { - // Nothing to do. - return; - } - NodeHeader * const latest_node_header = - get_node_header(header_->latest_unlinked_node_id); - const Time threshold = clock_.now() - lifetime; - do { - NodeHeader * const oldest_node_header = - get_node_header(latest_node_header->next_unlinked_node_id); - if (oldest_node_header->status != STORAGE_NODE_UNLINKED) { - // This error must not occur. - GRNXX_ERROR() << "invalid argument: status = " - << oldest_node_header->status; - throw LogicError(); - } - if (oldest_node_header->modified_time > threshold) { - // Remaining unlinked nodes are too early for reuse. - break; - } - const uint32_t next_node_id = oldest_node_header->next_unlinked_node_id; - sweep_subtree(oldest_node_header); - if (oldest_node_header != latest_node_header) { - latest_node_header->next_unlinked_node_id = next_node_id; - } else { - header_->latest_unlinked_node_id = STORAGE_INVALID_NODE_ID; - } - } while (header_->latest_unlinked_node_id != STORAGE_INVALID_NODE_ID); -} - -const char *StorageImpl::path() const { - return path_.get(); -} - -StorageFlags StorageImpl::flags() const { - return flags_; -} - -uint64_t StorageImpl::max_file_size() const { - return header_->max_file_size; -} - -uint16_t StorageImpl::max_num_files() const { - return header_->max_num_files; -} - -uint32_t StorageImpl::num_nodes() const { - return header_->num_active_or_unlinked_nodes; -} - -uint16_t StorageImpl::num_chunks() const { - return header_->num_body_chunks; -} - -uint64_t StorageImpl::body_usage() const { - return header_->body_usage; -} - -uint64_t StorageImpl::body_size() const { - return header_->body_size; -} - -uint64_t StorageImpl::total_size() const { - return header_->total_size; -} - -void StorageImpl::create_file_backed_storage(const char *path, - StorageFlags flags, - const StorageOptions &options) { - if (path) { - path_.reset(Path::clone_path(path)); - } - if (flags & STORAGE_TEMPORARY) { - flags_ |= STORAGE_TEMPORARY; - } - if (flags & STORAGE_HUGE_TLB) { - flags_ |= STORAGE_HUGE_TLB; - } - FileFlags file_flags = FILE_DEFAULT; - if (flags_ & STORAGE_TEMPORARY) { - file_flags |= FILE_TEMPORARY; - } - std::unique_ptr<File> header_file(File::create(path, file_flags)); - try { - header_file->resize(ROOT_CHUNK_SIZE); - std::unique_ptr<Chunk> root_chunk( - create_chunk(header_file.get(), 0, ROOT_CHUNK_SIZE)); - header_ = static_cast<Header *>(root_chunk->address()); - *header_ = Header(); - header_->max_file_size = options.max_file_size & ~(CHUNK_UNIT_SIZE - 1); - header_->max_num_files = options.max_num_files; - header_->total_size = ROOT_CHUNK_SIZE; - prepare_pointers(); - prepare_indexes(); - files_[0] = std::move(header_file); - root_chunk_ = std::move(root_chunk); - create_active_node(options.root_size); - header_->validate(); - } catch (...) { - unlink_storage(); - throw; - } -} - -void StorageImpl::create_anonymous_storage(StorageFlags flags, - const StorageOptions &options) { - flags_ |= STORAGE_ANONYMOUS; - if (flags & STORAGE_HUGE_TLB) { - flags_ |= STORAGE_HUGE_TLB; - } - std::unique_ptr<Chunk> root_chunk(create_chunk(nullptr, 0, ROOT_CHUNK_SIZE)); - header_ = static_cast<Header *>(root_chunk->address()); - *header_ = Header(); - header_->max_file_size = options.max_file_size & ~(CHUNK_UNIT_SIZE - 1); - header_->max_num_files = options.max_num_files; - header_->total_size = ROOT_CHUNK_SIZE; - prepare_pointers(); - prepare_indexes(); - root_chunk_ = std::move(root_chunk); - create_active_node(options.root_size); - header_->validate(); -} - -void StorageImpl::open_storage(const char *path, StorageFlags flags) { - path_.reset(Path::clone_path(path)); - if (flags & STORAGE_READ_ONLY) { - flags_ |= STORAGE_READ_ONLY; - } - if (flags & STORAGE_HUGE_TLB) { - flags_ |= STORAGE_HUGE_TLB; - } - FileFlags file_flags = FILE_DEFAULT; - if (flags_ & STORAGE_READ_ONLY) { - file_flags |= FILE_READ_ONLY; - } - std::unique_ptr<File> header_file(File::open(path, file_flags)); - std::unique_ptr<Chunk> root_chunk( - create_chunk(header_file.get(), 0, ROOT_CHUNK_SIZE)); - header_ = static_cast<Header *>(root_chunk->address()); - if (!*header_) { - GRNXX_ERROR() << "invalid format: path = " << path_.get(); - throw LogicError(); - } - prepare_pointers(); - files_[0] = std::move(header_file); - root_chunk_ = std::move(root_chunk); -} - -void StorageImpl::open_or_create_storage(const char *path, StorageFlags flags, - const StorageOptions &options) { - path_.reset(Path::clone_path(path)); - if (flags & STORAGE_HUGE_TLB) { - flags_ |= STORAGE_HUGE_TLB; - } - std::unique_ptr<File> header_file; - if (File::exists(path)) { - header_file.reset(File::open(path)); - } - if (header_file) { - // Open an existing storage. - std::unique_ptr<Chunk> root_chunk( - create_chunk(header_file.get(), 0, ROOT_CHUNK_SIZE)); - header_ = static_cast<Header *>(root_chunk->address()); - if (!*header_) { - GRNXX_ERROR() << "invalid format: path = " << path_.get(); - throw LogicError(); - } - prepare_pointers(); - files_[0] = std::move(header_file); - root_chunk_ = std::move(root_chunk); - } else { - // Create a storage. - header_file.reset(File::create(path)); - try { - header_file->resize(ROOT_CHUNK_SIZE); - std::unique_ptr<Chunk> root_chunk( - create_chunk(header_file.get(), 0, ROOT_CHUNK_SIZE)); - header_ = static_cast<Header *>(root_chunk->address()); - *header_ = Header(); - header_->max_file_size = options.max_file_size & ~(CHUNK_UNIT_SIZE - 1); - header_->max_num_files = options.max_num_files; - header_->total_size = ROOT_CHUNK_SIZE; - prepare_pointers(); - prepare_indexes(); - files_[0] = std::move(header_file); - root_chunk_ = std::move(root_chunk); - create_active_node(options.root_size); - header_->validate(); - } catch (...) { - unlink_storage(); - throw; - } - } -} - -void StorageImpl::unlink_storage() { - if (flags_ & STORAGE_TEMPORARY) { - // Nothing to do. - return; - } - uint16_t max_file_id = 0; - if (header_) { - max_file_id = header_->total_size / header_->max_file_size; - } - File::unlink(path_.get()); - for (uint16_t i = 1; i <= max_file_id; ++i) { - // Component files may be left if an error occurs. - std::unique_ptr<char[]> numbered_path(generate_path(i)); - File::unlink(numbered_path.get()); - } -} - -void StorageImpl::prepare_pointers() { - header_chunk_indexes_ = reinterpret_cast<ChunkIndex *>(header_ + 1); - body_chunk_indexes_ = header_chunk_indexes_ + MAX_NUM_HEADER_CHUNKS; - if (~flags_ & STORAGE_ANONYMOUS) { - files_.reset( - new (std::nothrow) std::unique_ptr<File>[header_->max_num_files]); - if (!files_) { - GRNXX_ERROR() << "new std::unique_ptr<grnxx::storage::File>[] failed: " - << "size = " << header_->max_num_files; - throw MemoryError(); - } - } - header_chunks_.reset( - new (std::nothrow) std::unique_ptr<Chunk>[MAX_NUM_HEADER_CHUNKS]); - if (!header_chunks_) { - GRNXX_ERROR() << "new std::unique_ptr<grnxx::storage::Chunk>[] failed: " - << "size = " << MAX_NUM_HEADER_CHUNKS; - throw MemoryError(); - } - body_chunks_.reset( - new (std::nothrow) std::unique_ptr<Chunk>[MAX_NUM_BODY_CHUNKS]); - if (!header_chunks_) { - GRNXX_ERROR() << "new std::unique_ptr<grnxx::storage::Chunk>[] failed: " - << "size = " << MAX_NUM_BODY_CHUNKS; - throw MemoryError(); - } -} - -void StorageImpl::prepare_indexes() { - for (uint16_t i = 0; i < MAX_NUM_HEADER_CHUNKS; ++i) { - header_chunk_indexes_[i] = ChunkIndex(i, HEADER_CHUNK); - } - for (uint16_t i = 0; i < MAX_NUM_BODY_CHUNKS; ++i) { - body_chunk_indexes_[i] = ChunkIndex(i, REGULAR_BODY_CHUNK); - } -} - -NodeHeader *StorageImpl::create_active_node(uint64_t size) { - if (size == 0) { - size = SMALL_NODE_UNIT_SIZE; - } else if (size <= NODE_SIZE_THRESHOLD) { - size = (size + SMALL_NODE_UNIT_SIZE - 1) & ~(SMALL_NODE_UNIT_SIZE - 1); - } else { - size = (size + REGULAR_NODE_UNIT_SIZE - 1) & ~(REGULAR_NODE_UNIT_SIZE - 1); - } - NodeHeader *node_header = find_idle_node(size); - if (!node_header) { - node_header = create_idle_node(size); - } - if (node_header->size > size) { - divide_idle_node(node_header, size); - } - activate_idle_node(node_header); - return node_header; -} - -NodeHeader *StorageImpl::find_idle_node(uint64_t size) { - const size_t begin = bit_scan_reverse(size); - const size_t end = (size <= NODE_SIZE_THRESHOLD) ? - bit_scan_reverse(NODE_SIZE_THRESHOLD << 1) : NUM_IDLE_NODE_LISTS; - for (size_t i = begin; i < end; ++i) { - if (header_->oldest_idle_node_ids[i] != STORAGE_INVALID_NODE_ID) { - NodeHeader * const node_header = - get_node_header(header_->oldest_idle_node_ids[i]); - if (node_header->size >= size) { - return node_header; - } - } - } - return nullptr; -} - -NodeHeader *StorageImpl::create_idle_node(uint64_t size) { - NodeHeader * const node_header = reserve_phantom_node(); - ChunkIndex *remainder_chunk_index = nullptr; - ChunkIndex * const chunk_index = - create_body_chunk(size, &remainder_chunk_index); - associate_node_with_chunk(node_header, chunk_index); - if (remainder_chunk_index) { - // Create an idle node for the remaining space. - NodeHeader * const remainder_node_header = create_phantom_node(); - // The following may fail but the requested node is ready. - associate_node_with_chunk(remainder_node_header, remainder_chunk_index); - } - return node_header; -} - -void StorageImpl::divide_idle_node(NodeHeader *node_header, uint64_t size) { - NodeHeader *next_node_header = nullptr; - if (node_header->next_node_id != STORAGE_INVALID_NODE_ID) { - next_node_header = get_node_header(node_header->next_node_id); - } - NodeHeader * const second_node_header = reserve_phantom_node(); - unregister_idle_node(node_header); - header_->latest_phantom_node_id = second_node_header->next_phantom_node_id; - second_node_header->status = STORAGE_NODE_IDLE; - second_node_header->chunk_id = node_header->chunk_id; - second_node_header->offset = node_header->offset + size; - second_node_header->size = node_header->size - size; - second_node_header->next_node_id = node_header->next_node_id; - second_node_header->prev_node_id = node_header->id; - second_node_header->modified_time = clock_.now(); - if (next_node_header) { - next_node_header->prev_node_id = second_node_header->id; - } - node_header->size = size; - node_header->next_node_id = second_node_header->id; - second_node_header->modified_time = clock_.now(); - register_idle_node(node_header); - register_idle_node(second_node_header); -} - -void StorageImpl::activate_idle_node(NodeHeader *node_header) { - unregister_idle_node(node_header); - node_header->status = STORAGE_NODE_ACTIVE; - node_header->child_node_id = STORAGE_INVALID_NODE_ID; - node_header->sibling_node_id = STORAGE_INVALID_NODE_ID; - node_header->modified_time = clock_.now(); - ++header_->num_active_or_unlinked_nodes; - header_->body_usage += node_header->size; -} - -NodeHeader *StorageImpl::reserve_phantom_node() { - if (header_->latest_phantom_node_id != STORAGE_INVALID_NODE_ID) { - return get_node_header(header_->latest_phantom_node_id); - } else { - return create_phantom_node(); - } -} - -NodeHeader *StorageImpl::create_phantom_node() { - const uint32_t node_id = header_->num_nodes; - ChunkIndex *remainder_chunk_index = nullptr; - if (node_id == header_->max_num_nodes) { - create_header_chunk(&remainder_chunk_index); - } - // Create a phantom node. - NodeHeader * const node_header = get_node_header(node_id); - *node_header = NodeHeader(node_id); - node_header->next_phantom_node_id = header_->latest_phantom_node_id; - node_header->modified_time = clock_.now(); - ++header_->num_nodes; - header_->latest_phantom_node_id = node_id; - if (remainder_chunk_index) { - // Create an idle node for the remaining space. - NodeHeader * const remainder_node_header = create_phantom_node(); - // The following may fail but the requested node is ready. - associate_node_with_chunk(remainder_node_header, remainder_chunk_index); - } - return node_header; -} - -void StorageImpl::associate_node_with_chunk(NodeHeader *node_header, - ChunkIndex *chunk_index) { - if ((node_header->id != header_->latest_phantom_node_id) || - (node_header->status != STORAGE_NODE_PHANTOM)) { - // This error must not occur. - GRNXX_ERROR() << "invalid argument: id = " << node_header->id - << ", status = " << node_header->status - << ", num_nodes = " << header_->num_nodes - << ", latest_phantom_node_id = " - << header_->latest_phantom_node_id; - throw LogicError(); - } - header_->latest_phantom_node_id = node_header->next_phantom_node_id; - node_header->status = STORAGE_NODE_IDLE; - node_header->chunk_id = chunk_index->id; - node_header->offset = 0; - node_header->size = chunk_index->size; - node_header->modified_time = clock_.now(); - register_idle_node(node_header); -} - -void StorageImpl::sweep_subtree(NodeHeader *node_header) { - uint32_t child_node_id = node_header->child_node_id; - while (child_node_id != STORAGE_INVALID_NODE_ID) { - NodeHeader * const child_node_header = get_node_header(child_node_id); - child_node_id = child_node_header->sibling_node_id; - sweep_subtree(child_node_header); - node_header->child_node_id = child_node_id; - } - node_header->status = STORAGE_NODE_IDLE; - node_header->modified_time = clock_.now(); - --header_->num_active_or_unlinked_nodes; - header_->body_usage -= node_header->size; - register_idle_node(node_header); - if (node_header->next_node_id != STORAGE_INVALID_NODE_ID) { - NodeHeader * const next_node_header = - get_node_header(node_header->next_node_id); - if (next_node_header->status == STORAGE_NODE_IDLE) { - merge_idle_nodes(node_header, next_node_header); - } - } - if (node_header->prev_node_id != STORAGE_INVALID_NODE_ID) { - NodeHeader * const prev_node_header = - get_node_header(node_header->prev_node_id); - if (prev_node_header->status == STORAGE_NODE_IDLE) { - merge_idle_nodes(prev_node_header, node_header); - } - } -} - -void StorageImpl::merge_idle_nodes(NodeHeader *node_header, - NodeHeader *next_node_header) { - NodeHeader *next_next_node_header = nullptr; - if (next_node_header->next_node_id != STORAGE_INVALID_NODE_ID) { - next_next_node_header = get_node_header(next_node_header->next_node_id); - } - unregister_idle_node(node_header); - unregister_idle_node(next_node_header); - node_header->size += next_node_header->size; - node_header->next_node_id = next_node_header->next_node_id; - if (next_next_node_header) { - next_next_node_header->prev_node_id = node_header->id; - } - *next_node_header = NodeHeader(next_node_header->id); - next_node_header->next_phantom_node_id = header_->latest_phantom_node_id; - next_node_header->modified_time = clock_.now(); - header_->latest_phantom_node_id = next_node_header->id; - register_idle_node(node_header); -} - -ChunkIndex *StorageImpl::create_header_chunk( - ChunkIndex **remainder_chunk_index) { - if (header_->num_nodes > MAX_NODE_ID) { - GRNXX_ERROR() << "too many nodes: " - << "num_nodes = " << header_->num_nodes - << ", max_node_id = " << MAX_NODE_ID; - throw LogicError(); - } - const uint16_t chunk_id = - bit_scan_reverse(header_->num_nodes + HEADER_CHUNK_MIN_SIZE); - const uint64_t size = static_cast<uint64_t>(NODE_HEADER_SIZE) << chunk_id; - if (size > header_->max_file_size) { - GRNXX_ERROR() << "too large chunk: size = " << size - << ", max_file_size = " << header_->max_file_size; - throw LogicError(); - } - uint16_t file_id = header_->total_size / header_->max_file_size; - uint64_t offset = header_->total_size % header_->max_file_size; - uint64_t size_left = header_->max_file_size - offset; - if (size_left < size) { - *remainder_chunk_index = create_body_chunk(size_left); - file_id = header_->total_size / header_->max_file_size; - offset = header_->total_size % header_->max_file_size; - size_left = header_->max_file_size - offset; - if (size_left < size) { - // This error must not occur. - GRNXX_ERROR() << "too large chunk: size = " << size - << ", size_left = " << size_left; - throw LogicError(); - } - } - if (file_id == header_->max_num_files) { - GRNXX_ERROR() << "too many files: file_id = " << file_id - << ", max_num_files = " << header_->max_num_files; - throw LogicError(); - } - ChunkIndex * const chunk_index = &header_chunk_indexes_[chunk_id]; - chunk_index->file_id = file_id; - chunk_index->offset = offset; - chunk_index->size = size; - header_->total_size += size; - header_->max_num_nodes += size / NODE_HEADER_SIZE; - return chunk_index; -} - -ChunkIndex *StorageImpl::create_body_chunk( - uint64_t size, ChunkIndex **remainder_chunk_index) { - uint64_t chunk_size = size; - if (size <= NODE_SIZE_THRESHOLD) { - chunk_size = SMALL_BODY_CHUNK_MIN_SIZE << header_->num_small_body_chunks; - } - uint64_t offset = header_->total_size % header_->max_file_size; - uint64_t size_left = header_->max_file_size - offset; - if (size_left < chunk_size) { - *remainder_chunk_index = create_body_chunk(size_left); - size_left = header_->max_file_size; - } - if (size > NODE_SIZE_THRESHOLD) { - chunk_size = static_cast<uint64_t>( - header_->total_size * REGULAR_BODY_CHUNK_SIZE_RATIO); - chunk_size &= ~(CHUNK_UNIT_SIZE - 1); - if (size > chunk_size) { - chunk_size = size; - } - if (chunk_size > size_left) { - chunk_size = size_left; - } - if (chunk_size < REGULAR_BODY_CHUNK_MIN_SIZE) { - chunk_size = REGULAR_BODY_CHUNK_MIN_SIZE; - } - } - ChunkIndex * const chunk_index = create_body_chunk(chunk_size); - if (size <= NODE_SIZE_THRESHOLD) { - chunk_index->type = SMALL_BODY_CHUNK; - ++header_->num_small_body_chunks; - } - return chunk_index; -} - -ChunkIndex *StorageImpl::create_body_chunk(uint64_t size) { - const uint16_t chunk_id = header_->num_body_chunks; - if (header_->num_body_chunks >= MAX_NUM_BODY_CHUNKS) { - GRNXX_ERROR() << "too many chunks: " - << "num_chunks = " << header_->num_body_chunks - << ", max_num_chunks = " << MAX_NUM_BODY_CHUNKS; - throw LogicError(); - } - const uint16_t file_id = header_->total_size / header_->max_file_size; - const uint64_t offset = header_->total_size % header_->max_file_size; - const uint64_t size_left = header_->max_file_size - offset; - if (file_id >= header_->max_num_files) { - GRNXX_ERROR() << "too many files: file_id = " << file_id - << ", max_num_files = " << header_->max_num_files; - throw LogicError(); - } - if (size_left < size) { - // This error must not occur. - GRNXX_ERROR() << "too large chunk: size = " << size - << ", size_left = " << size_left; - throw LogicError(); - } - ChunkIndex * const chunk_index = &body_chunk_indexes_[chunk_id]; - chunk_index->file_id = file_id; - chunk_index->offset = offset; - chunk_index->size = size; - header_->body_size += size; - header_->total_size += size; - ++header_->num_body_chunks; - return chunk_index; -} - -void StorageImpl::register_idle_node(NodeHeader *node_header) { - if (node_header->status != STORAGE_NODE_IDLE) { - // This error must not occur. - GRNXX_ERROR() << "invalid argument: status = " << node_header->status; - throw LogicError(); - } - size_t list_id = bit_scan_reverse(node_header->size); - if (body_chunk_indexes_[node_header->chunk_id].type == SMALL_BODY_CHUNK) { - if (list_id > bit_scan_reverse(NODE_SIZE_THRESHOLD)) { - list_id = bit_scan_reverse(NODE_SIZE_THRESHOLD); - } - } - if (header_->oldest_idle_node_ids[list_id] == STORAGE_INVALID_NODE_ID) { - // The given node is appended to the empty list. - node_header->next_idle_node_id = node_header->id; - node_header->prev_idle_node_id = node_header->id; - header_->oldest_idle_node_ids[list_id] = node_header->id; - } else { - // The given node is inserted as the new lastest idle node. - NodeHeader * const oldest_idle_node_header = - get_node_header(header_->oldest_idle_node_ids[list_id]); - NodeHeader * const latest_idle_node_header = - get_node_header(oldest_idle_node_header->prev_idle_node_id); - node_header->next_idle_node_id = oldest_idle_node_header->id; - node_header->prev_idle_node_id = latest_idle_node_header->id; - latest_idle_node_header->next_idle_node_id = node_header->id; - oldest_idle_node_header->prev_idle_node_id = node_header->id; - } -} - -void StorageImpl::unregister_idle_node(NodeHeader *node_header) { - if (node_header->status != STORAGE_NODE_IDLE) { - // This error must not occur. - GRNXX_ERROR() << "invalid argument: status = " << node_header->status; - throw LogicError(); - } - size_t list_id = bit_scan_reverse(node_header->size); - if (body_chunk_indexes_[node_header->chunk_id].type == SMALL_BODY_CHUNK) { - if (list_id > bit_scan_reverse(NODE_SIZE_THRESHOLD)) { - list_id = bit_scan_reverse(NODE_SIZE_THRESHOLD); - } - } - if (node_header->id == node_header->next_idle_node_id) { - // The list becomes empty. - header_->oldest_idle_node_ids[list_id] = STORAGE_INVALID_NODE_ID; - } else { - // The specified node is removed from the list. - NodeHeader * const next_idle_node_header = - get_node_header(node_header->next_idle_node_id); - NodeHeader * const prev_idle_node_header = - get_node_header(node_header->prev_idle_node_id); - next_idle_node_header->prev_idle_node_id = prev_idle_node_header->id; - prev_idle_node_header->next_idle_node_id = next_idle_node_header->id; - if (node_header->id == header_->oldest_idle_node_ids[list_id]) { - header_->oldest_idle_node_ids[list_id] = next_idle_node_header->id; - } - } -} - -NodeHeader *StorageImpl::get_node_header(uint32_t node_id) { - if (node_id >= header_->max_num_nodes) { - GRNXX_ERROR() << "invalid argument: node_id = " << node_id - << ", max_num_nodes = " << header_->max_num_nodes; - throw LogicError(); - } - const uint16_t chunk_id = - bit_scan_reverse(node_id + HEADER_CHUNK_MIN_SIZE); - Chunk * const chunk = get_header_chunk(chunk_id); - const uint32_t chunk_size = 1U << chunk_id; - NodeHeader * const headers = static_cast<NodeHeader *>(chunk->address()); - return headers + (node_id & (chunk_size - 1)); -} - -void *StorageImpl::get_node_body(const NodeHeader *node_header) { - Chunk * const chunk = get_body_chunk(node_header->chunk_id); - return static_cast<uint8_t *>(chunk->address()) + node_header->offset; -} - -Chunk *StorageImpl::get_header_chunk(uint16_t chunk_id) { - if (!header_chunks_[chunk_id]) { - const ChunkIndex &chunk_index = header_chunk_indexes_[chunk_id]; - File *file = nullptr; - if (~flags_ & STORAGE_ANONYMOUS) { - file = reserve_file(chunk_index.file_id, - chunk_index.offset + chunk_index.size); - } - Lock lock(&mutex_); - if (!header_chunks_[chunk_id]) { - header_chunks_[chunk_id].reset( - create_chunk(file, chunk_index.offset, chunk_index.size)); - } - } - return header_chunks_[chunk_id].get(); -} - -Chunk *StorageImpl::get_body_chunk(uint16_t chunk_id) { - if (!body_chunks_[chunk_id]) { - const ChunkIndex &chunk_index = body_chunk_indexes_[chunk_id]; - File *file = nullptr; - if (~flags_ & STORAGE_ANONYMOUS) { - file = reserve_file(chunk_index.file_id, - chunk_index.offset + chunk_index.size); - } - Lock lock(&mutex_); - if (!body_chunks_[chunk_id]) { - body_chunks_[chunk_id].reset( - create_chunk(file, chunk_index.offset, chunk_index.size)); - } - } - return body_chunks_[chunk_id].get(); -} - -File *StorageImpl::reserve_file(uint16_t file_id, uint64_t size) { - if (!files_[file_id]) { - // Create a file if missing. - Lock file_lock(&header_->file_mutex); - if (!files_[file_id]) { - FileFlags file_flags = FILE_DEFAULT; - if (flags_ & STORAGE_READ_ONLY) { - file_flags |= FILE_READ_ONLY; - std::unique_ptr<char[]> path(generate_path(file_id)); - files_[file_id].reset(File::open(path.get(), file_flags)); - } else { - if (flags_ & STORAGE_TEMPORARY) { - file_flags |= FILE_TEMPORARY; - files_[file_id].reset(File::create(path_.get(), file_flags)); - } else { - std::unique_ptr<char[]> path(generate_path(file_id)); - files_[file_id].reset(File::open_or_create(path.get(), file_flags)); - } - } - } - } - // Expand the file if its size is not enough - uint64_t file_size = files_[file_id]->get_size(); - if (file_size < size) { - Lock file_lock(&header_->file_mutex); - file_size = files_[file_id]->get_size(); - if (file_size < size) { - files_[file_id]->resize(size); - } - } - return files_[file_id].get(); -} - -char *StorageImpl::generate_path(uint16_t file_id) { - // If "path_" ends with ".grn", the generated path also ends with ".grn". - // In this case, "file_id" is inserted before the ".grn". - // Otherwise, "file_id" is appended as a suffix. - const Bytes prefix = path_.get(); - const bool has_extension = prefix.ends_with(".grn"); - const size_t path_size = prefix.size() + 5; - char * const path = new (std::nothrow) char[path_size]; - if (!path) { - GRNXX_ERROR() << "new char[] failed: size = " << path_size; - throw MemoryError(); - } - if (has_extension) { - std::memcpy(path, prefix.data(), prefix.size() - 4); - std::sprintf(path + prefix.size() - 4, "_%03d", file_id); - std::strcpy(path + prefix.size(), ".grn"); - } else { - std::memcpy(path, prefix.data(), prefix.size()); - std::sprintf(path + prefix.size(), "_%03d", file_id); - } - return path; -} - -Chunk *StorageImpl::create_chunk(File *file, uint64_t offset, uint64_t size) { - ChunkFlags chunk_flags = CHUNK_DEFAULT; - if (flags_ & STORAGE_HUGE_TLB) { - chunk_flags |= CHUNK_HUGE_TLB; - } - return Chunk::create(file, offset, size, chunk_flags); -} - -} // namespace storage -} // namespace grnxx Deleted: lib/grnxx/storage/storage_impl.hpp (+0 -133) 100644 =================================================================== --- lib/grnxx/storage/storage_impl.hpp 2013-08-23 10:46:34 +0900 (e8fee14) +++ /dev/null @@ -1,133 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_STORAGE_STORAGE_IMPL_HPP -#define GRNXX_STORAGE_STORAGE_IMPL_HPP - -#include "grnxx/features.hpp" - -#include <memory> - -#include "grnxx/duration.hpp" -#include "grnxx/mutex.hpp" -#include "grnxx/periodic_clock.hpp" -#include "grnxx/storage.hpp" -#include "grnxx/time.hpp" - -namespace grnxx { -namespace storage { - -struct Header; -class File; -class Chunk; -struct ChunkIndex; -struct NodeHeader; - -class StorageImpl : public Storage { - public: - StorageImpl(); - ~StorageImpl(); - - static StorageImpl *create(const char *path, - StorageFlags flags, - const StorageOptions &options); - static StorageImpl *open(const char *path, - StorageFlags flags); - static StorageImpl *open_or_create(const char *path, - StorageFlags flags, - const StorageOptions &options); - - static bool exists(const char *path); - static void unlink(const char *path); - - StorageNode create_node(uint32_t parent_node_id, uint64_t size); - StorageNode open_node(uint32_t node_id); - - void unlink_node(uint32_t node_id); - - void sweep(Duration lifetime); - - const char *path() const; - StorageFlags flags() const; - uint64_t max_file_size() const; - uint16_t max_num_files() const; - uint32_t num_nodes() const; - uint16_t num_chunks() const; - uint64_t body_usage() const; - uint64_t body_size() const; - uint64_t total_size() const; - - private: - std::unique_ptr<char[]> path_; - StorageFlags flags_; - Header *header_; - ChunkIndex *header_chunk_indexes_; - ChunkIndex *body_chunk_indexes_; - std::unique_ptr<std::unique_ptr<File>[]> files_; - std::unique_ptr<Chunk> root_chunk_; - std::unique_ptr<std::unique_ptr<Chunk>[]> header_chunks_; - std::unique_ptr<std::unique_ptr<Chunk>[]> body_chunks_; - Mutex mutex_; - PeriodicClock clock_; - - void create_file_backed_storage(const char *path, StorageFlags flags, - const StorageOptions &options); - void create_anonymous_storage(StorageFlags flags, - const StorageOptions &options); - void open_storage(const char *path, StorageFlags flags); - void open_or_create_storage(const char *path, StorageFlags flags, - const StorageOptions &options); - void unlink_storage(); - - void prepare_pointers(); - void prepare_indexes(); - - NodeHeader *create_active_node(uint64_t size); - NodeHeader *find_idle_node(uint64_t size); - NodeHeader *create_idle_node(uint64_t size); - void divide_idle_node(NodeHeader *node_header, uint64_t size); - void activate_idle_node(NodeHeader *node_header); - NodeHeader *reserve_phantom_node(); - NodeHeader *create_phantom_node(); - void associate_node_with_chunk(NodeHeader *node_header, - ChunkIndex *chunk_index); - - void sweep_subtree(NodeHeader *node_header); - void merge_idle_nodes(NodeHeader *node_header, NodeHeader *next_node_header); - - ChunkIndex *create_header_chunk(ChunkIndex **remainder_chunk_index); - ChunkIndex *create_body_chunk(uint64_t size, - ChunkIndex **remainder_chunk_index); - ChunkIndex *create_body_chunk(uint64_t size); - - void register_idle_node(NodeHeader *node_header); - void unregister_idle_node(NodeHeader *node_header); - - NodeHeader *get_node_header(uint32_t node_id); - void *get_node_body(const NodeHeader *node_header); - Chunk *get_header_chunk(uint16_t chunk_id); - Chunk *get_body_chunk(uint16_t chunk_id); - File *reserve_file(uint16_t file_id, uint64_t size); - char *generate_path(uint16_t file_id); - - Chunk *create_chunk(File *file, uint64_t offset, uint64_t size); -}; - -} // namespace storage -} // namespace grnxx - -#endif // GRNXX_STORAGE_STORAGE_IMPL_HPP Deleted: lib/grnxx/string_builder.cpp (+0 -311) 100644 =================================================================== --- lib/grnxx/string_builder.cpp 2013-08-23 10:46:34 +0900 (0343164) +++ /dev/null @@ -1,311 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/string_builder.hpp" - -#include <cmath> -#include <cstdio> -#include <cstring> -#include <new> -#include <utility> - -#include "grnxx/exception.hpp" -#include "grnxx/intrinsic.hpp" -#include "grnxx/logger.hpp" - -namespace grnxx { -namespace { - -constexpr size_t STRING_BUILDER_MIN_BUF_SIZE = 64; - -} // namespace - -StringBuilder::StringBuilder(StringBuilderFlags flags) - : buf_(), - begin_(nullptr), - end_(nullptr), - ptr_(nullptr), - flags_(flags), - failed_(false) {} - -StringBuilder::StringBuilder(size_t size, StringBuilderFlags flags) - : buf_(), - begin_(nullptr), - end_(nullptr), - ptr_(nullptr), - flags_(flags), - failed_(false) { - if (size != 0) { - buf_.reset(new (std::nothrow) char[size]); - if (!buf_) { - failed_ = true; - if (~flags_ & STRING_BUILDER_NOEXCEPT) { - GRNXX_ERROR() << "new char[" << size << "] failed"; - throw MemoryError(); - } - } else { - begin_ = buf_.get(); - end_ = begin_ + size - 1; - ptr_ = begin_; - *ptr_ = '\0'; - } - } -} - -StringBuilder::StringBuilder(char *buf, size_t size, StringBuilderFlags flags) - : buf_(), - begin_(buf), - end_(buf + size - 1), - ptr_(buf), - flags_(flags), - failed_(false) { - *ptr_ = '\0'; -} - -StringBuilder::~StringBuilder() {} - -StringBuilder &StringBuilder::append(int byte) { - if (failed_) { - return *this; - } - if (ptr_ == end_) { - if (!auto_resize(length() + 2)) { - return *this; - } - } - *ptr_ = static_cast<char>(byte); - *++ptr_ = '\0'; - return *this; -} - -StringBuilder &StringBuilder::append(int byte, size_t length) { - if (failed_ || (length == 0)) { - return *this; - } - const size_t size_left = end_ - ptr_; - if (length > size_left) { - if (!auto_resize(this->length() + length + 1)) { - length = size_left; - if (length == 0) { - return *this; - } - } - } - std::memset(ptr_, byte, length); - ptr_ += length; - *ptr_ = '\0'; - return *this; -} - -StringBuilder &StringBuilder::append(const char *ptr, size_t length) { - if (failed_ || !ptr || (length == 0)) { - return *this; - } - const size_t size_left = end_ - ptr_; - if (length > size_left) { - if (!auto_resize(this->length() + length + 1)) { - length = size_left; - if (length == 0) { - return *this; - } - } - } - std::memcpy(ptr_, ptr, length); - ptr_ += length; - *ptr_ = '\0'; - return *this; -} - -StringBuilder &StringBuilder::resize(size_t length) { - const size_t size = end_ - ptr_; - if (length > size) { - if (!resize_buf(length + 1)) { - return *this; - } - } - ptr_ = begin_ + length; - *ptr_ = '\0'; - return *this; -} - -void StringBuilder::clear() { - ptr_ = begin_; - if (ptr_) { - *ptr_ = '\0'; - } - failed_ = false; -} - -bool StringBuilder::auto_resize(size_t size) { - if (~flags_ & STRING_BUILDER_AUTO_RESIZE) { - failed_ = true; - return false; - } - return resize_buf(size); -} - -bool StringBuilder::resize_buf(size_t size) { - if (size < STRING_BUILDER_MIN_BUF_SIZE) { - size = STRING_BUILDER_MIN_BUF_SIZE; - } else { - size = size_t(2) << bit_scan_reverse(size - 1); - } - std::unique_ptr<char[]> new_buf(new (std::nothrow) char[size]); - if (!new_buf) { - failed_ = true; - if (~flags_ & STRING_BUILDER_NOEXCEPT) { - GRNXX_ERROR() << "new char [" << size << "] failed"; - throw MemoryError(); - } - return false; - } - const size_t length = ptr_ - begin_; - std::memcpy(new_buf.get(), begin_, length); - buf_ = std::move(new_buf); - begin_ = buf_.get(); - end_ = begin_ + size - 1; - ptr_ = begin_ + length; - return true; -} - -StringBuilder &operator<<(StringBuilder &builder, long long value) { - if (!builder) { - return builder; - } - char buf[32]; - char *ptr = buf; - char *left = ptr; - if (value >= 0) { - do { - *ptr++ = static_cast<char>('0' + (value % 10)); - value /= 10; - } while (value != 0); - } else { - *ptr++ = '-'; - ++left; - do { - // C++11 always rounds the result toward 0. - *ptr++ = static_cast<char>('0' - (value % 10)); - value /= 10; - } while (value != 0); - } - char *right = ptr - 1; - while (left < right) { - using std::swap; - swap(*left++, *right--); - } - return builder.append(buf, ptr - buf); -} -StringBuilder &operator<<(StringBuilder &builder, unsigned long long value) { - if (!builder) { - return builder; - } - char buf[32]; - char *ptr = buf; - do { - *ptr++ = static_cast<char>('0' + (value % 10)); - value /= 10; - } while (value != 0); - char *left = buf; - char *right = ptr - 1; - while (left < right) { - using std::swap; - swap(*left++, *right--); - } - return builder.append(buf, ptr - buf); -} - -StringBuilder &operator<<(StringBuilder &builder, double value) { - if (!builder) { - return builder; - } - switch (std::fpclassify(value)) { - case FP_NORMAL: - case FP_SUBNORMAL: - case FP_ZERO: { - break; - } - case FP_INFINITE: { - if (value > 0.0) { - return builder.append("inf", 3); - } else { - return builder.append("-inf", 4); - } - } - case FP_NAN: - default: { - return builder.append("nan", 3); - } - } - // The maximum value of double-precision floating point number (IEEE754) - // is 1.797693134862316E+308. - char buf[512]; - int length = std::snprintf(buf, sizeof(buf), "%f", value); - if (length < 0) { - return builder.append("n/a", 3); - } - if (static_cast<size_t>(length) >= sizeof(buf)) { - length = sizeof(buf) - 1; - } - return builder.append(buf, length); -} - -StringBuilder &operator<<(StringBuilder &builder, bool value) { - return value ? builder.append("true", 4) : builder.append("false", 5); -} - -StringBuilder &operator<<(StringBuilder &builder, const void *value) { - if (!builder) { - return builder; - } - if (!value) { - return builder.append("nullptr", 7); - } - char buf[(sizeof(value) * 2) + 2]; - buf[0] = '0'; - buf[1] = 'x'; - uintptr_t address = reinterpret_cast<uintptr_t>(value); - for (size_t i = 2; i < sizeof(buf); ++i) { - const uintptr_t digit = address >> ((sizeof(value) * 8) - 4); - buf[i] = static_cast<char>( - (digit < 10) ? ('0' + digit) : ('A' + digit - 10)); - address <<= 4; - } - return builder.append(buf, sizeof(buf)); -} - -StringBuilder &operator<<(StringBuilder &builder, const char *value) { - if (!builder) { - return builder; - } - if (!value) { - return builder.append("nullptr", 7); - } - return builder.append(value, std::strlen(value)); -} - -StringBuilder &operator<<(StringBuilder &builder, const Bytes &bytes) { - return builder.append(reinterpret_cast<const char *>(bytes.data()), - bytes.size()); -} - -StringBuilder &operator<<(StringBuilder &builder, - const std::exception &exception) { - return builder << "{ what = " << exception.what() << " }"; -} - -} // namespace grnxx Deleted: lib/grnxx/string_builder.hpp (+0 -194) 100644 =================================================================== --- lib/grnxx/string_builder.hpp 2013-08-23 10:46:34 +0900 (36cd09d) +++ /dev/null @@ -1,194 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_STRING_BUILDER_HPP -#define GRNXX_STRING_BUILDER_HPP - -#include "grnxx/features.hpp" - -#include <exception> -#include <memory> - -#include "grnxx/bytes.hpp" -#include "grnxx/flags_impl.hpp" -#include "grnxx/types.hpp" - -namespace grnxx { - -class StringBuilder; -typedef FlagsImpl<StringBuilder> StringBuilderFlags; - -// Use the default settings. -constexpr StringBuilderFlags STRING_BUILDER_DEFAULT = - StringBuilderFlags::define(0x00); -// Automatically resize the buffer. -constexpr StringBuilderFlags STRING_BUILDER_AUTO_RESIZE = - StringBuilderFlags::define(0x01); -// Don't throw even if memory allocation fails. -constexpr StringBuilderFlags STRING_BUILDER_NOEXCEPT = - StringBuilderFlags::define(0x02); - -class StringBuilder { - public: - // Create an empty StringBuilder. - explicit StringBuilder(StringBuilderFlags flags = STRING_BUILDER_DEFAULT); - // Allocate "size" bytes to the internal buffer. - explicit StringBuilder(size_t size, - StringBuilderFlags flags = STRING_BUILDER_DEFAULT); - // Use "buf" ("T" bytes) as the internal buffer. - template <size_t T> - explicit StringBuilder(char (&buf)[T], - StringBuilderFlags flags = STRING_BUILDER_DEFAULT) - : buf_(), - begin_(buf), - end_(buf + T - 1), - ptr_(buf), - flags_(flags), - failed_(false) { - *ptr_ = '\0'; - } - // Use "buf" ("size" bytes) as the internal buffer. - StringBuilder(char *buf, size_t size, - StringBuilderFlags flags = STRING_BUILDER_DEFAULT); - ~StringBuilder(); - - // Return true iff the builder is appendable. - explicit operator bool() const { - return !failed_; - } - - // Return "*this" for one-liners. - StringBuilder &builder() { - return *this; - } - - // Append a character. - StringBuilder &append(int byte); - // Append a sequence of the same character. - StringBuilder &append(int byte, size_t length); - // Append a sequence of length characters. - StringBuilder &append(const char *ptr, size_t length); - - // Resize the string. - // Note that the contents of the extended part are undefined. - StringBuilder &resize(size_t length); - - // Move the pointer to the beginning and clear the failure flag. - void clear(); - - // Return the "i"-th byte. - const char &operator[](size_t i) const { - return begin_[i]; - } - // Return the "i"-th byte. - char &operator[](size_t i) { - return begin_[i]; - } - - // Return the string as a sequence of bytes. - Bytes bytes() const { - return Bytes(begin_, ptr_ - begin_); - } - // Return the address of the string. - const char *c_str() const { - return begin_ ? begin_ : ""; - } - // Return the length of the string. - size_t length() const { - return ptr_ - begin_; - } - - private: - std::unique_ptr<char[]> buf_; - char *begin_; - char *end_; - char *ptr_; - StringBuilderFlags flags_; - bool failed_; - - // Resize the internal buffer. - bool auto_resize(size_t size); - // Resize the internal buffer to greater than or equal to "size" bytes. - bool resize_buf(size_t size); - - StringBuilder(const StringBuilder &) = delete; - StringBuilder &operator=(const StringBuilder &) = delete; -}; - -// Append a character. -inline StringBuilder &operator<<(StringBuilder &builder, char value) { - return builder.append(value); -} - -// Append a signed integer. -StringBuilder &operator<<(StringBuilder &builder, long long value); - -inline StringBuilder &operator<<(StringBuilder &builder, signed char value) { - return builder << static_cast<long long>(value); -} -inline StringBuilder &operator<<(StringBuilder &builder, short value) { - return builder << static_cast<long long>(value); -} -inline StringBuilder &operator<<(StringBuilder &builder, int value) { - return builder << static_cast<long long>(value); -} -inline StringBuilder &operator<<(StringBuilder &builder, long value) { - return builder << static_cast<long long>(value); -} - -// Append an unsigned integer. -StringBuilder &operator<<(StringBuilder &builder, unsigned long long value); - -inline StringBuilder &operator<<(StringBuilder &builder, unsigned char value) { - return builder << static_cast<unsigned long long>(value); -} -inline StringBuilder &operator<<(StringBuilder &builder, unsigned short value) { - return builder << static_cast<unsigned long long>(value); -} -inline StringBuilder &operator<<(StringBuilder &builder, unsigned int value) { - return builder << static_cast<unsigned long long>(value); -} -inline StringBuilder &operator<<(StringBuilder &builder, unsigned long value) { - return builder << static_cast<unsigned long long>(value); -} - -// Append a floating point number. -StringBuilder &operator<<(StringBuilder &builder, double value); - -inline StringBuilder &operator<<(StringBuilder &builder, float value) { - return builder << static_cast<double>(value); -} - -// Append a boolean value (true/false). -StringBuilder &operator<<(StringBuilder &builder, bool value); - -// Append a pointer. -StringBuilder &operator<<(StringBuilder &builder, const void *value); - -// Append a zero-terminated string. -StringBuilder &operator<<(StringBuilder &builder, const char *value); - -// Append a sequence of bytes. -StringBuilder &operator<<(StringBuilder &builder, const Bytes &bytes); - -// Append an exception. -StringBuilder &operator<<(StringBuilder &builder, - const std::exception &exception); - -} // namespace grnxx - -#endif // GRNXX_STRING_BUILDER_HPP Deleted: lib/grnxx/string_format.hpp (+0 -137) 100644 =================================================================== --- lib/grnxx/string_format.hpp 2013-08-23 10:46:34 +0900 (60ffda8) +++ /dev/null @@ -1,137 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_STRING_FORMAT_HPP -#define GRNXX_STRING_FORMAT_HPP - -#include "grnxx/features.hpp" - -#include "grnxx/string_builder.hpp" -#include "grnxx/types.hpp" - -namespace grnxx { - -constexpr size_t STRING_FORMAT_LOCAL_BUF_SIZE = 64; - -enum StringFormatAlignmentAttribute { - STRING_FORMAT_ALIGNMENT_LEFT, - STRING_FORMAT_ALIGNMENT_RIGHT, - STRING_FORMAT_ALIGNMENT_CENTER -}; - -template <typename T> -class StringFormatAlignment { - public: - constexpr StringFormatAlignment(const T &value, size_t width, int pad, - StringFormatAlignmentAttribute attribute) - : value_(value), - width_(width), - pad_(pad), - attribute_(attribute) {} - - constexpr const T &value() const { - return value_; - } - constexpr size_t width() const { - return width_; - } - constexpr int pad() const { - return pad_; - } - constexpr StringFormatAlignmentAttribute attribute() const { - return attribute_; - } - - private: - const T &value_; - size_t width_; - int pad_; - StringFormatAlignmentAttribute attribute_; -}; - -class StringFormat { - public: - StringFormat() = delete; - ~StringFormat() = delete; - - StringFormat(const StringFormat &) = delete; - StringFormat &operator=(const StringFormat &) = delete; - - template <typename T> - static constexpr StringFormatAlignment<T> align_left( - const T &value, size_t width, int pad = ' ') { - return align<T>(value, width, pad, STRING_FORMAT_ALIGNMENT_LEFT); - } - template <typename T> - static constexpr StringFormatAlignment<T> align_right( - const T &value, size_t width, int pad = ' ') { - return align<T>(value, width, pad, STRING_FORMAT_ALIGNMENT_RIGHT); - } - template <typename T> - static constexpr StringFormatAlignment<T> align_center( - const T &value, size_t width, int pad = ' ') { - return align<T>(value, width, pad, STRING_FORMAT_ALIGNMENT_CENTER); - } - - template <typename T> - static constexpr StringFormatAlignment<T> align( - const T &value, size_t width, int pad = ' ', - StringFormatAlignmentAttribute attribute = STRING_FORMAT_ALIGNMENT_LEFT) { - return StringFormatAlignment<T>(value, width, pad, attribute); - } -}; - -template <typename T> -StringBuilder &operator<<(StringBuilder &builder, - const StringFormatAlignment<T> &alignment) { - char local_buf[STRING_FORMAT_LOCAL_BUF_SIZE]; - const StringBuilderFlags local_flags = - (alignment.width() >= sizeof(local_buf)) ? - STRING_BUILDER_AUTO_RESIZE : STRING_BUILDER_DEFAULT; - - StringBuilder local_builder(local_buf, local_flags); - local_builder << alignment.value(); - if (local_builder.length() >= alignment.width()) { - return builder.append(local_builder.c_str(), alignment.width()); - } - - const size_t unused_size = alignment.width() - local_builder.length(); - switch (alignment.attribute()) { - case STRING_FORMAT_ALIGNMENT_LEFT: { - builder.append(local_builder.c_str(), local_builder.length()); - builder.append(alignment.pad(), unused_size); - break; - } - case STRING_FORMAT_ALIGNMENT_RIGHT: { - builder.append(alignment.pad(), unused_size); - builder.append(local_builder.c_str(), local_builder.length()); - break; - } - case STRING_FORMAT_ALIGNMENT_CENTER: { - const size_t offset = unused_size / 2; - builder.append(alignment.pad(), offset); - builder.append(local_builder.c_str(), local_builder.length()); - builder.append(alignment.pad(), unused_size - offset); - break; - } - } - return builder; -} - -} // namespace grnxx - -#endif // GRNXX_STRING_FORMAT_HPP Deleted: lib/grnxx/system_clock.cpp (+0 -32) 100644 =================================================================== --- lib/grnxx/system_clock.cpp 2013-08-23 10:46:34 +0900 (39d390a) +++ /dev/null @@ -1,32 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/system_clock.hpp" - -#include <chrono> - -namespace grnxx { - -Time SystemClock::now() { - // The epoch of std::chrono::system_clock is not guaranteed to be the Unix - // epoch. So, (now() - from_time_t(0)) is used instead of time_since_epoch(). - return Time(std::chrono::duration_cast<std::chrono::microseconds>( - (std::chrono::system_clock::now() - - std::chrono::system_clock::from_time_t(0))).count()); -} - -} // namespace grnxx Deleted: lib/grnxx/system_clock.hpp (+0 -35) 100644 =================================================================== --- lib/grnxx/system_clock.hpp 2013-08-23 10:46:34 +0900 (c92ee3f) +++ /dev/null @@ -1,35 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_SYSTEM_CLOCK_HPP -#define GRNXX_SYSTEM_CLOCK_HPP - -#include "grnxx/features.hpp" - -#include "grnxx/time.hpp" - -namespace grnxx { - -class SystemClock { - public: - // Return the current time. - static Time now(); -}; - -} // namespace grnxx - -#endif // GRNXX_SYSTEM_CLOCK_HPP Deleted: lib/grnxx/thread.cpp (+0 -298) 100644 =================================================================== --- lib/grnxx/thread.cpp 2013-08-23 10:46:34 +0900 (b8f2ec3) +++ /dev/null @@ -1,298 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/thread.hpp" - -#ifdef GRNXX_WINDOWS -# include <process.h> -# include <windows.h> -#else // GRNXX_WINDOWS -# include <pthread.h> -#endif // GRNXX_WINDOWS - -#ifdef GRNXX_HAS_SCHED_YIELD -# include <sched.h> -#endif // GRNXX_HAS_SCHED_YIELD - -#ifdef GRNXX_HAS_NANOSLEEP -# include <time.h> -#endif // GRNXX_HAS_NANOSLEEP - -#ifdef GRNXX_WINDOWS -# include <cerrno> -#endif // GRNXX_WINDOWS - -#include <limits> -#include <memory> -#include <new> - -// TODO: Use the following in future. -//#include <chrono> -//#include <thread> - -#include "grnxx/errno.hpp" -#include "grnxx/exception.hpp" -#include "grnxx/logger.hpp" -#include "grnxx/string_builder.hpp" -#include "grnxx/system_clock.hpp" -#include "grnxx/types.hpp" - -namespace grnxx { -namespace { - -enum ThreadStatus : uint32_t { - THREAD_INITIAL = 0, - THREAD_JOINABLE = 1, - THREAD_JOINED = 2, - THREAD_DETACHED = 3 -}; - -StringBuilder &operator<<(StringBuilder &builder, ThreadStatus status) { - switch (status) { - case THREAD_INITIAL: { - return builder << "THREAD_INITIAL"; - } - case THREAD_JOINABLE: { - return builder << "THREAD_JOINABLE"; - } - case THREAD_JOINED: { - return builder << "THREAD_JOINED"; - } - case THREAD_DETACHED: { - return builder << "THREAD_DETACHED"; - } - default: { - return builder << "n/a"; - } - } -} - -class ThreadImpl : public Thread { - public: - using Routine = Thread::Routine; - - ThreadImpl(); - ~ThreadImpl(); - - void start(const Routine &routine); - - void join(); - void detach(); - - private: -#ifdef GRNXX_WINDOWS - HANDLE thread_; -#else // GRNXX_WINDOWS - pthread_t thread_; -#endif // GRNXX_WINDOWS - ThreadStatus status_; - -#ifdef GRNXX_WINDOWS - static unsigned thread_main(void *arg); -#else // GRNXX_WINDOWS - static void *thread_main(void *arg); -#endif // GRNXX_WINDOWS -}; - -ThreadImpl::ThreadImpl() : thread_(), status_(THREAD_INITIAL) {} - -ThreadImpl::~ThreadImpl() { - // A thread must be joined or detached before destruction. - if (status_ == THREAD_JOINABLE) { - GRNXX_WARNING() << "Bad thread destruction: status = " << status_; - } -} - -void ThreadImpl::start(const Routine &routine) { - std::unique_ptr<Routine> routine_clone(new (std::nothrow) Routine(routine)); - if (!routine_clone) { - GRNXX_ERROR() << "new grnxx::Thread::Routine failed"; - throw MemoryError(); - } -#ifdef GRNXX_WINDOWS - const uintptr_t handle = ::_beginthreadex(nullptr, 0, thread_main, - routine_clone.get(), 0, nullptr); - if (handle == 0) { - const Errno error_code(errno); - GRNXX_ERROR() << "failed to create thread: call = _beginthreadex" - << ", errno = " << error_code; - throw SystemError(error_code); - } - thread_ = reinterpret_cast<HANDLE>(handle); -#else // GRNXX_WINDOWS - const int error = ::pthread_create(&thread_, nullptr, thread_main, - routine_clone.get()); - if (error != 0) { - const Errno error_code(error); - GRNXX_ERROR() << "failed to create thread: call = ::pthread_create" - << ", errno = " << error_code; - throw SystemError(error_code); - } -#endif // GRNXX_WINDOWS - routine_clone.release(); - status_ = THREAD_JOINABLE; -} - -void ThreadImpl::join() { - if (status_ != THREAD_JOINABLE) { - GRNXX_ERROR() << "invalid operation: status = " << status_; - throw LogicError(); - } - status_ = THREAD_JOINED; -#ifdef GRNXX_WINDOWS - if (::WaitForSingleObject(thread_, INFINITE) == WAIT_FAILED) { - const Errno error_code(::GetLastError()); - GRNXX_ERROR() << "failed to join thread: call = ::WaitForSingleObject" - << ", errno = " << error_code; - throw SystemError(error_code); - } - if (::CloseHandle(thread_) != 0) { - const Errno error_code(::GetLastError()); - GRNXX_ERROR() << "failed to close thread: call = ::CloseHandle" - << ", errno = " << error_code; - throw SystemError(error_code); - } -#else // GRNXX_WINDOWS - const int error = ::pthread_join(thread_, nullptr); - if (error != 0) { - const Errno error_code(error); - GRNXX_ERROR() << "failed to join thread: call = ::pthread_join" - << ", errno = " << error_code; - throw SystemError(error_code); - } -#endif // GRNXX_WINDOWS -} - -void ThreadImpl::detach() { - if (status_ != THREAD_JOINABLE) { - GRNXX_ERROR() << "invalid operation: status = " << status_; - throw LogicError(); - } - status_ = THREAD_DETACHED; -#ifdef GRNXX_WINDOWS - if (::CloseHandle(thread_) != 0) { - const Errno error_code(::GetLastError()); - GRNXX_ERROR() << "failed to detach thread: call = ::CloseHandle" - << ", errno = " << error_code; - throw SystemError(error_code); - } -#else // GRNXX_WINDOWS - const int error = ::pthread_detach(thread_); - if (error != 0) { - const Errno error_code(error); - GRNXX_ERROR() << "failed to detach thread: call = ::pthread_detach" - << ", errno = " << error_code; - throw SystemError(error_code); - } -#endif // GRNXX_WINDOWS -} - -#ifdef GRNXX_WINDOWS -unsigned ThreadImpl::thread_main(void *arg) { - std::unique_ptr<Routine> routine(static_cast<Routine *>(arg)); - (*routine)(); - ::_endthreadex(0); - return 0; -} -#else // GRNXX_WINDOWS -void *ThreadImpl::thread_main(void *arg) { - std::unique_ptr<Routine> routine(static_cast<Routine *>(arg)); - (*routine)(); - return nullptr; -} -#endif // GRNXX_WINDOWS - -} // namespace - -Thread::Thread() {} -Thread::~Thread() {} - -Thread *Thread::create(const Routine &routine) { - std::unique_ptr<ThreadImpl> thread(new (std::nothrow) ThreadImpl); - if (!thread) { - GRNXX_ERROR() << "new grnxx::ThreadImpl failed"; - throw MemoryError(); - } - thread->start(routine); - return thread.release(); -} - -void Thread::yield() { -#ifdef GRNXX_WINDOWS - ::SwitchToThread(); -#elif defined(GRNXX_HAS_SCHED_YIELD) - ::sched_yield(); -#else // defined(GRNXX_HAS_SCHED_YIELD) - sleep_for(Duration(0)); -#endif // defined(GRNXX_HAS_SCHED_YIELD) - // TODO: Use the following in future. -// std::this_thread::yield(); -} - -void Thread::sleep_for(Duration duration) { -#ifdef GRNXX_WINDOWS - if (duration.count() <= 0) { - ::Sleep(0); - } else { - const int64_t milliseconds = duration.count() / 1000; - if (milliseconds < - static_cast<int64_t>(std::numeric_limits<DWORD>::max())) { - ::Sleep(static_cast<DWORD>(milliseconds)); - } else { - ::Sleep(std::numeric_limits<DWORD>::max()); - } - } -#elif defined(GRNXX_HAS_NANOSLEEP) - struct timespec request; - if (duration.count() <= 0) { - request.tv_sec = 0; - request.tv_nsec = 0; - } else { - const int64_t seconds = duration.count() / 1000000; - if (seconds < std::numeric_limits<time_t>::max()) { - request.tv_sec = static_cast<time_t>(seconds); - } else { - request.tv_sec = std::numeric_limits<time_t>::max(); - } - duration %= Duration::seconds(1); - request.tv_nsec = static_cast<long>(duration.count() * 1000); - } - // Note that ::nanosleep() requires -lrt option. - ::nanosleep(&request, nullptr); -#else // defined(GRNXX_HAS_NANOSLEEP) - // Note that POSIX.1-2008 removes the specification of ::usleep(). - if (duration.count() <= 0) { - ::usleep(0); - } else { - const int64_t microseconds = duration.count(); - if (microseconds < std::numeric_limits<useconds_t>::max()) { - ::usleep(static_cast<useconds_t>(microseconds)); - } else { - ::usleep(std::numeric_limits<useconds_t>::max()); - } - } -#endif // defined(GRNXX_HAS_NANOSLEEP) - // TODO: Use the following in future. -// std::this_thread::sleep_for(std::chrono::microseconds(duration.count())); -} - -void Thread::sleep_until(Time time) { - const Time now = SystemClock::now(); - sleep_for((time > now) ? (time - now) : Duration(0)); -} - -} // namespace grnxx Deleted: lib/grnxx/thread.hpp (+0 -56) 100644 =================================================================== --- lib/grnxx/thread.hpp 2013-08-23 10:46:34 +0900 (2ebde3e) +++ /dev/null @@ -1,56 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_THREAD_HPP -#define GRNXX_THREAD_HPP - -#include "grnxx/features.hpp" - -#include <functional> - -#include "grnxx/duration.hpp" -#include "grnxx/time.hpp" - -namespace grnxx { - -class Thread { - public: - using Routine = std::function<void()>; - - Thread(); - virtual ~Thread(); - - // Create a thread. - static Thread *create(const Routine &routine); - - // Yield the processor/core associated with the current thread. - static void yield(); - - // Sleep for "duration". - static void sleep_for(Duration duration); - // Sleep until "time". - static void sleep_until(Time time); - - // Wait until the thread finishes. - virtual void join() = 0; - // Separate the thread from this object. - virtual void detach() = 0; -}; - -} // namespace grnxx - -#endif // GRNXX_THREAD_HPP Deleted: lib/grnxx/time.cpp (+0 -117) 100644 =================================================================== --- lib/grnxx/time.cpp 2013-08-23 10:46:34 +0900 (abd3e53) +++ /dev/null @@ -1,117 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/time.hpp" - -#include <ctime> - -#include "grnxx/lock.hpp" -#include "grnxx/mutex.hpp" -#include "grnxx/string_builder.hpp" -#include "grnxx/string_format.hpp" - -namespace grnxx { -namespace { - -// Note: std::tm does not support usec (microseconds). -BrokenDownTime create_broken_down_time(const std::tm &tm, int64_t count) { - BrokenDownTime time; - time.usec = static_cast<int>(count % 1000000); - time.sec = tm.tm_sec; - time.min = tm.tm_min; - time.hour = tm.tm_hour; - time.mday = tm.tm_mday; - time.mon = tm.tm_mon; - time.year = tm.tm_year; - time.wday = tm.tm_wday; - time.yday = tm.tm_yday; - time.isdst = tm.tm_isdst; - return time; -} - -} // namespace - -BrokenDownTime Time::universal_time() const { - const std::time_t posix_time = static_cast<std::time_t>(count_ / 1000000); - std::tm tm; -#ifdef GRNXX_MSC - if (::gmtime_s(&posix_time, &tm) != 0) { - return BrokenDownTime::invalid_value(); - } -#elif defined(GRNXX_HAS_GMTIME_R) - if (::gmtime_r(&posix_time, &tm) == nullptr) { - return BrokenDownTime::invalid_value(); - } -#else // defined(GRNXX_HAS_GMTIME_R) - // Lock is used for exclusive access, but it is still not thread-safe - // because other threads may call std::gmtime(). - static Mutex mutex; - Lock lock(&mutex); - std::tm * const shared_tm = std::gmtime(&posix_time); - if (!shared_tm) { - return BrokenDownTime::invalid_value(); - } - tm = *shared_tm; -#endif // defined(GRNXX_HAS_GMTIME_R) - return create_broken_down_time(tm, count_); -} - -BrokenDownTime Time::local_time() const { - const std::time_t posix_time = static_cast<std::time_t>(count_ / 1000000); - std::tm tm; -#ifdef GRNXX_MSC - if (::localtime_s(&posix_time, &tm) != 0) { - return BrokenDownTime::invalid_value(); - } -#elif defined(GRNXX_HAS_LOCALTIME_R) - if (::localtime_r(&posix_time, &tm) == nullptr) { - return BrokenDownTime::invalid_value(); - } -#else // defined(GRNXX_HAS_LOCALTIME_R) - // Lock is used for exclusive access, but it is still not thread-safe - // because other threads may call std::localtime(). - static Mutex mutex; - Lock lock(&mutex); - std::tm * const shared_tm = std::localtime(&posix_time); - if (!shared_tm) { - return BrokenDownTime::invalid_value(); - } - tm = *shared_tm; -#endif // defined(GRNXX_HAS_LOCALTIME_R) - return create_broken_down_time(tm, count_); -} - -StringBuilder &operator<<(StringBuilder &builder, Time time) { - if (!builder) { - return builder; - } - uint64_t count; - if (time.count() >= 0) { - count = time.count(); - } else { - builder << '-'; - count = -time.count(); - } - builder << (count / 1000000); - count %= 1000000; - if (count != 0) { - builder << '.' << StringFormat::align_right(count, 6, '0'); - } - return builder; -} - -} // namespace grnxx Deleted: lib/grnxx/time.hpp (+0 -116) 100644 =================================================================== --- lib/grnxx/time.hpp 2013-08-23 10:46:34 +0900 (c8748b3) +++ /dev/null @@ -1,116 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_TIME_HPP -#define GRNXX_TIME_HPP - -#include "grnxx/features.hpp" - -#include <limits> - -#include "grnxx/broken_down_time.hpp" -#include "grnxx/duration.hpp" -#include "grnxx/types.hpp" - -namespace grnxx { - -class StringBuilder; - -// Time in microseconds since the Unix epoch (1970-01-01 00:00:00 UTC). -// 64-bit tick count (usec) is used. -class Time { - public: - // Trivial default constructor. - Time() = default; - // Construct a time object whose tick count is "count". - explicit constexpr Time(int64_t count) : count_(count) {} - - // Return the minimum tick count. - static constexpr Time min() { - return Time(std::numeric_limits<int64_t>::min()); - } - // Return the maximum tick count. - static constexpr Time max() { - return Time(std::numeric_limits<int64_t>::max()); - } - - // Transform tick count to broken-down time (UTC). - BrokenDownTime universal_time() const; - // Transform tick count to broken-down time (local). - BrokenDownTime local_time() const; - - // Return the tick count. - constexpr int64_t count() const { - return count_; - } - // Set the tick count. - void set_count(int64_t count) { - count_ = count; - } - - private: - int64_t count_; - - // Copyable. -}; - -inline Time &operator+=(Time &lhs, Duration rhs) { - lhs.set_count(lhs.count() + rhs.count()); - return lhs; -} -inline Time &operator-=(Time &lhs, Duration rhs) { - lhs.set_count(lhs.count() - rhs.count()); - return lhs; -} - -inline constexpr Time operator+(Time lhs, Duration rhs) { - return Time(lhs.count() + rhs.count()); -} -inline constexpr Time operator+(Duration lhs, Time rhs) { - return Time(lhs.count() + rhs.count()); -} -inline constexpr Time operator-(Time lhs, Duration rhs) { - return Time(lhs.count() - rhs.count()); -} -inline constexpr Duration operator-(Time lhs, Time rhs) { - return Duration(lhs.count() - rhs.count()); -} - -inline constexpr bool operator==(Time lhs, Time rhs) { - return lhs.count() == rhs.count(); -} -inline constexpr bool operator!=(Time lhs, Time rhs) { - return lhs.count() != rhs.count(); -} -inline constexpr bool operator<(Time lhs, Time rhs) { - return lhs.count() < rhs.count(); -} -inline constexpr bool operator<=(Time lhs, Time rhs) { - return lhs.count() <= rhs.count(); -} -inline constexpr bool operator>(Time lhs, Time rhs) { - return lhs.count() > rhs.count(); -} -inline constexpr bool operator>=(Time lhs, Time rhs) { - return lhs.count() >= rhs.count(); -} - -StringBuilder &operator<<(StringBuilder &builder, Time time); - -} // namespace grnxx - -#endif // GRNXX_TIME_HPP Deleted: lib/grnxx/traits.hpp (+0 -89) 100644 =================================================================== --- lib/grnxx/traits.hpp 2013-08-23 10:46:34 +0900 (cb57723) +++ /dev/null @@ -1,89 +0,0 @@ -/* - Copyright (C) 2012 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_TRAITS_HPP -#define GRNXX_TRAITS_HPP - -#include "grnxx/features.hpp" - -#include <type_traits> - -namespace grnxx { - -class GeoPoint; - -// A simple/complex type should use pass by value/reference. -template <typename T> -struct PreferredArgument { - using Type = typename std::conditional<std::is_scalar<T>::value, - T, const T &>::type; -}; -// GeoPoint is not a scalar type but a simple type. -template <> struct PreferredArgument<GeoPoint> { - using Type = GeoPoint; -}; - -//// Check if operator<() is defined or not. -//struct HasLessHelper { -// template <typename T> -// static auto check(T *p) -> decltype(p->operator<(*p), std::true_type()); -// template <typename T> -// static auto check(T *p) -> decltype(operator<(*p, *p), std::true_type()); -// template <typename> -// static auto check(...) -> decltype(std::false_type()); -//}; -//// Check if T has operator<() or not. -//template <typename T> -//struct HasLess { -// static constexpr bool value() { -// return std::conditional<std::is_scalar<T>::value, std::true_type, -// decltype(HasLessHelper::check<T>(0))>::type::value; -// } -//}; - -//// Check if T has starts_with() or not. -//struct HasStartsWithHelper { -// template <typename T> -// static auto check(T *p) -> decltype(p->starts_with(*p), std::true_type()); -// template <typename> -// static auto check(...) -> decltype(std::false_type()); -//}; -//// Check if T has operator<() or not. -//template <typename T> -//struct HasStartsWith { -// static constexpr bool value() { -// return decltype(HasStartsWithHelper::check<T>(0))::value; -// } -//}; - -// Type traits. -template <typename T> -struct Traits { - using Type = T; - using ArgumentType = typename PreferredArgument<T>::Type; - -// static constexpr bool has_less() { -// return HasLess<T>::value(); -// } -// static constexpr bool has_starts_with() { -// return HasStartsWith<T>::value(); -// } -}; - -} // namespace grnxx - -#endif // GRNXX_TRAITS_HPP Deleted: lib/grnxx/types.hpp (+0 -47) 100644 =================================================================== --- lib/grnxx/types.hpp 2013-08-23 10:46:34 +0900 (670f4f1) +++ /dev/null @@ -1,47 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_STDINT_HPP -#define GRNXX_STDINT_HPP - -#include "grnxx/features.hpp" - -#include <cstddef> -#include <cstdint> - -namespace grnxx { - -using std::nullptr_t; - -using std::size_t; - -using std::int8_t; -using std::int16_t; -using std::int32_t; -using std::int64_t; - -using std::uint8_t; -using std::uint16_t; -using std::uint32_t; -using std::uint64_t; - -using std::intptr_t; -using std::uintptr_t; - -} // namespace grnxx - -#endif // GRNXX_STDINT_HPP Deleted: obsolete/lib/grnxx/alpha/Makefile.am (+0 -20) 100644 =================================================================== --- obsolete/lib/grnxx/alpha/Makefile.am 2013-08-23 10:46:34 +0900 (ab734ad) +++ /dev/null @@ -1,20 +0,0 @@ -SUBDIRS = map - -noinst_LTLIBRARIES = libgrnxx_alpha.la - -libgrnxx_alpha_la_LIBADD = \ - map/libgrnxx_alpha_map.la - -libgrnxx_alpha_la_LDFLAGS = @AM_LTLDFLAGS@ - -libgrnxx_alpha_la_SOURCES = \ - double_array.cpp \ - dummy.cpp \ - map.cpp - -libgrnxx_alpha_includedir = ${includedir}/grnxx/alpha -libgrnxx_alpha_include_HEADERS = \ - double_array.hpp \ - dummy.hpp \ - map.hpp \ - map_range.hpp Deleted: obsolete/lib/grnxx/alpha/double_array.cpp (+0 -814) 100644 =================================================================== --- obsolete/lib/grnxx/alpha/double_array.cpp 2013-08-23 10:46:34 +0900 (95a2f44) +++ /dev/null @@ -1,814 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/alpha/double_array.hpp" - -#include "grnxx/exception.hpp" -#include "grnxx/lock.hpp" -#include "grnxx/logger.hpp" - -namespace grnxx { -namespace alpha { - -DoubleArrayCreate DOUBLE_ARRAY_CREATE; -DoubleArrayOpen DOUBLE_ARRAY_OPEN; - -DoubleArrayHeader::DoubleArrayHeader() - : nodes_block_id_(io::BLOCK_INVALID_ID), - siblings_block_id_(io::BLOCK_INVALID_ID), - chunks_block_id_(io::BLOCK_INVALID_ID), - entries_block_id_(io::BLOCK_INVALID_ID), - keys_block_id_(io::BLOCK_INVALID_ID), - root_node_id_(0), - total_key_length_(0), - next_key_id_(0), - next_key_pos_(0), - max_key_id_(-1), - num_keys_(0), - num_chunks_(0), - num_phantoms_(0), - num_zombies_(0), - leaders_(), - inter_process_mutex_(MUTEX_UNLOCKED) { - for (uint32_t i = 0; i < DOUBLE_ARRAY_MAX_CHUNK_LEVEL; ++i) { - leaders_[i] = DOUBLE_ARRAY_INVALID_LEADER; - } -} - -DoubleArrayKey::DoubleArrayKey(uint64_t id, const void *address, - uint64_t length) - : id_low_(static_cast<uint32_t>(id)), - id_high_(static_cast<uint8_t>(id >> 32)), - buf_{ '\0', '\0', '\0' } { - std::memcpy(buf_, address, length); -} - -DoubleArrayImpl::~DoubleArrayImpl() { - if (!initialized_) try { - // Allocated blocks are unlinked if initialization failed. - if (header_->nodes_block_id() != io::BLOCK_INVALID_ID) { - nodes_.unlink(pool_, header_->nodes_block_id()); - } - if (header_->siblings_block_id() != io::BLOCK_INVALID_ID) { - siblings_.unlink(pool_, header_->siblings_block_id()); - } - if (header_->chunks_block_id() != io::BLOCK_INVALID_ID) { - chunks_.unlink(pool_, header_->chunks_block_id()); - } - if (header_->entries_block_id() != io::BLOCK_INVALID_ID) { - entries_.unlink(pool_, header_->entries_block_id()); - } - if (header_->keys_block_id() != io::BLOCK_INVALID_ID) { - keys_.unlink(pool_, header_->keys_block_id()); - } - if (block_info_) { - pool_.free_block(*block_info_); - } - } catch (...) { - } -} - -std::unique_ptr<DoubleArrayImpl> DoubleArrayImpl::create(io::Pool pool) { - std::unique_ptr<DoubleArrayImpl> impl(new (std::nothrow) DoubleArrayImpl); - if (!impl) { - GRNXX_ERROR() << "new grnxx::alpha::DoubleArrayImpl failed"; - GRNXX_THROW(); - } - impl->create_double_array(pool); - return impl; -} - -std::unique_ptr<DoubleArrayImpl> DoubleArrayImpl::open(io::Pool pool, - uint32_t block_id) { - std::unique_ptr<DoubleArrayImpl> impl(new (std::nothrow) DoubleArrayImpl); - if (!impl) { - GRNXX_ERROR() << "new grnxx::alpha::DoubleArrayImpl failed"; - GRNXX_THROW(); - } - impl->open_double_array(pool, block_id); - return impl; -} - -bool DoubleArrayImpl::search(const uint8_t *ptr, uint64_t length, - uint64_t *key_pos) { - uint64_t node_id = root_node_id(); - uint64_t query_pos = 0; - if (!search_leaf(ptr, length, node_id, query_pos)) { - return false; - } - - // Note that nodes_[node_id] might be updated by other threads/processes. - const DoubleArrayNode node = nodes_[node_id]; - if (!node.is_leaf()) { - return false; - } - - if (node.key_length() == length) { - if (get_key(node.key_pos()).equals_to(ptr, length, query_pos)) { - if (key_pos) { - *key_pos = node.key_pos(); - } - return true; - } - } - return false; -} - -bool DoubleArrayImpl::insert(const uint8_t *ptr, uint64_t length, - uint64_t *key_pos) { - // TODO: Exclusive access control is required. - -// GRN_DAT_THROW_IF(STATUS_ERROR, (status_flags() & CHANGING_MASK) != 0); -// StatusFlagManager status_flag_manager(header_, INSERTING_FLAG); - -// GRN_DAT_DEBUG_THROW_IF(!ptr && (length != 0)); - - uint64_t node_id = root_node_id(); - uint64_t query_pos = 0; - - search_leaf(ptr, length, node_id, query_pos); - if (!insert_leaf(ptr, length, node_id, query_pos)) { - if (key_pos) { - *key_pos = nodes_[node_id].key_pos(); - } - return false; - } - - const int64_t new_key_id = header_->next_key_id(); - const uint64_t new_key_pos = append_key(ptr, length, new_key_id); - - header_->set_total_key_length(header_->total_key_length() + length); - header_->set_num_keys(header_->num_keys() + 1); - - // TODO: The first key ID should be fixed to 0 or 1. - // Currently, 0 is used. - if (new_key_id > header_->max_key_id()) { - header_->set_max_key_id(new_key_id); - header_->set_next_key_id(new_key_id + 1); - } else { - header_->set_next_key_id(entries_[new_key_id].next()); - } - - entries_[new_key_id].set_key(new_key_pos, length); - nodes_[node_id].set_key(new_key_pos, length); - if (key_pos) { - *key_pos = new_key_pos; - } - return true; -} - -bool DoubleArrayImpl::remove(int64_t key_id) { - // TODO: Exclusive access control is required. - if ((key_id < 0) || (key_id > header_->max_key_id())) { - return false; - } - const DoubleArrayEntry entry = entries_[key_id]; - if (!entry) { - return false; - } - const DoubleArrayKey &key = get_key(entry.key_pos()); - return remove_key(static_cast<const uint8_t *>( - key.ptr()), entry.key_length()); -} - -bool DoubleArrayImpl::remove(const uint8_t *ptr, uint64_t length) { - // TODO: Exclusive access control is required. -// GRN_DAT_THROW_IF(STATUS_ERROR, (status_flags() & CHANGING_MASK) != 0); -// StatusFlagManager status_flag_manager(header_, REMOVING_FLAG); - -// GRN_DAT_DEBUG_THROW_IF((ptr == nullptr) && (length != 0)); - return remove_key(ptr, length); -} - -bool DoubleArrayImpl::update(int64_t key_id, const uint8_t *ptr, - uint64_t length, uint64_t *key_pos) { - // TODO: Exclusive access control is required. - if ((key_id < 0) || (key_id > header_->max_key_id())) { - return false; - } - const DoubleArrayEntry entry = entries_[key_id]; - if (!entry) { - return false; - } - const DoubleArrayKey &key = get_key(entry.key_pos()); - return update_key(static_cast<const uint8_t *>(key.ptr()), entry.key_length(), - key_id, ptr, length, key_pos); -} - -bool DoubleArrayImpl::update(const uint8_t *src_ptr, uint64_t src_length, - const uint8_t *dest_ptr, uint64_t dest_length, - uint64_t *key_pos) { - // TODO: Exclusive access control is required. - uint64_t src_key_id; - if (!search(src_ptr, src_length, &src_key_id)) { - return false; - } - return update_key(src_ptr, src_length, src_key_id, - dest_ptr, dest_length, key_pos); -} - -bool DoubleArrayImpl::update_key(const uint8_t *src_ptr, uint64_t src_length, - uint64_t src_key_id, const uint8_t *dest_ptr, - uint64_t dest_length, uint64_t *key_pos) { -// GRN_DAT_THROW_IF(STATUS_ERROR, (status_flags() & CHANGING_MASK) != 0); -// StatusFlagManager status_flag_manager(header_, UPDATING_FLAG); - -// GRN_DAT_DEBUG_THROW_IF((ptr == NULL) && (length != 0)); - - uint64_t node_id = root_node_id(); - uint64_t query_pos = 0; - - search_leaf(dest_ptr, dest_length, node_id, query_pos); - if (!insert_leaf(dest_ptr, dest_length, node_id, query_pos)) { - if (key_pos) { - *key_pos = nodes_[node_id].key_pos(); - } - return false; - } - - const uint64_t new_key_pos = append_key(dest_ptr, dest_length, src_key_id); - header_->set_total_key_length( - header_->total_key_length() + dest_length - src_length); - entries_[src_key_id].set_key(new_key_pos, dest_length); - nodes_[node_id].set_key(new_key_pos, dest_length); - if (key_pos) { - *key_pos = new_key_pos; - } - - node_id = root_node_id(); - query_pos = 0; - if (!search_leaf(src_ptr, src_length, node_id, query_pos)) { - // TODO: Unexpected error! - } - nodes_[node_id].set_offset(DOUBLE_ARRAY_INVALID_OFFSET); - return true; -} - -DoubleArrayImpl::DoubleArrayImpl() - : pool_(), - block_info_(nullptr), - header_(nullptr), - nodes_(), - siblings_(), - chunks_(), - entries_(), - keys_(), - initialized_(false) {} - -void DoubleArrayImpl::create_double_array(io::Pool pool) { - pool_ = pool; - - block_info_ = pool_.create_block(sizeof(DoubleArrayHeader)); - - void * const block_address = pool_.get_block_address(*block_info_); - header_ = static_cast<DoubleArrayHeader *>(block_address); - *header_ = DoubleArrayHeader(); - - nodes_.create(pool); - header_->set_nodes_block_id(nodes_.block_id()); - siblings_.create(pool); - header_->set_siblings_block_id(siblings_.block_id()); - chunks_.create(pool); - header_->set_chunks_block_id(chunks_.block_id()); - entries_.create(pool); - header_->set_entries_block_id(entries_.block_id()); - keys_.create(pool); - header_->set_keys_block_id(keys_.block_id()); - - reserve_node(root_node_id()); - nodes_[DOUBLE_ARRAY_INVALID_OFFSET].set_is_origin(true); - - initialized_ = true; -} - -void DoubleArrayImpl::open_double_array(io::Pool pool, uint32_t block_id) { - pool_ = pool; - initialized_ = true; - - block_info_ = pool_.get_block_info(block_id); - - void * const block_address = pool_.get_block_address(*block_info_); - header_ = static_cast<DoubleArrayHeader *>(block_address); - - // TODO: Check the format. - - nodes_.open(pool_, header_->nodes_block_id()); - siblings_.open(pool_, header_->siblings_block_id()); - chunks_.open(pool_, header_->chunks_block_id()); - entries_.open(pool_, header_->entries_block_id()); - keys_.open(pool_, header_->keys_block_id()); -} - -bool DoubleArrayImpl::remove_key(const uint8_t *ptr, uint64_t length) { - uint64_t node_id = root_node_id(); - uint64_t query_pos = 0; - if (!search_leaf(ptr, length, node_id, query_pos)) { - return false; - } - - if (length != nodes_[node_id].key_length()) { - return false; - } - - const uint64_t key_pos = nodes_[node_id].key_pos(); - const DoubleArrayKey &key = get_key(key_pos); - if (!key.equals_to(ptr, length, query_pos)) { - return false; - } - - const uint64_t key_id = key.id(); - nodes_[node_id].set_offset(DOUBLE_ARRAY_INVALID_OFFSET); - entries_[key_id].set_next(header_->next_key_id()); - - header_->set_next_key_id(key_id); - header_->set_total_key_length(header_->total_key_length() - length); - header_->set_num_keys(header_->num_keys() - 1); - return true; -} - -bool DoubleArrayImpl::search_leaf(const uint8_t *ptr, uint64_t length, - uint64_t &node_id, uint64_t &query_pos) { - for ( ; query_pos < length; ++query_pos) { - const DoubleArrayNode node = nodes_[node_id]; - if (node.is_leaf()) { - return true; - } - - const uint64_t next = node.offset() ^ ptr[query_pos]; - if (nodes_[next].label() != ptr[query_pos]) { - return false; - } - node_id = next; - } - - const DoubleArrayNode node = nodes_[node_id]; - if (node.is_leaf()) { - return true; - } - - if (node.child() != DOUBLE_ARRAY_TERMINAL_LABEL) { - return false; - } - node_id = node.offset() ^ DOUBLE_ARRAY_TERMINAL_LABEL; - return nodes_[node_id].is_leaf(); -} - -bool DoubleArrayImpl::insert_leaf(const uint8_t *ptr, uint64_t length, - uint64_t &node_id, uint64_t query_pos) { - const DoubleArrayNode node = nodes_[node_id]; - if (node.is_leaf()) { - const DoubleArrayKey &key = get_key(node.key_pos()); - uint64_t i = query_pos; - while ((i < length) && (i < node.key_length())) { - if (ptr[i] != key[i]) { - break; - } - ++i; - } - if ((i == length) && (i == node.key_length())) { - return false; - } - // TODO -// GRN_DAT_THROW_IF(SIZE_ERROR, num_keys() >= max_num_keys()); -// GRN_DAT_DEBUG_THROW_IF(next_key_id() > max_num_keys()); - - for (uint64_t j = query_pos; j < i; ++j) { - node_id = insert_node(node_id, ptr[j]); - } - node_id = separate(ptr, length, node_id, i); - return true; - } else if (node.label() == DOUBLE_ARRAY_TERMINAL_LABEL) { - return true; - } else { - // TODO -// GRN_DAT_THROW_IF(SIZE_ERROR, num_keys() >= max_num_keys()); - const uint16_t label = (query_pos < length) ? - static_cast<uint16_t>(ptr[query_pos]) : DOUBLE_ARRAY_TERMINAL_LABEL; - if ((node.offset() == DOUBLE_ARRAY_INVALID_OFFSET) || - !nodes_[node.offset() ^ label].is_phantom()) { - // The offset of this node must be updated. - resolve(node_id, label); - } - // The new node will be the leaf node associated with the query. - node_id = insert_node(node_id, label); - return true; - } -} - -uint64_t DoubleArrayImpl::insert_node(uint64_t node_id, uint16_t label) { -// GRN_DAT_DEBUG_THROW_IF(node_id >= num_nodes()); -// GRN_DAT_DEBUG_THROW_IF(label > MAX_LABEL); - - const DoubleArrayNode node = nodes_[node_id]; - uint64_t offset; - if (node.is_leaf() || (node.offset() == DOUBLE_ARRAY_INVALID_OFFSET)) { - offset = find_offset(&label, 1); - } else { - offset = node.offset(); - } - - const uint64_t next = offset ^ label; - reserve_node(next); - - nodes_[next].set_label(label); - if (node.is_leaf()) { -// GRN_DAT_DEBUG_THROW_IF(nodes_[offset].is_origin()); - nodes_[offset].set_is_origin(true); - nodes_[next].set_key(node.key_pos(), node.key_length()); - // TODO: Must be update at once. - } else if (node.offset() == DOUBLE_ARRAY_INVALID_OFFSET) { -// GRN_DAT_DEBUG_THROW_IF(nodes_[offset].is_origin()); - nodes_[offset].set_is_origin(true); -// } else { -// GRN_DAT_DEBUG_THROW_IF(!nodes_[offset].is_origin()); - } - nodes_[node_id].set_offset(offset); - - const uint16_t child_label = nodes_[node_id].child(); -// GRN_DAT_DEBUG_THROW_IF(child_label == label); - if (child_label == DOUBLE_ARRAY_INVALID_LABEL) { - nodes_[node_id].set_child(label); - } else if ((label == DOUBLE_ARRAY_TERMINAL_LABEL) || - ((child_label != DOUBLE_ARRAY_TERMINAL_LABEL) && - (label < child_label))) { - // The next node becomes the first child. -// GRN_DAT_DEBUG_THROW_IF(nodes_[offset ^ child_label).is_phantom()); -// GRN_DAT_DEBUG_THROW_IF(nodes_[offset ^ child_label).label() != child_label); - siblings_[next] = child_label; - nodes_[next].set_has_sibling(true); - nodes_[node_id].set_child(label); - } else { - uint64_t prev = offset ^ child_label; -// GRN_DAT_DEBUG_THROW_IF(nodes_[prev).label() != child_label); - uint16_t sibling_label = nodes_[prev].has_sibling() ? - siblings_[prev] : DOUBLE_ARRAY_INVALID_LABEL; - while (label > sibling_label) { - prev = offset ^ sibling_label; -// GRN_DAT_DEBUG_THROW_IF(nodes_[prev].label() != sibling_label); - sibling_label = nodes_[prev].has_sibling() ? - siblings_[prev] : DOUBLE_ARRAY_INVALID_LABEL; - } -// GRN_DAT_DEBUG_THROW_IF(label == sibling_label); - siblings_[next] = siblings_[prev]; - siblings_[prev] = label; - nodes_[next].set_has_sibling(nodes_[prev].has_sibling()); - nodes_[prev].set_has_sibling(true); - } - return next; -} - -uint64_t DoubleArrayImpl::append_key(const uint8_t *ptr, uint64_t length, - uint64_t key_id) { - // TODO -// GRN_DAT_THROW_IF(SIZE_ERROR, key_id > max_num_keys()); - - uint64_t key_pos = header_->next_key_pos(); - const uint64_t key_size = DoubleArrayKey::estimate_size(length); - - // TODO -// GRN_DAT_THROW_IF(SIZE_ERROR, key_size > (key_buf_size() - key_pos)); - const uint64_t size_left_in_page = - (~key_pos + 1) % DOUBLE_ARRAY_KEYS_PAGE_SIZE; - if (size_left_in_page < key_size) { - key_pos += size_left_in_page; - } - new (&keys_[key_pos]) DoubleArrayKey(key_id, ptr, length); - - header_->set_next_key_pos(key_pos + key_size); - return key_pos; -} - -uint64_t DoubleArrayImpl::separate(const uint8_t *ptr, uint64_t length, - uint64_t node_id, uint64_t i) { -// GRN_DAT_DEBUG_THROW_IF(node_id >= num_nodes()); -// GRN_DAT_DEBUG_THROW_IF(!nodes_[node_id].is_leaf()); -// GRN_DAT_DEBUG_THROW_IF(i > length); - - const DoubleArrayNode node = nodes_[node_id]; - const DoubleArrayKey &key = get_key(node.key_pos()); - - uint16_t labels[2]; - labels[0] = (i < node.key_length()) ? - static_cast<uint16_t>(key[i]) : DOUBLE_ARRAY_TERMINAL_LABEL; - labels[1] = (i < length) ? - static_cast<uint16_t>(ptr[i]) : DOUBLE_ARRAY_TERMINAL_LABEL; -// GRN_DAT_DEBUG_THROW_IF(labels[0] == labels[1]); - - const uint64_t offset = find_offset(labels, 2); - - uint64_t next = offset ^ labels[0]; - reserve_node(next); -// GRN_DAT_DEBUG_THROW_IF(nodes_[offset).is_origin()); - - nodes_[next].set_label(labels[0]); - nodes_[next].set_key(node.key_pos(), node.key_length()); - - next = offset ^ labels[1]; - reserve_node(next); - - nodes_[next].set_label(labels[1]); - - nodes_[offset].set_is_origin(true); - nodes_[node_id].set_offset(offset); - - if ((labels[0] == DOUBLE_ARRAY_TERMINAL_LABEL) || - ((labels[1] != DOUBLE_ARRAY_TERMINAL_LABEL) && - (labels[0] < labels[1]))) { - siblings_[offset ^ labels[0]] = labels[1]; - nodes_[offset ^ labels[0]].set_has_sibling(true); - nodes_[node_id].set_child(labels[0]); - } else { - siblings_[offset ^ labels[1]] = labels[0]; - nodes_[offset ^ labels[1]].set_has_sibling(true); - nodes_[node_id].set_child(labels[1]); - } - return next; -} - -void DoubleArrayImpl::resolve(uint64_t node_id, uint16_t label) { -// GRN_DAT_DEBUG_THROW_IF(node_id >= num_nodes()); -// GRN_DAT_DEBUG_THROW_IF(nodes_[node_id].is_leaf()); -// GRN_DAT_DEBUG_THROW_IF(label > MAX_LABEL); - - uint64_t offset = nodes_[node_id].offset(); - if (offset != DOUBLE_ARRAY_INVALID_OFFSET) { - uint16_t labels[DOUBLE_ARRAY_MAX_LABEL + 1]; - uint16_t num_labels = 0; - - uint16_t next_label = nodes_[node_id].child(); - // FIXME: How to check if the node has children or not. -// GRN_DAT_DEBUG_THROW_IF(next_label == INVALID_LABEL); - while (next_label != DOUBLE_ARRAY_INVALID_LABEL) { -// GRN_DAT_DEBUG_THROW_IF(next_label > MAX_LABEL); - labels[num_labels++] = next_label; - next_label = nodes_[offset ^ next_label].has_sibling() ? - siblings_[offset ^ next_label] : DOUBLE_ARRAY_INVALID_LABEL; - } -// GRN_DAT_DEBUG_THROW_IF(num_labels == 0); - - labels[num_labels] = label; - offset = find_offset(labels, num_labels + 1); - migrate_nodes(node_id, offset, labels, num_labels); - } else { - offset = find_offset(&label, 1); - if (offset >= header_->num_nodes()) { -// GRN_DAT_DEBUG_THROW_IF((offset / BLOCK_SIZE) != num_blocks()); - reserve_chunk(header_->num_chunks()); - } - nodes_[offset].set_is_origin(true); - nodes_[node_id].set_offset(offset); - } -} - -void DoubleArrayImpl::migrate_nodes(uint64_t node_id, uint64_t dest_offset, - const uint16_t *labels, - uint16_t num_labels) { -// GRN_DAT_DEBUG_THROW_IF(node_id >= num_nodes()); -// GRN_DAT_DEBUG_THROW_IF(nodes_[node_id].is_leaf()); -// GRN_DAT_DEBUG_THROW_IF(labels == nullptr); -// GRN_DAT_DEBUG_THROW_IF(num_labels == 0); -// GRN_DAT_DEBUG_THROW_IF(num_labels > (DOUBLE_ARRAY_MAX_LABEL + 1)); - - const uint64_t src_offset = nodes_[node_id].offset(); -// GRN_DAT_DEBUG_THROW_IF(src_offset == DOUBLE_ARRAY_INVALID_OFFSET); -// GRN_DAT_DEBUG_THROW_IF(!nodes_[src_offset].is_origin()); - - for (uint16_t i = 0; i < num_labels; ++i) { - const uint64_t src_node_id = src_offset ^ labels[i]; - const uint64_t dest_node_id = dest_offset ^ labels[i]; -// GRN_DAT_DEBUG_THROW_IF(ith_node(src_node_id).is_phantom()); -// GRN_DAT_DEBUG_THROW_IF(ith_node(src_node_id).label() != labels[i]); - - reserve_node(dest_node_id); - DoubleArrayNode dest_node = nodes_[src_node_id]; - dest_node.set_is_origin(nodes_[dest_node_id].is_origin()); - nodes_[dest_node_id] = dest_node; - siblings_[dest_node_id] = siblings_[src_node_id]; - } - header_->set_num_zombies(header_->num_zombies() + num_labels); - -// GRN_DAT_DEBUG_THROW_IF(nodes_[dest_offset].is_origin()); - nodes_[dest_offset].set_is_origin(true); - nodes_[node_id].set_offset(dest_offset); -} - -uint64_t DoubleArrayImpl::find_offset(const uint16_t *labels, - uint16_t num_labels) { -// GRN_DAT_DEBUG_THROW_IF(labels == nullptr); -// GRN_DAT_DEBUG_THROW_IF(num_labels == 0); -// GRN_DAT_DEBUG_THROW_IF(num_labels > (MAX_LABEL + 1)); - - // Chunks are tested in descending order of level. Basically, lower level - // chunks contain more phantom nodes. - uint32_t level = 1; - while (num_labels >= (1U << level)) { - ++level; - } - level = (level < DOUBLE_ARRAY_MAX_CHUNK_LEVEL) ? - (DOUBLE_ARRAY_MAX_CHUNK_LEVEL - level) : 0; - - uint64_t chunk_count = 0; - do { - uint64_t leader = header_->ith_leader(level); - if (leader == DOUBLE_ARRAY_INVALID_LEADER) { - // This level group is skipped because it is empty. - continue; - } - - uint64_t chunk_id = leader; - do { - const DoubleArrayChunk &chunk = chunks_[chunk_id]; -// GRN_DAT_DEBUG_THROW_IF(chunk.level() != level); - - const uint64_t first = - (chunk_id * DOUBLE_ARRAY_CHUNK_SIZE) | chunk.first_phantom(); - uint64_t node_id = first; - do { -// GRN_DAT_DEBUG_THROW_IF(!nodes_[node_id=]).is_phantom()); - const uint64_t offset = node_id ^ labels[0]; - if (!nodes_[offset].is_origin()) { - uint16_t i = 1; - for ( ; i < num_labels; ++i) { - if (!nodes_[offset ^ labels[i]].is_phantom()) { - break; - } - } - if (i >= num_labels) { - return offset; - } - } - node_id = (chunk_id * DOUBLE_ARRAY_CHUNK_SIZE) | nodes_[node_id].next(); - } while (node_id != first); - - const uint64_t prev = chunk_id; - const uint64_t next = chunk.next(); - chunk_id = next; - chunks_[prev].set_failure_count(chunks_[prev].failure_count() + 1); - - // The level of a chunk is updated when this function fails many times, - // actually DOUBLE_ARRAY_MAX_FAILURE_COUNT times, in that chunk. - if (chunks_[prev].failure_count() == DOUBLE_ARRAY_MAX_FAILURE_COUNT) { - update_chunk_level(prev, level + 1); - if (next == leader) { - break; - } else { - // Note that the leader might be updated in the level update. - leader = header_->ith_leader(level); - continue; - } - } - } while ((++chunk_count < DOUBLE_ARRAY_MAX_CHUNK_COUNT) && - (chunk_id != leader)); - } while ((chunk_count < DOUBLE_ARRAY_MAX_CHUNK_COUNT) && (level-- != 0)); - - return header_->num_nodes() ^ labels[0]; -} - -void DoubleArrayImpl::reserve_node(uint64_t node_id) { - if (node_id >= header_->num_nodes()) { - reserve_chunk(node_id / DOUBLE_ARRAY_CHUNK_SIZE); - } - - DoubleArrayNode &node = nodes_[node_id]; -// GRN_DAT_DEBUG_THROW_IF(!node.is_phantom()); - - const uint64_t chunk_id = node_id / DOUBLE_ARRAY_CHUNK_SIZE; - DoubleArrayChunk &chunk = chunks_[chunk_id]; -// GRN_DAT_DEBUG_THROW_IF(chunk.num_phantoms() == 0); - - const uint64_t next = (chunk_id * DOUBLE_ARRAY_CHUNK_SIZE) | node.next(); - const uint64_t prev = (chunk_id * DOUBLE_ARRAY_CHUNK_SIZE) | node.prev(); -// GRN_DAT_DEBUG_THROW_IF(next >= header_->num_nodes()); -// GRN_DAT_DEBUG_THROW_IF(prev >= header_->num_nodes()); - - if ((node_id & DOUBLE_ARRAY_CHUNK_MASK) == chunk.first_phantom()) { - // The first phantom node is removed from the chunk and the second phantom - // node comes first. - chunk.set_first_phantom(next & DOUBLE_ARRAY_CHUNK_MASK); - } - - nodes_[next].set_prev(prev & DOUBLE_ARRAY_CHUNK_MASK); - nodes_[prev].set_next(next & DOUBLE_ARRAY_CHUNK_MASK); - - if (chunk.level() != DOUBLE_ARRAY_MAX_CHUNK_LEVEL) { - const uint64_t threshold = - uint64_t(1) << ((DOUBLE_ARRAY_MAX_CHUNK_LEVEL - chunk.level() - 1) * 2); - if (chunk.num_phantoms() == threshold) { - update_chunk_level(chunk_id, chunk.level() + 1); - } - } - chunk.set_num_phantoms(chunk.num_phantoms() - 1); - - node.set_is_phantom(false); - -// GRN_DAT_DEBUG_THROW_IF(node.offset() != DOUBLE_ARRAY_INVALID_OFFSET); -// GRN_DAT_DEBUG_THROW_IF(node.label() != DOUBLE_ARRAY_INVALID_LABEL); - - header_->set_num_phantoms(header_->num_phantoms() - 1); -} - -void DoubleArrayImpl::reserve_chunk(uint64_t chunk_id) { -// GRN_DAT_DEBUG_THROW_IF(chunk_id != num_chunks()); - // TODO -// GRN_DAT_THROW_IF(SIZE_ERROR, chunk_id >= max_num_chunks()); - - header_->set_num_chunks(chunk_id + 1); - chunks_[chunk_id].set_failure_count(0); - chunks_[chunk_id].set_first_phantom(0); - chunks_[chunk_id].set_num_phantoms(DOUBLE_ARRAY_CHUNK_SIZE); - - const uint64_t begin = chunk_id * DOUBLE_ARRAY_CHUNK_SIZE; - const uint64_t end = begin + DOUBLE_ARRAY_CHUNK_SIZE; -// GRN_DAT_DEBUG_THROW_IF(end != num_nodes()); - - DoubleArrayNode node; - node.set_is_phantom(true); - - for (uint64_t i = begin; i < end; ++i) { - node.set_prev((i - 1) & DOUBLE_ARRAY_CHUNK_MASK); - node.set_next((i + 1) & DOUBLE_ARRAY_CHUNK_MASK); - nodes_[i] = node; - siblings_[i] = '\0'; - } - - // The level of the new chunk is 0. - set_chunk_level(chunk_id, 0); - header_->set_num_phantoms(header_->num_phantoms() + DOUBLE_ARRAY_CHUNK_SIZE); -} - -void DoubleArrayImpl::update_chunk_level(uint64_t chunk_id, uint32_t level) { -// GRN_DAT_DEBUG_THROW_IF(chunk_id >= num_chunks()); -// GRN_DAT_DEBUG_THROW_IF(level > DOUBLE_ARRAY_MAX_CHUNK_LEVEL); - - unset_chunk_level(chunk_id); - set_chunk_level(chunk_id, level); -} - -void DoubleArrayImpl::set_chunk_level(uint64_t chunk_id, uint32_t level) { -// GRN_DAT_DEBUG_THROW_IF(chunk_id >= num_chunks()); -// GRN_DAT_DEBUG_THROW_IF(level > DOUBLE_ARRAY_MAX_CHUNK_LEVEL); - - const uint64_t leader = header_->ith_leader(level); - if (leader == DOUBLE_ARRAY_INVALID_LEADER) { - // The chunk becomes the only one member of the level group. - chunks_[chunk_id].set_next(chunk_id); - chunks_[chunk_id].set_prev(chunk_id); - header_->set_ith_leader(level, chunk_id); - } else { - // The chunk is appended to the level group, in practice. - const uint64_t next = leader; - const uint64_t prev = chunks_[leader].prev(); -// GRN_DAT_DEBUG_THROW_IF(next >= num_chunks()); -// GRN_DAT_DEBUG_THROW_IF(prev >= num_chunks()); - chunks_[chunk_id].set_next(next); - chunks_[chunk_id].set_prev(prev); - chunks_[next].set_prev(chunk_id); - chunks_[prev].set_next(chunk_id); - } - chunks_[chunk_id].set_level(level); - chunks_[chunk_id].set_failure_count(0); -} - -void DoubleArrayImpl::unset_chunk_level(uint64_t chunk_id) { -// GRN_DAT_DEBUG_THROW_IF(chunk_id >= num_chunk()); - - const uint32_t level = chunks_[chunk_id].level(); -// GRN_DAT_DEBUG_THROW_IF(level > DOUBLE_ARRAY_MAX_CHUNK_LEVEL); - - const uint64_t leader = header_->ith_leader(level); -// GRN_DAT_DEBUG_THROW_IF(leader == DOUBLE_ARRAY_INVALID_LEADER); - - const uint64_t next = chunks_[chunk_id].next(); - const uint64_t prev = chunks_[chunk_id].prev(); -// GRN_DAT_DEBUG_THROW_IF(next >= num_chunks()); -// GRN_DAT_DEBUG_THROW_IF(prev >= num_chunks()); - - if (next == chunk_id) { - // The level group becomes empty. - header_->set_ith_leader(level, DOUBLE_ARRAY_INVALID_LEADER); - } else { - chunks_[next].set_prev(prev); - chunks_[prev].set_next(next); - if (chunk_id == leader) { - // The second chunk becomes the leader of the level group. - header_->set_ith_leader(level, next); - } - } -} - -} // namespace alpha -} // namespace grnxx Deleted: obsolete/lib/grnxx/alpha/double_array.hpp (+0 -701) 100644 =================================================================== --- obsolete/lib/grnxx/alpha/double_array.hpp 2013-08-23 10:46:34 +0900 (9ce7169) +++ /dev/null @@ -1,701 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_ALPHA_DOUBLE_ARRAY_HPP -#define GRNXX_ALPHA_DOUBLE_ARRAY_HPP - -#include "grnxx/db/vector.hpp" - -namespace grnxx { -namespace alpha { - -// FIXME: To be removed in future. -using namespace grnxx::db; - -extern struct DoubleArrayCreate {} DOUBLE_ARRAY_CREATE; -extern struct DoubleArrayOpen {} DOUBLE_ARRAY_OPEN; - -constexpr uint64_t DOUBLE_ARRAY_MAX_ID = (uint64_t(1) << 40) - 2; -constexpr uint64_t DOUBLE_ARRAY_INVALID_ID = DOUBLE_ARRAY_MAX_ID + 1; -constexpr uint64_t DOUBLE_ARRAY_INVALID_OFFSET = 0; - -constexpr uint16_t DOUBLE_ARRAY_TERMINAL_LABEL = 0x100; -constexpr uint16_t DOUBLE_ARRAY_MAX_LABEL = DOUBLE_ARRAY_TERMINAL_LABEL; -constexpr uint16_t DOUBLE_ARRAY_INVALID_LABEL = 0x1FF; - -constexpr uint64_t DOUBLE_ARRAY_CHUNK_SIZE = 0x200; -constexpr uint64_t DOUBLE_ARRAY_CHUNK_MASK = 0x1FF; - -// Chunks are grouped by the level which indicates how easily update operations -// can find a good offset in that chunk. The chunk level rises when -// find_offset() fails in that chunk many times. DOUBLE_ARRAY_MAX_FAILURE_COUNT -// is the threshold. Also, in order to limit the time cost, find_offset() scans -// at most DOUBLE_ARRAY_MAX_CHUNK_COUNT chunks. -// Larger parameters bring more chances of finding good offsets but it leads to -// more node renumberings, which are costly operations, and thus results in -// degradation of space/time efficiencies. -constexpr uint64_t DOUBLE_ARRAY_MAX_FAILURE_COUNT = 4; -constexpr uint64_t DOUBLE_ARRAY_MAX_CHUNK_COUNT = 16; -constexpr uint64_t DOUBLE_ARRAY_MAX_CHUNK_LEVEL = 5; - -// Chunks in the same level compose a doubly linked list. The entry chunk of -// a linked list is called a leader. DOUBLE_ARRAY_INVALID_LEADER means that -// the linked list is empty and there exists no leader. -constexpr uint64_t DOUBLE_ARRAY_INVALID_LEADER = 0x7FFFFFFF; - -// The memory allocation unit size for keys. -constexpr uint64_t DOUBLE_ARRAY_KEYS_PAGE_SIZE = - VECTOR_DEFAULT_PAGE_SIZE; - -class DoubleArrayHeader { - public: - DoubleArrayHeader(); - - uint32_t nodes_block_id() const { - return nodes_block_id_; - } - uint32_t siblings_block_id() const { - return siblings_block_id_; - } - uint32_t chunks_block_id() const { - return chunks_block_id_; - } - uint32_t entries_block_id() const { - return entries_block_id_; - } - uint32_t keys_block_id() const { - return keys_block_id_; - } - uint64_t root_node_id() const { - return root_node_id_; - } - uint64_t total_key_length() const { - return total_key_length_; - } - uint64_t next_key_id() const { - return next_key_id_; - } - uint64_t next_key_pos() const { - return next_key_pos_; - } - int64_t max_key_id() const { - return max_key_id_; - } - uint64_t num_keys() const { - return num_keys_; - } - uint64_t num_chunks() const { - return num_chunks_; - } - uint64_t num_nodes() const { - return num_chunks_ * DOUBLE_ARRAY_CHUNK_SIZE; - } - uint64_t num_phantoms() const { - return num_phantoms_; - } - uint64_t num_zombies() const { - return num_zombies_; - } - uint64_t ith_leader(uint64_t i) const { - return leaders_[i]; - } - - void set_nodes_block_id(uint32_t value) { - nodes_block_id_ = value; - } - void set_siblings_block_id(uint32_t value) { - siblings_block_id_ = value; - } - void set_chunks_block_id(uint32_t value) { - chunks_block_id_ = value; - } - void set_entries_block_id(uint32_t value) { - entries_block_id_ = value; - } - void set_keys_block_id(uint32_t value) { - keys_block_id_ = value; - } - void set_root_node_id(uint64_t value) { - root_node_id_ = value; - } - void set_total_key_length(uint64_t value) { - total_key_length_ = value; - } - void set_next_key_id(uint64_t value) { - next_key_id_ = value; - } - void set_next_key_pos(uint64_t value) { - next_key_pos_ = value; - } - void set_max_key_id(int64_t value) { - max_key_id_ = value; - } - void set_num_keys(uint64_t value) { - num_keys_ = value; - } - void set_num_chunks(uint64_t value) { - num_chunks_ = value; - } - void set_num_phantoms(uint64_t value) { - num_phantoms_ = value; - } - void set_num_zombies(uint64_t value) { - num_zombies_ = value; - } - void set_ith_leader(uint64_t i, uint64_t x) { - leaders_[i] = x; - } - - Mutex *mutable_inter_process_mutex() { - return &inter_process_mutex_; - } - - private: - uint32_t nodes_block_id_; - uint32_t siblings_block_id_; - uint32_t chunks_block_id_; - uint32_t entries_block_id_; - uint32_t keys_block_id_; - uint64_t root_node_id_; - uint64_t total_key_length_; - uint64_t next_key_id_; - uint64_t next_key_pos_; - int64_t max_key_id_; - uint64_t num_keys_; - uint64_t num_chunks_; - uint64_t num_phantoms_; - uint64_t num_zombies_; - uint64_t leaders_[DOUBLE_ARRAY_MAX_CHUNK_LEVEL + 1]; - Mutex inter_process_mutex_; -}; - -class DoubleArrayNode { - public: - DoubleArrayNode() : qword_(0) {} - - // The ID of this node is used as an offset (true) or not (false). - bool is_origin() const { - // 1 bit. - return qword_ & IS_ORIGIN_FLAG; - } - // This node is valid (false) or not (true). - bool is_phantom() const { - // 1 bit. - return qword_ & IS_PHANTOM_FLAG; - } - // This node is associated with a key (true) or not (false). - bool is_leaf() const { - // 1 bit. - return qword_ & IS_LEAF_FLAG; - } - // This node has an elder sibling (true) or not (false). - bool has_sibling() const { - // 1 bit. - return qword_ & HAS_SIBLING_FLAG; - } - - void set_is_origin(bool value) { - if (value) { - qword_ |= IS_ORIGIN_FLAG; - } else { - qword_ &= ~IS_ORIGIN_FLAG; - } - } - void set_is_phantom(bool value) { - if (value) { - qword_ = (qword_ & IS_ORIGIN_FLAG) | IS_PHANTOM_FLAG; - } else { - qword_ = (qword_ & IS_ORIGIN_FLAG) | - (DOUBLE_ARRAY_INVALID_OFFSET << OFFSET_SHIFT) | - (uint64_t(DOUBLE_ARRAY_INVALID_LABEL) << CHILD_SHIFT) | - DOUBLE_ARRAY_INVALID_LABEL; - } - } - void set_is_leaf(bool value) { - if (value) { - qword_ |= IS_LEAF_FLAG; - } else { - qword_ &= ~IS_LEAF_FLAG; - } - } - void set_has_sibling(bool value) { - if (value) { - qword_ |= HAS_SIBLING_FLAG; - } else { - qword_ &= ~HAS_SIBLING_FLAG; - } - } - - // Phantom nodes are doubly linked in each chunk. - // Each chunk consists of 512 nodes. - uint16_t next() const { - // 9 bits. - return static_cast<uint16_t>((qword_ >> NEXT_SHIFT) & NEXT_MASK); - } - uint16_t prev() const { - // 9 bits. - return static_cast<uint16_t>((qword_ >> PREV_SHIFT) & PREV_MASK); - } - - void set_next(uint16_t value) { - qword_ = (qword_ & ~(NEXT_MASK << NEXT_SHIFT)) | - (static_cast<uint64_t>(value) << NEXT_SHIFT); - } - void set_prev(uint16_t value) { - qword_ = (qword_ & ~(PREV_MASK << PREV_SHIFT)) | - (static_cast<uint64_t>(value) << PREV_SHIFT); - } - - // A non-phantom node stores its label. - // A phantom node returns an invalid label with IS_PHANTOM_FLAG. - uint64_t label() const { - // 9 bits. - return qword_ & (IS_PHANTOM_FLAG | LABEL_MASK); - } - - void set_label(uint16_t value) { - qword_ = (qword_ & ~LABEL_MASK) | value; - } - - // A leaf node stores the start position and the length of the associated - // key. - uint64_t key_pos() const { - // 39 bits. - return (qword_ >> KEY_POS_SHIFT) & KEY_POS_MASK; - } - uint64_t key_length() const { - // 12 bits. - return (qword_ >> KEY_LENGTH_SHIFT) & KEY_LENGTH_MASK; - } - - void set_key(uint64_t key_pos, uint64_t key_length) { - qword_ = (qword_ & ~((KEY_POS_MASK << KEY_POS_SHIFT) | - (KEY_LENGTH_MASK << KEY_LENGTH_SHIFT))) | - (key_pos << KEY_POS_SHIFT) | - (key_length << KEY_LENGTH_SHIFT) | - IS_LEAF_FLAG; - } - - // A non-phantom and non-leaf node stores the offset to its children, - // the label of its next sibling, and the label of its first child. - uint64_t offset() const { - // 42 bits. - return (qword_ >> OFFSET_SHIFT) & OFFSET_MASK; - } - uint16_t child() const { - // 9 bits. - return static_cast<uint16_t>((qword_ >> CHILD_SHIFT) & CHILD_MASK); - } - - void set_offset(uint64_t value) { - if (qword_ & IS_LEAF_FLAG) { - qword_ = ((qword_ & ~IS_LEAF_FLAG) & ~(OFFSET_MASK << OFFSET_SHIFT)) | - (value << OFFSET_SHIFT) | - (uint64_t(DOUBLE_ARRAY_INVALID_LABEL) << CHILD_SHIFT); - } else { - qword_ = (qword_ & ~(OFFSET_MASK << OFFSET_SHIFT)) | - (value << OFFSET_SHIFT); - } - } - void set_child(uint16_t value) { - qword_ = (qword_ & ~(CHILD_MASK << CHILD_SHIFT)) | - (static_cast<uint64_t>(value) << CHILD_SHIFT); - } - - private: - uint64_t qword_; - - // 60 - 63. - static constexpr uint64_t IS_ORIGIN_FLAG = uint64_t(1) << 63; - static constexpr uint64_t IS_PHANTOM_FLAG = uint64_t(1) << 62; - static constexpr uint64_t IS_LEAF_FLAG = uint64_t(1) << 61; - static constexpr uint64_t HAS_SIBLING_FLAG = uint64_t(1) << 60; - - // 0 - 17. - static constexpr uint64_t NEXT_MASK = (uint64_t(1) << 9) - 1; - static constexpr uint8_t NEXT_SHIFT = 0; - static constexpr uint64_t PREV_MASK = (uint64_t(1) << 9) - 1; - static constexpr uint8_t PREV_SHIFT = 9; - - // 0 - 8. - static constexpr uint64_t LABEL_MASK = (uint64_t(1) << 9) - 1; - - // 9 - 59 - static constexpr uint64_t KEY_POS_MASK = (uint64_t(1) << 39) - 1; - static constexpr uint8_t KEY_POS_SHIFT = 9; - static constexpr uint64_t KEY_LENGTH_MASK = (uint64_t(1) << 12) - 1; - static constexpr uint8_t KEY_LENGTH_SHIFT = 48; - - static constexpr uint64_t OFFSET_MASK = (uint64_t(1) << 42) - 1; - static constexpr uint8_t OFFSET_SHIFT = 9; - static constexpr uint64_t CHILD_MASK = (uint64_t(1) << 9) - 1; - static constexpr uint8_t CHILD_SHIFT = 51; -}; - -class DoubleArrayChunk { - public: - // Chunks in the same level are doubly linked. - uint64_t next() const { - // 44 bits. - return (qwords_[0] & UPPER_MASK) >> UPPER_SHIFT; - } - uint64_t prev() const { - // 44 bits. - return (qwords_[1] & UPPER_MASK) >> UPPER_SHIFT; - } - - void set_next(uint64_t value) { - qwords_[0] = (qwords_[0] & ~UPPER_MASK) | (value << UPPER_SHIFT); - } - void set_prev(uint64_t value) { - qwords_[1] = (qwords_[1] & ~UPPER_MASK) | (value << UPPER_SHIFT); - } - - // The chunk level indicates how easily nodes can be put in this chunk. - uint64_t level() const { - // 10 bits. - return (qwords_[0] & MIDDLE_MASK) >> MIDDLE_SHIFT; - } - uint64_t failure_count() const { - // 10 bits. - return (qwords_[1] & MIDDLE_MASK) >> MIDDLE_SHIFT; - } - - void set_level(uint64_t value) { - qwords_[0] = (qwords_[0] & ~MIDDLE_MASK) | (value << MIDDLE_SHIFT); - } - void set_failure_count(uint64_t value) { - qwords_[1] = (qwords_[1] & ~MIDDLE_MASK) | (value << MIDDLE_SHIFT); - } - - // The first phantom node and the number of phantom nodes in this chunk. - uint64_t first_phantom() const { - // 10 bits. - return (qwords_[0] & LOWER_MASK) >> LOWER_SHIFT; - } - uint64_t num_phantoms() const { - // 10 bits. - return (qwords_[1] & LOWER_MASK) >> LOWER_SHIFT; - } - - void set_first_phantom(uint64_t value) { - qwords_[0] = (qwords_[0] & ~LOWER_MASK) | (value << LOWER_SHIFT); - } - void set_num_phantoms(uint64_t value) { - qwords_[1] = (qwords_[1] & ~LOWER_MASK) | (value << LOWER_SHIFT); - } - - private: - uint64_t qwords_[2]; - - static constexpr uint8_t UPPER_SHIFT = 20; - static constexpr uint64_t UPPER_MASK = - ((uint64_t(1) << 44) - 1) << UPPER_SHIFT; - static constexpr uint8_t MIDDLE_SHIFT = 10; - static constexpr uint64_t MIDDLE_MASK = - ((uint64_t(1) << 10) - 1) << MIDDLE_SHIFT; - static constexpr uint8_t LOWER_SHIFT = 0; - static constexpr uint64_t LOWER_MASK = - ((uint64_t(1) << 10) - 1) << LOWER_SHIFT; -}; - -class DoubleArrayEntry { - public: - DoubleArrayEntry() : qword_(0) {} - - // This entry is associated with a key (true) or not (false). - explicit operator bool() const { - return qword_ & IS_VALID_FLAG; - } - - // A valid entry stores the offset and the length of its associated key. - uint64_t key_pos() const { - return qword_ & POS_MASK; - } - uint64_t key_length() const { - return qword_ >> 48; - } - - void set_key(uint64_t pos, uint64_t length) { - qword_ = IS_VALID_FLAG | pos | (length << 48); - } - - // An invalid entry stores the index of the next invalid entry. - uint64_t next() const { - return qword_; - } - - void set_next(uint64_t next) { - qword_ = next; - } - - private: - uint64_t qword_; - - // 11 (= 64 - (1 + 40 + 12)) bits are not used. - static constexpr uint64_t POS_MASK = (uint64_t(1) << 40) - 1; - static constexpr uint64_t IS_VALID_FLAG = uint64_t(1) << 47; -}; - -// TODO -class DoubleArrayKey { - public: - DoubleArrayKey(uint64_t id, const void *address, uint64_t length); - - explicit operator bool() const { - return id() != DOUBLE_ARRAY_INVALID_ID; - } - - const uint8_t &operator[](uint64_t i) const { - return buf_[i]; - } - - uint64_t id() const { - return id_low_ | (static_cast<uint64_t>(id_high_) << 32); - } - const void *ptr() const { - return buf_; - } - - bool equals_to(const void *ptr, uint64_t length, uint64_t offset = 0) const { - for ( ; offset < length; ++offset) { - if (buf_[offset] != static_cast<const uint8_t *>(ptr)[offset]) { - return false; - } - } - return true; - } - - static const DoubleArrayKey &invalid_key() { - static const DoubleArrayKey invalid_key( - DOUBLE_ARRAY_INVALID_ID, nullptr, 0); - return invalid_key; - } - - static uint64_t estimate_size(uint64_t length) { - return 2 + (length / sizeof(uint32_t)); - } - - private: - uint32_t id_low_; - uint8_t id_high_; - uint8_t buf_[3]; -}; - -// FIXME -class DoubleArrayImpl { - public: - ~DoubleArrayImpl(); - - static std::unique_ptr<DoubleArrayImpl> create(io::Pool pool); - static std::unique_ptr<DoubleArrayImpl> open(io::Pool pool, - uint32_t block_id); - - bool search(const uint8_t *ptr, uint64_t length, - uint64_t *key_pos = nullptr); - bool insert(const uint8_t *ptr, uint64_t length, - uint64_t *key_pos = nullptr); - - bool remove(int64_t key_id); - bool remove(const uint8_t *ptr, uint64_t length); - - bool update(int64_t key_id, const uint8_t *ptr, uint64_t length, - uint64_t *key_pos = nullptr); - bool update(const uint8_t *src_ptr, uint64_t src_length, - const uint8_t *dest_ptr, uint64_t dest_length, - uint64_t *key_pos = nullptr); - - const DoubleArrayKey &get_key(uint64_t key_pos) { - return *reinterpret_cast<const DoubleArrayKey *>(&keys_[key_pos]); - } - const DoubleArrayKey &ith_key(uint64_t key_id) { - if (entries_[key_id]) { - return get_key(entries_[key_id].key_pos()); - } - return DoubleArrayKey::invalid_key(); - } - - const DoubleArrayHeader &header() const { - return *header_; - } - - uint32_t block_id() const { - return block_info_->id(); - } - uint64_t root_node_id() const { - return header_->root_node_id(); - } - - StringBuilder &write_to(StringBuilder &builder) const; - - private: - io::Pool pool_; - const io::BlockInfo *block_info_; - DoubleArrayHeader *header_; - Vector<DoubleArrayNode> nodes_; - Vector<uint8_t> siblings_; - Vector<DoubleArrayChunk> chunks_; - Vector<DoubleArrayEntry> entries_; - Vector<uint32_t> keys_; - bool initialized_; - - DoubleArrayImpl(); - - void create_double_array(io::Pool pool); - void open_double_array(io::Pool pool, uint32_t block_id); - - bool remove_key(const uint8_t *ptr, uint64_t length); - bool update_key(const uint8_t *src_ptr, uint64_t src_length, - uint64_t src_key_id, const uint8_t *dest_ptr, - uint64_t dest_length, uint64_t *key_pos); - - bool search_leaf(const uint8_t *ptr, uint64_t length, - uint64_t &node_id, uint64_t &query_pos); - - bool insert_leaf(const uint8_t *ptr, uint64_t length, - uint64_t &node_id, uint64_t query_pos); - - uint64_t insert_node(uint64_t node_id, uint16_t label); - uint64_t append_key(const uint8_t *ptr, uint64_t length, uint64_t key_id); - - uint64_t separate(const uint8_t *ptr, uint64_t length, - uint64_t node_id, uint64_t i); - void resolve(uint64_t node_id, uint16_t label); - void migrate_nodes(uint64_t node_id, uint64_t dest_offset, - const uint16_t *labels, uint16_t num_labels); - - uint64_t find_offset(const uint16_t *labels, uint16_t num_labels); - - void reserve_node(uint64_t node_id); - void reserve_chunk(uint64_t chunk_id); - - void update_chunk_level(uint64_t chunk_id, uint32_t level); - void set_chunk_level(uint64_t chunk_id, uint32_t level); - void unset_chunk_level(uint64_t chunk_id); -}; - -// TODO -class DoubleArray { - public: - DoubleArray() = default; - DoubleArray(const DoubleArrayCreate &, io::Pool pool) - : impl_(DoubleArrayImpl::create(pool)) {} - DoubleArray(const DoubleArrayOpen &, io::Pool pool, uint32_t block_id) - : impl_(DoubleArrayImpl::open(pool, block_id)) {} - - explicit operator bool() const { - return static_cast<bool>(impl_); - } - - void create(io::Pool pool) { - *this = DoubleArray(DOUBLE_ARRAY_CREATE, pool); - } - void open(io::Pool pool, uint32_t block_id) { - *this = DoubleArray(DOUBLE_ARRAY_OPEN, pool, block_id); - } - void close() { - *this = DoubleArray(); - } - - bool search(const void *ptr, uint64_t length, - uint64_t *key_id = nullptr) { - if (key_id) { - uint64_t key_pos; - if (!impl_->search(static_cast<const uint8_t *>(ptr), length, &key_pos)) { - return false; - } - *key_id = impl_->get_key(key_pos).id(); - return true; - } else { - return impl_->search(static_cast<const uint8_t *>(ptr), length, nullptr); - } - } - bool insert(const void *ptr, uint64_t length, - uint64_t *key_id = nullptr) { - if (key_id) { - uint64_t key_pos; - if (!impl_->insert(static_cast<const uint8_t *>(ptr), length, &key_pos)) { - return false; - } - *key_id = impl_->get_key(key_pos).id(); - return true; - } else { - return impl_->insert(static_cast<const uint8_t *>(ptr), length, nullptr); - } - } - - bool remove(int64_t key_id) { - return impl_->remove(key_id); - } - bool remove(const void *ptr, uint64_t length) { - return impl_->remove(static_cast<const uint8_t *>(ptr), length); - } - - bool update(int64_t key_id, const void *ptr, uint64_t length) { - return impl_->update(key_id, static_cast<const uint8_t *>(ptr), length); - } - bool update(const void *src_ptr, uint64_t src_length, - const void *dest_ptr, uint64_t dest_length, - uint64_t *key_id = nullptr) { - if (key_id) { - uint64_t key_pos; - if (!impl_->update(static_cast<const uint8_t *>(src_ptr), src_length, - static_cast<const uint8_t *>(dest_ptr), dest_length, - &key_pos)) { - return false; - } - *key_id = impl_->get_key(key_pos).id(); - return true; - } else { - return impl_->update(static_cast<const uint8_t *>(src_ptr), src_length, - static_cast<const uint8_t *>(dest_ptr), dest_length); - } - } - - const DoubleArrayHeader &header() const { - return impl_->header(); - } - - uint32_t block_id() const { - return impl_->block_id(); - } - - void swap(DoubleArray &rhs) { - impl_.swap(rhs.impl_); - } - - StringBuilder &write_to(StringBuilder &builder) const { - return impl_ ? impl_->write_to(builder) : (builder << "n/a"); - } - - private: - std::shared_ptr<DoubleArrayImpl> impl_; -}; - -inline void swap(DoubleArray &lhs, DoubleArray &rhs) { - lhs.swap(rhs); -} - -inline StringBuilder &operator<<(StringBuilder &builder, - const DoubleArray &da) { - return da.write_to(builder); -} - -} // namespace alpha -} // namespace grnxx - -#endif // GRNXX_ALPHA_DOUBLE_ARRAY_HPP Deleted: obsolete/lib/grnxx/alpha/dummy.cpp (+0 -24) 100644 =================================================================== --- obsolete/lib/grnxx/alpha/dummy.cpp 2013-08-23 10:46:34 +0900 (ca66023) +++ /dev/null @@ -1,24 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/alpha/dummy.hpp" - -namespace grnxx { -namespace alpha { - -} // namespace alpha -} // namespace grnxx Deleted: obsolete/lib/grnxx/alpha/dummy.hpp (+0 -29) 100644 =================================================================== --- obsolete/lib/grnxx/alpha/dummy.hpp 2013-08-23 10:46:34 +0900 (e398c83) +++ /dev/null @@ -1,29 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_ALPHA_DUMMY_HPP -#define GRNXX_ALPHA_DUMMY_HPP - -#include "grnxx/features.hpp" - -namespace grnxx { -namespace alpha { - -} // namespace alpha -} // namespace grnxx - -#endif // GRNXX_ALPHA_DUMMY_HPP Deleted: obsolete/lib/grnxx/alpha/map.cpp (+0 -453) 100644 =================================================================== --- obsolete/lib/grnxx/alpha/map.cpp 2013-08-23 10:46:34 +0900 (d1b6ab6) +++ /dev/null @@ -1,453 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/alpha/map.hpp" - -#include "grnxx/alpha/map/array.hpp" -#include "grnxx/alpha/map/cursor.hpp" -#include "grnxx/alpha/map/double_array.hpp" -#include "grnxx/alpha/map/header.hpp" -#include "grnxx/alpha/map/scan.hpp" -#include "grnxx/exception.hpp" -#include "grnxx/geo_point.hpp" -#include "grnxx/slice.hpp" -#include "grnxx/logger.hpp" - -namespace grnxx { -namespace alpha { - -template <typename T> -MapCursor<T>::MapCursor() : key_id_(-1), key_() {} - -template <typename T> -MapCursor<T>::~MapCursor() {} - -template <typename T> -bool MapCursor<T>::next() { - // Not supported. - return false; -} - -template <typename T> -bool MapCursor<T>::remove() { - // Not supported. - return false; -} - -template class MapCursor<int8_t>; -template class MapCursor<int16_t>; -template class MapCursor<int32_t>; -template class MapCursor<int64_t>; -template class MapCursor<uint8_t>; -template class MapCursor<uint16_t>; -template class MapCursor<uint32_t>; -template class MapCursor<uint64_t>; -template class MapCursor<double>; -template class MapCursor<GeoPoint>; -template class MapCursor<Slice>; - -template <typename T> -Map<T>::Map() {} - -template <typename T> -Map<T>::~Map() {} - -template <typename T> -Map<T> *Map<T>::create(MapType type, io::Pool pool, - const MapOptions &options) { - switch (type) { - case MAP_ARRAY: { - return map::Array<T>::create(pool, options); - } - case MAP_DOUBLE_ARRAY: { - return map::DoubleArray<T>::create(pool, options); - } - case MAP_PATRICIA: { - // TODO: Not supported yet. - return nullptr; - } - case MAP_HASH_TABLE: { - // TODO: Not supported yet. - return nullptr; - } - default: { - return nullptr; - } - } -} - -template <typename T> -Map<T> *Map<T>::open(io::Pool pool, uint32_t block_id) { - const map::Header *header = static_cast<const map::Header *>( - pool.get_block_address(block_id)); - switch (header->type) { - case MAP_ARRAY: { - return map::Array<T>::open(pool, block_id); - } - case MAP_DOUBLE_ARRAY: { - return map::DoubleArray<T>::open(pool, block_id); - } - case MAP_PATRICIA: { - // TODO: Not supported yet. - return nullptr; - } - case MAP_HASH_TABLE: { - // TODO: Not supported yet. - return nullptr; - } - default: { - return nullptr; - } - } -} - -template <typename T> -bool Map<T>::unlink(io::Pool pool, uint32_t block_id) { - const map::Header *header = static_cast<const map::Header *>( - pool.get_block_address(block_id)); - switch (header->type) { - case MAP_ARRAY: { - return map::Array<T>::unlink(pool, block_id); - } - case MAP_DOUBLE_ARRAY: { - return map::DoubleArray<T>::unlink(pool, block_id); - } - case MAP_PATRICIA: { - // TODO: Not supported yet. - return false; - } - case MAP_HASH_TABLE: { - // TODO: Not supported yet. - return false; - } - default: { - // Not supported yet. - return false; - } - } -} - -template <typename T> -uint32_t Map<T>::block_id() const { - // Not supported. - return io::BLOCK_INVALID_ID; -} - -template <typename T> -MapType Map<T>::type() const { - // Not supported. - return MAP_UNKNOWN; -} - -template <typename T> -int64_t Map<T>::max_key_id() const { - // Not supported. - return -1; -} - -template <typename T> -int64_t Map<T>::next_key_id() const { - // Not supported. - return -1; -} - -template <typename T> -uint64_t Map<T>::num_keys() const { - // Not supported. - return 0; -} - -template <typename T> -bool Map<T>::get(int64_t, T *) { - // Not supported. - return false; -} - -template <typename T> -bool Map<T>::get_next(int64_t, int64_t *, T *) { - // Not supported. - return false; -} - -template <typename T> -bool Map<T>::unset(int64_t) { - // Not supported. - return false; -} - -template <typename T> -bool Map<T>::reset(int64_t, T) { - // Not supported. - return false; -} - -template <typename T> -bool Map<T>::find(T, int64_t *) { - // Not supported. - return false; -} - -template <typename T> -bool Map<T>::insert(T, int64_t *) { - // Not supported. - return false; -} - -template <typename T> -bool Map<T>::remove(T) { - // Not supported. - return false; -} - -template <typename T> -bool Map<T>::update(T, T, int64_t *) { - // Not supported. - return false; -} - -template <typename T> -bool Map<T>::find_longest_prefix_match(T, int64_t *, T *) { - // Not supported. - return false; -} - -template <> -bool Map<Slice>::find_longest_prefix_match(Slice query, int64_t *key_id, - Slice *key) { - // Naive implementation. - for (size_t size = query.size(); size > 0; --size) { - const Slice prefix = query.prefix(size); - if (find(prefix, key_id)) { - if (key) { - *key = prefix; - } - return true; - } - } - return false; -} - -template <typename T> -bool Map<T>::truncate() { - // Not supported. - return false; -} - -template <typename T> -MapCursor<T> *Map<T>::open_basic_cursor(const MapCursorOptions &options) { - return new (std::nothrow) map::IDCursor<T>(this, -1, -1, options); -} - -template <typename T> -MapCursor<T> *Map<T>::open_id_cursor(int64_t min, int64_t max, - const MapCursorOptions &options) { - return new (std::nothrow) map::IDCursor<T>(this, min, max, options); -} - -template <typename T> -MapCursor<T> *Map<T>::open_key_cursor(T min, T max, - const MapCursorOptions &options) { - return new (std::nothrow) map::KeyCursor<T>(this, min, max, options); -} - -template <> -MapCursor<GeoPoint> *Map<GeoPoint>::open_key_cursor(GeoPoint, GeoPoint, - const MapCursorOptions &) { - // Not supported. - return nullptr; -} - -template <typename T> -MapCursor<T> *Map<T>::open_bitwise_completion_cursor( - T, size_t, const MapCursorOptions &) { - // Not supported. - return nullptr; -} - -template <> -MapCursor<GeoPoint> *Map<GeoPoint>::open_bitwise_completion_cursor( - GeoPoint query, size_t bit_size, const MapCursorOptions &options) { - return new (std::nothrow) map::BitwiseCompletionCursor( - this, query, bit_size, options); -} - -template <typename T> -MapCursor<T> *Map<T>::open_prefix_cursor( - T, size_t, const MapCursorOptions &) { - // Not supported. - return nullptr; -} - -template <> -MapCursor<Slice> *Map<Slice>::open_prefix_cursor( - Slice query, size_t min_size, const MapCursorOptions &options) { - return new (std::nothrow) map::PrefixCursor(this, query, min_size, options); -} - -template <typename T> -MapCursor<T> *Map<T>::open_completion_cursor(T, const MapCursorOptions &) { - // Not supported. - return nullptr; -} - -template <> -MapCursor<Slice> *Map<Slice>::open_completion_cursor( - Slice query, const MapCursorOptions &options) { - return new (std::nothrow) map::CompletionCursor(this, query, options); -} - -template <typename T> -MapCursor<T> *Map<T>::open_reverse_completion_cursor( - T, const MapCursorOptions &) { - // Not supported. - return nullptr; -} - -template <> -MapCursor<Slice> *Map<Slice>::open_reverse_completion_cursor( - Slice query, const MapCursorOptions &options) { - return new (std::nothrow) map::ReverseCompletionCursor(this, query, options); -} - -template <typename T> -MapCursor<T> *Map<T>::open_cursor(const MapIDRange &range, - const MapCursorOptions &options) { - int64_t min = -1; - int64_t max = -1; - MapCursorOptions options_clone = options; - options_clone.flags &= ~(MAP_CURSOR_EXCEPT_MIN | MAP_CURSOR_EXCEPT_MAX); - if (range.flags & (MAP_RANGE_GREATER | MAP_RANGE_GREATER_EQUAL)) { - min = range.min; - if (range.flags & MAP_RANGE_GREATER) { - options_clone.flags |= MAP_CURSOR_EXCEPT_MIN; - } - } - if (range.flags & (MAP_RANGE_LESS | MAP_RANGE_LESS_EQUAL)) { - max = range.max; - if (range.flags & MAP_RANGE_LESS) { - options_clone.flags |= MAP_CURSOR_EXCEPT_MAX; - } - } - return new (std::nothrow) map::IDCursor<T>(this, min, max, options_clone); -} - -template <typename T> -MapCursor<T> *Map<T>::open_cursor(const MapKeyRange<T> &range, - const MapCursorOptions &options) { - T min = std::numeric_limits<T>::min(); - T max = std::numeric_limits<T>::max(); - MapCursorOptions options_clone = options; - options_clone.flags &= ~(MAP_CURSOR_EXCEPT_MIN | MAP_CURSOR_EXCEPT_MAX); - if (range.flags & (MAP_RANGE_GREATER | MAP_RANGE_GREATER_EQUAL)) { - min = range.min; - if (range.flags & MAP_RANGE_GREATER) { - options_clone.flags |= MAP_CURSOR_EXCEPT_MIN; - } - } - if (range.flags & (MAP_RANGE_LESS | MAP_RANGE_LESS_EQUAL)) { - max = range.max; - if (range.flags & MAP_RANGE_LESS) { - options_clone.flags |= MAP_CURSOR_EXCEPT_MAX; - } - } - return new (std::nothrow) map::KeyCursor<T>(this, min, max, options_clone); -} - -template <> -MapCursor<double> *Map<double>::open_cursor( - const MapKeyRange<double> &range, const MapCursorOptions &options) { - double min = -std::numeric_limits<double>::infinity(); - double max = +std::numeric_limits<double>::infinity(); - MapCursorOptions options_clone = options; - options_clone.flags &= ~(MAP_CURSOR_EXCEPT_MIN | MAP_CURSOR_EXCEPT_MAX); - if (range.flags & (MAP_RANGE_GREATER | MAP_RANGE_GREATER_EQUAL)) { - min = range.min; - if (range.flags & MAP_RANGE_GREATER) { - options_clone.flags |= MAP_CURSOR_EXCEPT_MIN; - } - } - if (range.flags & (MAP_RANGE_LESS | MAP_RANGE_LESS_EQUAL)) { - max = range.max; - if (range.flags & MAP_RANGE_LESS) { - options_clone.flags |= MAP_CURSOR_EXCEPT_MAX; - } - } - return new (std::nothrow) map::KeyCursor<double>(this, min, max, options_clone); -} - -template <> -MapCursor<GeoPoint> *Map<GeoPoint>::open_cursor( - const MapKeyRange<GeoPoint> &, const MapCursorOptions &) { - // Not supported. - return nullptr; -} - -template <> -MapCursor<Slice> *Map<Slice>::open_cursor( - const MapKeyRange<Slice> &range, const MapCursorOptions &options) { - Slice min = nullptr; - Slice max = nullptr; - MapCursorOptions options_clone = options; - options_clone.flags &= ~(MAP_CURSOR_EXCEPT_MIN | MAP_CURSOR_EXCEPT_MAX); - if (range.flags & (MAP_RANGE_GREATER | MAP_RANGE_GREATER_EQUAL)) { - min = range.min; - if (range.flags & MAP_RANGE_GREATER) { - options_clone.flags |= MAP_CURSOR_EXCEPT_MIN; - } - } - if (range.flags & (MAP_RANGE_LESS | MAP_RANGE_LESS_EQUAL)) { - max = range.max; - if (range.flags & MAP_RANGE_LESS) { - options_clone.flags |= MAP_CURSOR_EXCEPT_MAX; - } - } - return new (std::nothrow) map::KeyCursor<Slice>(this, min, max, options_clone); -} - -template <typename T> -MapScan<T> *Map<T>::open_scan(T, const Charset *) { - // Not supported - return nullptr; -} - -template <> -MapScan<Slice> *Map<Slice>::open_scan(Slice query, const Charset *charset) { - return new (std::nothrow) map::Scan(this, query, charset); -} - -template class Map<int8_t>; -template class Map<int16_t>; -template class Map<int32_t>; -template class Map<int64_t>; -template class Map<uint8_t>; -template class Map<uint16_t>; -template class Map<uint32_t>; -template class Map<uint64_t>; -template class Map<double>; -template class Map<GeoPoint>; -template class Map<Slice>; - -template <typename T> -MapScan<T>::MapScan() : offset_(0), size_(0), key_id_(-1), key_() {} - -template <typename T> -MapScan<T>::~MapScan() {} - -template class MapScan<Slice>; - -} // namespace alpha -} // namespace grnxx Deleted: obsolete/lib/grnxx/alpha/map.hpp (+0 -262) 100644 =================================================================== --- obsolete/lib/grnxx/alpha/map.hpp 2013-08-23 10:46:34 +0900 (d9c5448) +++ /dev/null @@ -1,262 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_ALPHA_MAP_HPP -#define GRNXX_ALPHA_MAP_HPP - -#include "grnxx/alpha/map_range.hpp" -#include "grnxx/io/pool.hpp" -#include "grnxx/slice.hpp" - -namespace grnxx { - -class Charset; - -namespace alpha { - -template <typename T> class Map; -template <typename T> class MapCursor; -template <typename T> class MapScan; - -enum MapType : int32_t { - MAP_UNKNOWN = 0, - MAP_ARRAY = 1, // Array-based implementation. - MAP_DOUBLE_ARRAY = 2, // DoubleArray-based implementation. - MAP_PATRICIA = 3, // TODO: Patricia-based implementation. - MAP_HASH_TABLE = 4 // TODO: HashTable-based implementation. -}; - -struct MapOptions { -}; - -struct MapCursorFlagsIdentifier; -using MapCursorFlags = FlagsImpl<MapCursorFlagsIdentifier>; - -// Use the default settings. -constexpr MapCursorFlags MAP_CURSOR_DEFAULT = - MapCursorFlags::define(0x000); -// Sort keys by ID. -constexpr MapCursorFlags MAP_CURSOR_ORDER_BY_ID = - MapCursorFlags::define(0x001); -// Sort keys by key. -constexpr MapCursorFlags MAP_CURSOR_ORDER_BY_KEY = - MapCursorFlags::define(0x002); -// TODO: Sort keys by distance. -//constexpr MapCursorFlags MAP_CURSOR_ORDER_BY_DISTANCE = -// MapCursorFlags::define(0x004); -// Access keys in reverse order. -constexpr MapCursorFlags MAP_CURSOR_REVERSE_ORDER = - MapCursorFlags::define(0x010); -// Return keys except min. -constexpr MapCursorFlags MAP_CURSOR_EXCEPT_MIN = - MapCursorFlags::define(0x100); -// Return keys except max. -constexpr MapCursorFlags MAP_CURSOR_EXCEPT_MAX = - MapCursorFlags::define(0x200); -// Return keys except exact match. -constexpr MapCursorFlags MAP_CURSOR_EXCEPT_QUERY = - MapCursorFlags::define(0x400); - -struct MapCursorOptions { - MapCursorFlags flags; - uint64_t offset; - uint64_t limit; - - MapCursorOptions() : flags(MAP_CURSOR_DEFAULT), offset(0), limit(-1) {} -}; - -template <typename T> -class Map { - public: - Map(); - virtual ~Map(); - - // Create a map on "pool". - static Map *create(MapType type, io::Pool pool, - const MapOptions &options = MapOptions()); - // Open an existing map. - static Map *open(io::Pool pool, uint32_t block_id); - - // Free blocks allocated to a map. - static bool unlink(io::Pool pool, uint32_t block_id); - - // Return the header block ID of "*this". - virtual uint32_t block_id() const; - // Return the type of "*this". - virtual MapType type() const; - - // Return the minimum key ID. - constexpr int64_t min_key_id() const { - return 0; - } - // Return the maximum key ID ever used. - // If the map is empty, the return value can be -1. - virtual int64_t max_key_id() const; - // Return the ID of the expected next inserted ID. - virtual int64_t next_key_id() const; - // Return the number of keys. - virtual uint64_t num_keys() const; - - // Get a key associated with "key_id" and return true on success. - // Assign the found key to "*key" iff "key" != nullptr. - virtual bool get(int64_t key_id, T *key = nullptr); - // Find the next key and return true on success. The next key means the key - // associated with the smallest valid ID that is greater than "key_id". - // If "key_id" < 0, this finds the first key. - // Assign the ID to "*next_key_id" iff "next_key_id" != nullptr. - // Assign the key to "*next_key" iff "next_key" != nullptr. - virtual bool get_next(int64_t key_id, int64_t *next_key_id = nullptr, - T *next_key = nullptr); - // Remove a key associated with "key_id" and return true on success. - virtual bool unset(int64_t key_id); - // Replace a key associated with "key_id" with "dest_key" and return true - // on success. - virtual bool reset(int64_t key_id, T dest_key); - - // Find "key" and return true on success. - // Assign the ID to "*key_id" iff "key_id" != nullptr. - virtual bool find(T key, int64_t *key_id = nullptr); - // Insert "key" and return true on success. - // Assign the ID to "*key_id" iff "key_id" != nullptr. - virtual bool insert(T key, int64_t *key_id = nullptr); - // Remove "key" and return true on success. - virtual bool remove(T key); - // Replace "src_key" with "dest_key" and return true on success. - // Assign the ID to "*key_id" iff "key_id" != nullptr. - virtual bool update(T src_key, T dest_key, int64_t *key_id = nullptr); - - // Perform the longest prefix matching and return true on success. - // Assign the ID to "*key_id" iff "key_id" != nullptr. - // Assign the key to "*key" iff "key" != nullptr. - virtual bool find_longest_prefix_match(T query, int64_t *key_id = nullptr, - T *key = nullptr); - - // Remove all the keys in "*this" and return true on success. - virtual bool truncate(); - - // Create a cursor for accessing all the keys. - virtual MapCursor<T> *open_basic_cursor( - const MapCursorOptions &options = MapCursorOptions()); - // Create a cursor for accessing keys in range [min, max]. - virtual MapCursor<T> *open_id_cursor( - int64_t min, int64_t max, - const MapCursorOptions &options = MapCursorOptions()); - // Create a cursor for accessing keys in range [min, max]. - virtual MapCursor<T> *open_key_cursor( - T min, T max, const MapCursorOptions &options = MapCursorOptions()); - - // Only for GeoPoint. - // Create a cursor for accessing keys whose most significant "bit_size" bits - // are same as the MSBs of "query". - virtual MapCursor<T> *open_bitwise_completion_cursor( - T query, size_t bit_size, - const MapCursorOptions &options = MapCursorOptions()); - - // Only for Slice. - // Create a cursor for accessing keys matching a prefix of "query". - virtual MapCursor<T> *open_prefix_cursor( - T query, size_t min_size, - const MapCursorOptions &options = MapCursorOptions()); - // Create a cursor for accessing keys starting with "query". - virtual MapCursor<T> *open_completion_cursor( - T query, const MapCursorOptions &options = MapCursorOptions()); - // Create a cursor for accessing keys ending with "query". - virtual MapCursor<T> *open_reverse_completion_cursor( - T query, const MapCursorOptions &options = MapCursorOptions()); - - MapID id() const { - return MapID(); - } - MapKey<T> key() const { - return MapKey<T>(); - } - - virtual MapCursor<T> *open_cursor( - const MapIDRange &range, - const MapCursorOptions &options = MapCursorOptions()); - virtual MapCursor<T> *open_cursor( - const MapKeyRange<T> &range, - const MapCursorOptions &options = MapCursorOptions()); - - // Only for Slice. - // Create a MapScan object to find keys in "query". - virtual MapScan<T> *open_scan(T query, const Charset *charset = nullptr); -}; - -template <typename T> -class MapCursor { - public: - MapCursor(); - virtual ~MapCursor(); - - // Move the cursor to the next key and return true on success. - virtual bool next(); - // Remove the current key and return true on success. - virtual bool remove(); - - // Return the ID of the current key. - int64_t key_id() const { - return key_id_; - } - // Return a reference to the current key. - const T &key() const { - return key_; - } - - protected: - int64_t key_id_; - T key_; -}; - -template <typename T> -class MapScan { - public: - MapScan(); - virtual ~MapScan(); - - // Scan the rest of the query and return true iff a key is found (success). - // On success, the found key is accessible via accessors. - virtual bool next() = 0; - - // Return the start position of the found key. - uint64_t offset() const { - return offset_; - } - // Return the size of the found key. - uint64_t size() const { - return size_; - } - // Return the ID of the found key. - int64_t key_id() const { - return key_id_; - } - // Return a reference to the found key. - const T &key() const { - return key_; - } - - protected: - uint64_t offset_; - uint64_t size_; - int64_t key_id_; - T key_; -}; - -} // namespace alpha -} // namespace grnxx - -#endif // GRNXX_ALPHA_MAP_HPP Deleted: obsolete/lib/grnxx/alpha/map/Makefile.am (+0 -18) 100644 =================================================================== --- obsolete/lib/grnxx/alpha/map/Makefile.am 2013-08-23 10:46:34 +0900 (ab16b6e) +++ /dev/null @@ -1,18 +0,0 @@ -noinst_LTLIBRARIES = libgrnxx_alpha_map.la - -libgrnxx_alpha_map_la_LDFLAGS = @AM_LTLDFLAGS@ - -libgrnxx_alpha_map_la_SOURCES = \ - array.cpp \ - cursor.cpp \ - double_array.cpp \ - double_array-slice.cpp \ - scan.cpp - -libgrnxx_alpha_map_includedir = ${includedir}/grnxx/alpha/map -libgrnxx_alpha_map_include_HEADERS = \ - array.hpp \ - cursor.hpp \ - double_array.hpp \ - header.hpp \ - scan.hpp Deleted: obsolete/lib/grnxx/alpha/map/array.cpp (+0 -538) 100644 =================================================================== --- obsolete/lib/grnxx/alpha/map/array.cpp 2013-08-23 10:46:34 +0900 (38f1db4) +++ /dev/null @@ -1,538 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/alpha/map/array.hpp" - -#include <cmath> -#include <string> - -#include "grnxx/geo_point.hpp" - -namespace grnxx { -namespace alpha { -namespace map { -namespace { - -template <typename T, bool HAS_NAN = std::numeric_limits<T>::has_quiet_NaN> -struct Helper; - -template <typename T> -struct Helper<T, true> { - static bool equal_to(T x, T y) { - return *reinterpret_cast<const uint64_t *>(&x) == - *reinterpret_cast<const uint64_t *>(&y); - } - static T normalize(T x) { - if (std::isnan(x)) { - return std::numeric_limits<T>::quiet_NaN(); - } else if (x == 0.0) { - return +0.0; - } - return x; - } -}; - -template <typename T> -struct Helper<T, false> { - static bool equal_to(T x, T y) { - return x == y; - } - static T normalize(T x) { - return x; - } -}; - -db::Blob slice_to_blob(Slice slice, std::string *buf) { - buf->assign(reinterpret_cast<const char *>(slice.ptr()), slice.size()); - buf->resize(buf->size() + 7, ' '); - return db::Blob(buf->data(), buf->size()); -} - -Slice blob_to_slice(const db::Blob &blob) { - return Slice(blob.address(), blob.length() - 7); -} - -} // namespace - -ArrayHeader::ArrayHeader() - : map_type(MAP_ARRAY), - bits_block_id(io::BLOCK_INVALID_ID), - keys_block_id(io::BLOCK_INVALID_ID), - max_key_id(-1), - next_key_id(0), - num_keys(0) {} - -template <typename T> -Array<T>::Array() - : pool_(), - block_info_(nullptr), - header_(nullptr), - bits_(), - keys_() {} - -template <typename T> -Array<T>::~Array() {} - -template <typename T> -Array<T> *Array<T>::create(io::Pool pool, const MapOptions &) { - std::unique_ptr<Array<T>> array(new (std::nothrow) Array<T>); - array->pool_ = pool; - array->block_info_ = pool.create_block(sizeof(ArrayHeader)); - array->header_ = static_cast<ArrayHeader *>( - pool.get_block_address(*array->block_info_)); - *array->header_ = ArrayHeader(); - array->bits_.create(pool, 0); - array->header_->bits_block_id = array->bits_.block_id(); - array->keys_.create(pool); - array->header_->keys_block_id = array->keys_.block_id(); - return array.release(); -} - -template <typename T> -Array<T> *Array<T>::open(io::Pool pool, uint32_t block_id) { - std::unique_ptr<Array<T>> array(new (std::nothrow) Array<T>); - array->pool_ = pool; - array->block_info_ = pool.get_block_info(block_id); - array->header_ = static_cast<ArrayHeader *>( - pool.get_block_address(*array->block_info_)); - array->bits_.open(pool, array->header_->bits_block_id); - array->keys_.open(pool, array->header_->keys_block_id); - return array.release(); -} - -template <typename T> -bool Array<T>::unlink(io::Pool pool, uint32_t block_id) { - std::unique_ptr<Array<T>> array(open(pool, block_id)); - array->bits_.unlink(pool, array->header_->bits_block_id); - array->keys_.unlink(pool, array->header_->keys_block_id); - pool.free_block(array->block_id()); - return false; -} - -template <typename T> -uint32_t Array<T>::block_id() const { - return block_info_->id(); -} - -template <typename T> -MapType Array<T>::type() const { - return MAP_ARRAY; -} - -template <typename T> -int64_t Array<T>::max_key_id() const { - return header_->max_key_id; -} - -template <typename T> -int64_t Array<T>::next_key_id() const { - return header_->next_key_id; -} - -template <typename T> -uint64_t Array<T>::num_keys() const { - return header_->num_keys; -} - -template <typename T> -bool Array<T>::get(int64_t key_id, T *key) { - if ((key_id < 0) || (key_id > header_->max_key_id)) { - return false; - } - if (!get_bit(key_id)) { - return false; - } - if (key) { - *key = keys_[key_id]; - } - return true; -} - -template <typename T> -bool Array<T>::get_next(int64_t key_id, int64_t *next_key_id, T *next_key) { - if (key_id >= header_->max_key_id) { - return false; - } - if (key_id < 0) { - key_id = -1; - } - for (++key_id; key_id <= header_->max_key_id; ++key_id) { - if (get_bit(key_id)) { - if (next_key_id) { - *next_key_id = key_id; - } - if (next_key) { - *next_key = keys_[key_id]; - } - return true; - } - } - return false; -} - -template <typename T> -bool Array<T>::unset(int64_t key_id) { - if ((key_id < 0) || (key_id > header_->max_key_id)) { - return false; - } - if (!get_bit(key_id)) { - return false; - } - set_bit(key_id, false); - if (key_id < header_->next_key_id) { - header_->next_key_id = key_id; - } - --header_->num_keys; - return true; -} - -template <typename T> -bool Array<T>::reset(int64_t key_id, T dest_key) { - if ((key_id < 0) || (key_id > header_->max_key_id)) { - return false; - } - if (!get_bit(key_id)) { - return false; - } - if (find(dest_key)) { - return false; - } - keys_[key_id] = Helper<T>::normalize(dest_key); - return true; -} - -template <typename T> -bool Array<T>::find(T key, int64_t *key_id) { - key = Helper<T>::normalize(key); - for (int64_t i = 0; i <= header_->max_key_id; ++i) { - if (get_bit(i)) { - if (Helper<T>::equal_to(key, keys_[i])) { - if (key_id) { - *key_id = i; - } - return true; - } - } - } - return false; -} - -template <typename T> -bool Array<T>::insert(T key, int64_t *key_id) { - key = Helper<T>::normalize(key); - int64_t key_id_candidate = -1; - int64_t next_key_id_candidate = -1; - for (int64_t i = 0; i <= header_->max_key_id; ++i) { - if (get_bit(i)) { - if (Helper<T>::equal_to(key, keys_[i])) { - if (key_id) { - *key_id = i; - } - return false; - } - } else if (key_id_candidate == -1) { - // Use the first invalid ID if exists. - key_id_candidate = i; - } else if (next_key_id_candidate == -1) { - // Use the second invalid ID if exists. - next_key_id_candidate = i; - } - } - if (key_id_candidate == -1) { - key_id_candidate = ++header_->max_key_id; - } - keys_[key_id_candidate] = Helper<T>::normalize(key); - set_bit(key_id_candidate, true); - header_->next_key_id = (next_key_id_candidate != -1) ? - next_key_id_candidate : (header_->max_key_id + 1); - ++header_->num_keys; - if (key_id) { - *key_id = key_id_candidate; - } - return true; -} - -template <typename T> -bool Array<T>::remove(T key) { - int64_t key_id; - if (!find(key, &key_id)) { - return false; - } - set_bit(key_id, false); - if (key_id < header_->next_key_id) { - header_->next_key_id = key_id; - } - --header_->num_keys; - return true; -} - -template <typename T> -bool Array<T>::update(T src_key, T dest_key, int64_t *key_id) { - int64_t src_key_id; - if (!find(src_key, &src_key_id)) { - return false; - } - if (find(dest_key)) { - return false; - } - keys_[src_key_id] = Helper<T>::normalize(dest_key); - if (key_id) { - *key_id = src_key_id; - } - return true; -} - -template <typename T> -bool Array<T>::truncate() { - for (int64_t i = 0; i <= header_->max_key_id; ++i) { - set_bit(i, false); - } - header_->max_key_id = -1; - header_->next_key_id = 0; - header_->num_keys = 0; - return true; -} - -template class Array<int8_t>; -template class Array<int16_t>; -template class Array<int32_t>; -template class Array<int64_t>; -template class Array<uint8_t>; -template class Array<uint16_t>; -template class Array<uint32_t>; -template class Array<uint64_t>; -template class Array<double>; -template class Array<GeoPoint>; - -Array<Slice>::Array() - : pool_(), - block_info_(nullptr), - header_(nullptr), - keys_() {} - -Array<Slice>::~Array() {} - -Array<Slice> *Array<Slice>::create(io::Pool pool, const MapOptions &) { - std::unique_ptr<Array<Slice>> array(new (std::nothrow) Array<Slice>); - array->pool_ = pool; - array->block_info_ = pool.create_block(sizeof(ArrayHeader)); - array->header_ = static_cast<ArrayHeader *>( - pool.get_block_address(*array->block_info_)); - *array->header_ = ArrayHeader(); - array->keys_.create(pool); - array->header_->keys_block_id = array->keys_.block_id(); - return array.release(); -} - -Array<Slice> *Array<Slice>::open(io::Pool pool, uint32_t block_id) { - std::unique_ptr<Array<Slice>> array(new (std::nothrow) Array<Slice>); - array->pool_ = pool; - array->block_info_ = pool.get_block_info(block_id); - array->header_ = static_cast<ArrayHeader *>( - pool.get_block_address(*array->block_info_)); - array->keys_.open(pool, array->header_->keys_block_id); - return array.release(); -} - -bool Array<Slice>::unlink(io::Pool pool, uint32_t block_id) { - std::unique_ptr<Array<Slice>> array(open(pool, block_id)); - array->keys_.unlink(pool, array->header_->keys_block_id); - pool.free_block(array->block_id()); - return false; -} - -uint32_t Array<Slice>::block_id() const { - return block_info_->id(); -} - -MapType Array<Slice>::type() const { - return MAP_ARRAY; -} - -int64_t Array<Slice>::max_key_id() const { - return header_->max_key_id; -} - -int64_t Array<Slice>::next_key_id() const { - return header_->next_key_id; -} - -uint64_t Array<Slice>::num_keys() const { - return header_->num_keys; -} - -bool Array<Slice>::get(int64_t key_id, Slice *key) { - if ((key_id < 0) || (key_id > header_->max_key_id)) { - return false; - } - db::Blob blob = keys_[key_id].get(); - if (!blob) { - return false; - } - if (key) { - *key = blob_to_slice(blob); - } - return true; -} - -bool Array<Slice>::get_next(int64_t key_id, int64_t *next_key_id, - Slice *next_key) { - if (key_id >= header_->max_key_id) { - return false; - } - if (key_id < 0) { - key_id = -1; - } - for (++key_id; key_id <= header_->max_key_id; ++key_id) { - db::Blob blob = keys_[key_id].get(); - if (blob) { - if (next_key_id) { - *next_key_id = key_id; - } - if (next_key) { - *next_key = blob_to_slice(blob); - } - return true; - } - } - return false; -} - -bool Array<Slice>::unset(int64_t key_id) { - if ((key_id < 0) || (key_id > header_->max_key_id)) { - return false; - } - db::Blob blob = keys_[key_id].get(); - if (!blob) { - return false; - } - keys_[key_id] = nullptr; - if (key_id < header_->next_key_id) { - header_->next_key_id = key_id; - } - --header_->num_keys; - return true; -} - -bool Array<Slice>::reset(int64_t key_id, Slice dest_key) { - if ((key_id < 0) || (key_id > header_->max_key_id)) { - return false; - } - db::Blob blob = keys_[key_id].get(); - if (!blob) { - return false; - } - if (!dest_key || find(dest_key)) { - return false; - } - std::string buf; - keys_[key_id] = slice_to_blob(dest_key, &buf); - return true; -} - -bool Array<Slice>::find(Slice key, int64_t *key_id) { - for (int64_t i = 0; i <= header_->max_key_id; ++i) { - db::Blob blob = keys_[i].get(); - if (key == blob_to_slice(blob)) { - if (key_id) { - *key_id = i; - } - return true; - } - } - return false; -} - -bool Array<Slice>::insert(Slice key, int64_t *key_id) { - if (!key) { - return false; - } - int64_t key_id_candidate = -1; - int64_t next_key_id_candidate = -1; - for (int64_t i = 0; i <= header_->max_key_id; ++i) { - db::Blob blob = keys_[i].get(); - if (key == blob_to_slice(blob)) { - if (key_id) { - *key_id = i; - } - return false; - } else if (!blob) { - if (key_id_candidate == -1) { - // Use the first invalid ID if exists. - key_id_candidate = i; - } else if (next_key_id_candidate == -1) { - // Use the second invalid ID if exists. - next_key_id_candidate = i; - } - } - } - if (key_id_candidate == -1) { - key_id_candidate = ++header_->max_key_id; - } - std::string buf; - keys_[key_id_candidate] = slice_to_blob(key, &buf); - header_->next_key_id = (next_key_id_candidate != -1) ? - next_key_id_candidate : (header_->max_key_id + 1); - ++header_->num_keys; - if (key_id) { - *key_id = key_id_candidate; - } - return true; -} - -bool Array<Slice>::remove(Slice key) { - int64_t key_id; - if (!find(key, &key_id)) { - return false; - } - keys_[key_id] = nullptr; - if (key_id < header_->next_key_id) { - header_->next_key_id = key_id; - } - --header_->num_keys; - return true; -} - -bool Array<Slice>::update(Slice src_key, Slice dest_key, int64_t *key_id) { - int64_t src_key_id; - if (!find(src_key, &src_key_id)) { - return false; - } - if (!dest_key || find(dest_key)) { - return false; - } - std::string buf; - keys_[src_key_id] = slice_to_blob(dest_key, &buf); - if (key_id) { - *key_id = src_key_id; - } - return true; -} - -bool Array<Slice>::truncate() { - for (int64_t i = 0; i <= header_->max_key_id; ++i) { - keys_[i] = nullptr; - } - header_->max_key_id = -1; - header_->next_key_id = 0; - header_->num_keys = 0; - return true; -} - -} // namespace map -} // namespace alpha -} // namespace grnxx Deleted: obsolete/lib/grnxx/alpha/map/array.hpp (+0 -134) 100644 =================================================================== --- obsolete/lib/grnxx/alpha/map/array.hpp 2013-08-23 10:46:34 +0900 (908b6e6) +++ /dev/null @@ -1,134 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_ALPHA_MAP_ARRAY_HPP -#define GRNXX_ALPHA_MAP_ARRAY_HPP - -#include "grnxx/alpha/map.hpp" -#include "grnxx/db/vector.hpp" -#include "grnxx/db/blob_vector.hpp" - -namespace grnxx { -namespace alpha { -namespace map { - -struct ArrayHeader { - MapType map_type; - uint32_t bits_block_id; - uint32_t keys_block_id; - int64_t max_key_id; - int64_t next_key_id; - uint64_t num_keys; - - ArrayHeader(); -}; - -template <typename T> -class Array : public grnxx::alpha::Map<T> { - public: - Array(); - ~Array(); - - static Array *create(io::Pool pool, - const MapOptions &options = MapOptions()); - static Array *open(io::Pool pool, uint32_t block_id); - - static bool unlink(io::Pool pool, uint32_t block_id); - - uint32_t block_id() const; - MapType type() const; - - int64_t max_key_id() const; - int64_t next_key_id() const; - uint64_t num_keys() const; - - bool get(int64_t key_id, T *key = nullptr); - bool get_next(int64_t key_id, int64_t *next_key_id = nullptr, - T *next_key = nullptr); - bool unset(int64_t key_id); - bool reset(int64_t key_id, T dest_key); - - bool find(T key, int64_t *key_id = nullptr); - bool insert(T key, int64_t *key_id = nullptr); - bool remove(T key); - bool update(T src_key, T dest_key, int64_t *key_id = nullptr); - - bool truncate(); - - private: - io::Pool pool_; - const io::BlockInfo *block_info_; - ArrayHeader *header_; - db::Vector<uint32_t> bits_; - db::Vector<T> keys_; - - bool get_bit(int64_t key_id) { - return bits_[key_id / 32] & (1U << (key_id % 32)); - } - void set_bit(int64_t key_id, bool bit) { - if (bit) { - bits_[key_id / 32] |= 1U << (key_id % 32); - } else { - bits_[key_id / 32] &= ~(1U << (key_id % 32)); - } - } -}; - -template <> -class Array<Slice> : public grnxx::alpha::Map<Slice> { - public: - Array(); - ~Array(); - - static Array *create(io::Pool pool, - const MapOptions &options = MapOptions()); - static Array *open(io::Pool pool, uint32_t block_id); - - static bool unlink(io::Pool pool, uint32_t block_id); - - uint32_t block_id() const; - MapType type() const; - - int64_t max_key_id() const; - int64_t next_key_id() const; - uint64_t num_keys() const; - - bool get(int64_t key_id, Slice *key = nullptr); - bool get_next(int64_t key_id, int64_t *next_key_id = nullptr, - Slice *next_key = nullptr); - bool unset(int64_t key_id); - bool reset(int64_t key_id, Slice dest_key); - - bool find(Slice key, int64_t *key_id = nullptr); - bool insert(Slice key, int64_t *key_id = nullptr); - bool remove(Slice key); - bool update(Slice src_key, Slice dest_key, int64_t *key_id = nullptr); - - bool truncate(); - - private: - io::Pool pool_; - const io::BlockInfo *block_info_; - ArrayHeader *header_; - db::BlobVector keys_; -}; - -} // namespace map -} // namespace alpha -} // namespace grnxx - -#endif // GRNXX_ALPHA_MAP_ARRAY_HPP Deleted: obsolete/lib/grnxx/alpha/map/cursor.cpp (+0 -417) 100644 =================================================================== --- obsolete/lib/grnxx/alpha/map/cursor.cpp 2013-08-23 10:46:34 +0900 (97b7cb7) +++ /dev/null @@ -1,417 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/alpha/map/cursor.hpp" - -#include <algorithm> - -namespace grnxx { -namespace alpha { -namespace map { - -template <typename T> -IDCursor<T>::IDCursor(Map<T> *map, int64_t min, int64_t max, - const MapCursorOptions &options) - : MapCursor<T>(), map_(map), cur_(), end_(), step_(), count_(0), - options_(options), keys_() { - if (min < 0) { - min = 0; - } else if (options_.flags & MAP_CURSOR_EXCEPT_MIN) { - ++min; - } - if ((max < 0) || (max > map_->max_key_id())) { - max = map_->max_key_id(); - } else if (options_.flags & MAP_CURSOR_EXCEPT_MAX) { - --max; - } - if (min > max) { - cur_ = end_ = 0; - return; - } - if ((options_.flags & MAP_CURSOR_ORDER_BY_ID) || - (~options_.flags & MAP_CURSOR_ORDER_BY_KEY)) { - init_order_by_id(min, max); - } else { - init_order_by_key(min, max); - } -} - -template <typename T> -IDCursor<T>::~IDCursor() {} - -template <typename T> -bool IDCursor<T>::next() { - if (count_ >= options_.limit) { - return false; - } - if (options_.flags & MAP_CURSOR_ORDER_BY_ID) { - while (cur_ != end_) { - cur_ += step_; - if (map_->get(cur_, &this->key_)) { - this->key_id_ = cur_; - ++count_; - return true; - } - } - } else if (cur_ != end_) { - cur_ += step_; - this->key_ = keys_[cur_].first; - this->key_id_ = keys_[cur_].second; - ++count_; - return true; - } - return false; -} - -template <typename T> -bool IDCursor<T>::remove() { - return map_->unset(this->key_id_); -} - -template <typename T> -void IDCursor<T>::init_order_by_id(int64_t min, int64_t max) { - options_.flags |= MAP_CURSOR_ORDER_BY_ID; - options_.flags &= ~MAP_CURSOR_ORDER_BY_KEY; - if (~options_.flags & MAP_CURSOR_REVERSE_ORDER) { - cur_ = min - 1; - end_ = max; - step_ = 1; - } else { - cur_ = max + 1; - end_ = min; - step_ = -1; - } - uint64_t count = 0; - while ((count < options_.offset) && (cur_ != end_)) { - cur_ += step_; - if (map_->get(cur_)) { - ++count; - } - } -} - -template <typename T> -void IDCursor<T>::init_order_by_key(int64_t min, int64_t max) { - cur_ = min - 1; - end_ = max; - while (cur_ != end_) { - ++cur_; - T key; - if (map_->get(cur_, &key)) { - keys_.push_back(std::make_pair(key, cur_)); - } - } - std::sort(keys_.begin(), keys_.end()); - - if (~options_.flags & MAP_CURSOR_REVERSE_ORDER) { - cur_ = -1; - end_ = keys_.size() - 1; - step_ = 1; - } else { - cur_ = keys_.size(); - end_ = 0; - step_ = -1; - } -} - -template <> -void IDCursor<GeoPoint>::init_order_by_key(int64_t min, int64_t max) { - // Ignore MAP_CURSOR_ORDER_BY_KEY. - init_order_by_id(min, max); -} - -template class IDCursor<int8_t>; -template class IDCursor<int16_t>; -template class IDCursor<int32_t>; -template class IDCursor<int64_t>; -template class IDCursor<uint8_t>; -template class IDCursor<uint16_t>; -template class IDCursor<uint32_t>; -template class IDCursor<uint64_t>; -template class IDCursor<double>; -template class IDCursor<GeoPoint>; -template class IDCursor<Slice>; - -template <typename T> -ConditionalCursor<T>::ConditionalCursor(Map<T> *map, - const MapCursorOptions &options) - : MapCursor<T>(), map_(map), cur_(), end_(), step_(), count_(0), - options_(options), keys_() {} - -template <typename T> -ConditionalCursor<T>::~ConditionalCursor() {} - -template <typename T> -bool ConditionalCursor<T>::next() { - if (count_ >= options_.limit) { - return false; - } - if (options_.flags & MAP_CURSOR_ORDER_BY_ID) { - while (cur_ != end_) { - cur_ += step_; - if (map_->get(cur_, &this->key_)) { - if (is_valid(this->key_)) { - this->key_id_ = cur_; - ++count_; - return true; - } - } - } - } else if (cur_ != end_) { - cur_ += step_; - this->key_ = keys_[cur_].first; - this->key_id_ = keys_[cur_].second; - ++count_; - return true; - } - return false; -} - -template <typename T> -bool ConditionalCursor<T>::remove() { - return map_->unset(this->key_id_); -} - -template <typename T> -void ConditionalCursor<T>::init() { - if ((options_.flags & MAP_CURSOR_ORDER_BY_ID) || - (~options_.flags & MAP_CURSOR_ORDER_BY_KEY)) { - init_order_by_id(); - } else { - init_order_by_key(); - } -} - -template <> -void ConditionalCursor<GeoPoint>::init() { - init_order_by_id(); -} - -template <typename T> -void ConditionalCursor<T>::init_order_by_id() { - options_.flags |= MAP_CURSOR_ORDER_BY_ID; - options_.flags &= ~MAP_CURSOR_ORDER_BY_KEY; - if (~options_.flags & MAP_CURSOR_REVERSE_ORDER) { - cur_ = -1; - end_ = map_->max_key_id(); - step_ = 1; - } else { - cur_ = map_->max_key_id() + 1; - end_ = 0; - step_ = -1; - } - uint64_t count = 0; - while ((count < options_.offset) && (cur_ != end_)) { - cur_ += step_; - if (map_->get(cur_, &this->key_)) { - if (is_valid(this->key_)) { - ++count; - } - } - } -} - -template <typename T> -void ConditionalCursor<T>::init_order_by_key() { - const std::int64_t max_key_id = map_->max_key_id(); - for (std::int64_t i = 0; i <= max_key_id; ++i) { - T key; - if (map_->get(i, &key)) { - if (is_valid(key)) { - keys_.push_back(std::make_pair(key, i)); - } - } - } - std::sort(keys_.begin(), keys_.end()); - if (~options_.flags & MAP_CURSOR_REVERSE_ORDER) { - cur_ = -1; - end_ = keys_.size() - 1; - step_ = 1; - } else { - cur_ = keys_.size(); - end_ = 0; - step_ = -1; - } -} - -template <> -void ConditionalCursor<GeoPoint>::init_order_by_key() { - // Ignore MAP_CURSOR_ORDER_BY_KEY. - init_order_by_id(); -} - -template class ConditionalCursor<int8_t>; -template class ConditionalCursor<int16_t>; -template class ConditionalCursor<int32_t>; -template class ConditionalCursor<int64_t>; -template class ConditionalCursor<uint8_t>; -template class ConditionalCursor<uint16_t>; -template class ConditionalCursor<uint32_t>; -template class ConditionalCursor<uint64_t>; -template class ConditionalCursor<double>; -template class ConditionalCursor<Slice>; - -template <typename T> -KeyCursor<T>::KeyCursor(Map<T> *map, T min, T max, - const MapCursorOptions &options) - : ConditionalCursor<T>(map, options), min_(min), max_(max) { - this->init(); -} - -template <typename T> -KeyCursor<T>::~KeyCursor() {} - -template <typename T> -bool KeyCursor<T>::is_valid(T key) const { - if (this->options_.flags & MAP_CURSOR_EXCEPT_MIN) { - if (key <= min_) { - return false; - } - } else if (key < min_) { - return false; - } - if (this->options_.flags & MAP_CURSOR_EXCEPT_MAX) { - if (key >= max_) { - return false; - } - } else if (key > max_) { - return false; - } - return true; -} - -template <> -bool KeyCursor<Slice>::is_valid(Slice key) const { - if (this->options_.flags & MAP_CURSOR_EXCEPT_MIN) { - if (key <= min_) { - return false; - } - } else if (key < min_) { - return false; - } - if (max_) { - if (this->options_.flags & MAP_CURSOR_EXCEPT_MAX) { - if (key >= max_) { - return false; - } - } else if (key > max_) { - return false; - } - } - return true; -} - -template class KeyCursor<int8_t>; -template class KeyCursor<int16_t>; -template class KeyCursor<int32_t>; -template class KeyCursor<int64_t>; -template class KeyCursor<uint8_t>; -template class KeyCursor<uint16_t>; -template class KeyCursor<uint32_t>; -template class KeyCursor<uint64_t>; -template class KeyCursor<double>; -template class KeyCursor<Slice>; - -BitwiseCompletionCursor::BitwiseCompletionCursor( - Map<GeoPoint> *map, GeoPoint query, size_t bit_size, - const MapCursorOptions &options) - : ConditionalCursor<GeoPoint>(map, options), - query_(query), - mask_() { - if (bit_size >= 64) { - bit_size = 64; - } - switch (bit_size) { - case 0: { - mask_ = 0; - break; - } - case 1: { - mask_ = GeoPoint(1 << 31, 0).value(); - break; - } - default: { - mask_ = GeoPoint(0xFFFFFFFFU << (32 - (bit_size / 2) - (bit_size % 2)), - 0xFFFFFFFFU << (32 - (bit_size / 2))).value(); - break; - } - } - this->init(); -} - -BitwiseCompletionCursor::~BitwiseCompletionCursor() {} - -bool BitwiseCompletionCursor::is_valid(GeoPoint key) const { - return ((key.value() ^ query_.value()) & mask_) == 0; -} - -PrefixCursor::PrefixCursor(Map<Slice> *map, Slice query, size_t min_size, - const MapCursorOptions &options) - : ConditionalCursor<Slice>(map, options), - query_(query), min_size_(min_size) { - if (this->options_.flags & MAP_CURSOR_EXCEPT_QUERY) { - query_.remove_suffix(1); - } - this->init(); -} - -PrefixCursor::~PrefixCursor() {} - -bool PrefixCursor::is_valid(Slice key) const { - if (key.size() < min_size_) { - return false; - } - return query_.starts_with(key); -} - -CompletionCursor::CompletionCursor(Map<Slice> *map, Slice query, - const MapCursorOptions &options) - : ConditionalCursor<Slice>(map, options), query_(query) { - this->init(); -} - -CompletionCursor::~CompletionCursor() {} - -bool CompletionCursor::is_valid(Slice key) const { - if (this->options_.flags & MAP_CURSOR_EXCEPT_QUERY) { - if (key.size() <= query_.size()) { - return false; - } - } - return key.starts_with(query_); -} - -ReverseCompletionCursor::ReverseCompletionCursor( - Map<Slice> *map, Slice query, const MapCursorOptions &options) - : ConditionalCursor<Slice>(map, options), query_(query) { - this->init(); -} - -ReverseCompletionCursor::~ReverseCompletionCursor() {} - -bool ReverseCompletionCursor::is_valid(Slice key) const { - if (this->options_.flags & MAP_CURSOR_EXCEPT_QUERY) { - if (key.size() <= query_.size()) { - return false; - } - } - return key.ends_with(query_); -} - -} // namespace map -} // namespace alpha -} // namespace grnxx Deleted: obsolete/lib/grnxx/alpha/map/cursor.hpp (+0 -148) 100644 =================================================================== --- obsolete/lib/grnxx/alpha/map/cursor.hpp 2013-08-23 10:46:34 +0900 (f92195f) +++ /dev/null @@ -1,148 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_ALPHA_MAP_CURSOR_HPP -#define GRNXX_ALPHA_MAP_CURSOR_HPP - -#include "grnxx/alpha/map.hpp" - -#include <vector> - -#include "grnxx/geo_point.hpp" - -namespace grnxx { -namespace alpha { -namespace map { - -template <typename T> -class IDCursor : public MapCursor<T> { - public: - IDCursor(Map<T> *map, int64_t min, int64_t max, - const MapCursorOptions &options); - ~IDCursor(); - - bool next(); - bool remove(); - - private: - Map<T> *map_; - int64_t cur_; - int64_t end_; - int64_t step_; - uint64_t count_; - MapCursorOptions options_; - std::vector<std::pair<T, int64_t>> keys_; - - void init_order_by_id(int64_t min, int64_t max); - void init_order_by_key(int64_t min, int64_t max); -}; - -template <typename T> -class ConditionalCursor : public MapCursor<T> { - public: - ConditionalCursor(Map<T> *map, const MapCursorOptions &options); - virtual ~ConditionalCursor(); - - bool next(); - bool remove(); - - protected: - Map<T> *map_; - int64_t cur_; - int64_t end_; - int64_t step_; - uint64_t count_; - MapCursorOptions options_; - std::vector<std::pair<T, int64_t>> keys_; - - void init(); - - virtual bool is_valid(T key) const = 0; - - private: - void init_order_by_id(); - void init_order_by_key(); -}; - -template <typename T> -class KeyCursor : public ConditionalCursor<T> { - public: - KeyCursor(Map<T> *map, T min, T max, const MapCursorOptions &options); - ~KeyCursor(); - - private: - T min_; - T max_; - - bool is_valid(T key) const; -}; - -class BitwiseCompletionCursor : public ConditionalCursor<GeoPoint> { - public: - BitwiseCompletionCursor(Map<GeoPoint> *map, GeoPoint query, size_t bit_size, - const MapCursorOptions &options); - ~BitwiseCompletionCursor(); - - private: - GeoPoint query_; - uint64_t mask_; - - bool is_valid(GeoPoint key) const; -}; - -class PrefixCursor : public ConditionalCursor<Slice> { - public: - PrefixCursor(Map<Slice> *map, Slice query, size_t min_size, - const MapCursorOptions &options); - ~PrefixCursor(); - - private: - Slice query_; - size_t min_size_; - - bool is_valid(Slice key) const; -}; - -class CompletionCursor : public ConditionalCursor<Slice> { - public: - CompletionCursor(Map<Slice> *map, Slice query, - const MapCursorOptions &options); - ~CompletionCursor(); - - private: - Slice query_; - - bool is_valid(Slice key) const; -}; - -class ReverseCompletionCursor : public ConditionalCursor<Slice> { - public: - ReverseCompletionCursor(Map<Slice> *map, Slice query, - const MapCursorOptions &options); - ~ReverseCompletionCursor(); - - private: - Slice query_; - - bool is_valid(Slice key) const; -}; - -} // namespace map -} // namespace alpha -} // namespace grnxx - -#endif // GRNXX_ALPHA_MAP_CURSOR_HPP Deleted: obsolete/lib/grnxx/alpha/map/double_array-slice.cpp (+0 -2161) 100644 =================================================================== --- obsolete/lib/grnxx/alpha/map/double_array-slice.cpp 2013-08-23 10:46:34 +0900 (f18b539) +++ /dev/null @@ -1,2161 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/alpha/map/double_array.hpp" - -#include <algorithm> -#include <vector> - -#include "grnxx/lock.hpp" -#include "grnxx/logger.hpp" - -namespace grnxx { -namespace alpha { -namespace map { -namespace { - -constexpr int32_t MIN_KEY_ID = 0; -constexpr int32_t MAX_KEY_ID = 0x7FFFFFFE; - -constexpr size_t MIN_KEY_SIZE = 1; -constexpr size_t MAX_KEY_SIZE = 4095; - -constexpr uint32_t INVALID_OFFSET = 0; - -constexpr uint32_t ROOT_NODE_ID = 0; - -constexpr uint16_t TERMINAL_LABEL = 0x100; -constexpr uint16_t MAX_LABEL = TERMINAL_LABEL; -constexpr uint16_t INVALID_LABEL = 0x1FF; - -constexpr uint32_t CHUNK_SIZE = 0x200; -constexpr uint32_t CHUNK_MASK = 0x1FF; - -// Assume that #nodes per key is 4 and #uint32_ts per key is 8. -// Note that an entries is associated with a key. -constexpr uint32_t INITIAL_NODES_SIZE = 1 << 16; -constexpr uint32_t INITIAL_ENTRIES_SIZE = 1 << 14; -constexpr uint32_t INITIAL_KEYS_SIZE = 1 << 17; - -constexpr uint32_t MAX_NODES_SIZE = - std::numeric_limits<uint32_t>::max() & ~CHUNK_MASK; -constexpr uint32_t MAX_ENTRIES_SIZE = uint32_t(MAX_KEY_ID) + 1; -constexpr uint32_t MAX_KEYS_SIZE = uint32_t(1) << 31; - -// Chunks are grouped by the level which indicates how easily update operations -// can find a good offset in that chunk. The chunk level rises when -// find_offset() fails in that chunk many times. MAX_FAILURE_COUNT -// is the threshold. Also, in order to limit the time cost, find_offset() scans -// at most MAX_CHUNK_COUNT chunks. -// Larger parameters bring more chances of finding good offsets but it leads to -// more node renumberings, which are costly operations, and thus results in -// degradation of space/time efficiencies. -constexpr uint32_t MAX_FAILURE_COUNT = 4; -constexpr uint32_t MAX_CHUNK_COUNT = 16; -constexpr uint32_t MAX_CHUNK_LEVEL = 5; - -// Chunks in the same level compose a doubly linked list. The entry chunk of -// a linked list is called a leader. INVALID_LEADER means that -// the linked list is empty and there exists no leader. -constexpr uint32_t INVALID_LEADER = std::numeric_limits<uint32_t>::max(); - -} // namespace - -struct SliceDoubleArrayHeader { - MapType map_type; - uint32_t nodes_block_id; - uint32_t chunks_block_id; - uint32_t entries_block_id; - uint32_t keys_block_id; - uint32_t nodes_size; - uint32_t chunks_size; - uint32_t entries_size; - uint32_t keys_size; - int32_t next_key_id; - uint32_t next_key_pos; - int32_t max_key_id; - uint64_t total_key_length; - uint32_t num_keys; - uint32_t num_chunks; - uint32_t num_phantoms; - uint32_t num_zombies; - uint32_t leaders[MAX_CHUNK_LEVEL + 1]; - Mutex inter_process_mutex; - - SliceDoubleArrayHeader(); -}; - -SliceDoubleArrayHeader::SliceDoubleArrayHeader() - : map_type(MAP_DOUBLE_ARRAY), - nodes_block_id(io::BLOCK_INVALID_ID), - chunks_block_id(io::BLOCK_INVALID_ID), - entries_block_id(io::BLOCK_INVALID_ID), - keys_block_id(io::BLOCK_INVALID_ID), - nodes_size(0), - chunks_size(0), - entries_size(0), - keys_size(0), - next_key_id(0), - next_key_pos(0), - max_key_id(-1), - total_key_length(0), - num_keys(0), - num_chunks(0), - num_phantoms(0), - num_zombies(0), - leaders(), - inter_process_mutex(MUTEX_UNLOCKED) { - for (uint32_t i = 0; i <= MAX_CHUNK_LEVEL; ++i) { - leaders[i] = INVALID_LEADER; - } -} - -class SliceDoubleArrayNode { - public: - SliceDoubleArrayNode() : qword_(IS_PHANTOM_FLAG) {} - - // Structure overview. - // 0- 8 ( 9): next (is_phantom). - // 9-17 ( 9): prev (is_phantom). - // 0- 8 ( 9): label (!is_phantom). - // 9-17 ( 9): sibling (!is_phantom). - // 18-48 (31): key_pos (!is_phantom && is_leaf). - // 18-49 (32): offset (!is_phantom && !is_leaf). - // 50-58 ( 9): child (!is_phantom && !is_leaf). - // 61-61 ( 1): is_leaf. - // 62-62 ( 1): is_phantom. - // 63-63 ( 1): is_origin. - // Note that 0 is the LSB and 63 is the MSB. - - // The ID of this node is used as an offset (true) or not (false). - bool is_origin() const { - return qword_ & IS_ORIGIN_FLAG; - } - // This node is valid (false) or not (true). - bool is_phantom() const { - return qword_ & IS_PHANTOM_FLAG; - } - // This node is associated with a key (true) or not (false). - bool is_leaf() const { - return qword_ & IS_LEAF_FLAG; - } - - void set_is_origin(bool value) { - if (value) { - qword_ |= IS_ORIGIN_FLAG; - } else { - qword_ &= ~IS_ORIGIN_FLAG; - } - } - void set_is_phantom(bool value) { - if (value) { - qword_ = (qword_ & IS_ORIGIN_FLAG) | IS_PHANTOM_FLAG; - } else { - qword_ = (qword_ & IS_ORIGIN_FLAG) | - (uint64_t(INVALID_OFFSET) << OFFSET_SHIFT) | - (uint64_t(INVALID_LABEL) << CHILD_SHIFT) | - (uint64_t(INVALID_LABEL) << SIBLING_SHIFT) | INVALID_LABEL; - } - } - - // Phantom nodes are doubly linked in each chunk. - // Each chunk consists of 512 nodes. - uint16_t next() const { - return static_cast<uint16_t>(qword_ & NEXT_MASK); - } - uint16_t prev() const { - return static_cast<uint16_t>((qword_ >> PREV_SHIFT) & PREV_MASK); - } - - void set_next(uint16_t value) { - qword_ = (qword_ & ~NEXT_MASK) | value; - } - void set_prev(uint16_t value) { - qword_ = (qword_ & ~(PREV_MASK << PREV_SHIFT)) | - (static_cast<uint64_t>(value) << PREV_SHIFT); - } - - // A non-phantom node stores its label and the label of its next sibling. - // A phantom node returns an invalid label with IS_PHANTOM_FLAG. - // sibling() == INVALID_LABEL means that the node doesn't have next sibling. - uint64_t label() const { - return qword_ & (IS_PHANTOM_FLAG | LABEL_MASK); - } - uint16_t sibling() const { - return static_cast<uint16_t>((qword_ >> SIBLING_SHIFT) & SIBLING_MASK); - } - - void set_label(uint16_t value) { - qword_ = (qword_ & ~LABEL_MASK) | value; - } - void set_sibling(uint16_t value) { - qword_ = (qword_ & ~(SIBLING_MASK << SIBLING_SHIFT)) | - (static_cast<uint64_t>(value) << SIBLING_SHIFT); - } - - // A leaf node stores the start position of the associated key. - uint32_t key_pos() const { - return static_cast<uint32_t>((qword_ >> KEY_POS_SHIFT) & KEY_POS_MASK); - } - - void set_key_pos(uint32_t value) { - qword_ = (qword_ & ~(KEY_POS_MASK << KEY_POS_SHIFT)) | - (static_cast<uint64_t>(value) << KEY_POS_SHIFT) | IS_LEAF_FLAG; - } - - // A non-phantom and non-leaf node stores the offset to its children and the - // label of its first child. - // child() == INVALID_LABEL means that the node has no child. - uint32_t offset() const { - return static_cast<uint32_t>((qword_ >> OFFSET_SHIFT) & OFFSET_MASK); - } - uint16_t child() const { - return static_cast<uint16_t>((qword_ >> CHILD_SHIFT) & CHILD_MASK); - } - - void set_offset(uint32_t value) { - if (qword_ & IS_LEAF_FLAG) { - qword_ = ((qword_ & ~IS_LEAF_FLAG) & ~(OFFSET_MASK << OFFSET_SHIFT)) | - (static_cast<uint64_t>(value) << OFFSET_SHIFT) | - (uint64_t(INVALID_LABEL) << CHILD_SHIFT); - } else { - qword_ = (qword_ & ~(OFFSET_MASK << OFFSET_SHIFT)) | - (static_cast<uint64_t>(value) << OFFSET_SHIFT); - } - } - void set_child(uint16_t value) { - qword_ = (qword_ & ~(CHILD_MASK << CHILD_SHIFT)) | - (static_cast<uint64_t>(value) << CHILD_SHIFT); - } - - private: - uint64_t qword_; - - // 61-63. - static constexpr uint64_t IS_ORIGIN_FLAG = uint64_t(1) << 63; - static constexpr uint64_t IS_PHANTOM_FLAG = uint64_t(1) << 62; - static constexpr uint64_t IS_LEAF_FLAG = uint64_t(1) << 61; - - // 0-17 (is_phantom). - static constexpr uint64_t NEXT_MASK = (uint64_t(1) << 9) - 1; - static constexpr uint64_t PREV_MASK = (uint64_t(1) << 9) - 1; - static constexpr uint8_t PREV_SHIFT = 9; - - // 0-17 (!is_phantom). - static constexpr uint64_t LABEL_MASK = (uint64_t(1) << 9) - 1; - static constexpr uint64_t SIBLING_MASK = (uint64_t(1) << 9) - 1; - static constexpr uint8_t SIBLING_SHIFT = 9; - - // 18-48 (!is_phantom && is_leaf) - static constexpr uint64_t KEY_POS_MASK = (uint64_t(1) << 31) - 1; - static constexpr uint8_t KEY_POS_SHIFT = 18; - - // 18-58 (!is_phantom && !is_leaf) - static constexpr uint64_t OFFSET_MASK = (uint64_t(1) << 32) - 1; - static constexpr uint8_t OFFSET_SHIFT = 18; - static constexpr uint64_t CHILD_MASK = (uint64_t(1) << 9) - 1; - static constexpr uint8_t CHILD_SHIFT = 50; -}; - -class SliceDoubleArrayChunk { - public: - SliceDoubleArrayChunk() : next_(0), prev_(0), others_(0) {} - - // Chunks in the same level are doubly linked. - uint32_t next() const { - return next_; - } - uint32_t prev() const { - return prev_; - } - - void set_next(uint32_t value) { - next_ = value; - } - void set_prev(uint32_t value) { - prev_ = value; - } - - // The chunk level indicates how easily nodes can be put in this chunk. - uint32_t level() const { - return (others_ >> LEVEL_SHIFT) & LEVEL_MASK; - } - uint32_t failure_count() const { - return (others_ >> FAILURE_COUNT_SHIFT) & FAILURE_COUNT_MASK; - } - - void set_level(uint32_t value) { - others_ = (others_ & ~(LEVEL_MASK << LEVEL_SHIFT)) | - (value << LEVEL_SHIFT); - } - void set_failure_count(uint32_t value) { - others_ = (others_ & ~(FAILURE_COUNT_MASK << FAILURE_COUNT_SHIFT)) | - (value << FAILURE_COUNT_SHIFT); - } - - // The first phantom node and the number of phantom nodes in this chunk. - uint32_t first_phantom() const { - return (others_ >> FIRST_PHANTOM_SHIFT) & FIRST_PHANTOM_MASK; - } - uint32_t num_phantoms() const { - return (others_ >> NUM_PHANTOMS_SHIFT) & NUM_PHANTOMS_MASK; - } - - void set_first_phantom(uint32_t value) { - others_ = (others_ & ~(FIRST_PHANTOM_MASK << FIRST_PHANTOM_SHIFT)) | - (value << FIRST_PHANTOM_SHIFT); - } - void set_num_phantoms(uint32_t value) { - others_ = (others_ & ~(NUM_PHANTOMS_MASK << NUM_PHANTOMS_SHIFT)) | - (value << NUM_PHANTOMS_SHIFT); - } - - private: - uint32_t next_; - uint32_t prev_; - uint32_t others_; - - static constexpr uint32_t LEVEL_MASK = (1 << 4) - 1; - static constexpr uint8_t LEVEL_SHIFT = 0; - - static constexpr uint32_t FAILURE_COUNT_MASK = (1 << 6) - 1; - static constexpr uint8_t FAILURE_COUNT_SHIFT = 4; - - static constexpr uint32_t FIRST_PHANTOM_MASK = (1 << 10) - 1; - static constexpr uint32_t FIRST_PHANTOM_SHIFT = 10; - - static constexpr uint32_t NUM_PHANTOMS_MASK = (1 << 10) - 1; - static constexpr uint32_t NUM_PHANTOMS_SHIFT = 20; -}; - -class SliceDoubleArrayEntry { - public: - // Create a valid entry. - static SliceDoubleArrayEntry valid_entry(uint32_t key_pos) { - return SliceDoubleArrayEntry(IS_VALID_FLAG | key_pos); - } - // Create an invalid entry. - static SliceDoubleArrayEntry invalid_entry(uint32_t next) { - return SliceDoubleArrayEntry(next); - } - - // Return true iff "*this" is valid (associated with a key). - explicit operator bool() const { - return dword_ & IS_VALID_FLAG; - } - - // Return the starting address of the associated key. - // Available iff "*this' is valid. - uint32_t key_pos() const { - return dword_ & ~IS_VALID_FLAG; - } - - // Return the next invalid entry. - // Available iff "*this' is invalid. - uint32_t next() const { - return dword_; - } - - private: - uint32_t dword_; - - static constexpr uint32_t IS_VALID_FLAG = uint32_t(1) << 31; - - explicit SliceDoubleArrayEntry(uint32_t x) : dword_(x) {} -}; - -class SliceDoubleArrayKey { - public: - SliceDoubleArrayKey(int32_t id, const Slice &key) - : id_(id), - size_(static_cast<uint16_t>(key.size())), - buf_{ '\0', '\0' } { - std::memcpy(buf_, key.ptr(), key.size()); - } - - const uint8_t &operator[](size_t i) const { - return buf_[i]; - } - - int32_t id() const { - return id_; - } - size_t size() const { - return size_; - } - const uint8_t *ptr() const { - return buf_; - } - Slice slice() const { - return Slice(buf_, size_); - } - - bool equals_to(const Slice &key, size_t offset = 0) const { - if (key.size() != size_) { - return false; - } - for ( ; offset < key.size(); ++offset) { - if (buf_[offset] != key[offset]) { - return false; - } - } - return true; - } - - static uint32_t estimate_size(const size_t key_size) { - return (9 + key_size) / sizeof(uint32_t); - } - - private: - int32_t id_; - uint16_t size_; - uint8_t buf_[2]; -}; - -constexpr uint64_t IS_ROOT_FLAG = uint64_t(1) << 63; -constexpr uint64_t POST_ORDER_FLAG = uint64_t(1) << 63; - -template <> -class DoubleArrayIDCursor<Slice> : public MapCursor<Slice> { - public: - DoubleArrayIDCursor(DoubleArray<Slice> *double_array, - int64_t min, int64_t max, - const MapCursorOptions &options); - ~DoubleArrayIDCursor(); - - bool next(); - bool remove(); - - private: - DoubleArray<Slice> *double_array_; - int64_t cur_; - int64_t end_; - int64_t step_; - uint64_t count_; - MapCursorOptions options_; - std::vector<std::pair<Slice, int64_t>> keys_; - - void init_order_by_id(int64_t min, int64_t max); - void init_order_by_key(int64_t min, int64_t max); -}; - -DoubleArrayIDCursor<Slice>::DoubleArrayIDCursor( - DoubleArray<Slice> *double_array, int64_t min, int64_t max, - const MapCursorOptions &options) - : MapCursor<Slice>(), double_array_(double_array), cur_(), end_(), step_(), - count_(0), options_(options), keys_() { - if (min < 0) { - min = 0; - } else if (options_.flags & MAP_CURSOR_EXCEPT_MIN) { - ++min; - } - if ((max < 0) || (max > double_array_->max_key_id())) { - max = double_array_->max_key_id(); - } else if (options_.flags & MAP_CURSOR_EXCEPT_MAX) { - --max; - } - if (min > max) { - cur_ = end_ = 0; - return; - } - if ((options_.flags & MAP_CURSOR_ORDER_BY_ID) || - (~options_.flags & MAP_CURSOR_ORDER_BY_KEY)) { - init_order_by_id(min, max); - } else { - init_order_by_key(min, max); - } -} - -DoubleArrayIDCursor<Slice>::~DoubleArrayIDCursor() {} - -bool DoubleArrayIDCursor<Slice>::next() { - if (count_ >= options_.limit) { - return false; - } - if (options_.flags & MAP_CURSOR_ORDER_BY_ID) { - while (cur_ != end_) { - cur_ += step_; - if (double_array_->get(cur_, &this->key_)) { - this->key_id_ = cur_; - ++count_; - return true; - } - } - } else if (cur_ != end_) { - cur_ += step_; - this->key_ = keys_[cur_].first; - this->key_id_ = keys_[cur_].second; - ++count_; - return true; - } - return false; -} - -bool DoubleArrayIDCursor<Slice>::remove() { - return double_array_->unset(this->key_id_); -} - -void DoubleArrayIDCursor<Slice>::init_order_by_id(int64_t min, int64_t max) { - options_.flags |= MAP_CURSOR_ORDER_BY_ID; - options_.flags &= ~MAP_CURSOR_ORDER_BY_KEY; - if (~options_.flags & MAP_CURSOR_REVERSE_ORDER) { - cur_ = min - 1; - end_ = max; - step_ = 1; - } else { - cur_ = max + 1; - end_ = min; - step_ = -1; - } - uint64_t count = 0; - while ((count < options_.offset) && (cur_ != end_)) { - cur_ += step_; - if (double_array_->get(cur_)) { - ++count; - } - } -} - -void DoubleArrayIDCursor<Slice>::init_order_by_key(int64_t min, int64_t max) { - cur_ = min - 1; - end_ = max; - while (cur_ != end_) { - ++cur_; - Slice key; - if (double_array_->get(cur_, &key)) { - keys_.push_back(std::make_pair(key, cur_)); - } - } - std::sort(keys_.begin(), keys_.end()); - if (~options_.flags & MAP_CURSOR_REVERSE_ORDER) { - cur_ = -1; - end_ = keys_.size() - 1; - step_ = 1; - } else { - cur_ = keys_.size(); - end_ = 0; - step_ = -1; - } -} - -template <> -class DoubleArrayKeyCursor<Slice> : public MapCursor<Slice> { - public: - DoubleArrayKeyCursor(DoubleArray<Slice> *double_array, - Slice min, Slice max, - const MapCursorOptions &options); - ~DoubleArrayKeyCursor(); - - bool next(); - bool remove(); - - private: - DoubleArray<Slice> *double_array_; - uint64_t cur_; - uint64_t count_; - Slice min_; - Slice max_; - MapCursorOptions options_; - std::vector<uint64_t> node_ids_; - std::vector<std::pair<int64_t, Slice>> keys_; - - void init_order_by_id(); - void init_order_by_key(); - void init_reverse_order_by_key(); - - bool next_order_by_id(); - bool next_order_by_key(); - bool next_reverse_order_by_key(); -}; - -DoubleArrayKeyCursor<Slice>::DoubleArrayKeyCursor( - DoubleArray<Slice> *double_array, Slice min, Slice max, - const MapCursorOptions &options) - : MapCursor<Slice>(), double_array_(double_array), cur_(), count_(0), - min_(min), max_(max), options_(options), node_ids_(), keys_() { - if ((options_.flags & MAP_CURSOR_ORDER_BY_ID) && - (~options_.flags & MAP_CURSOR_ORDER_BY_KEY)) { - init_order_by_id(); - } else { - options_.flags &= ~MAP_CURSOR_ORDER_BY_ID; - options_.flags |= MAP_CURSOR_ORDER_BY_KEY; - if (~options_.flags & MAP_CURSOR_REVERSE_ORDER) { - init_order_by_key(); - } else { - init_reverse_order_by_key(); - } - } -} - -DoubleArrayKeyCursor<Slice>::~DoubleArrayKeyCursor() {} - -bool DoubleArrayKeyCursor<Slice>::next() { - if (count_ >= options_.limit) { - return false; - } - if (options_.flags & MAP_CURSOR_ORDER_BY_ID) { - return next_order_by_id(); - } else if (~options_.flags & MAP_CURSOR_REVERSE_ORDER) { - return next_order_by_key(); - } else { - return next_reverse_order_by_key(); - } -} - -bool DoubleArrayKeyCursor<Slice>::remove() { - return double_array_->unset(this->key_id_); -} - -void DoubleArrayKeyCursor<Slice>::init_order_by_id() { - init_order_by_key(); - while (!node_ids_.empty()) { - const uint64_t node_id = node_ids_.back(); - node_ids_.pop_back(); - const SliceDoubleArrayNode node = double_array_->nodes_[node_id]; - if (node.sibling() != INVALID_LABEL) { - node_ids_.push_back(node_id ^ node.label() ^ node.sibling()); - } - if (node.is_leaf()) { - const SliceDoubleArrayKey &key = - double_array_->get_key(node.key_pos()); - if (max_) { - const int result = key.slice().compare(Slice(max_.ptr(), max_.size())); - if ((result > 0) || - ((result == 0) && (options_.flags & MAP_CURSOR_EXCEPT_MAX))) { - break; - } - } - keys_.push_back(std::make_pair(key.id(), key.slice())); - } else if (node.child() != INVALID_LABEL) { - node_ids_.push_back(node.offset() ^ node.child()); - } - } - std::sort(keys_.begin(), keys_.end()); - if (options_.flags & MAP_CURSOR_REVERSE_ORDER) { - std::reverse(keys_.begin(), keys_.end()); - } - cur_ = options_.offset; -} - -void DoubleArrayKeyCursor<Slice>::init_order_by_key() { - if (!min_) { - node_ids_.push_back(ROOT_NODE_ID); - return; - } - uint64_t node_id = ROOT_NODE_ID; - SliceDoubleArrayNode node; - for (size_t i = 0; i < min_.size(); ++i) { - node = double_array_->nodes_[node_id]; - if (node.is_leaf()) { - const SliceDoubleArrayKey &key = - double_array_->get_key(node.key_pos()); - const int result = key.slice().compare(min_, i); - if ((result > 0) || - ((result == 0) && (~options_.flags & MAP_CURSOR_EXCEPT_MIN))) { - node_ids_.push_back(node_id); - } else if (node.sibling() != INVALID_LABEL) { - node_ids_.push_back(node_id ^ node.label() ^ node.sibling()); - } - return; - } else if (node.sibling() != INVALID_LABEL) { - node_ids_.push_back(node_id ^ node.label() ^ node.sibling()); - } - node_id = node.offset() ^ min_[i]; - if (double_array_->nodes_[node_id].label() != min_[i]) { - uint16_t label = node.child(); - if (label == TERMINAL_LABEL) { - label = double_array_->nodes_[node.offset() ^ label].sibling(); - } - while (label != INVALID_LABEL) { - if (label > min_[i]) { - node_ids_.push_back(node.offset() ^ label); - break; - } - label = double_array_->nodes_[node.offset() ^ label].sibling(); - } - return; - } - } - - node = double_array_->nodes_[node_id]; - if (node.is_leaf()) { - const SliceDoubleArrayKey &key = double_array_->get_key(node.key_pos()); - if ((key.size() != min_.size()) || - (~options_.flags & MAP_CURSOR_EXCEPT_MIN)) { - node_ids_.push_back(node_id); - } else if (node.sibling() != INVALID_LABEL) { - node_ids_.push_back(node_id ^ node.label() ^ node.sibling()); - } - return; - } else if (node.sibling() != INVALID_LABEL) { - node_ids_.push_back(node_id ^ node.label() ^ node.sibling()); - } - - uint16_t label = node.child(); - if ((label == TERMINAL_LABEL) && (options_.flags & MAP_CURSOR_EXCEPT_MIN)) { - label = double_array_->nodes_[node.offset() ^ label].sibling(); - } - if (label != INVALID_LABEL) { - node_ids_.push_back(node.offset() ^ label); - } -} - -void DoubleArrayKeyCursor<Slice>::init_reverse_order_by_key() { - if (!max_) { - node_ids_.push_back(ROOT_NODE_ID); - return; - } - uint64_t node_id = ROOT_NODE_ID; - for (size_t i = 0; i < max_.size(); ++i) { - const SliceDoubleArrayNode node = double_array_->nodes_[node_id]; - if (node.is_leaf()) { - const SliceDoubleArrayKey &key = - double_array_->get_key(node.key_pos()); - const int result = key.slice().compare(max_, i); - if ((result < 0) || - ((result == 0) && (~options_.flags & MAP_CURSOR_EXCEPT_MAX))) { - node_ids_.push_back(node_id | POST_ORDER_FLAG); - } - return; - } - uint16_t label = double_array_->nodes_[node_id].child(); - if (label == TERMINAL_LABEL) { - node_id = node.offset() ^ label; - node_ids_.push_back(node_id | POST_ORDER_FLAG); - label = double_array_->nodes_[node_id].sibling(); - } - while (label != INVALID_LABEL) { - node_id = node.offset() ^ label; - if (label < max_[i]) { - node_ids_.push_back(node_id); - } else if (label > max_[i]) { - return; - } else { - break; - } - label = double_array_->nodes_[node_id].sibling(); - } - if (label == INVALID_LABEL) { - return; - } - } - - const SliceDoubleArrayNode node = double_array_->nodes_[node_id]; - if (node.is_leaf()) { - const SliceDoubleArrayKey &key = double_array_->get_key(node.key_pos()); - if ((key.size() == max_.size()) && - (~options_.flags & MAP_CURSOR_EXCEPT_MAX)) { - node_ids_.push_back(node_id | POST_ORDER_FLAG); - } - return; - } - - uint16_t label = double_array_->nodes_[node_id].child(); - if ((label == TERMINAL_LABEL) && - (~options_.flags & MAP_CURSOR_EXCEPT_MAX)) { - node_ids_.push_back((node.offset() ^ label) | POST_ORDER_FLAG); - } -} - -bool DoubleArrayKeyCursor<Slice>::next_order_by_id() { - if (cur_ < keys_.size()) { - this->key_id_ = keys_[cur_].first; - this->key_ = keys_[cur_].second; - ++cur_; - ++count_; - return true; - } - return false; -} - -bool DoubleArrayKeyCursor<Slice>::next_order_by_key() { - while (!node_ids_.empty()) { - const uint64_t node_id = node_ids_.back(); - node_ids_.pop_back(); - const SliceDoubleArrayNode node = double_array_->nodes_[node_id]; - if (node.sibling() != INVALID_LABEL) { - node_ids_.push_back(node_id ^ node.label() ^ node.sibling()); - } - if (node.is_leaf()) { - const SliceDoubleArrayKey &key = - double_array_->get_key(node.key_pos()); - if (max_) { - const int result = key.slice().compare(Slice(max_.ptr(), max_.size())); - if ((result > 0) || - ((result == 0) && (options_.flags & MAP_CURSOR_EXCEPT_MAX))) { - node_ids_.clear(); - return false; - } - } - if (options_.offset > 0) { - --options_.offset; - } else { - this->key_id_ = key.id(); - this->key_ = key.slice(); - ++count_; - return true; - } - } else if (node.child() != INVALID_LABEL) { - node_ids_.push_back(node.offset() ^ node.child()); - } - } - return false; -} - -bool DoubleArrayKeyCursor<Slice>::next_reverse_order_by_key() { - while (!node_ids_.empty()) { - const bool post_order = node_ids_.back() & POST_ORDER_FLAG; - const uint64_t node_id = node_ids_.back() & ~POST_ORDER_FLAG; - const SliceDoubleArrayNode node = double_array_->nodes_[node_id]; - if (post_order) { - node_ids_.pop_back(); - if (node.is_leaf()) { - const SliceDoubleArrayKey &key = - double_array_->get_key(node.key_pos()); - if (min_) { - const int result = - key.slice().compare(Slice(min_.ptr(), min_.size())); - if ((result < 0) || - ((result == 0) && (options_.flags & MAP_CURSOR_EXCEPT_MIN))) { - node_ids_.clear(); - return false; - } - } - if (options_.offset > 0) { - --options_.offset; - } else { - this->key_id_ = key.id(); - this->key_ = key.slice(); - ++count_; - return true; - } - } - } else { - node_ids_.back() |= POST_ORDER_FLAG; - uint16_t label = double_array_->nodes_[node_id].child(); - while (label != INVALID_LABEL) { - node_ids_.push_back(node.offset() ^ label); - label = double_array_->nodes_[node.offset() ^ label].sibling(); - } - } - } - return false; -} - -template <> -class DoubleArrayPrefixCursor<Slice> : public MapCursor<Slice> { - public: - DoubleArrayPrefixCursor(DoubleArray<Slice> *double_array, - Slice query, size_t min_size, - const MapCursorOptions &options); - ~DoubleArrayPrefixCursor(); - - bool next(); - bool remove(); - - private: - DoubleArray<Slice> *double_array_; - uint64_t cur_; - uint64_t count_; - MapCursorOptions options_; - std::vector<std::pair<int64_t, Slice>> keys_; - - void init_order_by_id(Slice query, size_t min_size); - void init_order_by_key(Slice query, size_t min_size); -}; - -DoubleArrayPrefixCursor<Slice>::DoubleArrayPrefixCursor( - DoubleArray<Slice> *double_array, Slice query, size_t min_size, - const MapCursorOptions &options) - : MapCursor<Slice>(), double_array_(double_array), cur_(), - count_(0), options_(options), keys_() { - if ((options_.flags & MAP_CURSOR_ORDER_BY_ID) && - (~options_.flags & MAP_CURSOR_ORDER_BY_KEY)) { - init_order_by_id(query, min_size); - } else { - options_.flags &= ~MAP_CURSOR_ORDER_BY_ID; - options_.flags |= MAP_CURSOR_ORDER_BY_KEY; - init_order_by_key(query, min_size); - } - if (options_.flags & MAP_CURSOR_REVERSE_ORDER) { - std::reverse(keys_.begin(), keys_.end()); - } - cur_ = options_.offset; -} - -DoubleArrayPrefixCursor<Slice>::~DoubleArrayPrefixCursor() {} - -bool DoubleArrayPrefixCursor<Slice>::next() { - if (count_ >= options_.limit) { - return false; - } - if (cur_ < keys_.size()) { - this->key_id_ = keys_[cur_].first; - this->key_ = keys_[cur_].second; - ++cur_; - ++count_; - return true; - } - return false; -} - -bool DoubleArrayPrefixCursor<Slice>::remove() { - return double_array_->unset(this->key_id_); -} - -void DoubleArrayPrefixCursor<Slice>::init_order_by_id( - Slice query, size_t min_size) { - init_order_by_key(query, min_size); - std::sort(keys_.begin(), keys_.end()); -} - -void DoubleArrayPrefixCursor<Slice>::init_order_by_key( - Slice query, size_t min_size) { - if ((query.size() > 0) && (options_.flags & MAP_CURSOR_EXCEPT_QUERY)) { - query.remove_suffix(1); - } - uint64_t node_id = ROOT_NODE_ID; - size_t i; - for (i = 0; i < query.size(); ++i) { - const SliceDoubleArrayNode node = double_array_->nodes_[node_id]; - if (node.is_leaf()) { - const SliceDoubleArrayKey &key = - double_array_->get_key(node.key_pos()); - if ((key.size() >= min_size) && (key.size() <= query.size()) && - key.equals_to(query.prefix(key.size()), i)) { - keys_.push_back(std::make_pair(key.id(), key.slice())); - } - break; - } - if ((i >= min_size) && - (double_array_->nodes_[node_id].child() == TERMINAL_LABEL)) { - const SliceDoubleArrayNode leaf_node = - double_array_->nodes_[node.offset() ^ TERMINAL_LABEL]; - if (leaf_node.is_leaf()) { - const SliceDoubleArrayKey &key = - double_array_->get_key(leaf_node.key_pos()); - keys_.push_back(std::make_pair(key.id(), key.slice())); - } - } - node_id = node.offset() ^ query[i]; - if (double_array_->nodes_[node_id].label() != query[i]) { - break; - } - } - - if (i == query.size()) { - const SliceDoubleArrayNode node = double_array_->nodes_[node_id]; - if (node.is_leaf()) { - const SliceDoubleArrayKey &key = - double_array_->get_key(node.key_pos()); - if ((key.size() >= min_size) && (key.size() <= query.size())) { - keys_.push_back(std::make_pair(key.id(), key.slice())); - } - } else if (double_array_->nodes_[node_id].child() == TERMINAL_LABEL) { - const SliceDoubleArrayNode leaf_node = - double_array_->nodes_[node.offset() ^ TERMINAL_LABEL]; - if (leaf_node.is_leaf()) { - const SliceDoubleArrayKey &key = - double_array_->get_key(leaf_node.key_pos()); - keys_.push_back(std::make_pair(key.id(), key.slice())); - } - } - } -} - -template <> -class DoubleArrayCompletionCursor<Slice> : public MapCursor<Slice> { - public: - DoubleArrayCompletionCursor(DoubleArray<Slice> *double_array, - Slice query, - const MapCursorOptions &options); - ~DoubleArrayCompletionCursor(); - - bool next(); - bool remove(); - - private: - DoubleArray<Slice> *double_array_; - uint64_t cur_; - uint64_t count_; - Slice query_; - size_t min_size_; - MapCursorOptions options_; - std::vector<uint64_t> node_ids_; - std::vector<std::pair<int64_t, Slice>> keys_; - - void init_order_by_id(); - void init_order_by_key(); - - bool next_order_by_id(); - bool next_order_by_key(); - bool next_reverse_order_by_key(); -}; - -DoubleArrayCompletionCursor<Slice>::DoubleArrayCompletionCursor( - DoubleArray<Slice> *double_array, Slice query, - const MapCursorOptions &options) - : MapCursor<Slice>(), double_array_(double_array), cur_(), count_(0), - query_(query), min_size_(), options_(options), node_ids_(), keys_() { - if ((options_.flags & MAP_CURSOR_ORDER_BY_ID) && - (~options_.flags & MAP_CURSOR_ORDER_BY_KEY)) { - init_order_by_id(); - } else { - options_.flags &= ~MAP_CURSOR_ORDER_BY_ID; - options_.flags |= MAP_CURSOR_ORDER_BY_KEY; - init_order_by_key(); - } -} - -DoubleArrayCompletionCursor<Slice>::~DoubleArrayCompletionCursor() {} - -bool DoubleArrayCompletionCursor<Slice>::next() { - if (count_ >= options_.limit) { - return false; - } - if (options_.flags & MAP_CURSOR_ORDER_BY_ID) { - return next_order_by_id(); - } else if (~options_.flags & MAP_CURSOR_REVERSE_ORDER) { - return next_order_by_key(); - } else { - return next_reverse_order_by_key(); - } -} - -bool DoubleArrayCompletionCursor<Slice>::remove() { - return double_array_->unset(this->key_id_); -} - -void DoubleArrayCompletionCursor<Slice>::init_order_by_id() { - init_order_by_key(); - while (!node_ids_.empty()) { - const bool is_root = node_ids_.back() & IS_ROOT_FLAG; - const uint64_t node_id = node_ids_.back() & ~IS_ROOT_FLAG; - node_ids_.pop_back(); - const SliceDoubleArrayNode node = double_array_->nodes_[node_id]; - if (!is_root && (node.sibling() != INVALID_LABEL)) { - node_ids_.push_back(node_id ^ node.label() ^ node.sibling()); - } - if (node.is_leaf()) { - const SliceDoubleArrayKey &key = - double_array_->get_key(node.key_pos()); - if (key.size() >= min_size_) { - keys_.push_back(std::make_pair(key.id(), key.slice())); - } - } else if (node.child() != INVALID_LABEL) { - node_ids_.push_back(node.offset() ^ node.child()); - } - } - std::sort(keys_.begin(), keys_.end()); - if (options_.flags & MAP_CURSOR_REVERSE_ORDER) { - std::reverse(keys_.begin(), keys_.end()); - } - cur_ = options_.offset; -} - -void DoubleArrayCompletionCursor<Slice>::init_order_by_key() { - min_size_ = query_.size(); - if (options_.flags & MAP_CURSOR_EXCEPT_QUERY) { - ++min_size_; - } - uint64_t node_id = ROOT_NODE_ID; - for (size_t i = 0; i < query_.size(); ++i) { - const SliceDoubleArrayNode node = double_array_->nodes_[node_id]; - if (node.is_leaf()) { - const SliceDoubleArrayKey &key = - double_array_->get_key(node.key_pos()); - if ((key.size() >= min_size_) && - (key.slice().subslice(i, query_.size() - i) == - query_.subslice(i, query_.size() - i))) { - if (~options_.flags & MAP_CURSOR_REVERSE_ORDER) { - node_id |= IS_ROOT_FLAG; - } - node_ids_.push_back(node_id); - } - return; - } - node_id = node.offset() ^ query_[i]; - if (double_array_->nodes_[node_id].label() != query_[i]) { - return; - } - } - if (~options_.flags & MAP_CURSOR_REVERSE_ORDER) { - node_id |= IS_ROOT_FLAG; - } - node_ids_.push_back(node_id); -} - -bool DoubleArrayCompletionCursor<Slice>::next_order_by_id() { - if (cur_ < keys_.size()) { - this->key_id_ = keys_[cur_].first; - this->key_ = keys_[cur_].second; - ++cur_; - ++count_; - return true; - } - return false; -} - -bool DoubleArrayCompletionCursor<Slice>::next_order_by_key() { - while (!node_ids_.empty()) { - const bool is_root = node_ids_.back() & IS_ROOT_FLAG; - const uint64_t node_id = node_ids_.back() & ~IS_ROOT_FLAG; - node_ids_.pop_back(); - const SliceDoubleArrayNode node = double_array_->nodes_[node_id]; - if (!is_root && (node.sibling() != INVALID_LABEL)) { - node_ids_.push_back(node_id ^ node.label() ^ node.sibling()); - } - if (node.is_leaf()) { - const SliceDoubleArrayKey &key = - double_array_->get_key(node.key_pos()); - if (key.size() >= min_size_) { - if (options_.offset > 0) { - --options_.offset; - } else { - this->key_id_ = key.id(); - this->key_ = key.slice(); - ++count_; - return true; - } - } - } else if (node.child() != INVALID_LABEL) { - node_ids_.push_back(node.offset() ^ node.child()); - } - } - return false; -} - -bool DoubleArrayCompletionCursor<Slice>::next_reverse_order_by_key() { - while (!node_ids_.empty()) { - const bool post_order = node_ids_.back() & POST_ORDER_FLAG; - const uint64_t node_id = node_ids_.back() & ~POST_ORDER_FLAG; - const SliceDoubleArrayNode node = double_array_->nodes_[node_id]; - if (post_order) { - node_ids_.pop_back(); - if (node.is_leaf()) { - const SliceDoubleArrayKey &key = - double_array_->get_key(node.key_pos()); - if (key.size() >= min_size_) { - if (options_.offset > 0) { - --options_.offset; - } else { - this->key_id_ = key.id(); - this->key_ = key.slice(); - ++count_; - return true; - } - } - } - } else { - node_ids_.back() |= POST_ORDER_FLAG; - uint16_t label = double_array_->nodes_[node_id].child(); - while (label != INVALID_LABEL) { - node_ids_.push_back(node.offset() ^ label); - label = double_array_->nodes_[node.offset() ^ label].sibling(); - } - } - } - return false; -} - -DoubleArray<Slice>::~DoubleArray() { - if (!initialized_) try { - // Free allocated blocks if initialization failed. - if (header_->nodes_block_id != io::BLOCK_INVALID_ID) { - pool_.free_block(header_->nodes_block_id); - } - if (header_->chunks_block_id != io::BLOCK_INVALID_ID) { - pool_.free_block(header_->chunks_block_id); - } - if (header_->entries_block_id != io::BLOCK_INVALID_ID) { - pool_.free_block(header_->entries_block_id); - } - if (header_->keys_block_id != io::BLOCK_INVALID_ID) { - pool_.free_block(header_->keys_block_id); - } - if (block_info_) { - pool_.free_block(*block_info_); - } - } catch (...) { - } -} - -DoubleArray<Slice> *DoubleArray<Slice>::create(io::Pool pool, - const MapOptions &options) { - std::unique_ptr<DoubleArray<Slice>> double_array( - new (std::nothrow) DoubleArray<Slice>); - if (!double_array) { - GRNXX_ERROR() << "new grnxx::alpha::map::DoubleArray failed"; - GRNXX_THROW(); - } - double_array->create_double_array(pool, options); - return double_array.release(); -} - -DoubleArray<Slice> *DoubleArray<Slice>::open(io::Pool pool, uint32_t block_id) { - std::unique_ptr<DoubleArray<Slice>> double_array( - new (std::nothrow) DoubleArray<Slice>); - if (!double_array) { - GRNXX_ERROR() << "new grnxx::alpha::map::DoubleArray failed"; - GRNXX_THROW(); - } - double_array->open_double_array(pool, block_id); - return double_array.release(); -} - -bool DoubleArray<Slice>::unlink(io::Pool pool, uint32_t block_id) { - std::unique_ptr<DoubleArray<Slice>> double_array(open(pool, block_id)); - - pool.free_block(double_array->header_->nodes_block_id); - pool.free_block(double_array->header_->chunks_block_id); - pool.free_block(double_array->header_->entries_block_id); - pool.free_block(double_array->header_->keys_block_id); - pool.free_block(block_id); - return true; -} - -uint32_t DoubleArray<Slice>::block_id() const { - return block_info_->id(); -} - -MapType DoubleArray<Slice>::type() const { - return MAP_DOUBLE_ARRAY; -} - -int64_t DoubleArray<Slice>::max_key_id() const { - return header_->max_key_id; -} - -int64_t DoubleArray<Slice>::next_key_id() const { - return header_->next_key_id; -} - -uint64_t DoubleArray<Slice>::num_keys() const { - return header_->num_keys; -} - -bool DoubleArray<Slice>::get(int64_t key_id, Slice *key) { - if ((key_id < MIN_KEY_ID) || (key_id > header_->max_key_id)) { - return false; - } - - const DoubleArrayEntry entry = entries_[key_id]; - if (!entry) { - return false; - } - if (key) { - const DoubleArrayKey &found_key = get_key(entry.key_pos()); - *key = found_key.slice(); - } - return true; -} - -bool DoubleArray<Slice>::get_next(int64_t key_id, int64_t *next_key_id, - Slice *next_key) { - if (key_id >= header_->max_key_id) { - return false; - } - if (key_id < 0) { - key_id = -1; - } - for (++key_id; key_id <= header_->max_key_id; ++key_id) { - const DoubleArrayEntry entry = entries_[key_id]; - if (entry) { - if (next_key_id) { - *next_key_id = key_id; - } - if (next_key) { - *next_key = get_key(entry.key_pos()).slice(); - } - return true; - } - } - return false; -} - -bool DoubleArray<Slice>::unset(int64_t key_id) { - Lock lock(&header_->inter_process_mutex); - - if ((key_id < MIN_KEY_ID) || (key_id > header_->max_key_id)) { - return false; - } - const DoubleArrayEntry entry = entries_[key_id]; - if (!entry) { - return false; - } - const DoubleArrayKey &key = get_key(entry.key_pos()); - return remove_key(key.slice()); -} - -bool DoubleArray<Slice>::reset(int64_t key_id, Slice dest_key) { - if ((dest_key.size() < MIN_KEY_SIZE) || (dest_key.size() > MAX_KEY_SIZE)) { - GRNXX_ERROR() << "invalid key: size = " << dest_key.size(); - GRNXX_THROW(); - } - - Lock lock(&header_->inter_process_mutex); - - if ((key_id < MIN_KEY_ID) || (key_id > header_->max_key_id)) { - return false; - } - const DoubleArrayEntry entry = entries_[key_id]; - if (!entry) { - return false; - } - const DoubleArrayKey &key = get_key(entry.key_pos()); - return update_key(key_id, key.slice(), dest_key); -} - -bool DoubleArray<Slice>::find(Slice key, int64_t *key_id) { - if ((key.size() < MIN_KEY_SIZE) || (key.size() > MAX_KEY_SIZE)) { - return false; - } - - uint32_t node_id = ROOT_NODE_ID; - size_t query_pos = 0; - if (!find_leaf(key, node_id, query_pos)) { - return false; - } - - // Note that nodes_[node_id] might be updated by other threads/processes. - const DoubleArrayNode node = nodes_[node_id]; - if (!node.is_leaf()) { - return false; - } - - const DoubleArrayKey &found_key = get_key(node.key_pos()); - if (found_key.equals_to(key, query_pos)) { - if (key_id) { - *key_id = found_key.id(); - } - return true; - } - return false; -} - -bool DoubleArray<Slice>::insert(Slice key, int64_t *key_id) { - if ((key.size() < MIN_KEY_SIZE) || (key.size() > MAX_KEY_SIZE)) { - GRNXX_ERROR() << "invalid key: size = " << key.size(); - GRNXX_THROW(); - } - - Lock lock(&header_->inter_process_mutex); - -// GRN_DAT_THROW_IF(STATUS_ERROR, (status_flags() & CHANGING_MASK) != 0); -// StatusFlagManager status_flag_manager(header_, INSERTING_FLAG); - - uint32_t node_id = ROOT_NODE_ID; - size_t query_pos = 0; - - find_leaf(key, node_id, query_pos); - if (!insert_leaf(key, node_id, query_pos)) { - if (key_id) { - *key_id = get_key(nodes_[node_id].key_pos()).id(); - } - return false; - } - - const int32_t new_key_id = header_->next_key_id; - const uint32_t new_key_pos = append_key(key, new_key_id); - - header_->total_key_length += key.size(); - ++header_->num_keys; - - if (new_key_id > header_->max_key_id) { - header_->max_key_id = new_key_id; - header_->next_key_id = new_key_id + 1; - } else { - header_->next_key_id = entries_[new_key_id].next(); - } - - entries_[new_key_id] = DoubleArrayEntry::valid_entry(new_key_pos); - nodes_[node_id].set_key_pos(new_key_pos); - if (key_id) { - *key_id = new_key_id; - } - return true; -} - -bool DoubleArray<Slice>::remove(Slice key) { - if ((key.size() < MIN_KEY_SIZE) || (key.size() > MAX_KEY_SIZE)) { - GRNXX_ERROR() << "invalid key: size = " << key.size(); - GRNXX_THROW(); - } - - Lock lock(&header_->inter_process_mutex); - -// GRN_DAT_THROW_IF(STATUS_ERROR, (status_flags() & CHANGING_MASK) != 0); -// StatusFlagManager status_flag_manager(header_, REMOVING_FLAG); - - return remove_key(key); -} - -bool DoubleArray<Slice>::update(Slice src_key, Slice dest_key, - int64_t *key_id) { - if ((src_key.size() < MIN_KEY_SIZE) || (src_key.size() > MAX_KEY_SIZE)) { - GRNXX_ERROR() << "invalid source key: size = " << src_key.size(); - GRNXX_THROW(); - } - if ((dest_key.size() < MIN_KEY_SIZE) || (dest_key.size() > MAX_KEY_SIZE)) { - GRNXX_ERROR() << "invalid destination key: size = " << dest_key.size(); - GRNXX_THROW(); - } - - Lock lock(&header_->inter_process_mutex); - - int64_t src_key_id; - if (!find(src_key, &src_key_id)) { - return false; - } - if (update_key(static_cast<int32_t>(src_key_id), src_key, dest_key)) { - if (key_id) { - *key_id = src_key_id; - } - return true; - } - return false; -} - -bool DoubleArray<Slice>::find_longest_prefix_match( - Slice query, int64_t *key_id, Slice *key) { - bool found = false; - uint32_t node_id = ROOT_NODE_ID; - uint32_t query_pos = 0; - - for ( ; query_pos < query.size(); ++query_pos) { - const DoubleArrayNode node = nodes_[node_id]; - if (node.is_leaf()) { - const DoubleArrayKey &match = get_key(node.key_pos()); - if ((match.size() <= query.size()) && - match.equals_to(Slice(query.address(), match.size()), query_pos)) { - if (key_id) { - *key_id = match.id(); - } - if (key) { - *key = match.slice(); - } - found = true; - } - return found; - } - - if (nodes_[node_id].child() == TERMINAL_LABEL) { - const DoubleArrayNode leaf_node = nodes_[node.offset() ^ TERMINAL_LABEL]; - if (leaf_node.is_leaf()) { - if (key_id || key) { - const DoubleArrayKey &match = get_key(leaf_node.key_pos()); - if (key_id) { - *key_id = match.id(); - } - if (key) { - *key = match.slice(); - } - } - found = true; - } - } - - node_id = node.offset() ^ query[query_pos]; - if (nodes_[node_id].label() != query[query_pos]) { - return found; - } - } - - const DoubleArrayNode node = nodes_[node_id]; - if (node.is_leaf()) { - const DoubleArrayKey &match = get_key(node.key_pos()); - if (match.size() <= query.size()) { - if (key_id) { - *key_id = match.id(); - } - if (key) { - *key = match.slice(); - } - found = true; - } - } else if (nodes_[node_id].child() == TERMINAL_LABEL) { - const DoubleArrayNode leaf_node = nodes_[node.offset() ^ TERMINAL_LABEL]; - if (leaf_node.is_leaf()) { - if (key_id || key) { - const DoubleArrayKey &match = get_key(leaf_node.key_pos()); - if (key_id) { - *key_id = match.id(); - } - if (key) { - *key = match.slice(); - } - } - found = true; - } - } - return found; -} - -bool DoubleArray<Slice>::truncate() { - nodes_[ROOT_NODE_ID].set_child(INVALID_LABEL); - nodes_[ROOT_NODE_ID].set_offset(INVALID_OFFSET); - header_->next_key_id = 0; - header_->max_key_id = -1; - header_->num_keys = 0; - return true; -} - -MapCursor<Slice> *DoubleArray<Slice>::open_basic_cursor( - const MapCursorOptions &options) { - if ((options.flags & MAP_CURSOR_ORDER_BY_ID) || - (~options.flags & MAP_CURSOR_ORDER_BY_KEY)) { - return open_id_cursor(-1, -1, options); - } else { - return open_key_cursor(nullptr, nullptr, options); - } -} - -MapCursor<Slice> *DoubleArray<Slice>::open_id_cursor( - int64_t min, int64_t max, const MapCursorOptions &options) { - return new (std::nothrow) DoubleArrayIDCursor<Slice>( - this, min, max, options); -} - -MapCursor<Slice> *DoubleArray<Slice>::open_key_cursor( - Slice min, Slice max, const MapCursorOptions &options) { - return new (std::nothrow) DoubleArrayKeyCursor<Slice>( - this, min, max, options); -} - -MapCursor<Slice> *DoubleArray<Slice>::open_prefix_cursor( - Slice query, size_t min_size, const MapCursorOptions &options) { - return new (std::nothrow) DoubleArrayPrefixCursor<Slice>( - this, query, min_size, options); -} - -MapCursor<Slice> *DoubleArray<Slice>::open_completion_cursor( - Slice query, const MapCursorOptions &options) { - return new (std::nothrow) DoubleArrayCompletionCursor<Slice>( - this, query, options); -} - -DoubleArray<Slice>::DoubleArray() - : pool_(), - block_info_(nullptr), - header_(nullptr), - nodes_(nullptr), - chunks_(nullptr), - entries_(nullptr), - keys_(nullptr), - initialized_(false) {} - -void DoubleArray<Slice>::create_double_array(io::Pool pool, - const MapOptions &) { - pool_ = pool; - - block_info_ = pool_.create_block(sizeof(DoubleArrayHeader)); - - void * const block_address = pool_.get_block_address(*block_info_); - header_ = static_cast<DoubleArrayHeader *>(block_address); - *header_ = DoubleArrayHeader(); - - // TODO: The size should be given as options. - header_->nodes_size = static_cast<uint32_t>(INITIAL_NODES_SIZE); - header_->nodes_size &= ~CHUNK_MASK; - if (header_->nodes_size == 0) { - header_->nodes_size = INITIAL_NODES_SIZE; - } - header_->chunks_size = header_->nodes_size / CHUNK_SIZE; - header_->entries_size = static_cast<uint32_t>(INITIAL_ENTRIES_SIZE); - if (header_->entries_size == 0) { - header_->entries_size = INITIAL_ENTRIES_SIZE; - } - header_->keys_size = static_cast<uint32_t>(INITIAL_KEYS_SIZE); - if (header_->keys_size == 0) { - header_->keys_size = INITIAL_KEYS_SIZE; - } - - create_arrays(); - - reserve_node(ROOT_NODE_ID); - nodes_[INVALID_OFFSET].set_is_origin(true); - - initialized_ = true; -} - -void DoubleArray<Slice>::open_double_array(io::Pool pool, uint32_t block_id) { - pool_ = pool; - initialized_ = true; - - block_info_ = pool_.get_block_info(block_id); - - void * const block_address = pool_.get_block_address(*block_info_); - header_ = static_cast<DoubleArrayHeader *>(block_address); - - // TODO: Check the format. - - nodes_ = static_cast<DoubleArrayNode *>( - pool_.get_block_address(header_->nodes_block_id)); - chunks_ = static_cast<DoubleArrayChunk *>( - pool_.get_block_address(header_->chunks_block_id)); - entries_ = static_cast<DoubleArrayEntry *>( - pool_.get_block_address(header_->entries_block_id)); - keys_ = static_cast<uint32_t *>( - pool_.get_block_address(header_->keys_block_id)); -} - -void DoubleArray<Slice>::create_arrays() { - const io::BlockInfo *block_info; - - block_info = pool_.create_block( - sizeof(DoubleArrayNode) * header_->nodes_size); - header_->nodes_block_id = block_info->id(); - nodes_ = static_cast<DoubleArrayNode *>( - pool_.get_block_address(*block_info)); - - block_info = pool_.create_block( - sizeof(DoubleArrayChunk) * header_->chunks_size); - header_->chunks_block_id = block_info->id(); - chunks_ = static_cast<DoubleArrayChunk *>( - pool_.get_block_address(*block_info)); - - block_info = pool_.create_block( - sizeof(DoubleArrayEntry) * header_->entries_size); - header_->entries_block_id = block_info->id(); - entries_ = static_cast<DoubleArrayEntry *>( - pool_.get_block_address(*block_info)); - - block_info = pool_.create_block(sizeof(uint32_t) * header_->keys_size); - header_->keys_block_id = block_info->id(); - keys_ = static_cast<uint32_t *>(pool_.get_block_address(*block_info)); -} - -bool DoubleArray<Slice>::remove_key(const Slice &key) { - uint32_t node_id = ROOT_NODE_ID; - size_t query_pos = 0; - if (!find_leaf(key, node_id, query_pos)) { - return false; - } - - const uint32_t key_pos = nodes_[node_id].key_pos(); - const DoubleArrayKey &found_key = get_key(key_pos); - if (!found_key.equals_to(key, query_pos)) { - return false; - } - - const int32_t key_id = found_key.id(); - nodes_[node_id].set_offset(INVALID_OFFSET); - entries_[key_id] = DoubleArrayEntry::invalid_entry(header_->next_key_id); - - header_->next_key_id = key_id; - header_->total_key_length -= key.size(); - --header_->num_keys; - return true; -} - -bool DoubleArray<Slice>::update_key(int32_t key_id, const Slice &src_key, - const Slice &dest_key) { - uint32_t node_id = ROOT_NODE_ID; - size_t query_pos = 0; - - find_leaf(dest_key, node_id, query_pos); - if (!insert_leaf(dest_key, node_id, query_pos)) { - return false; - } - - const uint32_t new_key_pos = append_key(dest_key, key_id); - header_->total_key_length = - header_->total_key_length + dest_key.size() - src_key.size(); - entries_[key_id] = DoubleArrayEntry::valid_entry(new_key_pos); - nodes_[node_id].set_key_pos(new_key_pos); - - node_id = ROOT_NODE_ID; - query_pos = 0; - if (!find_leaf(src_key, node_id, query_pos)) { - GRNXX_ERROR() << "key not found (unexpected)"; - GRNXX_THROW(); - } - nodes_[node_id].set_offset(INVALID_OFFSET); - return true; -} - -bool DoubleArray<Slice>::find_leaf(const Slice &key, uint32_t &node_id, - size_t &query_pos) { - for ( ; query_pos < key.size(); ++query_pos) { - const DoubleArrayNode node = nodes_[node_id]; - if (node.is_leaf()) { - return true; - } - - const uint32_t next = node.offset() ^ key[query_pos]; - if (nodes_[next].label() != key[query_pos]) { - return false; - } - node_id = next; - } - - const DoubleArrayNode node = nodes_[node_id]; - if (node.is_leaf()) { - return true; - } - - if (node.child() != TERMINAL_LABEL) { - return false; - } - node_id = node.offset() ^ TERMINAL_LABEL; - return nodes_[node_id].is_leaf(); -} - -bool DoubleArray<Slice>::insert_leaf(const Slice &key, uint32_t &node_id, - size_t query_pos) { - const DoubleArrayNode node = nodes_[node_id]; - if (node.is_leaf()) { - const DoubleArrayKey &found_key = get_key(node.key_pos()); - size_t i = query_pos; - while ((i < key.size()) && (i < found_key.size())) { - if (key[i] != found_key[i]) { - break; - } - ++i; - } - if ((i == key.size()) && (i == found_key.size())) { - return false; - } - - if (header_->num_keys >= header_->entries_size) { - GRNXX_NOTICE() << "too many keys: num_keys = " << header_->num_keys - << ", entries_size = " << header_->entries_size; - throw DoubleArrayException(); - } - -// GRNXX_DEBUG_THROW_IF(static_cast<uint32_t>(header_->next_key_id) >= header_->entries_size); - - for (size_t j = query_pos; j < i; ++j) { - node_id = insert_node(node_id, key[j]); - } - node_id = separate(key, node_id, i); - return true; - } else if (node.label() == TERMINAL_LABEL) { - return true; - } else { - if (header_->num_keys >= header_->entries_size) { - GRNXX_NOTICE() << "too many keys: num_keys = " << header_->num_keys - << ", entries_size = " << header_->entries_size; - throw DoubleArrayException(); - } - - const uint16_t label = (query_pos < key.size()) ? - static_cast<uint16_t>(key[query_pos]) : TERMINAL_LABEL; - if ((node.offset() == INVALID_OFFSET) || - !nodes_[node.offset() ^ label].is_phantom()) { - // The offset of this node must be updated. - resolve(node_id, label); - } - // The new node will be the leaf node associated with the query. - node_id = insert_node(node_id, label); - return true; - } -} - -uint32_t DoubleArray<Slice>::insert_node(uint32_t node_id, uint16_t label) { -// GRNXX_DEBUG_THROW_IF(node_id >= (header_->num_chunks * CHUNK_SIZE)); -// GRNXX_DEBUG_THROW_IF(label > MAX_LABEL); - - const DoubleArrayNode node = nodes_[node_id]; - uint32_t offset; - if (node.is_leaf() || (node.offset() == INVALID_OFFSET)) { - offset = find_offset(&label, 1); - } else { - offset = node.offset(); - } - - const uint32_t next = offset ^ label; - reserve_node(next); - - nodes_[next].set_label(label); - if (node.is_leaf()) { -// GRNXX_DEBUG_THROW_IF(nodes_[offset].is_origin()); - nodes_[offset].set_is_origin(true); - nodes_[next].set_key_pos(node.key_pos()); - } else if (node.offset() == INVALID_OFFSET) { -// GRNXX_DEBUG_THROW_IF(nodes_[offset].is_origin()); - nodes_[offset].set_is_origin(true); - } else { -// GRNXX_DEBUG_THROW_IF(!nodes_[offset].is_origin()); - } - nodes_[node_id].set_offset(offset); - - const uint16_t child_label = nodes_[node_id].child(); -// GRNXX_DEBUG_THROW_IF(child_label == label); - if (child_label == INVALID_LABEL) { - nodes_[node_id].set_child(label); - } else if ((label == TERMINAL_LABEL) || - ((child_label != TERMINAL_LABEL) && - (label < child_label))) { - // The next node becomes the first child. -// GRNXX_DEBUG_THROW_IF(nodes_[offset ^ child_label].is_phantom()); -// GRNXX_DEBUG_THROW_IF(nodes_[offset ^ child_label].label() != child_label); - nodes_[next].set_sibling(child_label); - nodes_[node_id].set_child(label); - } else { - uint32_t prev = offset ^ child_label; -// GRNXX_DEBUG_THROW_IF(nodes_[prev].label() != child_label); - uint16_t sibling_label = nodes_[prev].sibling(); - while (label > sibling_label) { - prev = offset ^ sibling_label; -// GRNXX_DEBUG_THROW_IF(nodes_[prev].label() != sibling_label); - sibling_label = nodes_[prev].sibling(); - } -// GRNXX_DEBUG_THROW_IF(label == sibling_label); - nodes_[next].set_sibling(nodes_[prev].sibling()); - nodes_[prev].set_sibling(label); - } - return next; -} - -uint32_t DoubleArray<Slice>::append_key(const Slice &key, int32_t key_id) { - if (static_cast<uint32_t>(key_id) >= header_->entries_size) { - GRNXX_NOTICE() << "too many keys: key_id = " << key_id - << ", entries_size = " << header_->entries_size; - throw DoubleArrayException(); - } - - const uint32_t key_pos = header_->next_key_pos; - const uint32_t key_size = DoubleArrayKey::estimate_size(key.size()); - - if (key_size > (header_->keys_size - key_pos)) { - GRNXX_NOTICE() << "too many keys: key_size = " << key_size - << ", keys_size = " << header_->keys_size - << ", key_pos = " << key_pos; - throw DoubleArrayException(); - } - new (&keys_[key_pos]) DoubleArrayKey(key_id, key); - - header_->next_key_pos = key_pos + key_size; - return key_pos; -} - -uint32_t DoubleArray<Slice>::separate(const Slice &key, uint32_t node_id, - size_t i) { -// GRNXX_DEBUG_THROW_IF(node_id >= (header_->num_chunks * CHUNK_SIZE)); -// GRNXX_DEBUG_THROW_IF(!nodes_[node_id].is_leaf()); -// GRNXX_DEBUG_THROW_IF(i > key.size()); - - const DoubleArrayNode node = nodes_[node_id]; - const DoubleArrayKey &found_key = get_key(node.key_pos()); - - uint16_t labels[2]; - labels[0] = (i < found_key.size()) ? - static_cast<uint16_t>(found_key[i]) : TERMINAL_LABEL; - labels[1] = (i < key.size()) ? - static_cast<uint16_t>(key[i]) : TERMINAL_LABEL; -// GRNXX_DEBUG_THROW_IF(labels[0] == labels[1]); - - const uint32_t offset = find_offset(labels, 2); - - uint32_t next = offset ^ labels[0]; - reserve_node(next); -// GRNXX_DEBUG_THROW_IF(nodes_[offset].is_origin()); - - nodes_[next].set_label(labels[0]); - nodes_[next].set_key_pos(node.key_pos()); - - next = offset ^ labels[1]; - reserve_node(next); - - nodes_[next].set_label(labels[1]); - - nodes_[offset].set_is_origin(true); - nodes_[node_id].set_offset(offset); - - if ((labels[0] == TERMINAL_LABEL) || - ((labels[1] != TERMINAL_LABEL) && - (labels[0] < labels[1]))) { - nodes_[offset ^ labels[0]].set_sibling(labels[1]); - nodes_[node_id].set_child(labels[0]); - } else { - nodes_[offset ^ labels[1]].set_sibling(labels[0]); - nodes_[node_id].set_child(labels[1]); - } - return next; -} - -void DoubleArray<Slice>::resolve(uint32_t node_id, uint16_t label) { -// GRNXX_DEBUG_THROW_IF(node_id >= (header_->num_chunks * CHUNK_SIZE)); -// GRNXX_DEBUG_THROW_IF(nodes_[node_id].is_leaf()); -// GRNXX_DEBUG_THROW_IF(label > MAX_LABEL); - - uint32_t offset = nodes_[node_id].offset(); - if (offset != INVALID_OFFSET) { - uint16_t labels[MAX_LABEL + 1]; - uint16_t num_labels = 0; - - uint16_t next_label = nodes_[node_id].child(); -// GRNXX_DEBUG_THROW_IF(next_label == INVALID_LABEL); - while (next_label != INVALID_LABEL) { -// GRNXX_DEBUG_THROW_IF(next_label > MAX_LABEL); - labels[num_labels++] = next_label; - next_label = nodes_[offset ^ next_label].sibling(); - } -// GRNXX_DEBUG_THROW_IF(num_labels == 0); - - labels[num_labels] = label; - offset = find_offset(labels, num_labels + 1); - migrate_nodes(node_id, offset, labels, num_labels); - } else { - offset = find_offset(&label, 1); - if (offset >= (header_->num_chunks * CHUNK_SIZE)) { -// GRNXX_DEBUG_THROW_IF((offset / CHUNK_SIZE) != header_->num_chunks); - reserve_chunk(header_->num_chunks); - } - nodes_[offset].set_is_origin(true); - nodes_[node_id].set_offset(offset); - } -} - -void DoubleArray<Slice>::migrate_nodes(uint32_t node_id, uint32_t dest_offset, - const uint16_t *labels, - uint16_t num_labels) { -// GRNXX_DEBUG_THROW_IF(node_id >= (header_->num_chunks * CHUNK_SIZE)); -// GRNXX_DEBUG_THROW_IF(nodes_[node_id].is_leaf()); -// GRNXX_DEBUG_THROW_IF(labels == nullptr); -// GRNXX_DEBUG_THROW_IF(num_labels == 0); -// GRNXX_DEBUG_THROW_IF(num_labels > (MAX_LABEL + 1)); - - const uint32_t src_offset = nodes_[node_id].offset(); -// GRNXX_DEBUG_THROW_IF(src_offset == INVALID_OFFSET); -// GRNXX_DEBUG_THROW_IF(!nodes_[src_offset].is_origin()); - - for (uint16_t i = 0; i < num_labels; ++i) { - const uint32_t src_node_id = src_offset ^ labels[i]; - const uint32_t dest_node_id = dest_offset ^ labels[i]; -// GRNXX_DEBUG_THROW_IF(nodes_[src_node_id].is_phantom()); -// GRNXX_DEBUG_THROW_IF(nodes_[src_node_id].label() != labels[i]); - - reserve_node(dest_node_id); - DoubleArrayNode dest_node = nodes_[src_node_id]; - dest_node.set_is_origin(nodes_[dest_node_id].is_origin()); - nodes_[dest_node_id] = dest_node; - } - header_->num_zombies += num_labels; - -// GRNXX_DEBUG_THROW_IF(nodes_[dest_offset].is_origin()); - nodes_[dest_offset].set_is_origin(true); - nodes_[node_id].set_offset(dest_offset); -} - -uint32_t DoubleArray<Slice>::find_offset(const uint16_t *labels, - uint16_t num_labels) { -// GRNXX_DEBUG_THROW_IF(labels == nullptr); -// GRNXX_DEBUG_THROW_IF(num_labels == 0); -// GRNXX_DEBUG_THROW_IF(num_labels > (MAX_LABEL + 1)); - - // Chunks are tested in descending order of level. Basically, lower level - // chunks contain more phantom nodes. - uint32_t level = 1; - while (num_labels >= (1U << level)) { - ++level; - } - level = (level < MAX_CHUNK_LEVEL) ? (MAX_CHUNK_LEVEL - level) : 0; - - uint32_t chunk_count = 0; - do { - uint32_t leader = header_->leaders[level]; - if (leader == INVALID_LEADER) { - // This level group is skipped because it is empty. - continue; - } - - uint32_t chunk_id = leader; - do { - const DoubleArrayChunk &chunk = chunks_[chunk_id]; -// GRNXX_DEBUG_THROW_IF(chunk.level() != level); - - const uint32_t first = (chunk_id * CHUNK_SIZE) | chunk.first_phantom(); - uint32_t node_id = first; - do { -// GRNXX_DEBUG_THROW_IF(!nodes_[node_id].is_phantom()); - const uint32_t offset = node_id ^ labels[0]; - if (!nodes_[offset].is_origin()) { - uint16_t i = 1; - for ( ; i < num_labels; ++i) { - if (!nodes_[offset ^ labels[i]].is_phantom()) { - break; - } - } - if (i >= num_labels) { - return offset; - } - } - node_id = (chunk_id * CHUNK_SIZE) | nodes_[node_id].next(); - } while (node_id != first); - - const uint32_t prev = chunk_id; - const uint32_t next = chunk.next(); - chunk_id = next; - chunks_[prev].set_failure_count(chunks_[prev].failure_count() + 1); - - // The level of a chunk is updated when this function fails many times, - // actually MAX_FAILURE_COUNT times, in that chunk. - if (chunks_[prev].failure_count() == MAX_FAILURE_COUNT) { - update_chunk_level(prev, level + 1); - if (next == leader) { - break; - } else { - // Note that the leader might be updated in the level update. - leader = header_->leaders[level]; - continue; - } - } - } while ((++chunk_count < MAX_CHUNK_COUNT) && - (chunk_id != leader)); - } while ((chunk_count < MAX_CHUNK_COUNT) && (level-- != 0)); - - return (header_->num_chunks * CHUNK_SIZE) ^ labels[0]; -} - -void DoubleArray<Slice>::reserve_node(uint32_t node_id) { - if (node_id >= (header_->num_chunks * CHUNK_SIZE)) { - reserve_chunk(node_id / CHUNK_SIZE); - } - - DoubleArrayNode &node = nodes_[node_id]; -// GRNXX_DEBUG_THROW_IF(!node.is_phantom()); - - const uint32_t chunk_id = node_id / CHUNK_SIZE; - DoubleArrayChunk &chunk = chunks_[chunk_id]; -// GRNXX_DEBUG_THROW_IF(chunk.num_phantoms() == 0); - - const uint32_t next = (chunk_id * CHUNK_SIZE) | node.next(); - const uint32_t prev = (chunk_id * CHUNK_SIZE) | node.prev(); -// GRNXX_DEBUG_THROW_IF(next >= (header_->num_chunks * CHUNK_SIZE)); -// GRNXX_DEBUG_THROW_IF(prev >= (header_->num_chunks * CHUNK_SIZE)); - - if ((node_id & CHUNK_MASK) == chunk.first_phantom()) { - // The first phantom node is removed from the chunk and the second phantom - // node comes first. - chunk.set_first_phantom(next & CHUNK_MASK); - } - - nodes_[next].set_prev(prev & CHUNK_MASK); - nodes_[prev].set_next(next & CHUNK_MASK); - - if (chunk.level() != MAX_CHUNK_LEVEL) { - const uint32_t threshold = - uint32_t(1) << ((MAX_CHUNK_LEVEL - chunk.level() - 1) * 2); - if (chunk.num_phantoms() == threshold) { - update_chunk_level(chunk_id, chunk.level() + 1); - } - } - chunk.set_num_phantoms(chunk.num_phantoms() - 1); - - node.set_is_phantom(false); - -// GRNXX_DEBUG_THROW_IF(node.offset() != INVALID_OFFSET); -// GRNXX_DEBUG_THROW_IF(node.label() != INVALID_LABEL); - - --header_->num_phantoms; -} - -void DoubleArray<Slice>::reserve_chunk(uint32_t chunk_id) { -// GRNXX_DEBUG_THROW_IF(chunk_id != header_->num_chunks); - - if (chunk_id >= header_->chunks_size) { - GRNXX_NOTICE() << "too many chunks: chunk_id = " << chunk_id - << ", chunks_size = " << header_->chunks_size; - throw DoubleArrayException(); - } - - header_->num_chunks = chunk_id + 1; - - DoubleArrayChunk chunk; - chunk.set_failure_count(0); - chunk.set_first_phantom(0); - chunk.set_num_phantoms(CHUNK_SIZE); - chunks_[chunk_id] = chunk; - - const uint32_t begin = chunk_id * CHUNK_SIZE; - const uint32_t end = begin + CHUNK_SIZE; -// GRNXX_DEBUG_THROW_IF(end != (header_->num_chunks * CHUNK_SIZE)); - - DoubleArrayNode node; - node.set_is_phantom(true); - for (uint32_t i = begin; i < end; ++i) { - node.set_prev((i - 1) & CHUNK_MASK); - node.set_next((i + 1) & CHUNK_MASK); - nodes_[i] = node; - } - - // The level of the new chunk is 0. - set_chunk_level(chunk_id, 0); - header_->num_phantoms += CHUNK_SIZE; -} - -void DoubleArray<Slice>::update_chunk_level(uint32_t chunk_id, uint32_t level) { -// GRNXX_DEBUG_THROW_IF(chunk_id >= header_->num_chunks); -// GRNXX_DEBUG_THROW_IF(level > MAX_CHUNK_LEVEL); - - unset_chunk_level(chunk_id); - set_chunk_level(chunk_id, level); -} - -void DoubleArray<Slice>::set_chunk_level(uint32_t chunk_id, uint32_t level) { -// GRNXX_DEBUG_THROW_IF(chunk_id >= header_->num_chunks); -// GRNXX_DEBUG_THROW_IF(level > MAX_CHUNK_LEVEL); - - const uint32_t leader = header_->leaders[level]; - if (leader == INVALID_LEADER) { - // The chunk becomes the only one member of the level group. - chunks_[chunk_id].set_next(chunk_id); - chunks_[chunk_id].set_prev(chunk_id); - header_->leaders[level] = chunk_id; - } else { - // The chunk is appended to the level group. - const uint32_t next = leader; - const uint32_t prev = chunks_[leader].prev(); -// GRNXX_DEBUG_THROW_IF(next >= header_->num_chunks); -// GRNXX_DEBUG_THROW_IF(prev >= header_->num_chunks); - chunks_[chunk_id].set_next(next); - chunks_[chunk_id].set_prev(prev); - chunks_[next].set_prev(chunk_id); - chunks_[prev].set_next(chunk_id); - } - chunks_[chunk_id].set_level(level); - chunks_[chunk_id].set_failure_count(0); -} - -void DoubleArray<Slice>::unset_chunk_level(uint32_t chunk_id) { - const uint32_t level = chunks_[chunk_id].level(); -// GRNXX_DEBUG_THROW_IF(level > MAX_CHUNK_LEVEL); - const uint32_t leader = header_->leaders[level]; -// GRNXX_DEBUG_THROW_IF(leader == INVALID_LEADER); - const uint32_t next = chunks_[chunk_id].next(); - const uint32_t prev = chunks_[chunk_id].prev(); -// GRNXX_DEBUG_THROW_IF(next >= header_->num_chunks); -// GRNXX_DEBUG_THROW_IF(prev >= header_->num_chunks); - - if (next == chunk_id) { - // The level group becomes empty. - header_->leaders[level] = INVALID_LEADER; - } else { - chunks_[next].set_prev(prev); - chunks_[prev].set_next(next); - if (chunk_id == leader) { - // The second chunk becomes the leader of the level group. - header_->leaders[level] = next; - } - } -} - -} // namespace map -} // namespace alpha -} // namespace grnxx Deleted: obsolete/lib/grnxx/alpha/map/double_array.cpp (+0 -2062) 100644 =================================================================== --- obsolete/lib/grnxx/alpha/map/double_array.cpp 2013-08-23 10:46:34 +0900 (fdb70cd) +++ /dev/null @@ -1,2062 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/alpha/map/double_array.hpp" - -#include <algorithm> -#include <cmath> -#include <vector> - -#include "../config.h" -#include "grnxx/geo_point.hpp" -#include "grnxx/lock.hpp" -#include "grnxx/logger.hpp" - -namespace grnxx { -namespace alpha { -namespace map { -namespace { - -constexpr int32_t MIN_KEY_ID = 0; -constexpr int32_t MAX_KEY_ID = 0x7FFFFFFE; - -constexpr uint32_t INVALID_OFFSET = 0; - -constexpr uint32_t ROOT_NODE_ID = 0; - -constexpr uint16_t TERMINAL_LABEL = 0x100; -constexpr uint16_t MAX_LABEL = TERMINAL_LABEL; -constexpr uint16_t INVALID_LABEL = 0x1FF; - -constexpr uint32_t CHUNK_SIZE = 0x200; -constexpr uint32_t CHUNK_MASK = 0x1FF; - -// Assume that #nodes per key is 4 and #uint32_ts per key is 8. -// Note that an entries is associated with a key. -constexpr uint32_t INITIAL_NODES_SIZE = 1 << 16; -constexpr uint32_t INITIAL_ENTRIES_SIZE = 1 << 14; -constexpr uint32_t INITIAL_KEYS_SIZE = INITIAL_ENTRIES_SIZE; - -constexpr uint32_t MAX_NODES_SIZE = - std::numeric_limits<uint32_t>::max() & ~CHUNK_MASK; -constexpr uint32_t MAX_ENTRIES_SIZE = uint32_t(MAX_KEY_ID) + 1; -constexpr uint32_t MAX_KEYS_SIZE = MAX_ENTRIES_SIZE; - -// Chunks are grouped by the level which indicates how easily update operations -// can find a good offset in that chunk. The chunk level rises when -// find_offset() fails in that chunk many times. MAX_FAILURE_COUNT -// is the threshold. Also, in order to limit the time cost, find_offset() scans -// at most MAX_CHUNK_COUNT chunks. -// Larger parameters bring more chances of finding good offsets but it leads to -// more node renumberings, which are costly operations, and thus results in -// degradation of space/time efficiencies. -constexpr uint32_t MAX_FAILURE_COUNT = 4; -constexpr uint32_t MAX_CHUNK_COUNT = 16; -constexpr uint32_t MAX_CHUNK_LEVEL = 5; - -// Chunks in the same level compose a doubly linked list. The entry chunk of -// a linked list is called a leader. INVALID_LEADER means that -// the linked list is empty and there exists no leader. -constexpr uint32_t INVALID_LEADER = std::numeric_limits<uint32_t>::max(); - -template <typename T, bool HAS_NAN = std::numeric_limits<T>::has_quiet_NaN> -struct Helper; - -template <typename T> -struct Helper<T, true> { - static bool equal_to(T x, T y) { - return *reinterpret_cast<uint64_t *>(&x) == - *reinterpret_cast<uint64_t *>(&y); - } - static T normalize(T x) { - if (std::isnan(x)) { - return std::numeric_limits<T>::quiet_NaN(); - } else if (x == 0.0) { - return +0.0; - } - return x; - } -}; - -template <typename T> -struct Helper<T, false> { - static bool equal_to(T x, T y) { - return x == y; - } - static T normalize(T x) { - return x; - } -}; - -void convert_key(int8_t key, uint8_t *key_buf) { -#ifndef WORDS_BIGENDIAN - key = byte_swap(static_cast<uint8_t>(key)); -#endif // WORDS_BIGENDIAN - std::memcpy(key_buf, &key, sizeof(key)); - *key_buf ^= 0x80; -} - -void convert_key(int16_t key, uint8_t *key_buf) { -#ifndef WORDS_BIGENDIAN - key = byte_swap(static_cast<uint16_t>(key)); -#endif // WORDS_BIGENDIAN - std::memcpy(key_buf, &key, sizeof(key)); - *key_buf ^= 0x80; -} - -void convert_key(int32_t key, uint8_t *key_buf) { -#ifndef WORDS_BIGENDIAN - key = byte_swap(static_cast<uint32_t>(key)); -#endif // WORDS_BIGENDIAN - std::memcpy(key_buf, &key, sizeof(key)); - *key_buf ^= 0x80; -} - -void convert_key(int64_t key, uint8_t *key_buf) { -#ifndef WORDS_BIGENDIAN - key = byte_swap(static_cast<uint64_t>(key)); -#endif // WORDS_BIGENDIAN - std::memcpy(key_buf, &key, sizeof(key)); - *key_buf ^= 0x80; -} - -void convert_key(uint8_t key, uint8_t *key_buf) { -#ifndef WORDS_BIGENDIAN - key = byte_swap(key); -#endif // WORDS_BIGENDIAN - std::memcpy(key_buf, &key, sizeof(key)); -} - -void convert_key(uint16_t key, uint8_t *key_buf) { -#ifndef WORDS_BIGENDIAN - key = byte_swap(key); -#endif // WORDS_BIGENDIAN - std::memcpy(key_buf, &key, sizeof(key)); -} - -void convert_key(uint32_t key, uint8_t *key_buf) { -#ifndef WORDS_BIGENDIAN - key = byte_swap(key); -#endif // WORDS_BIGENDIAN - std::memcpy(key_buf, &key, sizeof(key)); -} - -void convert_key(uint64_t key, uint8_t *key_buf) { -#ifndef WORDS_BIGENDIAN - key = byte_swap(key); -#endif // WORDS_BIGENDIAN - std::memcpy(key_buf, &key, sizeof(key)); -} - -void convert_key(double key, uint8_t *key_buf) { - int64_t x = *reinterpret_cast<const int64_t *>(&key); - x ^= (x >> 63) | (1ULL << 63); -#ifndef WORDS_BIGENDIAN - x = byte_swap(static_cast<uint64_t>(x)); -#endif // WORDS_BIGENDIAN - std::memcpy(key_buf, &x, sizeof(x)); -} - -void convert_key(GeoPoint key, uint8_t *key_buf) { - uint64_t interleaved_key = key.interleave(); -#ifndef WORDS_BIGENDIAN - interleaved_key = byte_swap(interleaved_key); -#endif // WORDS_BIGENDIAN - memcpy(key_buf, &interleaved_key, sizeof(interleaved_key)); -} - -} // namespace - -struct DoubleArrayHeader { - MapType map_type; - uint32_t nodes_block_id; - uint32_t chunks_block_id; - uint32_t entries_block_id; - uint32_t keys_block_id; - uint32_t nodes_size; - uint32_t chunks_size; - uint32_t entries_size; - uint32_t keys_size; - int32_t next_key_id; - int32_t max_key_id; - uint32_t num_keys; - uint32_t num_chunks; - uint32_t num_phantoms; - uint32_t num_zombies; - uint32_t leaders[MAX_CHUNK_LEVEL + 1]; - Mutex inter_process_mutex; - - DoubleArrayHeader(); -}; - -DoubleArrayHeader::DoubleArrayHeader() - : map_type(MAP_DOUBLE_ARRAY), - nodes_block_id(io::BLOCK_INVALID_ID), - chunks_block_id(io::BLOCK_INVALID_ID), - entries_block_id(io::BLOCK_INVALID_ID), - keys_block_id(io::BLOCK_INVALID_ID), - nodes_size(0), - chunks_size(0), - entries_size(0), - keys_size(0), - next_key_id(0), - max_key_id(-1), - num_keys(0), - num_chunks(0), - num_phantoms(0), - num_zombies(0), - leaders(), - inter_process_mutex(MUTEX_UNLOCKED) { - for (uint32_t i = 0; i <= MAX_CHUNK_LEVEL; ++i) { - leaders[i] = INVALID_LEADER; - } -} - -class DoubleArrayNode { - public: - DoubleArrayNode() : qword_(IS_PHANTOM_FLAG) {} - - // Structure overview. - // 0- 8 ( 9): next (is_phantom). - // 9-17 ( 9): prev (is_phantom). - // 0- 8 ( 9): label (!is_phantom). - // 9-17 ( 9): sibling (!is_phantom). - // 18-48 (31): key_id (!is_phantom && is_leaf). - // 18-49 (32): offset (!is_phantom && !is_leaf). - // 50-58 ( 9): child (!is_phantom && !is_leaf). - // 61-61 ( 1): is_leaf. - // 62-62 ( 1): is_phantom. - // 63-63 ( 1): is_origin. - // Note that 0 is the LSB and 63 is the MSB. - - // The ID of this node is used as an offset (true) or not (false). - bool is_origin() const { - return qword_ & IS_ORIGIN_FLAG; - } - // This node is valid (false) or not (true). - bool is_phantom() const { - return qword_ & IS_PHANTOM_FLAG; - } - // This node is associated with a key (true) or not (false). - bool is_leaf() const { - return qword_ & IS_LEAF_FLAG; - } - - void set_is_origin(bool value) { - if (value) { - qword_ |= IS_ORIGIN_FLAG; - } else { - qword_ &= ~IS_ORIGIN_FLAG; - } - } - void set_is_phantom(bool value) { - if (value) { - qword_ = (qword_ & IS_ORIGIN_FLAG) | IS_PHANTOM_FLAG; - } else { - qword_ = (qword_ & IS_ORIGIN_FLAG) | - (uint64_t(INVALID_OFFSET) << OFFSET_SHIFT) | - (uint64_t(INVALID_LABEL) << CHILD_SHIFT) | - (uint64_t(INVALID_LABEL) << SIBLING_SHIFT) | INVALID_LABEL; - } - } - - // Phantom nodes are doubly linked in each chunk. - // Each chunk consists of 512 nodes. - uint16_t next() const { - return static_cast<uint16_t>(qword_ & NEXT_MASK); - } - uint16_t prev() const { - return static_cast<uint16_t>((qword_ >> PREV_SHIFT) & PREV_MASK); - } - - void set_next(uint16_t value) { - qword_ = (qword_ & ~NEXT_MASK) | value; - } - void set_prev(uint16_t value) { - qword_ = (qword_ & ~(PREV_MASK << PREV_SHIFT)) | - (static_cast<uint64_t>(value) << PREV_SHIFT); - } - - // A non-phantom node stores its label and the label of its next sibling. - // A phantom node returns an invalid label with IS_PHANTOM_FLAG. - // sibling() == INVALID_LABEL means that the node doesn't have next sibling. - uint64_t label() const { - return qword_ & (IS_PHANTOM_FLAG | LABEL_MASK); - } - uint16_t sibling() const { - return static_cast<uint16_t>((qword_ >> SIBLING_SHIFT) & SIBLING_MASK); - } - - void set_label(uint16_t value) { - qword_ = (qword_ & ~LABEL_MASK) | value; - } - void set_sibling(uint16_t value) { - qword_ = (qword_ & ~(SIBLING_MASK << SIBLING_SHIFT)) | - (static_cast<uint64_t>(value) << SIBLING_SHIFT); - } - - // A leaf node stores the start position of the associated key. - int32_t key_id() const { - return static_cast<uint32_t>((qword_ >> KEY_ID_SHIFT) & KEY_ID_MASK); - } - - void set_key_id(int32_t value) { - qword_ = (qword_ & ~(KEY_ID_MASK << KEY_ID_SHIFT)) | - (static_cast<uint64_t>(value) << KEY_ID_SHIFT) | IS_LEAF_FLAG; - } - - // A non-phantom and non-leaf node stores the offset to its children and the - // label of its first child. - // child() == INVALID_LABEL means that the node has no child. - uint32_t offset() const { - return static_cast<uint32_t>((qword_ >> OFFSET_SHIFT) & OFFSET_MASK); - } - uint16_t child() const { - return static_cast<uint16_t>((qword_ >> CHILD_SHIFT) & CHILD_MASK); - } - - void set_offset(uint32_t value) { - if (qword_ & IS_LEAF_FLAG) { - qword_ = ((qword_ & ~IS_LEAF_FLAG) & ~(OFFSET_MASK << OFFSET_SHIFT)) | - (static_cast<uint64_t>(value) << OFFSET_SHIFT) | - (uint64_t(INVALID_LABEL) << CHILD_SHIFT); - } else { - qword_ = (qword_ & ~(OFFSET_MASK << OFFSET_SHIFT)) | - (static_cast<uint64_t>(value) << OFFSET_SHIFT); - } - } - void set_child(uint16_t value) { - qword_ = (qword_ & ~(CHILD_MASK << CHILD_SHIFT)) | - (static_cast<uint64_t>(value) << CHILD_SHIFT); - } - - private: - uint64_t qword_; - - // 61-63. - static constexpr uint64_t IS_ORIGIN_FLAG = uint64_t(1) << 63; - static constexpr uint64_t IS_PHANTOM_FLAG = uint64_t(1) << 62; - static constexpr uint64_t IS_LEAF_FLAG = uint64_t(1) << 61; - - // 0-17 (is_phantom). - static constexpr uint64_t NEXT_MASK = (uint64_t(1) << 9) - 1; - static constexpr uint64_t PREV_MASK = (uint64_t(1) << 9) - 1; - static constexpr uint8_t PREV_SHIFT = 9; - - // 0-17 (!is_phantom). - static constexpr uint64_t LABEL_MASK = (uint64_t(1) << 9) - 1; - static constexpr uint64_t SIBLING_MASK = (uint64_t(1) << 9) - 1; - static constexpr uint8_t SIBLING_SHIFT = 9; - - // 18-48 (!is_phantom && is_leaf) - static constexpr uint64_t KEY_ID_MASK = (uint64_t(1) << 31) - 1; - static constexpr uint8_t KEY_ID_SHIFT = 18; - - // 18-58 (!is_phantom && !is_leaf) - static constexpr uint64_t OFFSET_MASK = (uint64_t(1) << 32) - 1; - static constexpr uint8_t OFFSET_SHIFT = 18; - static constexpr uint64_t CHILD_MASK = (uint64_t(1) << 9) - 1; - static constexpr uint8_t CHILD_SHIFT = 50; -}; - -class DoubleArrayChunk { - public: - DoubleArrayChunk() : next_(0), prev_(0), others_(0) {} - - // Chunks in the same level are doubly linked. - uint32_t next() const { - return next_; - } - uint32_t prev() const { - return prev_; - } - - void set_next(uint32_t value) { - next_ = value; - } - void set_prev(uint32_t value) { - prev_ = value; - } - - // The chunk level indicates how easily nodes can be put in this chunk. - uint32_t level() const { - return (others_ >> LEVEL_SHIFT) & LEVEL_MASK; - } - uint32_t failure_count() const { - return (others_ >> FAILURE_COUNT_SHIFT) & FAILURE_COUNT_MASK; - } - - void set_level(uint32_t value) { - others_ = (others_ & ~(LEVEL_MASK << LEVEL_SHIFT)) | - (value << LEVEL_SHIFT); - } - void set_failure_count(uint32_t value) { - others_ = (others_ & ~(FAILURE_COUNT_MASK << FAILURE_COUNT_SHIFT)) | - (value << FAILURE_COUNT_SHIFT); - } - - // The first phantom node and the number of phantom nodes in this chunk. - uint32_t first_phantom() const { - return (others_ >> FIRST_PHANTOM_SHIFT) & FIRST_PHANTOM_MASK; - } - uint32_t num_phantoms() const { - return (others_ >> NUM_PHANTOMS_SHIFT) & NUM_PHANTOMS_MASK; - } - - void set_first_phantom(uint32_t value) { - others_ = (others_ & ~(FIRST_PHANTOM_MASK << FIRST_PHANTOM_SHIFT)) | - (value << FIRST_PHANTOM_SHIFT); - } - void set_num_phantoms(uint32_t value) { - others_ = (others_ & ~(NUM_PHANTOMS_MASK << NUM_PHANTOMS_SHIFT)) | - (value << NUM_PHANTOMS_SHIFT); - } - - private: - uint32_t next_; - uint32_t prev_; - uint32_t others_; - - static constexpr uint32_t LEVEL_MASK = (1 << 4) - 1; - static constexpr uint8_t LEVEL_SHIFT = 0; - - static constexpr uint32_t FAILURE_COUNT_MASK = (1 << 6) - 1; - static constexpr uint8_t FAILURE_COUNT_SHIFT = 4; - - static constexpr uint32_t FIRST_PHANTOM_MASK = (1 << 10) - 1; - static constexpr uint32_t FIRST_PHANTOM_SHIFT = 10; - - static constexpr uint32_t NUM_PHANTOMS_MASK = (1 << 10) - 1; - static constexpr uint32_t NUM_PHANTOMS_SHIFT = 20; -}; - -class DoubleArrayEntry { - public: - // Create a valid entry. - static DoubleArrayEntry valid_entry() { - return DoubleArrayEntry(0); - } - // Create an invalid entry. - static DoubleArrayEntry invalid_entry(uint32_t next) { - return DoubleArrayEntry(next); - } - - // Return true iff "*this" is valid (associated with a key). - explicit operator bool() const { - return dword_ == 0; - } - - // Return the next invalid entry. - // Available iff "*this' is invalid. - uint32_t next() const { - return dword_; - } - - private: - uint32_t dword_; - - explicit DoubleArrayEntry(uint32_t x) : dword_(x) {} -}; - -template <typename T> -class DoubleArrayIDCursor : public MapCursor<T> { - public: - DoubleArrayIDCursor(DoubleArray<T> *double_array, - int64_t min, int64_t max, - const MapCursorOptions &options); - ~DoubleArrayIDCursor(); - - bool next(); - bool remove(); - - private: - DoubleArray<T> *double_array_; - int64_t cur_; - int64_t end_; - int64_t step_; - uint64_t count_; - MapCursorOptions options_; - std::vector<std::pair<T, int64_t>> keys_; - - void init_order_by_id(int64_t min, int64_t max); - void init_order_by_key(int64_t min, int64_t max); -}; - -constexpr uint64_t IS_ROOT_FLAG = uint64_t(1) << 62; -constexpr uint64_t POST_ORDER_FLAG = uint64_t(1) << 63; - -template <typename T> -DoubleArrayIDCursor<T>::DoubleArrayIDCursor( - DoubleArray<T> *double_array, int64_t min, int64_t max, - const MapCursorOptions &options) - : MapCursor<T>(), double_array_(double_array), cur_(), end_(), step_(), - count_(0), options_(options), keys_() { - if (min < 0) { - min = 0; - } else if (options_.flags & MAP_CURSOR_EXCEPT_MIN) { - ++min; - } - if ((max < 0) || (max > double_array_->max_key_id())) { - max = double_array_->max_key_id(); - } else if (options_.flags & MAP_CURSOR_EXCEPT_MAX) { - --max; - } - if (min > max) { - cur_ = end_ = 0; - return; - } - if ((options_.flags & MAP_CURSOR_ORDER_BY_ID) || - (~options_.flags & MAP_CURSOR_ORDER_BY_KEY)) { - init_order_by_id(min, max); - } else { - init_order_by_key(min, max); - } -} - -template <typename T> -DoubleArrayIDCursor<T>::~DoubleArrayIDCursor() {} - -template <typename T> -bool DoubleArrayIDCursor<T>::next() { - if (count_ >= options_.limit) { - return false; - } - if (options_.flags & MAP_CURSOR_ORDER_BY_ID) { - while (cur_ != end_) { - cur_ += step_; - if (double_array_->get(cur_, &this->key_)) { - this->key_id_ = cur_; - ++count_; - return true; - } - } - } else if (cur_ != end_) { - cur_ += step_; - this->key_ = keys_[cur_].first; - this->key_id_ = keys_[cur_].second; - ++count_; - return true; - } - return false; -} - -template <typename T> -bool DoubleArrayIDCursor<T>::remove() { - return double_array_->unset(this->key_id_); -} - -template <typename T> -void DoubleArrayIDCursor<T>::init_order_by_id(int64_t min, int64_t max) { - options_.flags |= MAP_CURSOR_ORDER_BY_ID; - options_.flags &= ~MAP_CURSOR_ORDER_BY_KEY; - if (~options_.flags & MAP_CURSOR_REVERSE_ORDER) { - cur_ = min - 1; - end_ = max; - step_ = 1; - } else { - cur_ = max + 1; - end_ = min; - step_ = -1; - } - uint64_t count = 0; - while ((count < options_.offset) && (cur_ != end_)) { - cur_ += step_; - if (double_array_->get(cur_)) { - ++count; - } - } -} - -template <typename T> -void DoubleArrayIDCursor<T>::init_order_by_key(int64_t min, int64_t max) { - cur_ = min - 1; - end_ = max; - while (cur_ != end_) { - ++cur_; - T key; - if (double_array_->get(cur_, &key)) { - keys_.push_back(std::make_pair(key, cur_)); - } - } - std::sort(keys_.begin(), keys_.end()); - if (~options_.flags & MAP_CURSOR_REVERSE_ORDER) { - cur_ = -1; - end_ = keys_.size() - 1; - step_ = 1; - } else { - cur_ = keys_.size(); - end_ = 0; - step_ = -1; - } -} - -template <> -void DoubleArrayIDCursor<GeoPoint>::init_order_by_key(int64_t min, - int64_t max) { - // Ignore MAP_CURSOR_ORDER_BY_KEY. - init_order_by_id(min, max); -} - -template <typename T> -class DoubleArrayKeyCursor : public MapCursor<T> { - public: - DoubleArrayKeyCursor(DoubleArray<T> *double_array, T min, T max, - const MapCursorOptions &options); - ~DoubleArrayKeyCursor(); - - bool next(); - bool remove(); - - private: - DoubleArray<T> *double_array_; - uint64_t cur_; - uint64_t count_; - T min_; - T max_; - MapCursorOptions options_; - std::vector<uint64_t> node_ids_; - std::vector<std::pair<int64_t, T>> keys_; - - void init_order_by_id(); - void init_order_by_key(); - void init_reverse_order_by_key(); - - bool next_order_by_id(); - bool next_order_by_key(); - bool next_reverse_order_by_key(); -}; - -template <typename T> -DoubleArrayKeyCursor<T>::DoubleArrayKeyCursor( - DoubleArray<T> *double_array, T min, T max, - const MapCursorOptions &options) - : MapCursor<T>(), double_array_(double_array), cur_(), count_(0), - min_(min), max_(max), options_(options), node_ids_(), keys_() { - if ((options_.flags & MAP_CURSOR_ORDER_BY_ID) && - (~options_.flags & MAP_CURSOR_ORDER_BY_KEY)) { - init_order_by_id(); - } else { - options_.flags &= ~MAP_CURSOR_ORDER_BY_ID; - options_.flags |= MAP_CURSOR_ORDER_BY_KEY; - if (~options_.flags & MAP_CURSOR_REVERSE_ORDER) { - init_order_by_key(); - } else { - init_reverse_order_by_key(); - } - } -} - -template <typename T> -DoubleArrayKeyCursor<T>::~DoubleArrayKeyCursor() {} - -template <typename T> -bool DoubleArrayKeyCursor<T>::next() { - if (count_ >= options_.limit) { - return false; - } - if (options_.flags & MAP_CURSOR_ORDER_BY_ID) { - return next_order_by_id(); - } else if (~options_.flags & MAP_CURSOR_REVERSE_ORDER) { - return next_order_by_key(); - } else { - return next_reverse_order_by_key(); - } -} - -template <typename T> -bool DoubleArrayKeyCursor<T>::remove() { - return double_array_->unset(this->key_id_); -} - -template <typename T> -void DoubleArrayKeyCursor<T>::init_order_by_id() { - init_order_by_key(); - while (!node_ids_.empty()) { - const uint64_t node_id = node_ids_.back(); - node_ids_.pop_back(); - const DoubleArrayNode node = double_array_->nodes_[node_id]; - if (node.sibling() != INVALID_LABEL) { - node_ids_.push_back(node_id ^ node.label() ^ node.sibling()); - } - if (node.is_leaf()) { - const T key = double_array_->keys_[node.key_id()]; - if ((key > max_) || - ((key == max_) && (options_.flags & MAP_CURSOR_EXCEPT_MAX))) { - break; - } - keys_.push_back(std::make_pair(node.key_id(), key)); - } else if (node.child() != INVALID_LABEL) { - node_ids_.push_back(node.offset() ^ node.child()); - } - } - std::sort(keys_.begin(), keys_.end()); - if (options_.flags & MAP_CURSOR_REVERSE_ORDER) { - std::reverse(keys_.begin(), keys_.end()); - } - cur_ = options_.offset; -} - -template <typename T> -void DoubleArrayKeyCursor<T>::init_order_by_key() { - uint8_t min_buf[sizeof(T)]; - convert_key(min_, min_buf); - - uint64_t node_id = ROOT_NODE_ID; - DoubleArrayNode node; - for (size_t i = 0; i < sizeof(T); ++i) { - node = double_array_->nodes_[node_id]; - if (node.is_leaf()) { - const T key = double_array_->keys_[node.key_id()]; - if ((key > min_) || - ((key == min_) && (~options_.flags & MAP_CURSOR_EXCEPT_MIN))) { - node_ids_.push_back(node_id); - } else if (node.sibling() != INVALID_LABEL) { - node_ids_.push_back(node_id ^ node.label() ^ node.sibling()); - } - return; - } else if (node.sibling() != INVALID_LABEL) { - node_ids_.push_back(node_id ^ node.label() ^ node.sibling()); - } - node_id = node.offset() ^ min_buf[i]; - if (double_array_->nodes_[node_id].label() != min_buf[i]) { - uint16_t label = node.child(); - if (label == TERMINAL_LABEL) { - label = double_array_->nodes_[node.offset() ^ label].sibling(); - } - while (label != INVALID_LABEL) { - if (label > min_buf[i]) { - node_ids_.push_back(node.offset() ^ label); - break; - } - label = double_array_->nodes_[node.offset() ^ label].sibling(); - } - return; - } - } - - node = double_array_->nodes_[node_id]; - if (node.is_leaf()) { - if (~options_.flags & MAP_CURSOR_EXCEPT_MIN) { - node_ids_.push_back(node_id); - } else if (node.sibling() != INVALID_LABEL) { - node_ids_.push_back(node_id ^ node.label() ^ node.sibling()); - } - return; - } else if (node.sibling() != INVALID_LABEL) { - node_ids_.push_back(node_id ^ node.label() ^ node.sibling()); - } - - uint16_t label = node.child(); - if ((label == TERMINAL_LABEL) && (options_.flags & MAP_CURSOR_EXCEPT_MIN)) { - label = double_array_->nodes_[node.offset() ^ label].sibling(); - } - if (label != INVALID_LABEL) { - node_ids_.push_back(node.offset() ^ label); - } -} - -template <typename T> -void DoubleArrayKeyCursor<T>::init_reverse_order_by_key() { - uint8_t max_buf[sizeof(T)]; - convert_key(max_, max_buf); - - uint64_t node_id = ROOT_NODE_ID; - for (size_t i = 0; i < sizeof(T); ++i) { - const DoubleArrayNode node = double_array_->nodes_[node_id]; - if (node.is_leaf()) { - const T key = double_array_->keys_[node.key_id()]; - if ((key < max_) || - ((key == max_) && (~options_.flags & MAP_CURSOR_EXCEPT_MAX))) { - node_ids_.push_back(node_id | POST_ORDER_FLAG); - } - return; - } - uint16_t label = double_array_->nodes_[node_id].child(); - if (label == TERMINAL_LABEL) { - node_id = node.offset() ^ label; - node_ids_.push_back(node_id | POST_ORDER_FLAG); - label = double_array_->nodes_[node_id].sibling(); - } - while (label != INVALID_LABEL) { - node_id = node.offset() ^ label; - if (label < max_buf[i]) { - node_ids_.push_back(node_id); - } else if (label > max_buf[i]) { - return; - } else { - break; - } - label = double_array_->nodes_[node_id].sibling(); - } - if (label == INVALID_LABEL) { - return; - } - } - - const DoubleArrayNode node = double_array_->nodes_[node_id]; - if (node.is_leaf()) { - if (~options_.flags & MAP_CURSOR_EXCEPT_MAX) { - node_ids_.push_back(node_id | POST_ORDER_FLAG); - } - return; - } - - uint16_t label = double_array_->nodes_[node_id].child(); - if ((label == TERMINAL_LABEL) && - (~options_.flags & MAP_CURSOR_EXCEPT_MAX)) { - node_ids_.push_back((node.offset() ^ label) | POST_ORDER_FLAG); - } -} - -template <typename T> -bool DoubleArrayKeyCursor<T>::next_order_by_id() { - if (cur_ < keys_.size()) { - this->key_id_ = keys_[cur_].first; - this->key_ = keys_[cur_].second; - ++cur_; - ++count_; - return true; - } - return false; -} - -template <typename T> -bool DoubleArrayKeyCursor<T>::next_order_by_key() { - while (!node_ids_.empty()) { - const uint64_t node_id = node_ids_.back(); - node_ids_.pop_back(); - const DoubleArrayNode node = double_array_->nodes_[node_id]; - if (node.sibling() != INVALID_LABEL) { - node_ids_.push_back(node_id ^ node.label() ^ node.sibling()); - } - if (node.is_leaf()) { - const T key = double_array_->keys_[node.key_id()]; - if ((key > max_) || - ((key == max_) && (options_.flags & MAP_CURSOR_EXCEPT_MAX))) { - node_ids_.clear(); - return false; - } - if (options_.offset > 0) { - --options_.offset; - } else { - this->key_id_ = node.key_id(); - this->key_ = key; - ++count_; - return true; - } - } else if (node.child() != INVALID_LABEL) { - node_ids_.push_back(node.offset() ^ node.child()); - } - } - return false; -} - -template <typename T> -bool DoubleArrayKeyCursor<T>::next_reverse_order_by_key() { - while (!node_ids_.empty()) { - const bool post_order = node_ids_.back() & POST_ORDER_FLAG; - const uint64_t node_id = node_ids_.back() & ~POST_ORDER_FLAG; - const DoubleArrayNode node = double_array_->nodes_[node_id]; - if (post_order) { - node_ids_.pop_back(); - if (node.is_leaf()) { - const T key = double_array_->keys_[node.key_id()]; - if ((key < min_) || - ((key == min_) && (options_.flags & MAP_CURSOR_EXCEPT_MIN))) { - node_ids_.clear(); - return false; - } - if (options_.offset > 0) { - --options_.offset; - } else { - this->key_id_ = node.key_id(); - this->key_ = key; - ++count_; - return true; - } - } - } else { - node_ids_.back() |= POST_ORDER_FLAG; - uint16_t label = double_array_->nodes_[node_id].child(); - while (label != INVALID_LABEL) { - node_ids_.push_back(node.offset() ^ label); - label = double_array_->nodes_[node.offset() ^ label].sibling(); - } - } - } - return false; -} - -class DoubleArrayBitwiseCompletionCursor : public MapCursor<GeoPoint> { - public: - DoubleArrayBitwiseCompletionCursor(DoubleArray<GeoPoint> *double_array, - GeoPoint query, size_t bit_size, - const MapCursorOptions &options); - ~DoubleArrayBitwiseCompletionCursor(); - - bool next(); - bool remove(); - - private: - DoubleArray<GeoPoint> *double_array_; - uint64_t cur_; - uint64_t count_; - GeoPoint query_; - size_t bit_size_; - uint64_t mask_; - MapCursorOptions options_; - std::vector<uint64_t> node_ids_; - std::vector<std::pair<int64_t, GeoPoint>> keys_; - - void init_order_by_id(); - void init_order_by_key(); - - bool next_order_by_id(); - bool next_order_by_key(); - bool next_reverse_order_by_key(); -}; - -DoubleArrayBitwiseCompletionCursor::DoubleArrayBitwiseCompletionCursor( - DoubleArray<GeoPoint> *double_array, GeoPoint query, size_t bit_size, - const MapCursorOptions &options) - : MapCursor<GeoPoint>(), double_array_(double_array), cur_(), count_(0), - query_(query), bit_size_(bit_size), mask_(), options_(options), - node_ids_(), keys_() { - if ((options_.flags & MAP_CURSOR_ORDER_BY_ID) && - (~options_.flags & MAP_CURSOR_ORDER_BY_KEY)) { - init_order_by_id(); - } else { - options_.flags &= ~MAP_CURSOR_ORDER_BY_ID; - options_.flags |= MAP_CURSOR_ORDER_BY_KEY; - init_order_by_key(); - } -} - -DoubleArrayBitwiseCompletionCursor::~DoubleArrayBitwiseCompletionCursor() {} - -bool DoubleArrayBitwiseCompletionCursor::next() { - if (count_ >= options_.limit) { - return false; - } - if (options_.flags & MAP_CURSOR_ORDER_BY_ID) { - return next_order_by_id(); - } else if (~options_.flags & MAP_CURSOR_REVERSE_ORDER) { - return next_order_by_key(); - } else { - return next_reverse_order_by_key(); - } -} - -bool DoubleArrayBitwiseCompletionCursor::remove() { - return double_array_->unset(this->key_id_); -} - -void DoubleArrayBitwiseCompletionCursor::init_order_by_id() { - init_order_by_key(); - - while (!node_ids_.empty()) { - const bool is_root = node_ids_.back() & IS_ROOT_FLAG; - const uint64_t node_id = node_ids_.back() & ~IS_ROOT_FLAG; - node_ids_.pop_back(); - - const DoubleArrayNode node = double_array_->nodes_[node_id]; - if (!is_root && (node.sibling() != INVALID_LABEL)) { - node_ids_.push_back(node_id ^ node.label() ^ node.sibling()); - } - - if (node.is_leaf()) { - const GeoPoint key = double_array_->keys_[node.key_id()]; - if (((key.value() ^ query_.value()) & mask_) == 0) { - keys_.push_back(std::make_pair(node.key_id(), key)); - } - } else if (node.child() != INVALID_LABEL) { - node_ids_.push_back(node.offset() ^ node.child()); - } - } - - std::sort(keys_.begin(), keys_.end(), - [](const std::pair<int64_t, GeoPoint> &lhs, - const std::pair<int64_t, GeoPoint> &rhs) { - return lhs.first < rhs.first; - }); - if (options_.flags & MAP_CURSOR_REVERSE_ORDER) { - std::reverse(keys_.begin(), keys_.end()); - } - cur_ = options_.offset; -} - -void DoubleArrayBitwiseCompletionCursor::init_order_by_key() { - if (bit_size_ >= 64) { - bit_size_ = 64; - } - switch (bit_size_) { - case 0: { - mask_ = 0; - break; - } - case 1: { - mask_ = GeoPoint(1 << 31, 0).value(); - break; - } - default: { - mask_ = GeoPoint(0xFFFFFFFFU << (32 - (bit_size_ / 2) - (bit_size_ % 2)), - 0xFFFFFFFFU << (32 - (bit_size_ / 2))).value(); - break; - } - } - - // Note: MAP_CURSOR_EXCEPT_QUERY does not make sense. - - uint8_t query_buf[sizeof(GeoPoint)]; - convert_key(query_, query_buf); - - size_t min_size = bit_size_ / 8; - - uint64_t node_id = ROOT_NODE_ID; - for (size_t i = 0; i < min_size; ++i) { - const DoubleArrayNode node = double_array_->nodes_[node_id]; - if (node.is_leaf()) { - const GeoPoint key = double_array_->keys_[node.key_id()]; - if (((key.value() ^ query_.value()) & mask_) == 0) { - if (~options_.flags & MAP_CURSOR_REVERSE_ORDER) { - node_id |= IS_ROOT_FLAG; - } - node_ids_.push_back(node_id); - } - return; - } - node_id = node.offset() ^ query_buf[i]; - if (double_array_->nodes_[node_id].label() != query_buf[i]) { - return; - } - } - - if (~options_.flags & MAP_CURSOR_REVERSE_ORDER) { - node_id |= IS_ROOT_FLAG; - } - node_ids_.push_back(node_id); -} - -bool DoubleArrayBitwiseCompletionCursor::next_order_by_id() { - if (cur_ < keys_.size()) { - this->key_id_ = keys_[cur_].first; - this->key_ = keys_[cur_].second; - ++cur_; - ++count_; - return true; - } - return false; -} - -bool DoubleArrayBitwiseCompletionCursor::next_order_by_key() { - while (!node_ids_.empty()) { - const bool is_root = node_ids_.back() & IS_ROOT_FLAG; - const uint64_t node_id = node_ids_.back() & ~IS_ROOT_FLAG; - node_ids_.pop_back(); - const DoubleArrayNode node = double_array_->nodes_[node_id]; - if (!is_root && (node.sibling() != INVALID_LABEL)) { - node_ids_.push_back(node_id ^ node.label() ^ node.sibling()); - } - if (node.is_leaf()) { - const GeoPoint key = double_array_->keys_[node.key_id()]; - if (((key.value() ^ query_.value()) & mask_) == 0) { - if (options_.offset > 0) { - --options_.offset; - } else { - this->key_id_ = node.key_id(); - this->key_ = key; - ++count_; - return true; - } - } - } else if (node.child() != INVALID_LABEL) { - node_ids_.push_back(node.offset() ^ node.child()); - } - } - return false; -} - -bool DoubleArrayBitwiseCompletionCursor::next_reverse_order_by_key() { - while (!node_ids_.empty()) { - const bool post_order = node_ids_.back() & POST_ORDER_FLAG; - const uint64_t node_id = node_ids_.back() & ~POST_ORDER_FLAG; - const DoubleArrayNode node = double_array_->nodes_[node_id]; - if (post_order) { - node_ids_.pop_back(); - if (node.is_leaf()) { - const GeoPoint key = double_array_->keys_[node.key_id()]; - if (((key.value() ^ query_.value()) & mask_) == 0) { - if (options_.offset > 0) { - --options_.offset; - } else { - this->key_id_ = node.key_id(); - this->key_ = key; - ++count_; - return true; - } - } - } - } else { - node_ids_.back() |= POST_ORDER_FLAG; - uint16_t label = double_array_->nodes_[node_id].child(); - while (label != INVALID_LABEL) { - node_ids_.push_back(node.offset() ^ label); - label = double_array_->nodes_[node.offset() ^ label].sibling(); - } - } - } - return false; -} - -template <typename T> -DoubleArray<T>::~DoubleArray() { - if (!initialized_) try { - // Free allocated blocks if initialization failed. - if (header_->nodes_block_id != io::BLOCK_INVALID_ID) { - pool_.free_block(header_->nodes_block_id); - } - if (header_->chunks_block_id != io::BLOCK_INVALID_ID) { - pool_.free_block(header_->chunks_block_id); - } - if (header_->entries_block_id != io::BLOCK_INVALID_ID) { - pool_.free_block(header_->entries_block_id); - } - if (header_->keys_block_id != io::BLOCK_INVALID_ID) { - pool_.free_block(header_->keys_block_id); - } - if (block_info_) { - pool_.free_block(*block_info_); - } - } catch (...) { - } -} - -template <typename T> -DoubleArray<T> *DoubleArray<T>::create(io::Pool pool, - const MapOptions &options) { - std::unique_ptr<DoubleArray<T>> double_array( - new (std::nothrow) DoubleArray<T>); - if (!double_array) { - GRNXX_ERROR() << "new grnxx::alpha::map::DoubleArray failed"; - GRNXX_THROW(); - } - double_array->create_double_array(pool, options); - return double_array.release(); -} - -template <typename T> -DoubleArray<T> *DoubleArray<T>::open(io::Pool pool, uint32_t block_id) { - std::unique_ptr<DoubleArray<T>> double_array( - new (std::nothrow) DoubleArray<T>); - if (!double_array) { - GRNXX_ERROR() << "new grnxx::alpha::map::DoubleArray failed"; - GRNXX_THROW(); - } - double_array->open_double_array(pool, block_id); - return double_array.release(); -} - -template <typename T> -bool DoubleArray<T>::unlink(io::Pool pool, uint32_t block_id) { - std::unique_ptr<DoubleArray<T>> double_array(open(pool, block_id)); - - pool.free_block(double_array->header_->nodes_block_id); - pool.free_block(double_array->header_->chunks_block_id); - pool.free_block(double_array->header_->entries_block_id); - pool.free_block(double_array->header_->keys_block_id); - pool.free_block(block_id); - return true; -} - -template <typename T> -uint32_t DoubleArray<T>::block_id() const { - return block_info_->id(); -} - -template <typename T> -MapType DoubleArray<T>::type() const { - return MAP_DOUBLE_ARRAY; -} - -template <typename T> -int64_t DoubleArray<T>::max_key_id() const { - return header_->max_key_id; -} - -template <typename T> -int64_t DoubleArray<T>::next_key_id() const { - return header_->next_key_id; -} - -template <typename T> -uint64_t DoubleArray<T>::num_keys() const { - return header_->num_keys; -} - -template <typename T> -bool DoubleArray<T>::get(int64_t key_id, T *key) { - if ((key_id < MIN_KEY_ID) || (key_id > header_->max_key_id)) { - return false; - } - - const DoubleArrayEntry entry = entries_[key_id]; - if (!entry) { - return false; - } - if (key) { - *key = keys_[key_id]; - } - return true; -} - -template <typename T> -bool DoubleArray<T>::get_next(int64_t key_id, int64_t *next_key_id, - T *next_key) { - if (key_id >= header_->max_key_id) { - return false; - } - if (key_id < 0) { - key_id = -1; - } - for (++key_id; key_id <= header_->max_key_id; ++key_id) { - const DoubleArrayEntry entry = entries_[key_id]; - if (entry) { - if (next_key_id) { - *next_key_id = key_id; - } - if (next_key) { - *next_key = keys_[key_id]; - } - return true; - } - } - return false; -} - -template <typename T> -bool DoubleArray<T>::unset(int64_t key_id) { - Lock lock(&header_->inter_process_mutex); - - if ((key_id < MIN_KEY_ID) || (key_id > header_->max_key_id)) { - return false; - } - const DoubleArrayEntry entry = entries_[key_id]; - if (!entry) { - return false; - } - return remove_key(keys_[key_id]); -} - -template <typename T> -bool DoubleArray<T>::reset(int64_t key_id, T dest_key) { - Lock lock(&header_->inter_process_mutex); - - dest_key = Helper<T>::normalize(dest_key); - - if ((key_id < MIN_KEY_ID) || (key_id > header_->max_key_id)) { - return false; - } - const DoubleArrayEntry entry = entries_[key_id]; - if (!entry) { - return false; - } - return update_key(key_id, keys_[key_id], dest_key); -} - -template <typename T> -bool DoubleArray<T>::find(T key, int64_t *key_id) { - key = Helper<T>::normalize(key); - - uint8_t key_buf[sizeof(T)]; - convert_key(key, key_buf); - - uint32_t node_id = ROOT_NODE_ID; - size_t query_pos = 0; - if (!find_leaf(key_buf, node_id, query_pos)) { - return false; - } - - // Note that nodes_[node_id] might be updated by other threads/processes. - const DoubleArrayNode node = nodes_[node_id]; - if (!node.is_leaf()) { - return false; - } - - const int32_t found_key_id = node.key_id(); - if (Helper<T>::equal_to(keys_[found_key_id], key)) { - if (key_id) { - *key_id = found_key_id; - } - return true; - } - return false; -} - -template <typename T> -bool DoubleArray<T>::insert(T key, int64_t *key_id) { - Lock lock(&header_->inter_process_mutex); - - key = Helper<T>::normalize(key); - -// GRN_DAT_THROW_IF(STATUS_ERROR, (status_flags() & CHANGING_MASK) != 0); -// StatusFlagManager status_flag_manager(header_, INSERTING_FLAG); - - uint8_t key_buf[sizeof(T)]; - convert_key(key, key_buf); - - uint32_t node_id = ROOT_NODE_ID; - size_t query_pos = 0; - - find_leaf(key_buf, node_id, query_pos); - if (!insert_leaf(key, key_buf, node_id, query_pos)) { - if (key_id) { - *key_id = nodes_[node_id].key_id(); - } - return false; - } - - const int32_t new_key_id = header_->next_key_id; - keys_[new_key_id] = key; - - ++header_->num_keys; - - if (new_key_id > header_->max_key_id) { - header_->max_key_id = new_key_id; - header_->next_key_id = new_key_id + 1; - } else { - header_->next_key_id = entries_[new_key_id].next(); - } - - entries_[new_key_id] = DoubleArrayEntry::valid_entry(); - nodes_[node_id].set_key_id(new_key_id); - if (key_id) { - *key_id = new_key_id; - } - return true; -} - -template <typename T> -bool DoubleArray<T>::remove(T key) { - Lock lock(&header_->inter_process_mutex); - - key = Helper<T>::normalize(key); - -// GRN_DAT_THROW_IF(STATUS_ERROR, (status_flags() & CHANGING_MASK) != 0); -// StatusFlagManager status_flag_manager(header_, REMOVING_FLAG); - - return remove_key(key); -} - -template <typename T> -bool DoubleArray<T>::update(T src_key, T dest_key, int64_t *key_id) { - Lock lock(&header_->inter_process_mutex); - - src_key = Helper<T>::normalize(src_key); - dest_key = Helper<T>::normalize(dest_key); - - int64_t src_key_id; - if (!find(src_key, &src_key_id)) { - return false; - } - if (update_key(static_cast<int32_t>(src_key_id), src_key, dest_key)) { - if (key_id) { - *key_id = src_key_id; - } - return true; - } - return false; -} - -template <typename T> -bool DoubleArray<T>::truncate() { - nodes_[ROOT_NODE_ID].set_child(INVALID_LABEL); - nodes_[ROOT_NODE_ID].set_offset(INVALID_OFFSET); - header_->next_key_id = 0; - header_->max_key_id = -1; - header_->num_keys = 0; - return true; -} - -template <typename T> -MapCursor<T> *DoubleArray<T>::open_basic_cursor( - const MapCursorOptions &options) { - if ((options.flags & MAP_CURSOR_ORDER_BY_ID) || - (~options.flags & MAP_CURSOR_ORDER_BY_KEY)) { - return open_id_cursor(-1, -1, options); - } else { - // TODO: KeyCursor should be used. - return open_id_cursor(-1, -1, options); - } -} - -template <typename T> -MapCursor<T> *DoubleArray<T>::open_id_cursor(int64_t min, int64_t max, - const MapCursorOptions &options) { - return new (std::nothrow) DoubleArrayIDCursor<T>(this, min, max, options); -} - -template <typename T> -MapCursor<T> *DoubleArray<T>::open_key_cursor( - T min, T max, const MapCursorOptions &options) { - return new (std::nothrow) DoubleArrayKeyCursor<T>(this, min, max, options); -} - -template <> -MapCursor<GeoPoint> *DoubleArray<GeoPoint>::open_key_cursor( - GeoPoint, GeoPoint, const MapCursorOptions &) { - // Not supported. - return nullptr; -} - -template <typename T> -MapCursor<T> *DoubleArray<T>::open_bitwise_completion_cursor( - T, size_t, const MapCursorOptions &) { - // Not supported. - return nullptr; -} - -template <> -MapCursor<GeoPoint> *DoubleArray<GeoPoint>::open_bitwise_completion_cursor( - GeoPoint query, size_t bit_size, const MapCursorOptions &options) { - return new (std::nothrow) DoubleArrayBitwiseCompletionCursor( - this, query, bit_size, options); -} - -template <typename T> -DoubleArray<T>::DoubleArray() - : pool_(), - block_info_(nullptr), - header_(nullptr), - nodes_(nullptr), - chunks_(nullptr), - entries_(nullptr), - keys_(nullptr), - initialized_(false) {} - -template <typename T> -void DoubleArray<T>::create_double_array(io::Pool pool, const MapOptions &) { - pool_ = pool; - - block_info_ = pool_.create_block(sizeof(DoubleArrayHeader)); - - void * const block_address = pool_.get_block_address(*block_info_); - header_ = static_cast<DoubleArrayHeader *>(block_address); - *header_ = DoubleArrayHeader(); - - // TODO: The size should be given as options. - header_->nodes_size = static_cast<uint32_t>(INITIAL_NODES_SIZE); - header_->nodes_size &= ~CHUNK_MASK; - if (header_->nodes_size == 0) { - header_->nodes_size = INITIAL_NODES_SIZE; - } - header_->chunks_size = header_->nodes_size / CHUNK_SIZE; - header_->entries_size = static_cast<uint32_t>(INITIAL_ENTRIES_SIZE); - if (header_->entries_size == 0) { - header_->entries_size = INITIAL_ENTRIES_SIZE; - } - header_->keys_size = static_cast<uint32_t>(INITIAL_KEYS_SIZE); - if (header_->keys_size == 0) { - header_->keys_size = INITIAL_KEYS_SIZE; - } - - create_arrays(); - - reserve_node(ROOT_NODE_ID); - nodes_[INVALID_OFFSET].set_is_origin(true); - - initialized_ = true; -} - -template <typename T> -void DoubleArray<T>::open_double_array(io::Pool pool, uint32_t block_id) { - pool_ = pool; - initialized_ = true; - - block_info_ = pool_.get_block_info(block_id); - - void * const block_address = pool_.get_block_address(*block_info_); - header_ = static_cast<DoubleArrayHeader *>(block_address); - - // TODO: Check the format. - - nodes_ = static_cast<DoubleArrayNode *>( - pool_.get_block_address(header_->nodes_block_id)); - chunks_ = static_cast<DoubleArrayChunk *>( - pool_.get_block_address(header_->chunks_block_id)); - entries_ = static_cast<DoubleArrayEntry *>( - pool_.get_block_address(header_->entries_block_id)); - keys_ = static_cast<T *>( - pool_.get_block_address(header_->keys_block_id)); -} - -template <typename T> -void DoubleArray<T>::create_arrays() { - const io::BlockInfo *block_info; - - block_info = pool_.create_block( - sizeof(DoubleArrayNode) * header_->nodes_size); - header_->nodes_block_id = block_info->id(); - nodes_ = static_cast<DoubleArrayNode *>( - pool_.get_block_address(*block_info)); - - block_info = pool_.create_block( - sizeof(DoubleArrayChunk) * header_->chunks_size); - header_->chunks_block_id = block_info->id(); - chunks_ = static_cast<DoubleArrayChunk *>( - pool_.get_block_address(*block_info)); - - block_info = pool_.create_block( - sizeof(DoubleArrayEntry) * header_->entries_size); - header_->entries_block_id = block_info->id(); - entries_ = static_cast<DoubleArrayEntry *>( - pool_.get_block_address(*block_info)); - - block_info = pool_.create_block(sizeof(T) * header_->keys_size); - header_->keys_block_id = block_info->id(); - keys_ = static_cast<T *>(pool_.get_block_address(*block_info)); -} - -template <typename T> -bool DoubleArray<T>::remove_key(T key) { - uint8_t key_buf[sizeof(T)]; - convert_key(key, key_buf); - - uint32_t node_id = ROOT_NODE_ID; - size_t query_pos = 0; - if (!find_leaf(key_buf, node_id, query_pos)) { - return false; - } - - const int32_t key_id = nodes_[node_id].key_id(); - if (!Helper<T>::equal_to(keys_[key_id], key)) { - return false; - } - - nodes_[node_id].set_offset(INVALID_OFFSET); - entries_[key_id] = DoubleArrayEntry::invalid_entry(header_->next_key_id); - - header_->next_key_id = key_id; - --header_->num_keys; - return true; -} - -template <typename T> -bool DoubleArray<T>::update_key(int32_t key_id, T src_key, T dest_key) { - uint32_t node_id = ROOT_NODE_ID; - size_t query_pos = 0; - - uint8_t dest_key_buf[sizeof(T)]; - convert_key(dest_key, dest_key_buf); - - find_leaf(dest_key_buf, node_id, query_pos); - if (!insert_leaf(dest_key, dest_key_buf, node_id, query_pos)) { - return false; - } - - keys_[key_id] = dest_key; - entries_[key_id] = DoubleArrayEntry::valid_entry(); - nodes_[node_id].set_key_id(key_id); - - uint8_t src_key_buf[sizeof(T)]; - convert_key(src_key, src_key_buf); - - node_id = ROOT_NODE_ID; - query_pos = 0; - if (!find_leaf(src_key_buf, node_id, query_pos)) { - GRNXX_ERROR() << "key not found (unexpected)"; - GRNXX_THROW(); - } - nodes_[node_id].set_offset(INVALID_OFFSET); - return true; -} - -template <typename T> -bool DoubleArray<T>::find_leaf(const uint8_t *key_buf, uint32_t &node_id, - size_t &query_pos) { - for ( ; query_pos < sizeof(T); ++query_pos) { - const DoubleArrayNode node = nodes_[node_id]; - if (node.is_leaf()) { - return true; - } - - const uint32_t next = node.offset() ^ key_buf[query_pos]; - if (nodes_[next].label() != key_buf[query_pos]) { - return false; - } - node_id = next; - } - - const DoubleArrayNode node = nodes_[node_id]; - if (node.is_leaf()) { - return true; - } - - if (node.child() != TERMINAL_LABEL) { - return false; - } - node_id = node.offset() ^ TERMINAL_LABEL; - return nodes_[node_id].is_leaf(); -} - -template <typename T> -bool DoubleArray<T>::insert_leaf(T key, const uint8_t *key_buf, - uint32_t &node_id, size_t query_pos) { - const DoubleArrayNode node = nodes_[node_id]; - if (node.is_leaf()) { - const T found_key = keys_[node.key_id()]; - if (Helper<T>::equal_to(key, found_key)) { - return false; - } - - uint8_t found_key_buf[sizeof(T)]; - convert_key(found_key, found_key_buf); - size_t i = query_pos; - while (i < sizeof(T)) { - if (key_buf[i] != found_key_buf[i]) { - break; - } - ++i; - } - - if (header_->num_keys >= header_->entries_size) { - GRNXX_NOTICE() << "too many keys: num_keys = " << header_->num_keys - << ", entries_size = " << header_->entries_size; - throw DoubleArrayException(); - } - -// GRNXX_DEBUG_THROW_IF(static_cast<uint32_t>(header_->next_key_id) >= header_->entries_size); - - for (size_t j = query_pos; j < i; ++j) { - node_id = insert_node(node_id, key_buf[j]); - } - node_id = separate(key_buf, node_id, i); - return true; - } else if (node.label() == TERMINAL_LABEL) { - return true; - } else { - if (header_->num_keys >= header_->entries_size) { - GRNXX_NOTICE() << "too many keys: num_keys = " << header_->num_keys - << ", entries_size = " << header_->entries_size; - throw DoubleArrayException(); - } - - const uint16_t label = (query_pos < sizeof(T)) ? - static_cast<uint16_t>(key_buf[query_pos]) : TERMINAL_LABEL; - if ((node.offset() == INVALID_OFFSET) || - !nodes_[node.offset() ^ label].is_phantom()) { - // The offset of this node must be updated. - resolve(node_id, label); - } - // The new node will be the leaf node associated with the query. - node_id = insert_node(node_id, label); - return true; - } -} - -template <typename T> -uint32_t DoubleArray<T>::insert_node(uint32_t node_id, uint16_t label) { -// GRNXX_DEBUG_THROW_IF(node_id >= (header_->num_chunks * CHUNK_SIZE)); -// GRNXX_DEBUG_THROW_IF(label > MAX_LABEL); - - const DoubleArrayNode node = nodes_[node_id]; - uint32_t offset; - if (node.is_leaf() || (node.offset() == INVALID_OFFSET)) { - offset = find_offset(&label, 1); - } else { - offset = node.offset(); - } - - const uint32_t next = offset ^ label; - reserve_node(next); - - nodes_[next].set_label(label); - if (node.is_leaf()) { -// GRNXX_DEBUG_THROW_IF(nodes_[offset].is_origin()); - nodes_[offset].set_is_origin(true); - nodes_[next].set_key_id(node.key_id()); - } else if (node.offset() == INVALID_OFFSET) { -// GRNXX_DEBUG_THROW_IF(nodes_[offset].is_origin()); - nodes_[offset].set_is_origin(true); - } else { -// GRNXX_DEBUG_THROW_IF(!nodes_[offset].is_origin()); - } - nodes_[node_id].set_offset(offset); - - const uint16_t child_label = nodes_[node_id].child(); -// GRNXX_DEBUG_THROW_IF(child_label == label); - if (child_label == INVALID_LABEL) { - nodes_[node_id].set_child(label); - } else if ((label == TERMINAL_LABEL) || - ((child_label != TERMINAL_LABEL) && - (label < child_label))) { - // The next node becomes the first child. -// GRNXX_DEBUG_THROW_IF(nodes_[offset ^ child_label].is_phantom()); -// GRNXX_DEBUG_THROW_IF(nodes_[offset ^ child_label].label() != child_label); - nodes_[next].set_sibling(child_label); - nodes_[node_id].set_child(label); - } else { - uint32_t prev = offset ^ child_label; -// GRNXX_DEBUG_THROW_IF(nodes_[prev].label() != child_label); - uint16_t sibling_label = nodes_[prev].sibling(); - while (label > sibling_label) { - prev = offset ^ sibling_label; -// GRNXX_DEBUG_THROW_IF(nodes_[prev].label() != sibling_label); - sibling_label = nodes_[prev].sibling(); - } -// GRNXX_DEBUG_THROW_IF(label == sibling_label); - nodes_[next].set_sibling(nodes_[prev].sibling()); - nodes_[prev].set_sibling(label); - } - return next; -} - -template <typename T> -uint32_t DoubleArray<T>::separate(const uint8_t *key_buf, uint32_t node_id, - size_t i) { -// GRNXX_DEBUG_THROW_IF(node_id >= (header_->num_chunks * CHUNK_SIZE)); -// GRNXX_DEBUG_THROW_IF(!nodes_[node_id].is_leaf()); -// GRNXX_DEBUG_THROW_IF(i > sizeof(T)); - - const DoubleArrayNode node = nodes_[node_id]; - uint8_t found_key_buf[sizeof(T)]; - convert_key(keys_[node.key_id()], found_key_buf); - - uint16_t labels[2]; - labels[0] = (i < sizeof(T)) ? - static_cast<uint16_t>(found_key_buf[i]) : TERMINAL_LABEL; - labels[1] = (i < sizeof(T)) ? - static_cast<uint16_t>(key_buf[i]) : TERMINAL_LABEL; -// GRNXX_DEBUG_THROW_IF(labels[0] == labels[1]); - - const uint32_t offset = find_offset(labels, 2); - - uint32_t next = offset ^ labels[0]; - reserve_node(next); -// GRNXX_DEBUG_THROW_IF(nodes_[offset].is_origin()); - - nodes_[next].set_label(labels[0]); - nodes_[next].set_key_id(node.key_id()); - - next = offset ^ labels[1]; - reserve_node(next); - - nodes_[next].set_label(labels[1]); - - nodes_[offset].set_is_origin(true); - nodes_[node_id].set_offset(offset); - - if ((labels[0] == TERMINAL_LABEL) || - ((labels[1] != TERMINAL_LABEL) && - (labels[0] < labels[1]))) { - nodes_[offset ^ labels[0]].set_sibling(labels[1]); - nodes_[node_id].set_child(labels[0]); - } else { - nodes_[offset ^ labels[1]].set_sibling(labels[0]); - nodes_[node_id].set_child(labels[1]); - } - return next; -} - -template <typename T> -void DoubleArray<T>::resolve(uint32_t node_id, uint16_t label) { -// GRNXX_DEBUG_THROW_IF(node_id >= (header_->num_chunks * CHUNK_SIZE)); -// GRNXX_DEBUG_THROW_IF(nodes_[node_id].is_leaf()); -// GRNXX_DEBUG_THROW_IF(label > MAX_LABEL); - - uint32_t offset = nodes_[node_id].offset(); - if (offset != INVALID_OFFSET) { - uint16_t labels[MAX_LABEL + 1]; - uint16_t num_labels = 0; - - uint16_t next_label = nodes_[node_id].child(); -// GRNXX_DEBUG_THROW_IF(next_label == INVALID_LABEL); - while (next_label != INVALID_LABEL) { -// GRNXX_DEBUG_THROW_IF(next_label > MAX_LABEL); - labels[num_labels++] = next_label; - next_label = nodes_[offset ^ next_label].sibling(); - } -// GRNXX_DEBUG_THROW_IF(num_labels == 0); - - labels[num_labels] = label; - offset = find_offset(labels, num_labels + 1); - migrate_nodes(node_id, offset, labels, num_labels); - } else { - offset = find_offset(&label, 1); - if (offset >= (header_->num_chunks * CHUNK_SIZE)) { -// GRNXX_DEBUG_THROW_IF((offset / CHUNK_SIZE) != header_->num_chunks); - reserve_chunk(header_->num_chunks); - } - nodes_[offset].set_is_origin(true); - nodes_[node_id].set_offset(offset); - } -} - -template <typename T> -void DoubleArray<T>::migrate_nodes(uint32_t node_id, uint32_t dest_offset, - const uint16_t *labels, - uint16_t num_labels) { -// GRNXX_DEBUG_THROW_IF(node_id >= (header_->num_chunks * CHUNK_SIZE)); -// GRNXX_DEBUG_THROW_IF(nodes_[node_id].is_leaf()); -// GRNXX_DEBUG_THROW_IF(labels == nullptr); -// GRNXX_DEBUG_THROW_IF(num_labels == 0); -// GRNXX_DEBUG_THROW_IF(num_labels > (MAX_LABEL + 1)); - - const uint32_t src_offset = nodes_[node_id].offset(); -// GRNXX_DEBUG_THROW_IF(src_offset == INVALID_OFFSET); -// GRNXX_DEBUG_THROW_IF(!nodes_[src_offset].is_origin()); - - for (uint16_t i = 0; i < num_labels; ++i) { - const uint32_t src_node_id = src_offset ^ labels[i]; - const uint32_t dest_node_id = dest_offset ^ labels[i]; -// GRNXX_DEBUG_THROW_IF(nodes_[src_node_id].is_phantom()); -// GRNXX_DEBUG_THROW_IF(nodes_[src_node_id].label() != labels[i]); - - reserve_node(dest_node_id); - DoubleArrayNode dest_node = nodes_[src_node_id]; - dest_node.set_is_origin(nodes_[dest_node_id].is_origin()); - nodes_[dest_node_id] = dest_node; - } - header_->num_zombies += num_labels; - -// GRNXX_DEBUG_THROW_IF(nodes_[dest_offset].is_origin()); - nodes_[dest_offset].set_is_origin(true); - nodes_[node_id].set_offset(dest_offset); -} - -template <typename T> -uint32_t DoubleArray<T>::find_offset(const uint16_t *labels, - uint16_t num_labels) { -// GRNXX_DEBUG_THROW_IF(labels == nullptr); -// GRNXX_DEBUG_THROW_IF(num_labels == 0); -// GRNXX_DEBUG_THROW_IF(num_labels > (MAX_LABEL + 1)); - - // Chunks are tested in descending order of level. Basically, lower level - // chunks contain more phantom nodes. - uint32_t level = 1; - while (num_labels >= (1U << level)) { - ++level; - } - level = (level < MAX_CHUNK_LEVEL) ? (MAX_CHUNK_LEVEL - level) : 0; - - uint32_t chunk_count = 0; - do { - uint32_t leader = header_->leaders[level]; - if (leader == INVALID_LEADER) { - // This level group is skipped because it is empty. - continue; - } - - uint32_t chunk_id = leader; - do { - const DoubleArrayChunk &chunk = chunks_[chunk_id]; -// GRNXX_DEBUG_THROW_IF(chunk.level() != level); - - const uint32_t first = (chunk_id * CHUNK_SIZE) | chunk.first_phantom(); - uint32_t node_id = first; - do { -// GRNXX_DEBUG_THROW_IF(!nodes_[node_id].is_phantom()); - const uint32_t offset = node_id ^ labels[0]; - if (!nodes_[offset].is_origin()) { - uint16_t i = 1; - for ( ; i < num_labels; ++i) { - if (!nodes_[offset ^ labels[i]].is_phantom()) { - break; - } - } - if (i >= num_labels) { - return offset; - } - } - node_id = (chunk_id * CHUNK_SIZE) | nodes_[node_id].next(); - } while (node_id != first); - - const uint32_t prev = chunk_id; - const uint32_t next = chunk.next(); - chunk_id = next; - chunks_[prev].set_failure_count(chunks_[prev].failure_count() + 1); - - // The level of a chunk is updated when this function fails many times, - // actually MAX_FAILURE_COUNT times, in that chunk. - if (chunks_[prev].failure_count() == MAX_FAILURE_COUNT) { - update_chunk_level(prev, level + 1); - if (next == leader) { - break; - } else { - // Note that the leader might be updated in the level update. - leader = header_->leaders[level]; - continue; - } - } - } while ((++chunk_count < MAX_CHUNK_COUNT) && - (chunk_id != leader)); - } while ((chunk_count < MAX_CHUNK_COUNT) && (level-- != 0)); - - return (header_->num_chunks * CHUNK_SIZE) ^ labels[0]; -} - -template <typename T> -void DoubleArray<T>::reserve_node(uint32_t node_id) { - if (node_id >= (header_->num_chunks * CHUNK_SIZE)) { - reserve_chunk(node_id / CHUNK_SIZE); - } - - DoubleArrayNode &node = nodes_[node_id]; -// GRNXX_DEBUG_THROW_IF(!node.is_phantom()); - - const uint32_t chunk_id = node_id / CHUNK_SIZE; - DoubleArrayChunk &chunk = chunks_[chunk_id]; -// GRNXX_DEBUG_THROW_IF(chunk.num_phantoms() == 0); - - const uint32_t next = (chunk_id * CHUNK_SIZE) | node.next(); - const uint32_t prev = (chunk_id * CHUNK_SIZE) | node.prev(); -// GRNXX_DEBUG_THROW_IF(next >= (header_->num_chunks * CHUNK_SIZE)); -// GRNXX_DEBUG_THROW_IF(prev >= (header_->num_chunks * CHUNK_SIZE)); - - if ((node_id & CHUNK_MASK) == chunk.first_phantom()) { - // The first phantom node is removed from the chunk and the second phantom - // node comes first. - chunk.set_first_phantom(next & CHUNK_MASK); - } - - nodes_[next].set_prev(prev & CHUNK_MASK); - nodes_[prev].set_next(next & CHUNK_MASK); - - if (chunk.level() != MAX_CHUNK_LEVEL) { - const uint32_t threshold = - uint32_t(1) << ((MAX_CHUNK_LEVEL - chunk.level() - 1) * 2); - if (chunk.num_phantoms() == threshold) { - update_chunk_level(chunk_id, chunk.level() + 1); - } - } - chunk.set_num_phantoms(chunk.num_phantoms() - 1); - - node.set_is_phantom(false); - -// GRNXX_DEBUG_THROW_IF(node.offset() != INVALID_OFFSET); -// GRNXX_DEBUG_THROW_IF(node.label() != INVALID_LABEL); - - --header_->num_phantoms; -} - -template <typename T> -void DoubleArray<T>::reserve_chunk(uint32_t chunk_id) { -// GRNXX_DEBUG_THROW_IF(chunk_id != header_->num_chunks); - - if (chunk_id >= header_->chunks_size) { - GRNXX_NOTICE() << "too many chunks: chunk_id = " << chunk_id - << ", chunks_size = " << header_->chunks_size; - throw DoubleArrayException(); - } - - header_->num_chunks = chunk_id + 1; - - DoubleArrayChunk chunk; - chunk.set_failure_count(0); - chunk.set_first_phantom(0); - chunk.set_num_phantoms(CHUNK_SIZE); - chunks_[chunk_id] = chunk; - - const uint32_t begin = chunk_id * CHUNK_SIZE; - const uint32_t end = begin + CHUNK_SIZE; -// GRNXX_DEBUG_THROW_IF(end != (header_->num_chunks * CHUNK_SIZE)); - - DoubleArrayNode node; - node.set_is_phantom(true); - for (uint32_t i = begin; i < end; ++i) { - node.set_prev((i - 1) & CHUNK_MASK); - node.set_next((i + 1) & CHUNK_MASK); - nodes_[i] = node; - } - - // The level of the new chunk is 0. - set_chunk_level(chunk_id, 0); - header_->num_phantoms += CHUNK_SIZE; -} - -template <typename T> -void DoubleArray<T>::update_chunk_level(uint32_t chunk_id, uint32_t level) { -// GRNXX_DEBUG_THROW_IF(chunk_id >= header_->num_chunks); -// GRNXX_DEBUG_THROW_IF(level > MAX_CHUNK_LEVEL); - - unset_chunk_level(chunk_id); - set_chunk_level(chunk_id, level); -} - -template <typename T> -void DoubleArray<T>::set_chunk_level(uint32_t chunk_id, uint32_t level) { -// GRNXX_DEBUG_THROW_IF(chunk_id >= header_->num_chunks); -// GRNXX_DEBUG_THROW_IF(level > MAX_CHUNK_LEVEL); - - const uint32_t leader = header_->leaders[level]; - if (leader == INVALID_LEADER) { - // The chunk becomes the only one member of the level group. - chunks_[chunk_id].set_next(chunk_id); - chunks_[chunk_id].set_prev(chunk_id); - header_->leaders[level] = chunk_id; - } else { - // The chunk is appended to the level group. - const uint32_t next = leader; - const uint32_t prev = chunks_[leader].prev(); -// GRNXX_DEBUG_THROW_IF(next >= header_->num_chunks); -// GRNXX_DEBUG_THROW_IF(prev >= header_->num_chunks); - chunks_[chunk_id].set_next(next); - chunks_[chunk_id].set_prev(prev); - chunks_[next].set_prev(chunk_id); - chunks_[prev].set_next(chunk_id); - } - chunks_[chunk_id].set_level(level); - chunks_[chunk_id].set_failure_count(0); -} - -template <typename T> -void DoubleArray<T>::unset_chunk_level(uint32_t chunk_id) { - const uint32_t level = chunks_[chunk_id].level(); -// GRNXX_DEBUG_THROW_IF(level > MAX_CHUNK_LEVEL); - const uint32_t leader = header_->leaders[level]; -// GRNXX_DEBUG_THROW_IF(leader == INVALID_LEADER); - const uint32_t next = chunks_[chunk_id].next(); - const uint32_t prev = chunks_[chunk_id].prev(); -// GRNXX_DEBUG_THROW_IF(next >= header_->num_chunks); -// GRNXX_DEBUG_THROW_IF(prev >= header_->num_chunks); - - if (next == chunk_id) { - // The level group becomes empty. - header_->leaders[level] = INVALID_LEADER; - } else { - chunks_[next].set_prev(prev); - chunks_[prev].set_next(next); - if (chunk_id == leader) { - // The second chunk becomes the leader of the level group. - header_->leaders[level] = next; - } - } -} - -template class DoubleArray<int8_t>; -template class DoubleArray<int16_t>; -template class DoubleArray<int32_t>; -template class DoubleArray<int64_t>; -template class DoubleArray<uint8_t>; -template class DoubleArray<uint16_t>; -template class DoubleArray<uint32_t>; -template class DoubleArray<uint64_t>; -template class DoubleArray<double>; -template class DoubleArray<GeoPoint>; - -} // namespace map -} // namespace alpha -} // namespace grnxx Deleted: obsolete/lib/grnxx/alpha/map/double_array.hpp (+0 -259) 100644 =================================================================== --- obsolete/lib/grnxx/alpha/map/double_array.hpp 2013-08-23 10:46:34 +0900 (a19f9f6) +++ /dev/null @@ -1,259 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_ALPHA_MAP_DOUBLE_ARRAY_HPP -#define GRNXX_ALPHA_MAP_DOUBLE_ARRAY_HPP - -#include "grnxx/alpha/map.hpp" -#include "grnxx/exception.hpp" - -namespace grnxx { -namespace alpha { -namespace map { - -template <typename T> class DoubleArrayIDCursor; -template <typename T> class DoubleArrayKeyCursor; -template <typename T> class DoubleArrayPrefixCursor; -template <typename T> class DoubleArrayCompletionCursor; -class DoubleArrayBitwiseCompletionCursor; - -struct DoubleArrayHeader; -class DoubleArrayNode; -class DoubleArrayChunk; -class DoubleArrayEntry; - -struct SliceDoubleArrayHeader; -class SliceDoubleArrayNode; -class SliceDoubleArrayChunk; -class SliceDoubleArrayEntry; -class SliceDoubleArrayKey; - -class DoubleArrayException : Exception { - public: - DoubleArrayException() noexcept : Exception() {} - ~DoubleArrayException() noexcept {} - - DoubleArrayException(const DoubleArrayException &x) noexcept : Exception(x) {} - DoubleArrayException &operator=(const DoubleArrayException &) noexcept { - return *this; - } - - const char *what() const noexcept { - return ""; - } -}; - -template <typename T> -class DoubleArray : public Map<T> { - friend class DoubleArrayIDCursor<T>; - friend class DoubleArrayKeyCursor<T>; - friend class DoubleArrayBitwiseCompletionCursor; - - public: - ~DoubleArray(); - - static DoubleArray<T> *create(io::Pool pool, - const MapOptions &options = MapOptions()); - static DoubleArray<T> *open(io::Pool pool, uint32_t block_id); - - static bool unlink(io::Pool pool, uint32_t block_id); - - uint32_t block_id() const; - MapType type() const; - - int64_t max_key_id() const; - int64_t next_key_id() const; - uint64_t num_keys() const; - - bool get(int64_t key_id, T *key = nullptr); - bool get_next(int64_t key_id, int64_t *next_key_id = nullptr, - T *next_key = nullptr); - bool unset(int64_t key_id); - bool reset(int64_t key_id, T dest_key); - - bool find(T key, int64_t *key_id = nullptr); - bool insert(T key, int64_t *key_id = nullptr); - bool remove(T key); - bool update(T src_key, T dest_key, int64_t *key_id = nullptr); - - bool truncate(); - - MapCursor<T> *open_basic_cursor( - const MapCursorOptions &options = MapCursorOptions()); - MapCursor<T> *open_id_cursor( - int64_t min, int64_t max, - const MapCursorOptions &options = MapCursorOptions()); - MapCursor<T> *open_key_cursor( - T min, T max, - const MapCursorOptions &options = MapCursorOptions()); - - MapCursor<T> *open_bitwise_completion_cursor( - T query, size_t bit_size, - const MapCursorOptions &options = MapCursorOptions()); - - private: - io::Pool pool_; - const io::BlockInfo *block_info_; - DoubleArrayHeader *header_; - DoubleArrayNode *nodes_; - DoubleArrayChunk *chunks_; - DoubleArrayEntry *entries_; - T *keys_; - bool initialized_; - - DoubleArray(); - - void create_double_array(io::Pool pool, const MapOptions &options); - void open_double_array(io::Pool pool, uint32_t block_id); - - void create_arrays(); - - bool remove_key(T key); - bool update_key(int32_t key_id, T src_key, T dest_key); - - bool find_leaf(const uint8_t *key_buf, uint32_t &node_id, size_t &query_pos); - bool insert_leaf(T key, const uint8_t *key_buf, uint32_t &node_id, - size_t query_pos); - - uint32_t insert_node(uint32_t node_id, uint16_t label); - - uint32_t separate(const uint8_t *key_buf, uint32_t node_id, size_t i); - void resolve(uint32_t node_id, uint16_t label); - void migrate_nodes(uint32_t node_id, uint32_t dest_offset, - const uint16_t *labels, uint16_t num_labels); - - uint32_t find_offset(const uint16_t *labels, uint16_t num_labels); - - void reserve_node(uint32_t node_id); - void reserve_chunk(uint32_t chunk_id); - - void update_chunk_level(uint32_t chunk_id, uint32_t level); - void set_chunk_level(uint32_t chunk_id, uint32_t level); - void unset_chunk_level(uint32_t chunk_id); -}; - -template <> -class DoubleArray<Slice> : public Map<Slice> { - friend class DoubleArrayIDCursor<Slice>; - friend class DoubleArrayKeyCursor<Slice>; - friend class DoubleArrayPrefixCursor<Slice>; - friend class DoubleArrayCompletionCursor<Slice>; - - public: - typedef SliceDoubleArrayHeader DoubleArrayHeader; - typedef SliceDoubleArrayNode DoubleArrayNode; - typedef SliceDoubleArrayChunk DoubleArrayChunk; - typedef SliceDoubleArrayEntry DoubleArrayEntry; - typedef SliceDoubleArrayKey DoubleArrayKey; - - ~DoubleArray(); - - static DoubleArray<Slice> *create(io::Pool pool, - const MapOptions &options = MapOptions()); - static DoubleArray<Slice> *open(io::Pool pool, uint32_t block_id); - - static bool unlink(io::Pool pool, uint32_t block_id); - - uint32_t block_id() const; - MapType type() const; - - int64_t max_key_id() const; - int64_t next_key_id() const; - uint64_t num_keys() const; - - bool get(int64_t key_id, Slice *key = nullptr); - bool get_next(int64_t key_id, int64_t *next_key_id = nullptr, - Slice *next_key = nullptr); - bool unset(int64_t key_id); - bool reset(int64_t key_id, Slice dest_key); - - bool find(Slice key, int64_t *key_id = nullptr); - bool insert(Slice key, int64_t *key_id = nullptr); - bool remove(Slice key); - bool update(Slice src_key, Slice dest_key, int64_t *key_id = nullptr); - - bool find_longest_prefix_match(Slice query, int64_t *key_id = nullptr, - Slice *key = nullptr); - - bool truncate(); - - MapCursor<Slice> *open_basic_cursor( - const MapCursorOptions &options = MapCursorOptions()); - MapCursor<Slice> *open_id_cursor( - int64_t min, int64_t max, - const MapCursorOptions &options = MapCursorOptions()); - MapCursor<Slice> *open_key_cursor( - Slice min, Slice max, - const MapCursorOptions &options = MapCursorOptions()); - - MapCursor<Slice> *open_prefix_cursor( - Slice query, size_t min_size, - const MapCursorOptions &options = MapCursorOptions()); - MapCursor<Slice> *open_completion_cursor( - Slice query, const MapCursorOptions &options = MapCursorOptions()); - - private: - io::Pool pool_; - const io::BlockInfo *block_info_; - DoubleArrayHeader *header_; - DoubleArrayNode *nodes_; - DoubleArrayChunk *chunks_; - DoubleArrayEntry *entries_; - uint32_t *keys_; - bool initialized_; - - DoubleArray(); - - void create_double_array(io::Pool pool, const MapOptions &options); - void open_double_array(io::Pool pool, uint32_t block_id); - - void create_arrays(); - - const DoubleArrayKey &get_key(uint32_t key_pos) const { - return *reinterpret_cast<const DoubleArrayKey *>(&keys_[key_pos]); - } - - bool remove_key(const Slice &key); - bool update_key(int32_t key_id, const Slice &src_key, - const Slice &dest_key); - - bool find_leaf(const Slice &key, uint32_t &node_id, size_t &query_pos); - bool insert_leaf(const Slice &key, uint32_t &node_id, size_t query_pos); - - uint32_t insert_node(uint32_t node_id, uint16_t label); - uint32_t append_key(const Slice &key, int32_t key_id); - - uint32_t separate(const Slice &key, uint32_t node_id, size_t i); - void resolve(uint32_t node_id, uint16_t label); - void migrate_nodes(uint32_t node_id, uint32_t dest_offset, - const uint16_t *labels, uint16_t num_labels); - - uint32_t find_offset(const uint16_t *labels, uint16_t num_labels); - - void reserve_node(uint32_t node_id); - void reserve_chunk(uint32_t chunk_id); - - void update_chunk_level(uint32_t chunk_id, uint32_t level); - void set_chunk_level(uint32_t chunk_id, uint32_t level); - void unset_chunk_level(uint32_t chunk_id); -}; - -} // namespace map -} // namespace alpha -} // namespace grnxx - -#endif // GRNXX_ALPHA_MAP_DOUBLE_ARRAY_HPP Deleted: obsolete/lib/grnxx/alpha/map/header.hpp (+0 -35) 100644 =================================================================== --- obsolete/lib/grnxx/alpha/map/header.hpp 2013-08-23 10:46:34 +0900 (1c2ee92) +++ /dev/null @@ -1,35 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_ALPHA_MAP_HEADER_HPP -#define GRNXX_ALPHA_MAP_HEADER_HPP - -#include "grnxx/alpha/map.hpp" - -namespace grnxx { -namespace alpha { -namespace map { - -struct Header { - MapType type; -}; - -} // namespace map -} // namespace alpha -} // namespace grnxx - -#endif // GRNXX_ALPHA_MAP_HEADER_HPP Deleted: obsolete/lib/grnxx/alpha/map/scan.cpp (+0 -57) 100644 =================================================================== --- obsolete/lib/grnxx/alpha/map/scan.cpp 2013-08-23 10:46:34 +0900 (8bcfb2e) +++ /dev/null @@ -1,57 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/alpha/map/scan.hpp" - -#include "grnxx/charset.hpp" - -namespace grnxx { -namespace alpha { -namespace map { - -Scan::Scan(Map<Slice> *map, const Slice &query, const Charset *charset) - : MapScan<Slice>(), - map_(map), - query_(query), - charset_(charset) {} - -Scan::~Scan() {} - -bool Scan::next() { - this->offset_ += this->size_; - while (this->offset_ < query_.size()) { - const Slice query_left = - query_.subslice(this->offset_, query_.size() - this->offset_); - if (map_->find_longest_prefix_match(query_left, - &this->key_id_, &this->key_)) { - this->size_ = this->key_.size(); - return true; - } - // Move to the next character. - if (charset_) { - this->offset_ += charset_->get_char_size(query_left); - } else { - ++this->offset_; - } - } - this->size_ = 0; - return false; -} - -} // namespace map -} // namespace alpha -} // namespace grnxx Deleted: obsolete/lib/grnxx/alpha/map/scan.hpp (+0 -47) 100644 =================================================================== --- obsolete/lib/grnxx/alpha/map/scan.hpp 2013-08-23 10:46:34 +0900 (3e80527) +++ /dev/null @@ -1,47 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_ALPHA_MAP_SCAN_HPP -#define GRNXX_ALPHA_MAP_SCAN_HPP - -#include "grnxx/alpha/map.hpp" - -namespace grnxx { - -class Charset; - -namespace alpha { -namespace map { - -class Scan : public MapScan<Slice> { - public: - Scan(Map<Slice> *map, const Slice &query, const Charset *charset); - ~Scan(); - - bool next(); - - protected: - Map<Slice> *map_; - Slice query_; - const Charset *charset_; -}; - -} // namespace map -} // namespace alpha -} // namespace grnxx - -#endif // GRNXX_ALPHA_MAP_SCAN_HPP Deleted: obsolete/lib/grnxx/alpha/map_range.hpp (+0 -263) 100644 =================================================================== --- obsolete/lib/grnxx/alpha/map_range.hpp 2013-08-23 10:46:34 +0900 (eec0b27) +++ /dev/null @@ -1,263 +0,0 @@ -/* - Copyright (C) 2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_ALPHA_MAP_RANGE_HPP -#define GRNXX_ALPHA_MAP_RANGE_HPP - -#include "grnxx/basic.hpp" -#include "grnxx/flags_impl.hpp" - -namespace grnxx { -namespace alpha { - -struct MapRangeFlagsIdentifier; -using MapRangeFlags = FlagsImpl<MapRangeFlagsIdentifier>; - -constexpr MapRangeFlags MAP_RANGE_LESS = MapRangeFlags::define(0x01); -constexpr MapRangeFlags MAP_RANGE_LESS_EQUAL = MapRangeFlags::define(0x02); -constexpr MapRangeFlags MAP_RANGE_GREATER = MapRangeFlags::define(0x04); -constexpr MapRangeFlags MAP_RANGE_GREATER_EQUAL = MapRangeFlags::define(0x08); - -struct MapID {}; - -struct MapIDRange { - int64_t min; - int64_t max; - MapRangeFlags flags; -}; - -struct MapIDLess { - int64_t max; - constexpr MapRangeFlags flags() const { - return MAP_RANGE_LESS; - } - operator MapIDRange() const { - return MapIDRange{ int64_t(), max, flags() }; - } -}; - -struct MapIDLessEqual { - int64_t max; - constexpr MapRangeFlags flags() const { - return MAP_RANGE_LESS_EQUAL; - } - operator MapIDRange() const { - return MapIDRange{ int64_t(), max, flags() }; - } -}; - -struct MapIDGreater { - int64_t min; - constexpr MapRangeFlags flags() const { - return MAP_RANGE_GREATER; - } - operator MapIDRange() const { - return MapIDRange{ min, int64_t(), flags() }; - } -}; - -struct MapIDGreaterEqual { - int64_t min; - constexpr MapRangeFlags flags() const { - return MAP_RANGE_GREATER_EQUAL; - } - operator MapIDRange() const { - return MapIDRange{ min, int64_t(), flags() }; - } -}; - -inline MapIDLess operator<(MapID, int64_t max) { - return MapIDLess{ max }; -} -inline MapIDLessEqual operator<=(MapID, int64_t max) { - return MapIDLessEqual{ max }; -} -inline MapIDGreater operator>(MapID, int64_t min) { - return MapIDGreater{ min }; -} -inline MapIDGreaterEqual operator>=(MapID, int64_t min) { - return MapIDGreaterEqual{ min }; -} - -inline MapIDGreater operator<(int64_t min, MapID) { - return MapIDGreater{ min }; -} -inline MapIDGreaterEqual operator<=(int64_t min, MapID) { - return MapIDGreaterEqual{ min }; -} -inline MapIDLess operator>(int64_t max, MapID) { - return MapIDLess{ max }; -} -inline MapIDLessEqual operator>=(int64_t max, MapID) { - return MapIDLessEqual{ max }; -} - -inline MapIDRange operator&&(MapIDLess less, MapIDGreater greater) { - return MapIDRange{ greater.min, less.max, less.flags() | greater.flags() }; -} -inline MapIDRange operator&&(MapIDLess less, MapIDGreaterEqual greater) { - return MapIDRange{ greater.min, less.max, less.flags() | greater.flags() }; -} -inline MapIDRange operator&&(MapIDLessEqual less, MapIDGreater greater) { - return MapIDRange{ greater.min, less.max, less.flags() | greater.flags() }; -} -inline MapIDRange operator&&(MapIDLessEqual less, MapIDGreaterEqual greater) { - return MapIDRange{ greater.min, less.max, less.flags() | greater.flags() }; -} -inline MapIDRange operator&&(MapIDGreater greater, MapIDLess less) { - return less && greater; -} -inline MapIDRange operator&&(MapIDGreater greater, MapIDLessEqual less) { - return less && greater; -} -inline MapIDRange operator&&(MapIDGreaterEqual greater, MapIDLess less) { - return less && greater; -} -inline MapIDRange operator&&(MapIDGreaterEqual greater, MapIDLessEqual less) { - return less && greater; -} - -template <typename T> struct MapKey {}; - -template <typename T> -struct MapKeyRange { - T min; - T max; - MapRangeFlags flags; -}; - -template <typename T> -struct MapKeyLess { - T max; - constexpr MapRangeFlags flags() const { - return MAP_RANGE_LESS; - } - operator MapKeyRange<T>() const { - return MapKeyRange<T>{ int64_t(), max, flags() }; - } -}; - -template <typename T> -struct MapKeyLessEqual { - T max; - constexpr MapRangeFlags flags() const { - return MAP_RANGE_LESS_EQUAL; - } - operator MapKeyRange<T>() const { - return MapKeyRange<T>{ int64_t(), max, flags() }; - } -}; - -template <typename T> -struct MapKeyGreater { - T min; - constexpr MapRangeFlags flags() const { - return MAP_RANGE_GREATER; - } - operator MapKeyRange<T>() const { - return MapKeyRange<T>{ min, int64_t(), flags() }; - } -}; - -template <typename T> -struct MapKeyGreaterEqual { - T min; - constexpr MapRangeFlags flags() const { - return MAP_RANGE_GREATER_EQUAL; - } - operator MapKeyRange<T>() const { - return MapKeyRange<T>{ min, int64_t(), flags() }; - } -}; - -template <typename T> -MapKeyLess<T> operator<(MapKey<T>, T max) { - return MapKeyLess<T>{ max }; -} -template <typename T> -MapKeyLessEqual<T> operator<=(MapKey<T>, T max) { - return MapKeyLessEqual<T>{ max }; -} -template <typename T> -MapKeyGreater<T> operator>(MapKey<T>, T min) { - return MapKeyGreater<T>{ min }; -} -template <typename T> -MapKeyGreaterEqual<T> operator>=(MapKey<T>, T min) { - return MapKeyGreaterEqual<T>{ min }; -} - -template <typename T> -MapKeyGreater<T> operator<(T min, MapKey<T>) { - return MapKeyGreater<T>{ min }; -} -template <typename T> -MapKeyGreaterEqual<T> operator<=(T min, MapKey<T>) { - return MapKeyGreaterEqual<T>{ min }; -} -template <typename T> -MapKeyLess<T> operator>(T max, MapKey<T>) { - return MapKeyLess<T>{ max }; -} -template <typename T> -MapKeyLessEqual<T> operator>=(T max, MapKey<T>) { - return MapKeyLessEqual<T>{ max }; -} - -template <typename T> -MapKeyRange<T> operator&&(MapKeyLess<T> less, MapKeyGreater<T> greater) { - return MapKeyRange<T>{ greater.min, less.max, - less.flags() | greater.flags() }; -} -template <typename T> -MapKeyRange<T> operator&&(MapKeyLess<T> less, MapKeyGreaterEqual<T> greater) { - return MapKeyRange<T>{ greater.min, less.max, - less.flags() | greater.flags() }; -} -template <typename T> -MapKeyRange<T> operator&&(MapKeyLessEqual<T> less, MapKeyGreater<T> greater) { - return MapKeyRange<T>{ greater.min, less.max, - less.flags() | greater.flags() }; -} -template <typename T> -MapKeyRange<T> operator&&(MapKeyLessEqual<T> less, - MapKeyGreaterEqual<T> greater) { - return MapKeyRange<T>{ greater.min, less.max, - less.flags() | greater.flags() }; -} -template <typename T> -MapKeyRange<T> operator&&(MapKeyGreater<T> greater, MapKeyLess<T> less) { - return less && greater; -} -template <typename T> -MapKeyRange<T> operator&&(MapKeyGreater<T> greater, MapKeyLessEqual<T> less) { - return less && greater; -} -template <typename T> -MapKeyRange<T> operator&&(MapKeyGreaterEqual<T> greater, MapKeyLess<T> less) { - return less && greater; -} -template <typename T> -MapKeyRange<T> operator&&(MapKeyGreaterEqual<T> greater, - MapKeyLessEqual<T> less) { - return less && greater; -} - -} // namespace alpha -} // namespace grnxx - -#endif // GRNXX_ALPHA_MAP_RANGE_HPP Deleted: obsolete/lib/grnxx/alpha/paged_array.cpp (+0 -335) 100644 =================================================================== --- obsolete/lib/grnxx/alpha/paged_array.cpp 2013-08-23 10:46:34 +0900 (780f043) +++ /dev/null @@ -1,335 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/alpha/paged_array.hpp" - -#include <new> - -#include "grnxx/alpha/common_header.hpp" -#include "grnxx/bytes.hpp" -#include "grnxx/exception.hpp" -#include "grnxx/intrinsic.hpp" -#include "grnxx/lock.hpp" -#include "grnxx/logger.hpp" -#include "grnxx/mutex.hpp" -#include "grnxx/storage.hpp" - -namespace grnxx { -namespace alpha { - -constexpr char PAGED_ARRAY_FORMAT[CommonHeader::FORMAT_SIZE] = - "grnxx::alpha::PagedArray"; - -constexpr uint64_t PAGED_ARRAY_MIN_TABLE_SIZE = 16; - -struct PagedArrayHeader { - CommonHeader common_header; - uint64_t value_size; - uint64_t size; - uint64_t page_size; - uint64_t has_default_value; - uint64_t table_size; - uint32_t table_storage_node_id; - Mutex mutex; - - PagedArrayHeader(); -}; - -PagedArrayHeader::PagedArrayHeader() - : common_header(PAGED_ARRAY_FORMAT), - value_size(0), - size(0), - page_size(0), - has_default_value(0), - table_size(0), - table_storage_node_id(STORAGE_INVALID_NODE_ID), - mutex() {} - -PagedArrayImpl::PagedArrayImpl() - : storage_(nullptr), - storage_node_id_(STORAGE_INVALID_NODE_ID), - size_(0), - page_size_(0), - page_shift_(0), - page_mask_(0), - table_size_(0), - pages_(), - table_(nullptr), - header_(nullptr), - default_value_(nullptr), - fill_page_(nullptr) {} - -PagedArrayImpl::~PagedArrayImpl() {} - -void PagedArrayImpl::create(Storage *storage, uint32_t storage_node_id, - uint64_t value_size, uint64_t size, - uint64_t page_size, - const void *default_value, FillPage fill_page) { - if (page_size == 0) { - GRNXX_ERROR() << "invalid argument: page_size = " << page_size; - throw LogicError(); - } - if ((page_size & (page_size - 1)) != 0) { - const uint64_t revised_page_size = 2ULL << bit_scan_reverse(page_size); - GRNXX_WARNING() << "page_size must be a power of two: " - << "page_size = " << page_size - << ", revised_page_size = " << revised_page_size; - page_size = revised_page_size; - } - if ((size % page_size) != 0) { - const uint64_t revised_size = size + page_size - (size % page_size); - GRNXX_WARNING() << "size must be a multiple of page_size: size = " << size - << ", revised_size = " << revised_size - << ", page_size = " << page_size; - size = revised_size; - } - PagedArrayImpl new_impl; - new_impl.create_array(storage, storage_node_id, value_size, size, page_size, - default_value, fill_page); - swap(new_impl); -} - -void PagedArrayImpl::open(Storage *storage, uint32_t storage_node_id, - uint64_t value_size, FillPage fill_page) { - PagedArrayImpl new_impl; - new_impl.open_array(storage, storage_node_id, value_size, fill_page); - swap(new_impl); -} - -bool PagedArrayImpl::unlink(Storage *storage, uint32_t storage_node_id, - uint64_t value_size) { - PagedArrayImpl impl; - impl.open(storage, storage_node_id, value_size); - return storage->unlink_node(storage_node_id); -} - -void PagedArrayImpl::create_array(Storage *storage, uint32_t storage_node_id, - uint64_t value_size, uint64_t size, - uint64_t page_size, - const void *default_value, - FillPage fill_page) { - storage_ = storage; - uint64_t header_node_size = sizeof(PagedArrayHeader); - if (default_value) { - header_node_size += value_size; - } - StorageNode header_node = - storage->create_node(storage_node_id, header_node_size); - storage_node_id_ = header_node.id(); - try { - header_ = static_cast<PagedArrayHeader *>(header_node.body()); - *header_ = PagedArrayHeader(); - header_->value_size = value_size; - header_->size = size; - header_->page_size = page_size; - header_->has_default_value = default_value != nullptr; - size_ = size; - page_size_ = page_size; - page_shift_ = bit_scan_reverse(page_size_); - page_mask_ = page_size_ - 1; - if (header_->has_default_value) { - default_value_ = header_ + 1; - fill_page_ = fill_page; - } - } catch (...) { - storage->unlink_node(header_node.id()); - throw; - } -} - -void PagedArrayImpl::open_array(Storage *storage, uint32_t storage_node_id, - uint64_t value_size, FillPage fill_page) { - storage_ = storage; - storage_node_id_ = storage_node_id; - StorageNode header_node = storage->open_node(storage_node_id); - if (header_node.size() < sizeof(CommonHeader)) { - GRNXX_ERROR() << "too small header: size = " << header_node.size(); - throw LogicError(); - } - header_ = static_cast<PagedArrayHeader *>(header_node.body()); - if (header_->common_header.format() != - Bytes(PAGED_ARRAY_FORMAT, CommonHeader::FORMAT_SIZE)) { - GRNXX_ERROR() << "invalid format: expected = " << PAGED_ARRAY_FORMAT - << ", actual = " << header_->common_header.format(); - throw LogicError(); - } - if (header_->value_size != value_size) { - GRNXX_ERROR() << "invalid value size: expected = " << value_size - << ", actual = " << header_->value_size; - throw LogicError(); - } - size_ = header_->size; - page_size_ = header_->page_size; - page_shift_ = bit_scan_reverse(page_size_); - page_mask_ = page_size_ - 1; - if (header_->has_default_value) { - default_value_ = header_ + 1; - fill_page_ = fill_page; - } -} - -void PagedArrayImpl::resize_table(uint64_t table_size) { - Lock lock(&header_->mutex); - update_table(); - if (table_size <= table_size_) { - // Nothing to do. - return; - } - const uint64_t max_table_size = size_ / page_size_; - if (table_size > max_table_size) { - GRNXX_ERROR() << "too large size: table_size = " << table_size - << ", size = " << size_ << ", page_size = " << page_size_; - throw LogicError(); - } - if (table_size < PAGED_ARRAY_MIN_TABLE_SIZE) { - table_size = PAGED_ARRAY_MIN_TABLE_SIZE; - } - if ((table_size & (table_size - 1)) != 0) { - table_size = 2ULL << bit_scan_reverse(table_size); - } - if (table_size > max_table_size) { - table_size = max_table_size; - } - // Create a new table cache. - std::unique_ptr<void *[]> new_pages(new (std::nothrow) void *[table_size]); - if (!new_pages) { - GRNXX_ERROR() << "new void *[] failed: size = " << table_size; - throw MemoryError(); - } - for (uint64_t i = 0; i < table_size_; ++i) { - new_pages[i] = pages_[i]; - } - for (uint64_t i = table_size_; i < table_size; ++i) { - new_pages[i] = invalid_page_address(); - } - // Create a new table. - StorageNode table_node = - storage_->create_node(storage_node_id_, sizeof(uint32_t) * table_size); - uint32_t * const new_table = static_cast<uint32_t *>(table_node.body()); - for (uint64_t i = 0; i < table_size_; ++i) { - new_table[i] = table_[i]; - } - for (uint64_t i = table_size_; i < table_size; ++i) { - new_table[i] = STORAGE_INVALID_NODE_ID; - } - // Unlink the current table. - try { - if (header_->table_storage_node_id != STORAGE_INVALID_NODE_ID) { - storage_->unlink_node(header_->table_storage_node_id); - } - } catch (...) { - storage_->unlink_node(table_node.id()); - throw; - } - // Update pointers and the header. - table_ = new_table; - // TODO: Old table caches should be kept. - pages_.swap(new_pages); - header_->table_size = table_size_ = table_size; - header_->table_storage_node_id = table_node.id(); -} - -void *PagedArrayImpl::reserve_page(uint64_t page_id) { - Lock lock(&header_->mutex); - if (pages_[page_id] != invalid_page_address()) { - // Nothing to do. - return pages_[page_id]; - } - update_table(); - StorageNode page_node; - if (table_[page_id] != STORAGE_INVALID_NODE_ID) { - // Open an existing page. - page_node = storage_->open_node(table_[page_id]); - } else { - // Create a new page. - page_node = storage_->create_node(header_->table_storage_node_id, - header_->value_size * page_size_); - table_[page_id] = page_node.id(); - } - pages_[page_id] = static_cast<char *>(page_node.body()) - - (header_->value_size * page_size_ * page_id); - return pages_[page_id]; -} - -void PagedArrayImpl::update_table() { - if (table_size_ == header_->table_size) { - // Nothing to do. - return; - } - StorageNode table_node = storage_->open_node(header_->table_storage_node_id); - std::unique_ptr<void *[]> new_pages( - new (std::nothrow) void *[header_->table_size]); - if (!new_pages) { - GRNXX_ERROR() << "new void *[] failed: size = " << header_->table_size; - throw MemoryError(); - } - for (uint64_t i = 0; i < table_size_; ++i) { - new_pages[i] = pages_[i]; - } - for (uint64_t i = table_size_; i < header_->table_size; ++i) { - new_pages[i] = invalid_page_address(); - } - table_ = static_cast<uint32_t *>(table_node.body()); - // TODO: Old table caches should be kept. - pages_.swap(new_pages); - table_size_ = header_->table_size; -} - -void PagedArrayImpl::swap(PagedArrayImpl &rhs) { - std::swap(storage_, rhs.storage_); - std::swap(storage_node_id_, rhs.storage_node_id_); - std::swap(size_, rhs.size_); - std::swap(page_size_, rhs.page_size_); - std::swap(page_shift_, rhs.page_shift_); - std::swap(page_mask_, rhs.page_mask_); - std::swap(table_size_, rhs.table_size_); - std::swap(pages_, rhs.pages_); - std::swap(table_, rhs.table_); - std::swap(header_, rhs.header_); - std::swap(default_value_, rhs.default_value_); - std::swap(fill_page_, rhs.fill_page_); -} - -//void Array<bool>::create(Storage *storage, uint32_t storage_node_id, -// uint64_t size) { -// if ((size % UNIT_SIZE) != 0) { -// const uint64_t revised_size = size + UNIT_SIZE - (size % UNIT_SIZE); -// GRNXX_WARNING() << "size must be a multiple of UNIT_SIZE: size = " << size -// << ", revised_size = " << revised_size -// << ", UNIT_SIZE = " << UNIT_SIZE; -// size = revised_size; -// } -// impl_.create(storage, storage_node_id, size / UNIT_SIZE); -// size_ = size; -//} - -//void Array<bool>::create(Storage *storage, uint32_t storage_node_id, -// uint64_t size, ValueArg default_value) { -// if ((size % UNIT_SIZE) != 0) { -// const uint64_t revised_size = size + UNIT_SIZE - (size % UNIT_SIZE); -// GRNXX_WARNING() << "size must be a multiple of UNIT_SIZE: size = " << size -// << ", revised_size = " << revised_size -// << ", UNIT_SIZE = " << UNIT_SIZE; -// size = revised_size; -// } -// impl_.create(storage, storage_node_id, size / UNIT_SIZE, -// default_value ? ~Unit(0) : Unit(0)); -// size_ = size; -//} - -} // namespace alpha -} // namespace grnxx Deleted: obsolete/lib/grnxx/alpha/paged_array.hpp (+0 -200) 100644 =================================================================== --- obsolete/lib/grnxx/alpha/paged_array.hpp 2013-08-23 10:46:34 +0900 (4b5457a) +++ /dev/null @@ -1,200 +0,0 @@ -/* - Copyright (C) 2012-2013 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_ALPHA_PAGED_ARRAY_HPP -#define GRNXX_ALPHA_PAGED_ARRAY_HPP - -#include "grnxx/features.hpp" - -#include <memory> - -#include "grnxx/traits.hpp" -#include "grnxx/types.hpp" - -namespace grnxx { - -class Storage; - -namespace alpha { - -struct PagedArrayHeader; - -class PagedArrayImpl { - using FillPage = void (*)(void *page, const void *value, uint64_t page_size); - - public: - PagedArrayImpl(); - ~PagedArrayImpl(); - - // Return true iff "*this" is initialized. - explicit operator bool() const { - return storage_ != nullptr; - } - - // Create an array and fill it with "value". - void create(Storage *storage, uint32_t storage_node_id, - uint64_t value_size, uint64_t size, uint64_t page_size, - const void *default_value = nullptr, - FillPage fill_page = nullptr); - // Open an array. - void open(Storage *storage, uint32_t storage_node_id, - uint64_t value_size, FillPage fill_page = nullptr); - - // Unlink an array. - static bool unlink(Storage *storage, uint32_t storage_node_id, - uint64_t value_size); - - // Return the storage node ID. - uint32_t storage_node_id() const { - return storage_node_id_; - } - // Return the size. - uint64_t size() const { - return size_; - } - // Return the page size. - uint64_t page_size() const { - return page_size_; - } - - // Return a reference to a value. - template <typename T> - T &get_reference(uint64_t value_id) { - const uint64_t page_id = value_id >> page_shift_; - if (page_id >= table_size_) { - resize_table(page_id + 1); - } - void *page = pages_[page_id]; - if (page == invalid_page_address()) { - page = reserve_page(page_id); - } - return static_cast<T *>(page)[value_id]; - } - - private: - Storage *storage_; - uint32_t storage_node_id_; - uint64_t size_; - uint64_t page_size_; - uint64_t page_shift_; - uint64_t page_mask_; - uint64_t table_size_; - std::unique_ptr<void *[]> pages_; - uint32_t *table_; - PagedArrayHeader *header_; - const void *default_value_; - FillPage fill_page_; - - void create_array(Storage *storage, uint32_t storage_node_id, - uint64_t value_size, uint64_t size, uint64_t page_size, - const void *default_value, FillPage fill_page); - void open_array(Storage *storage, uint32_t storage_node_id, - uint64_t value_size, FillPage fill_page); - - void resize_table(uint64_t table_size); - void *reserve_page(uint64_t page_id); - void update_table(); - - static void *invalid_page_address() { - return reinterpret_cast<void *>(~uintptr_t(0)); - } - - void swap(PagedArrayImpl &rhs); -}; - -template <typename T> -class PagedArray { - public: - using Value = typename Traits<T>::Type; - using ValueArg = typename Traits<T>::ArgumentType; - - PagedArray() : impl_() {} - ~PagedArray() {} - - // Return true iff "*this" is initialized. - explicit operator bool() const { - return bool(impl_); - } - - // Create an array. - void create(Storage *storage, uint32_t storage_node_id, - uint64_t size, uint64_t page_size) { - impl_.create(storage, storage_node_id, sizeof(Value), size, page_size); - } - // Create an array and fill it with "value". - void create(Storage *storage, uint32_t storage_node_id, - uint64_t size, uint64_t page_size, ValueArg default_value) { - impl_.create(storage, storage_node_id, sizeof(Value), size, page_size, - &default_value, fill_page); - } - // Open an array. - void open(Storage *storage, uint32_t storage_node_id) { - impl_.open(storage, storage_node_id, sizeof(Value)); - } - - // Unlink an array. - static bool unlink(Storage *storage, uint32_t storage_node_id) { - return PagedArrayImpl::unlink(storage, storage_node_id, sizeof(Value)); - } - - // Return the storage node ID. - uint32_t storage_node_id() const { - return impl_.storage_node_id(); - } - // Return the size. - uint64_t size() const { - return impl_.size(); - } - // Return the page size. - uint64_t page_size() const { - return impl_.page_size(); - } - - // Return a reference to a value. - Value &operator[](uint64_t value_id) { - return get_reference(value_id); - } - - // Return a value. - Value get(uint64_t value_id) { - return get_reference(value_id); - } - // Set a value. - void set(uint64_t value_id, ValueArg value) { - get_reference(value_id) = value; - } - - private: - PagedArrayImpl impl_; - - // Return a reference to a value. - Value &get_reference(uint64_t value_id) { - return impl_.get_reference<Value>(value_id); - } - - // This function is used to fill a new page with the default value. - static void fill_page(void *page, const void *value, uint64_t page_size) { - for (uint64_t i = 0; i < page_size; ++i) { - static_cast<Value *>(page)[i] = *static_cast<const Value *>(value); - } - } -}; - -} // namespace alpha -} // namespace grnxx - -#endif // GRNXX_PAGED_ARRAY_HPP Deleted: obsolete/lib/grnxx/basic.hpp (+0 -59) 100644 =================================================================== --- obsolete/lib/grnxx/basic.hpp 2013-08-23 10:46:34 +0900 (251120f) +++ /dev/null @@ -1,59 +0,0 @@ -/* - Copyright (C) 2012 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_BASIC_HPP -#define GRNXX_BASIC_HPP - -#include "grnxx/features.hpp" - -#include <cstdint> -#include <cstdio> -#include <cstring> -#include <exception> -#include <iosfwd> -#include <limits> -#include <memory> -#include <new> -#include <type_traits> -#include <utility> - -namespace grnxx { - -using std::size_t; - -using std::int8_t; -using std::int16_t; -using std::int32_t; -using std::int64_t; - -using std::uint8_t; -using std::uint16_t; -using std::uint32_t; -using std::uint64_t; - -using std::intptr_t; -using std::uintptr_t; - -// TODO: This should use std::is_pod. However, gcc-4.7 uses the C++03 concept. -#define GRNXX_ASSERT_POD(type)\ - static_assert(std::is_trivial<type>::value &&\ - std::is_standard_layout<type>::value,\ - #type " is not a POD type") - -} // namespace grnxx - -#endif // GRNXX_BASIC_HPP Deleted: obsolete/lib/grnxx/db/Makefile.am (+0 -12) 100644 =================================================================== --- obsolete/lib/grnxx/db/Makefile.am 2013-08-23 10:46:34 +0900 (822d206) +++ /dev/null @@ -1,12 +0,0 @@ -noinst_LTLIBRARIES = libgrnxx_db.la - -libgrnxx_db_la_LDFLAGS = @AM_LTLDFLAGS@ - -libgrnxx_db_la_SOURCES = \ - blob_vector.cpp \ - vector.cpp - -libgrnxx_db_includedir = ${includedir}/grnxx/db -libgrnxx_db_include_HEADERS = \ - blob_vector.hpp \ - vector.hpp Deleted: obsolete/lib/grnxx/db/blob_vector.cpp (+0 -491) 100644 =================================================================== --- obsolete/lib/grnxx/db/blob_vector.cpp 2013-08-23 10:46:34 +0900 (a9ec58e) +++ /dev/null @@ -1,491 +0,0 @@ -/* - Copyright (C) 2012 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/db/blob_vector.hpp" - -#include "grnxx/exception.hpp" -#include "grnxx/lock.hpp" -#include "grnxx/logger.hpp" - -namespace grnxx { -namespace db { - -BlobVectorCreate BLOB_VECTOR_CREATE; -BlobVectorOpen BLOB_VECTOR_OPEN; - -BlobVectorHeader::BlobVectorHeader(uint32_t table_block_id) - : table_block_id_(table_block_id), - value_store_block_id_(io::BLOCK_INVALID_ID), - index_store_block_id_(io::BLOCK_INVALID_ID), - next_page_id_(0), - next_value_offset_(0), - latest_frozen_page_id_(BLOB_VECTOR_INVALID_PAGE_ID), - latest_large_value_block_id_(io::BLOCK_INVALID_ID), - inter_process_mutex_(MUTEX_UNLOCKED) {} - -StringBuilder &BlobVectorHeader::write_to(StringBuilder &builder) const { - if (!builder) { - return builder; - } - - builder << "{ table_block_id = " << table_block_id_ - << ", value_store_block_id = " << value_store_block_id_ - << ", index_store_block_id = " << index_store_block_id_ - << ", next_page_id = " << next_page_id_ - << ", next_value_offset = " << next_value_offset_ - << ", latest_large_value_block_id = " << latest_large_value_block_id_ - << ", inter_process_mutex = " << inter_process_mutex_; - return builder << " }"; -} - -std::unique_ptr<BlobVectorImpl> BlobVectorImpl::create(io::Pool pool) { - std::unique_ptr<BlobVectorImpl> vector(new (std::nothrow) BlobVectorImpl); - if (!vector) { - GRNXX_ERROR() << "new grnxx::db::BlobVectorImpl failed"; - GRNXX_THROW(); - } - vector->create_vector(pool); - return vector; -} - -std::unique_ptr<BlobVectorImpl> BlobVectorImpl::open(io::Pool pool, - uint32_t block_id) { - std::unique_ptr<BlobVectorImpl> vector(new (std::nothrow) BlobVectorImpl); - if (!vector) { - GRNXX_ERROR() << "new grnxx::db::BlobVectorImpl failed"; - GRNXX_THROW(); - } - vector->open_vector(pool, block_id); - return vector; -} - -void BlobVectorImpl::set_value(uint64_t id, const Blob &value) { - const BlobVectorCell new_cell = create_value(value); - BlobVectorCell old_cell; - try { - do { - old_cell = table_[id]; - } while (!atomic_compare_and_swap(old_cell, new_cell, &table_[id])); - } catch (...) { - // The new value is freed on failure. - free_value(new_cell); - throw; - } - // The old value is freed on success. - free_value(old_cell); -} - -void BlobVectorImpl::append(uint64_t id, const Blob &value) { - if (!value || (value.length() == 0)) { - return; - } - - for ( ; ; ) { - const BlobVectorCell old_cell = table_[id]; - const Blob old_value = get_value(old_cell); - const BlobVectorCell new_cell = join_values(old_value, value); - if (atomic_compare_and_swap(old_cell, new_cell, &table_[id])) { - // The old value is freed on success. - free_value(old_cell); - break; - } else { - // The new value is freed on failure. - free_value(new_cell); - } - } -} - -void BlobVectorImpl::prepend(uint64_t id, const Blob &value) { - if (!value || (value.length() == 0)) { - return; - } - - for ( ; ; ) { - const BlobVectorCell old_cell = table_[id]; - const Blob old_value = get_value(old_cell); - const BlobVectorCell new_cell = join_values(value, old_value); - if (atomic_compare_and_swap(old_cell, new_cell, &table_[id])) { - // The old value is freed on success. - free_value(old_cell); - break; - } else { - // The new value is freed on failure. - free_value(new_cell); - } - } -} - -void BlobVectorImpl::defrag() { - // TODO: To be more efficient. - table_.scan([this](uint64_t, BlobVectorCell *cell) -> bool { - if (cell->type() != BLOB_VECTOR_MEDIUM) { - return true; - } - - const BlobVectorCell old_cell = *cell; - const BlobVectorCell new_cell = create_value(get_value(old_cell)); - if (atomic_compare_and_swap(old_cell, new_cell, cell)) { - free_value(old_cell); - } else { - free_value(new_cell); - } - return true; - }); -} - -StringBuilder &BlobVectorImpl::write_to(StringBuilder &builder) const { - if (!builder) { - return builder; - } - - builder << "{ pool = " << pool_.path() - << ", block_info = " << *block_info_ - << ", header = " << *header_ - << ", inter_thread_mutex = " << inter_thread_mutex_; - return builder << " }"; -} - -void BlobVectorImpl::unlink(io::Pool pool, uint32_t block_id) { - std::unique_ptr<BlobVectorImpl> vector = - BlobVectorImpl::open(pool, block_id); - - if (vector->header_->latest_large_value_block_id() != io::BLOCK_INVALID_ID) { - uint32_t block_id = vector->header_->latest_large_value_block_id(); - do { - auto value_header = static_cast<const BlobVectorValueHeader *>( - pool.get_block_address(block_id)); - const uint32_t prev_block_id = value_header->prev_value_block_id(); - pool.free_block(block_id); - block_id = prev_block_id; - } while (block_id != vector->header_->latest_large_value_block_id()); - } - BlobVectorTable::unlink(pool, vector->header_->table_block_id()); - pool.free_block(vector->block_info_->id()); -} - -BlobVectorImpl::BlobVectorImpl() - : pool_(), - block_info_(nullptr), - header_(nullptr), - recycler_(nullptr), - table_(), - value_store_(), - index_store_(), - inter_thread_mutex_(MUTEX_UNLOCKED) {} - -void BlobVectorImpl::create_vector(io::Pool pool) { - pool_ = pool; - block_info_ = pool.create_block(sizeof(BlobVectorHeader)); - - try { - table_.create(pool_, BlobVectorCell::null_value()); - } catch (...) { - pool_.free_block(*block_info_); - throw; - } - - void * const block_address = pool_.get_block_address(*block_info_); - header_ = static_cast<BlobVectorHeader *>(block_address); - *header_ = BlobVectorHeader(table_.block_id()); - - recycler_ = pool.mutable_recycler(); -} - -void BlobVectorImpl::open_vector(io::Pool pool, uint32_t block_id) { - pool_ = pool; - block_info_ = pool.get_block_info(block_id); - if (block_info_->size() < sizeof(BlobVectorHeader)) { - GRNXX_ERROR() << "invalid argument: block_info = " << *block_info_ - << ", header_size = " << sizeof(BlobVectorHeader); - GRNXX_THROW(); - } - - void * const block_address = pool_.get_block_address(*block_info_); - header_ = static_cast<BlobVectorHeader *>(block_address); - - // TODO: Check the format! - - recycler_ = pool.mutable_recycler(); - - // Open the core table. - table_.open(pool, header_->table_block_id()); -} - -Blob BlobVectorImpl::get_value(BlobVectorCell cell) { - switch (cell.type()) { - case BLOB_VECTOR_NULL: { - return Blob(nullptr); - } - case BLOB_VECTOR_SMALL: { - return Blob(cell); - } - case BLOB_VECTOR_MEDIUM: { - if (!value_store_) { - Lock lock(mutable_inter_thread_mutex()); - if (!value_store_) { - value_store_.open(pool_, header_->value_store_block_id()); - } - } - return Blob(&value_store_[cell.offset()], cell.medium_length()); - } - case BLOB_VECTOR_LARGE: { - const auto value_header = static_cast<const BlobVectorValueHeader *>( - pool_.get_block_address(cell.block_id())); - return Blob(value_header + 1, value_header->length()); - } - default: { - GRNXX_ERROR() << "invalid value type"; - GRNXX_THROW(); - } - } -} - -BlobVectorCell BlobVectorImpl::create_value(const Blob &value) { - if (!value) { - return BlobVectorCell::null_value(); - } - - BlobVectorCell cell; - void *address; - if (value.length() < BLOB_VECTOR_MEDIUM_VALUE_MIN_LENGTH) { - address = create_small_value(value.length(), &cell); - } else if (value.length() < BLOB_VECTOR_LARGE_VALUE_MIN_LENGTH) { - address = create_medium_value(value.length(), &cell); - } else { - address = create_large_value(value.length(), &cell); - } - std::memcpy(address, value.address(), value.length()); - return cell; -} - -BlobVectorCell BlobVectorImpl::join_values(const Blob &lhs, const Blob &rhs) { - const uint64_t length = lhs.length() + rhs.length(); - BlobVectorCell cell; - void *address; - if (length < BLOB_VECTOR_MEDIUM_VALUE_MIN_LENGTH) { - address = create_small_value(length, &cell); - } else if (length < BLOB_VECTOR_LARGE_VALUE_MIN_LENGTH) { - address = create_medium_value(length, &cell); - } else { - address = create_large_value(length, &cell); - } - std::memcpy(address, lhs.address(), lhs.length()); - std::memcpy(static_cast<char *>(address) + lhs.length(), - rhs.address(), rhs.length()); - return cell; -} - -void *BlobVectorImpl::create_small_value(uint64_t length, - BlobVectorCell *cell) { - *cell = BlobVectorCell::small_value(length); - return cell->value(); -} - -void *BlobVectorImpl::create_medium_value(uint64_t length, - BlobVectorCell *cell) { - Lock lock(mutable_inter_thread_mutex()); - - if (!value_store_) { - if (header_->value_store_block_id() == io::BLOCK_INVALID_ID) { - Lock lock(mutable_inter_process_mutex()); - if (header_->value_store_block_id() == io::BLOCK_INVALID_ID) { - value_store_.create(pool_); - header_->set_value_store_block_id(value_store_.block_id()); - } - } - if (!value_store_) { - value_store_.open(pool_, header_->value_store_block_id()); - } - } - - if (!index_store_) { - if (header_->index_store_block_id() == io::BLOCK_INVALID_ID) { - Lock lock(mutable_inter_process_mutex()); - if (header_->index_store_block_id() == io::BLOCK_INVALID_ID) { - index_store_.create(pool_, BlobVectorPageInfo()); - header_->set_index_store_block_id(index_store_.block_id()); - } - } - if (!index_store_) { - index_store_.open(pool_, header_->index_store_block_id()); - } - } - - // Unfreeze the oldest frozen page for reuse. - unfreeze_oldest_frozen_page(); - - uint64_t offset = header_->next_value_offset(); - const uint64_t offset_in_page = - ((offset - 1) & (BLOB_VECTOR_VALUE_STORE_PAGE_SIZE - 1)) + 1; - const uint64_t size_left_in_page = - BLOB_VECTOR_VALUE_STORE_PAGE_SIZE - offset_in_page; - - // Reserve a new page if there is not enough space in the current page. - if (length > size_left_in_page) { - if (offset != 0) { - // Freeze the current page if it is empty. - const uint32_t page_id = static_cast<uint32_t>( - (offset - 1) >> BLOB_VECTOR_VALUE_STORE_PAGE_SIZE_BITS); - if (index_store_[page_id].num_values() == 0) { - freeze_page(page_id); - } - } - - const uint32_t page_id = header_->next_page_id(); - offset = static_cast<uint64_t>( - page_id << BLOB_VECTOR_VALUE_STORE_PAGE_SIZE_BITS); - if (index_store_[page_id].next_page_id() != BLOB_VECTOR_INVALID_PAGE_ID) { - header_->set_next_page_id(index_store_[page_id].next_page_id()); - } else { - header_->set_next_page_id(page_id + 1); - } - index_store_[page_id].set_num_values(0); - } - header_->set_next_value_offset(offset + length); - - const uint32_t page_id = static_cast<uint32_t>( - offset >> BLOB_VECTOR_VALUE_STORE_PAGE_SIZE_BITS); - index_store_[page_id].set_num_values(index_store_[page_id].num_values() + 1); - - *cell = BlobVectorCell::medium_value(offset, length); - return &value_store_[offset]; -} - -void *BlobVectorImpl::create_large_value(uint64_t length, - BlobVectorCell *cell) { - const io::BlockInfo *block_info = - pool_.create_block(sizeof(BlobVectorValueHeader) + length); - auto value_header = static_cast<BlobVectorValueHeader *>( - pool_.get_block_address(*block_info)); - value_header->set_length(length); - register_large_value(block_info->id(), value_header); - *cell = BlobVectorCell::large_value(block_info->id()); - return value_header + 1; -} - -void BlobVectorImpl::free_value(BlobVectorCell cell) { - switch (cell.type()) { - case BLOB_VECTOR_NULL: - case BLOB_VECTOR_SMALL: { - break; - } - case BLOB_VECTOR_MEDIUM: { - Lock lock(mutable_inter_thread_mutex()); - - if (!index_store_) { - index_store_.open(pool_, header_->index_store_block_id()); - } - - const uint32_t page_id = static_cast<uint32_t>( - cell.offset() >> BLOB_VECTOR_VALUE_STORE_PAGE_SIZE_BITS); - index_store_[page_id].set_num_values( - index_store_[page_id].num_values() - 1); - if (index_store_[page_id].num_values() == 0) { - const uint32_t current_page_id = - static_cast<uint32_t>(header_->next_value_offset() - >> BLOB_VECTOR_VALUE_STORE_PAGE_SIZE_BITS); - if (page_id != current_page_id) { - freeze_page(page_id); - } - } - break; - } - case BLOB_VECTOR_LARGE: { - const io::BlockInfo * const block_info = - pool_.get_block_info(cell.block_id()); - unregister_large_value(block_info->id(), - static_cast<BlobVectorValueHeader *>( - pool_.get_block_address(*block_info))); - pool_.free_block(*block_info); - break; - } - } -} - -void BlobVectorImpl::register_large_value(uint32_t block_id, - BlobVectorValueHeader *value_header) { - Lock lock(mutable_inter_process_mutex()); - if (header_->latest_large_value_block_id() == io::BLOCK_INVALID_ID) { - value_header->set_next_value_block_id(block_id); - value_header->set_prev_value_block_id(block_id); - } else { - const uint32_t prev_id = header_->latest_large_value_block_id(); - auto prev_header = static_cast<BlobVectorValueHeader *>( - pool_.get_block_address(prev_id)); - const uint32_t next_id = prev_header->next_value_block_id(); - auto next_header = static_cast<BlobVectorValueHeader *>( - pool_.get_block_address(next_id)); - value_header->set_next_value_block_id(next_id); - value_header->set_prev_value_block_id(prev_id); - prev_header->set_next_value_block_id(block_id); - next_header->set_prev_value_block_id(block_id); - } - header_->set_latest_large_value_block_id(block_id); -} - -void BlobVectorImpl::unregister_large_value(uint32_t block_id, - BlobVectorValueHeader *value_header) { - Lock lock(mutable_inter_process_mutex()); - const uint32_t next_id = value_header->next_value_block_id(); - const uint32_t prev_id = value_header->prev_value_block_id(); - auto next_header = static_cast<BlobVectorValueHeader *>( - pool_.get_block_address(next_id)); - auto prev_header = static_cast<BlobVectorValueHeader *>( - pool_.get_block_address(prev_id)); - next_header->set_prev_value_block_id(prev_id); - prev_header->set_next_value_block_id(next_id); - if (block_id == header_->latest_large_value_block_id()) { - header_->set_latest_large_value_block_id(prev_id); - } -} - -void BlobVectorImpl::freeze_page(uint32_t page_id) { - BlobVectorPageInfo &page_info = index_store_[page_id]; - if (header_->latest_frozen_page_id() != BLOB_VECTOR_INVALID_PAGE_ID) { - BlobVectorPageInfo &latest_frozen_page_info = - index_store_[header_->latest_frozen_page_id()]; - page_info.set_next_page_id(latest_frozen_page_info.next_page_id()); - latest_frozen_page_info.set_next_page_id(page_id); - } else { - page_info.set_next_page_id(page_id); - } - page_info.set_stamp(recycler_->stamp()); - header_->set_latest_frozen_page_id(page_id); -} - -void BlobVectorImpl::unfreeze_oldest_frozen_page() { - if (header_->latest_frozen_page_id() != BLOB_VECTOR_INVALID_PAGE_ID) { - BlobVectorPageInfo &latest_frozen_page_info = - index_store_[header_->latest_frozen_page_id()]; - const uint32_t oldest_frozen_page_id = - latest_frozen_page_info.next_page_id(); - BlobVectorPageInfo &oldest_frozen_page_info = - index_store_[oldest_frozen_page_id]; - if (recycler_->check(oldest_frozen_page_info.stamp())) { - latest_frozen_page_info.set_next_page_id( - oldest_frozen_page_info.next_page_id()); - oldest_frozen_page_info.set_next_page_id(header_->next_page_id()); - header_->set_next_page_id(oldest_frozen_page_id); - if (oldest_frozen_page_id == header_->latest_frozen_page_id()) { - header_->set_latest_frozen_page_id(BLOB_VECTOR_INVALID_PAGE_ID); - } - } - } -} - -} // namespace db -} // namespace grnxx Deleted: obsolete/lib/grnxx/db/blob_vector.hpp (+0 -574) 100644 =================================================================== --- obsolete/lib/grnxx/db/blob_vector.hpp 2013-08-23 10:46:34 +0900 (d25a8a2) +++ /dev/null @@ -1,574 +0,0 @@ -/* - Copyright (C) 2012 Brazil, Inc. - - 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-1301 USA -*/ -#ifndef GRNXX_DB_BLOB_VECTOR_HPP -#define GRNXX_DB_BLOB_VECTOR_HPP - -#include "grnxx/db/vector.hpp" -#include "grnxx/string_builder.hpp" - -namespace grnxx { -namespace db { - -constexpr uint64_t BLOB_VECTOR_MAX_ID = (uint64_t(1) << 40) - 1; - -constexpr uint32_t BLOB_VECTOR_INVALID_PAGE_ID = 0xFFFFFFFFU; - -constexpr uint64_t BLOB_VECTOR_SMALL_VALUE_MAX_LENGTH = 7; - -constexpr uint64_t BLOB_VECTOR_MEDIUM_VALUE_MIN_LENGTH = - BLOB_VECTOR_SMALL_VALUE_MAX_LENGTH + 1; -constexpr uint64_t BLOB_VECTOR_MEDIUM_VALUE_MAX_LENGTH = 65535; - -constexpr uint64_t BLOB_VECTOR_LARGE_VALUE_MIN_LENGTH = - BLOB_VECTOR_MEDIUM_VALUE_MAX_LENGTH + 1; - -constexpr uint8_t BLOB_VECTOR_UNIT_SIZE_BITS = 3; -constexpr uint64_t BLOB_VECTOR_UNIT_SIZE = - uint64_t(1) << BLOB_VECTOR_UNIT_SIZE_BITS; - -constexpr uint8_t BLOB_VECTOR_VALUE_STORE_PAGE_SIZE_BITS = 19; -constexpr uint8_t BLOB_VECTOR_VALUE_STORE_TABLE_SIZE_BITS = 12; -constexpr uint8_t BLOB_VECTOR_VALUE_STORE_SECONDARY_TABLE_SIZE_BITS = 16; - -constexpr uint64_t BLOB_VECTOR_VALUE_STORE_PAGE_SIZE = - uint64_t(1) << BLOB_VECTOR_VALUE_STORE_PAGE_SIZE_BITS; -constexpr uint64_t BLOB_VECTOR_VALUE_STORE_TABLE_SIZE = - uint64_t(1) << BLOB_VECTOR_VALUE_STORE_TABLE_SIZE_BITS; -constexpr uint64_t BLOB_VECTOR_VALUE_STORE_SECONDARY_TABLE_SIZE = - uint64_t(1) << BLOB_VECTOR_VALUE_STORE_SECONDARY_TABLE_SIZE_BITS; - -extern class BlobVectorCreate {} BLOB_VECTOR_CREATE; -extern class BlobVectorOpen {} BLOB_VECTOR_OPEN; - -class BlobVectorHeader { - public: - explicit BlobVectorHeader(uint32_t table_block_id); - - uint32_t table_block_id() const { - return table_block_id_; - } - uint32_t value_store_block_id() const { - return value_store_block_id_; - } - uint32_t index_store_block_id() const { - return index_store_block_id_; - } - uint32_t next_page_id() const { - return next_page_id_; - } - uint64_t next_value_offset() const { - return next_value_offset_; - } - uint32_t latest_frozen_page_id() const { - return latest_frozen_page_id_; - } - uint32_t latest_large_value_block_id() const { - return latest_large_value_block_id_; - } - - void set_value_store_block_id(uint32_t value) { - value_store_block_id_ = value; - } - void set_index_store_block_id(uint32_t value) { - index_store_block_id_ = value; - } - void set_next_page_id(uint32_t value) { - next_page_id_ = value; - } - void set_next_value_offset(uint64_t value) { - next_value_offset_ = value; - } - void set_latest_frozen_page_id(uint32_t value) { - latest_frozen_page_id_ = value; - } - void set_latest_large_value_block_id(uint32_t value) { - latest_large_value_block_id_ = value; - } - - Mutex *mutable_inter_process_mutex() { - return &inter_process_mutex_; - } - - StringBuilder &write_to(StringBuilder &builder) const; - - private: - uint32_t table_block_id_; - uint32_t value_store_block_id_; - uint32_t index_store_block_id_; - uint32_t next_page_id_; - uint64_t next_value_offset_; - uint32_t latest_frozen_page_id_; - uint32_t latest_large_value_block_id_; - Mutex inter_process_mutex_; -}; - -inline StringBuilder &operator<<(StringBuilder &builder, - const BlobVectorHeader &header) { - return header.write_to(builder); -} - -enum BlobVectorValueType : uint8_t { - BLOB_VECTOR_NULL = 0x00, - BLOB_VECTOR_SMALL = 0x10, - BLOB_VECTOR_MEDIUM = 0x20, - BLOB_VECTOR_LARGE = 0x30 -}; - -constexpr uint8_t BLOB_VECTOR_TYPE_MASK = 0x30; - -class BlobVectorPageInfo { - public: - BlobVectorPageInfo() - : next_page_id_(BLOB_VECTOR_INVALID_PAGE_ID), stamp_(0), reserved_(0) {} - - uint32_t next_page_id() const { - return next_page_id_; - } - uint32_t num_values() const { - return num_values_; - } - uint16_t stamp() const { - return reserved_; - } - - void set_next_page_id(uint32_t value) { - next_page_id_ = value; - } - void set_num_values(uint32_t value) { - num_values_ = value; - } - void set_stamp(uint16_t value) { - stamp_ = value; - } - - private: - union { - uint32_t next_page_id_; - uint32_t num_values_; - }; - uint16_t stamp_; - uint16_t reserved_; -}; - -class BlobVectorValueHeader { - public: - uint64_t length() const { - return length_; - } - uint32_t next_value_block_id() const { - return next_value_block_id_; - } - uint32_t prev_value_block_id() const { - return prev_value_block_id_; - } - - void set_length(uint64_t value) { - length_ = value; - } - void set_next_value_block_id(uint32_t value) { - next_value_block_id_ = value; - } - void set_prev_value_block_id(uint32_t value) { - prev_value_block_id_ = value; - } - - private: - uint64_t length_; - uint32_t next_value_block_id_; - uint32_t prev_value_block_id_; -}; - -const uint8_t BLOB_VECTOR_CELL_FLAGS_MASK = 0xF0; - -class BlobVectorCell { - public: - BlobVectorCell() = default; - explicit BlobVectorCell(std::nullptr_t) : qword_(0) {} - - static BlobVectorCell null_value() { - return BlobVectorCell(nullptr); - } - static BlobVectorCell small_value(uint64_t length) { - BlobVectorCell cell(nullptr); - cell.bytes_[0] = BLOB_VECTOR_SMALL | static_cast<uint8_t>(length); - return cell; - } - static BlobVectorCell medium_value(uint64_t offset, uint64_t length) { - BlobVectorCell cell; - cell.bytes_[0] = BLOB_VECTOR_MEDIUM | static_cast<uint8_t>(offset >> 40); - cell.bytes_[1] = static_cast<uint8_t>(offset >> 32); - cell.words_[1] = static_cast<uint16_t>(length); - cell.dwords_[1] = static_cast<uint32_t>(offset); - return cell; - } - static BlobVectorCell large_value(uint32_t block_id) { - BlobVectorCell cell(nullptr); - cell.bytes_[0] = BLOB_VECTOR_LARGE; - cell.dwords_[1] = block_id; - return cell; - } - - BlobVectorValueType type() const { - Flags flags; - flags.byte = flags_.byte & BLOB_VECTOR_TYPE_MASK; - return flags.type; - } - - // Accessors to small values. - uint64_t small_length() const { - return bytes_[0] & ~BLOB_VECTOR_CELL_FLAGS_MASK; - } - const void *value() const { - return &bytes_[1]; - } - void *value() { - return &bytes_[1]; - } - - // Accessors to medium values. - uint64_t medium_length() const { - return words_[1]; - } - uint64_t offset() const { - return (static_cast<uint64_t>(bytes_[0] & - ~BLOB_VECTOR_CELL_FLAGS_MASK) << 40) | - (static_cast<uint64_t>(bytes_[1]) << 32) | dwords_[1]; - } - - // Accessors to large values. - uint32_t block_id() const { - return dwords_[1]; - } - - private: - union Flags { - uint8_t byte; - BlobVectorValueType type; - }; - - union { - Flags flags_; - uint8_t bytes_[8]; - uint16_t words_[4]; - uint32_t dwords_[2]; - uint64_t qword_; - }; -}; - -static_assert(sizeof(BlobVectorCell) == sizeof(uint64_t), - "sizeof(BlobVectorCell) != sizeof(uint64_t)"); - -class Blob { - public: - Blob() : address_(nullptr), length_(0), cell_() {} - explicit Blob(std::nullptr_t) : address_(nullptr), length_(0), cell_() {} - Blob(const void *address, uint64_t length) - : address_(address), length_(length), cell_() {} - explicit Blob(BlobVectorCell small_value_cell) - : address_(), length_(), cell_(small_value_cell) { - address_ = cell_.value(); - length_ = cell_.small_length(); - } - - // Note: address_ refers to the own value if it is small. - Blob(const Blob &rhs) : address_(), length_(rhs.length_), cell_(rhs.cell_) { - if (rhs.address() == rhs.cell_.value()) { - address_ = cell_.value(); - } else { - address_ = rhs.address_; - } - } - Blob &operator=(const Blob &rhs) { - length_ = rhs.length_; - cell_ = rhs.cell_; - if (rhs.address() == rhs.cell_.value()) { - address_ = cell_.value(); - } else { - address_ = rhs.address_; - } - return *this; - } - - Blob &operator=(std::nullptr_t) { - return *this = Blob(nullptr); - } - - // Return true if address_ != nullptr. - explicit operator bool() const { - return static_cast<bool>(address_); - } - - const void *address() const { - return address_; - } - uint64_t length() const { - return length_; - } - - void set_address(const void *value) { - address_ = value; - } - void set_length(uint64_t value) { - length_ = value; - } - - private: - const void *address_; - uint64_t length_; - BlobVectorCell cell_; -}; - -class BlobVector; - -class BlobRef { - public: - BlobRef(BlobVector *vector, uint64_t id) : vector_(*vector), id_(id) {} - - // This conversion may throw an exception. - operator Blob() const { - return get(); - } - - // Update the current value to NULL. - BlobRef &operator=(std::nullptr_t) { - set(nullptr); - return *this; - } - // Update the current value. - BlobRef &operator=(const Blob &value) { - set(value); - return *this; - } - - // Get the address and the length of the current value. - Blob get() const; - // Update the current value to NULL. - void set(std::nullptr_t) { - set(Blob(nullptr)); - } - // Update the current value. - void set(const Blob &value); - void set(const void *ptr, uint64_t length) { - set(Blob(ptr, length)); - } - - // Append a value to the current value. - void append(const Blob &value); - void append(const void *ptr, uint64_t length) { - append(Blob(ptr, length)); - } - // Prepend a value to the current value. - void prepend(const Blob &value); - void prepend(const void *ptr, uint64_t length) { - prepend(Blob(ptr, length)); - } - - private: - BlobVector &vector_; - uint64_t id_; -}; - -typedef Vector<BlobVectorCell> BlobVectorTable; - -typedef Vector<char, BLOB_VECTOR_VALUE_STORE_PAGE_SIZE, - BLOB_VECTOR_VALUE_STORE_TABLE_SIZE, - BLOB_VECTOR_VALUE_STORE_SECONDARY_TABLE_SIZE> -BlobVectorValueStore; - -typedef Vector<BlobVectorPageInfo, - BLOB_VECTOR_VALUE_STORE_TABLE_SIZE, - BLOB_VECTOR_VALUE_STORE_SECONDARY_TABLE_SIZE> -BlobVectorIndexStore; - -class BlobVectorImpl { - public: - static std::unique_ptr<BlobVectorImpl> create(io::Pool pool); - static std::unique_ptr<BlobVectorImpl> open(io::Pool pool, - uint32_t block_id); - - Blob get_value(uint64_t id) { - return get_value(table_[id]); - } - void set_value(uint64_t id, const Blob &value); - - void append(uint64_t id, const Blob &value); - void prepend(uint64_t id, const Blob &value); - - void defrag(); - - uint32_t block_id() const { - return block_info_->id(); - } - - StringBuilder &write_to(StringBuilder &builder) const; - - static void unlink(io::Pool pool, uint32_t block_id); - - private: - io::Pool pool_; - const io::BlockInfo *block_info_; - BlobVectorHeader *header_; - Recycler *recycler_; - BlobVectorTable table_; - BlobVectorValueStore value_store_; - BlobVectorIndexStore index_store_; - Mutex inter_thread_mutex_; - - BlobVectorImpl(); - - void create_vector(io::Pool pool); - void open_vector(io::Pool pool, uint32_t block_id); - - Blob get_value(BlobVectorCell cell); - - inline BlobVectorCell create_value(const Blob &value); - inline BlobVectorCell join_values(const Blob &lhs, const Blob &rhs); - - inline void *create_small_value(uint64_t length, BlobVectorCell *cell); - inline void *create_medium_value(uint64_t length, BlobVectorCell *cell); - inline void *create_large_value(uint64_t length, BlobVectorCell *cell); - - void free_value(BlobVectorCell cell); - - void register_large_value(uint32_t block_id, - BlobVectorValueHeader *value_header); - void unregister_large_value(uint32_t block_id, - BlobVectorValueHeader *value_header); - - void freeze_page(uint32_t page_id); - void unfreeze_oldest_frozen_page(); - - Mutex *mutable_inter_thread_mutex() { - return &inter_thread_mutex_; - } - Mutex *mutable_inter_process_mutex() { - return header_->mutable_inter_process_mutex(); - } -}; - -inline StringBuilder &operator<<(StringBuilder &builder, - const BlobVectorImpl &vector) { - return vector.write_to(builder); -} - -class BlobVector { - public: - // BLOB_VECTOR_CREATE is available as an instance of BlobVectorCreate. - // BLOB_VECTOR_OPEN is available as an instance of BlobVectorOpen. - BlobVector() = default; - BlobVector(const BlobVectorCreate &, io::Pool pool) - : impl_(BlobVectorImpl::create(pool)) {} - BlobVector(const BlobVectorOpen &, io::Pool pool, uint32_t block_id) - : impl_(BlobVectorImpl::open(pool, block_id)) {} - - explicit operator bool() const { - return static_cast<bool>(impl_); - } - - void create(io::Pool pool) { - *this = BlobVector(BLOB_VECTOR_CREATE, pool); - } - void open(io::Pool pool, uint32_t block_id) { - *this = BlobVector(BLOB_VECTOR_OPEN, pool, block_id); - } - void close() { - *this = BlobVector(); - } - - // Access a value. Return a pseudo reference to a value. - // See also Blob and BlobRef. - BlobRef operator[](uint64_t id) { - return BlobRef(this, id); - } - - // Get/set blob_vector[id]. - Blob get_value(uint64_t id) { - return impl_->get_value(id); - } - void set_value(uint64_t id, const Blob &value) { - impl_->set_value(id, value); - } - - // Append/prepend a value to blob_vector[id]. - void append(uint64_t id, const Blob &value) { - impl_->append(id, value); - } - void prepend(uint64_t id, const Blob &value) { - impl_->prepend(id, value); - } - - // Defrag a blob vector. - void defrag() { - impl_->defrag(); - } - - // The ID of the lead block. - uint32_t block_id() const { - return impl_->block_id(); - } - - void swap(BlobVector &rhs) { - impl_.swap(rhs.impl_); - } - - StringBuilder &write_to(StringBuilder &builder) const { - return impl_ ? impl_->write_to(builder) : (builder << "n/a"); - } - - static constexpr uint64_t max_id() { - return BLOB_VECTOR_MAX_ID; - } - - // Free blocks associated with a blob vector. - static void unlink(io::Pool pool, uint32_t block_id) { - BlobVectorImpl::unlink(pool, block_id); - } - - private: - std::shared_ptr<BlobVectorImpl> impl_; -}; - -inline void swap(BlobVector &lhs, BlobVector &rhs) { - lhs.swap(rhs); -} - -inline StringBuilder &operator<<(StringBuilder &builder, - const BlobVector &vector) { - return vector.write_to(builder); -} - -inline Blob BlobRef::get() const { - return vector_.get_value(id_); -} - -inline void BlobRef::set(const Blob &value) { - vector_.set_value(id_, value); -} - -inline void BlobRef::append(const Blob &value) { - vector_.append(id_, value); -} - -inline void BlobRef::prepend(const Blob &value) { - vector_.prepend(id_, value); -} - -} // namespace db -} // namespace grnxx - -#endif // GRNXX_DB_BLOB_VECTOR_HPP Deleted: obsolete/lib/grnxx/db/vector.cpp (+0 -504) 100644 =================================================================== --- obsolete/lib/grnxx/db/vector.cpp 2013-08-23 10:46:34 +0900 (c373131) +++ /dev/null @@ -1,504 +0,0 @@ -/* - Copyright (C) 2012 Brazil, Inc. - - 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-1301 USA -*/ -#include "grnxx/db/vector.hpp" - -#include <vector> - -#include "grnxx/exception.hpp" -#include "grnxx/lock.hpp" -#include "grnxx/logger.hpp" - -namespace grnxx { -namespace db { - -VectorCreate VECTOR_CREATE; -VectorOpen VECTOR_OPEN; - -VectorHeader::VectorHeader(const void *default_value, - uint64_t value_size, - uint64_t page_size, - uint64_t table_size, - uint64_t secondary_table_size) - : value_size_(value_size), - page_size_(page_size), - table_size_(table_size), - secondary_table_size_(secondary_table_size), - has_default_value_(default_value ? 1 : 0), - first_table_block_id_(io::BLOCK_INVALID_ID), - secondary_table_block_id_(io::BLOCK_INVALID_ID), - inter_process_mutex_(MUTEX_UNLOCKED) {} - -StringBuilder &VectorHeader::write_to(StringBuilder &builder) const { - if (!builder) { - return builder; - } - - builder << "{ value_size = " << value_size_ - << ", page_size = " << page_size_ - << ", table_size = " << table_size_ - << ", secondary_table_size = " << secondary_table_size_ - << ", has_default_value = " << has_default_value_ - << ", first_table_block_id = " << first_table_block_id_ - << ", secondary_table_block_id = " << secondary_table_block_id_ - << ", inter_process_mutex = " << inter_process_mutex_; - return builder << " }"; -} - -std::unique_ptr<VectorImpl> VectorImpl::create(io::Pool pool, - const void *default_value, - uint64_t value_size, - uint64_t page_size, - uint64_t table_size, - uint64_t secondary_table_size, - FillPage fill_page) { - std::unique_ptr<VectorImpl> vector(new (std::nothrow) VectorImpl); - if (!vector) { - GRNXX_ERROR() << "new grnxx::db::VectorImpl failed"; - GRNXX_THROW(); - } - vector->create_vector(pool, default_value, value_size, page_size, table_size, - secondary_table_size, fill_page); - return vector; -} - -std::unique_ptr<VectorImpl> VectorImpl::open(io::Pool pool, - uint32_t block_id, - uint64_t value_size, - uint64_t page_size, - uint64_t table_size, - uint64_t secondary_table_size, - FillPage fill_page) { - std::unique_ptr<VectorImpl> vector(new (std::nothrow) VectorImpl); - if (!vector) { - GRNXX_ERROR() << "new grnxx::db::VectorImpl failed"; - GRNXX_THROW(); - } - vector->open_vector(pool, block_id, value_size, page_size, table_size, - secondary_table_size, fill_page); - return vector; -} - -bool VectorImpl::scan_pages(bool (*callback)(uint64_t page_id, - void *page_address, - void *argument), - void *argument) { - for (uint64_t page_id = 0; page_id < header_->table_size(); ++page_id) { - if (!first_table_cache_[page_id]) { - if (first_table_[page_id] == io::BLOCK_INVALID_ID) { - continue; - } - first_table_cache_[page_id] = - pool_.get_block_address(first_table_[page_id]); - } - if (!callback(page_id, first_table_cache_[page_id], argument)) { - return false; - } - } - - if (header_->secondary_table_block_id() == io::BLOCK_INVALID_ID) { - return true; - } - - if (!tables_cache_) { - if (!secondary_table_cache_) { - if (!secondary_table_) { - secondary_table_ = static_cast<uint32_t *>( - pool_.get_block_address(header_->secondary_table_block_id())); - } - initialize_secondary_table_cache(); - } - initialize_tables_cache(); - } - - for (uint64_t table_id = 0; table_id < header_->secondary_table_size(); - ++table_id) { - std::unique_ptr<void *[]> &table_cache = tables_cache_[table_id]; - if (!table_cache) { - if (secondary_table_[table_id] == io::BLOCK_INVALID_ID) { - continue; - } - secondary_table_cache_[table_id] = static_cast<uint32_t *>( - pool_.get_block_address(secondary_table_[table_id])); - initialize_table_cache(&table_cache); - } - - const uint64_t offset = table_id << table_size_bits_; - for (uint64_t page_id = 0; page_id < header_->table_size(); ++page_id) { - if (!table_cache[page_id]) { - uint32_t * const table = secondary_table_cache_[table_id]; - if (table[page_id] == io::BLOCK_INVALID_ID) { - continue; - } - table_cache[page_id] = pool_.get_block_address(table[page_id]); - } - if (!callback(offset + page_id, table_cache[page_id], argument)) { - return false; - } - } - } - - return true; -} - -StringBuilder &VectorImpl::write_to(StringBuilder &builder) const { - if (!builder) { - return builder; - } - - builder << "{ pool = " << pool_.path() - << ", block_info = " << *block_info_ - << ", header = " << *header_ - << ", max_page_id = " << max_page_id_ - << ", inter_thread_mutex = " << inter_thread_mutex_; - return builder << " }"; -} - -void VectorImpl::unlink(io::Pool pool, - uint32_t block_id, - uint64_t value_size, - uint64_t page_size, - uint64_t table_size, - uint64_t secondary_table_size) try { - std::vector<uint32_t> block_ids; - - { - std::unique_ptr<VectorImpl> vector = VectorImpl::open( - pool, block_id, value_size, - page_size, table_size, secondary_table_size, nullptr); - const VectorHeader * const header = vector->header_; - - block_ids.push_back(block_id); - - block_ids.push_back(header->first_table_block_id()); - for (uint64_t i = 0; i < header->table_size(); ++i) { - if (vector->first_table_[i] != io::BLOCK_INVALID_ID) { - block_ids.push_back(vector->first_table_[i]); - } - } - - if (header->secondary_table_block_id() != io::BLOCK_INVALID_ID) { - block_ids.push_back(header->secondary_table_block_id()); - uint32_t * const secondary_table = static_cast<uint32_t *>( - pool.get_block_address(header->secondary_table_block_id())); - for (uint64_t i = 0; i < header->secondary_table_size(); ++i) { - if (secondary_table[i] != io::BLOCK_INVALID_ID) { - block_ids.push_back(secondary_table[i]); - uint32_t * const table = static_cast<uint32_t *>( - pool.get_block_address(secondary_table[i])); - for (uint64_t j = 0; j < header->table_size(); ++j) { - if (table[j] != io::BLOCK_INVALID_ID) { - block_ids.push_back(table[j]); - } - } - } - } - } - } - - for (size_t i = 0; i < block_ids.size(); ++i) { - pool.free_block(block_ids[i]); - } -} catch (const std::exception &exception) { - GRNXX_ERROR() << exception; - GRNXX_THROW(); -} - -VectorImpl::VectorImpl() - : pool_(), - fill_page_(nullptr), - block_info_(nullptr), - header_(nullptr), - default_value_(nullptr), - table_size_bits_(0), - table_size_mask_(0), - max_page_id_(0), - first_table_(nullptr), - secondary_table_(nullptr), - secondary_table_cache_(), - first_table_cache_(), - tables_cache_(), - inter_thread_mutex_(MUTEX_UNLOCKED) {} - -void VectorImpl::create_vector(io::Pool pool, - const void *default_value, - uint64_t value_size, - uint64_t page_size, - uint64_t table_size, - uint64_t secondary_table_size, - FillPage fill_page) { - pool_ = pool; - - std::unique_ptr<void *[]> first_table_cache( - new (std::nothrow) void *[table_size]); - if (!first_table_cache) { - GRNXX_ERROR() << "new void *[" << table_size << "] failed"; - GRNXX_THROW(); - } - - uint64_t header_block_size = sizeof(VectorHeader); - if (default_value) { - header_block_size += value_size; - } - block_info_ = pool_.create_block(header_block_size); - - const io::BlockInfo *first_table_block_info; - try { - first_table_block_info = pool_.create_block(sizeof(uint32_t) * table_size); - } catch (...) { - pool_.free_block(*block_info_); - throw; - } - - void * const block_address = pool_.get_block_address(*block_info_); - header_ = static_cast<VectorHeader *>(block_address); - *header_ = VectorHeader(default_value, value_size, page_size, table_size, - secondary_table_size); - restore_from_header(); - - if (default_value_) { - std::memcpy(default_value_, default_value, - static_cast<size_t>(value_size)); - fill_page_ = fill_page; - } - - header_->set_first_table_block_id(first_table_block_info->id()); - first_table_ = static_cast<uint32_t *>( - pool_.get_block_address(*first_table_block_info)); - first_table_cache_ = std::move(first_table_cache); - for (uint64_t i = 0; i < header_->table_size(); ++i) { - first_table_[i] = io::BLOCK_INVALID_ID; - first_table_cache_[i] = nullptr; - } -} - -void VectorImpl::open_vector(io::Pool pool, - uint32_t block_id, - uint64_t value_size, - uint64_t page_size, - uint64_t table_size, - uint64_t secondary_table_size, - FillPage fill_page) { - pool_ = pool; - - block_info_ = pool_.get_block_info(block_id); - if (block_info_->size() < sizeof(VectorHeader)) { - GRNXX_ERROR() << "invalid argument: block_info = " << *block_info_ - << ", header_size = " << sizeof(VectorHeader); - GRNXX_THROW(); - } - - void * const block_address = pool_.get_block_address(*block_info_); - header_ = static_cast<VectorHeader *>(block_address); - restore_from_header(); - - if (default_value_) { - const uint64_t header_size = sizeof(VectorHeader) + value_size; - if (block_info_->size() < header_size) { - GRNXX_ERROR() << "invalid argument: block_info = " << *block_info_ - << ", header_size = " << header_size; - GRNXX_THROW(); - } - fill_page_ = fill_page; - } - - if (value_size != header_->value_size()) { - GRNXX_ERROR() << "invalid value size: actual = " << header_->value_size() - << ", expected = " << value_size; - GRNXX_THROW(); - } - if (page_size != header_->page_size()) { - GRNXX_ERROR() << "invalid page size: actual = " << header_->page_size() - << ", expected = " << page_size; - GRNXX_THROW(); - } - if (table_size != header_->table_size()) { - GRNXX_ERROR() << "invalid table size: actual = " << header_->table_size() - << ", expected = " << table_size; - GRNXX_THROW(); - } - if (secondary_table_size != header_->secondary_table_size()) { - GRNXX_ERROR() << "invalid secondary table size: actual = " - << header_->secondary_table_size() - << ", expected = " << secondary_table_size; - GRNXX_THROW(); - } - - first_table_ = static_cast<uint32_t *>( - pool_.get_block_address(header_->first_table_block_id())); - - first_table_cache_.reset(new (std::nothrow) void *[header_->table_size()]); - if (!first_table_cache_) { - GRNXX_ERROR() << "new void *[" << header_->table_size() << "] failed"; - GRNXX_THROW(); - } - for (uint64_t i = 0; i < header_->table_size(); ++i) { - first_table_cache_[i] = nullptr; - } -} - -void VectorImpl::restore_from_header() { - if (header_->has_default_value()) { - default_value_ = header_ + 1; - } - table_size_bits_ = bit_scan_reverse(header_->table_size()); - table_size_mask_ = header_->table_size() - 1; - max_page_id_ = header_->table_size() * header_->secondary_table_size() - 1; -} - -void *VectorImpl::get_page_address_on_failure(uint64_t page_id) { - if (page_id < header_->table_size()) { - if (!first_table_cache_[page_id]) { - if (first_table_[page_id] == io::BLOCK_INVALID_ID) { - initialize_page(&first_table_[page_id]); - } - first_table_cache_[page_id] = - pool_.get_block_address(first_table_[page_id]); - } - return first_table_cache_[page_id]; - } - - if (page_id <= max_page_id_) { - if (!tables_cache_) { - if (!secondary_table_cache_) { - if (!secondary_table_) { - if (header_->secondary_table_block_id() == io::BLOCK_INVALID_ID) { - initialize_secondary_table(); - } - secondary_table_ = static_cast<uint32_t *>( - pool_.get_block_address(header_->secondary_table_block_id())); - } - initialize_secondary_table_cache(); - } - initialize_tables_cache(); - } - - const uint64_t table_id = page_id >> table_size_bits_; - std::unique_ptr<void *[]> &table_cache = tables_cache_[table_id]; - if (!table_cache) { - if (secondary_table_[table_id] == io::BLOCK_INVALID_ID) { - initialize_table(&secondary_table_[table_id]); - } - secondary_table_cache_[table_id] = static_cast<uint32_t *>( - pool_.get_block_address(secondary_table_[table_id])); - initialize_table_cache(&table_cache); - } - - page_id &= table_size_mask_; - if (!table_cache[page_id]) { - uint32_t * const table = secondary_table_cache_[table_id]; - if (table[page_id] == io::BLOCK_INVALID_ID) { - initialize_page(&table[page_id]); - } - table_cache[page_id] = pool_.get_block_address(table[page_id]); - } - return table_cache[page_id]; - } - - GRNXX_ERROR() << "invalid argument: page_id = " << page_id - << ": [0, " << max_page_id_ <<']'; - GRNXX_THROW(); -} - -void VectorImpl::initialize_secondary_table() { - Lock lock(mutable_inter_process_mutex()); - if (header_->secondary_table_block_id() == io::BLOCK_INVALID_ID) { - const auto block_info = pool_.create_block( - sizeof(uint32_t) * header_->secondary_table_size()); ... truncated to 1.0MB