/* * Copyright (C) 2016 Charybdis Development Team * Copyright (C) 2016 Jason Volk * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice is present in all copies. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #pragma once #define HAVE_IRCD_DB_H namespace rocksdb { struct DB; } namespace ircd { namespace db { IRCD_EXCEPTION(ircd::error, error) IRCD_EXCEPTION(error, not_found) IRCD_EXCEPTION(error, corruption) IRCD_EXCEPTION(error, not_supported) IRCD_EXCEPTION(error, invalid_argument) IRCD_EXCEPTION(error, io_error) IRCD_EXCEPTION(error, merge_in_progress) IRCD_EXCEPTION(error, incomplete) IRCD_EXCEPTION(error, shutdown_in_progress) IRCD_EXCEPTION(error, timed_out) IRCD_EXCEPTION(error, aborted) IRCD_EXCEPTION(error, busy) IRCD_EXCEPTION(error, expired) IRCD_EXCEPTION(error, try_again) std::string path(const std::string &name); template struct optval :std::pair { optval(const T &key, const ssize_t &val = std::numeric_limits::min()); }; template using optlist = std::initializer_list>; template bool has_opt(const optlist &, const T &); template ssize_t opt_val(const optlist &, const T &); // Reads may be posted to a separate thread which incurs the time of IO while the calling // ircd::context yields. enum class get { PIN, // Keep iter data in memory for iter lifetime (good for lots of ++/--) CACHE, // Update the cache (CACHE is default for non-iterator operations) NO_CACHE, // Do not update the cache (NO_CACHE is default for iterators) NO_SNAPSHOT, // Snapshots provide consistent views for iteration. NO_CHECKSUM, // Integrity of data will be checked unless this is specified READAHEAD, // Pair with a size in bytes for prefetching additional data }; struct gopts :optlist { template gopts(list&&... l): optlist{std::forward(l)...} {} }; // Writes usually occur without yielding your context because the DB is write-log oriented. enum class set { FSYNC, // Uses kernel filesystem synchronization after write (slow) NO_JOURNAL, // Write Ahead Log (WAL) for some crash recovery MISSING_COLUMNS // No exception thrown when writing to a deleted column family }; struct sopts :optlist { template sopts(list&&... l): optlist{std::forward(l)...} {} }; enum class opt { NO_CREATE, // A new database may be created (if none found) unless this is specified NO_EXISTING, // An error is given if database already exists NO_CHECKSUM, // (paranoid_checks) NO_MADV_DONTNEED, // Never issue MADV_DONTNEED (on windows turns off all pagecaching!) NO_MADV_RANDOM, // Skip MADV_RANDOM on database file opening FALLOCATE, // Allow use of fallocate() NO_FALLOCATE, // Disallow use fallocate() calls NO_FDATASYNC, // Flushing is only ever directed by the kernel pagecache FSYNC, // Use fsync() instead of fdatasync() MMAP_READS, // mmap() table files for reading MMAP_WRITES, // mmap() table files for writing (hinders db journal) STATS_THREAD, // Stats collection etc related to DB threading (thread_track) STATS_MALLOC, // Stats collection for memory allocation when applicable OPEN_FAST, // Skips a lot of stuff to make opening a handle faster OPEN_SMALL, // Optimizes the cache hierarchy for < 1GiB databases. OPEN_BULKLOAD, // Optimizes the handle to accept a large amount of writes at once LRU_CACHE, // Pair with a size in bytes for the LRU cache size }; struct opts :optlist { template opts(list&&... l): optlist{std::forward(l)...} {} }; struct const_iterator { using key_type = std::pair; using mapped_type = std::pair; using value_type = std::pair; private: friend class handle; struct state; std::unique_ptr state; mutable value_type val; const_iterator(std::unique_ptr &&); public: operator bool() const; bool operator!() const; bool operator<(const const_iterator &) const; bool operator>(const const_iterator &) const; bool operator==(const const_iterator &) const; bool operator!=(const const_iterator &) const; bool operator<=(const const_iterator &) const; bool operator>=(const const_iterator &) const; const value_type *operator->() const; const value_type &operator*() const; const_iterator &operator++(); const_iterator &operator--(); const_iterator() = default; const_iterator(const_iterator &&) noexcept; const_iterator(const const_iterator &) = delete; ~const_iterator() noexcept; }; class handle { friend class const_iterator; std::unique_ptr meta; std::unique_ptr d; public: using closure = std::function; // Iterations const_iterator lower_bound(const std::string &key, const gopts & = {}); const_iterator upper_bound(const std::string &key, const gopts & = {}); const_iterator cbegin(const gopts & = {}); const_iterator cend(const gopts & = {}); // Tests if key exists bool has(const std::string &key, const gopts & = {}); // Perform a get into a closure. This offers a reference to the data with zero-copy. // Be very, very cognizant of the things you do as you sojourn on this odyssey. void get(const std::string &key, const closure &func, const gopts & = {}); // Get data into your buffer. The signed char buffer is null terminated; the unsigned is not. size_t get(const std::string &key, char *const &buf, const size_t &max, const gopts & = {}); size_t get(const std::string &key, uint8_t *const &buf, const size_t &max, const gopts & = {}); std::string get(const std::string &key, const gopts & = {}); // Write data to the db void set(const std::string &key, const char *const &buf, const size_t &size, const sopts & = {}); void set(const std::string &key, const uint8_t *const &buf, const size_t &size, const sopts & = {}); void set(const std::string &key, const std::string &value, const sopts & = {}); // Remove data from the db. not_found is never thrown. void del(const std::string &key, const sopts & = {}); handle(const std::string &name, const opts & = {}); ~handle() noexcept; }; const_iterator begin(handle &); const_iterator end(handle &); struct init { init(); ~init() noexcept; }; // db subsystem has its own SNOMASK'ed logging facility. extern struct log::log log; } // namespace db } // namespace ircd inline ircd::db::const_iterator ircd::db::end(handle &handle) { return handle.cend(); } inline ircd::db::const_iterator ircd::db::begin(handle &handle) { return handle.cbegin(); } template ssize_t ircd::db::opt_val(const optlist &list, const T &opt) { for(const auto &p : list) if(p.first == opt) return p.second; return std::numeric_limits::min(); } template bool ircd::db::has_opt(const optlist &list, const T &opt) { for(const auto &p : list) if(p.first == opt) return true; return false; } template ircd::db::optval::optval(const T &key, const ssize_t &val) :std::pair{key, val} { }