0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-09-24 01:18:53 +02:00

ircd::db: Database system developments.

This commit is contained in:
Jason Volk 2017-04-02 21:02:32 -07:00
parent 397d1dd3dd
commit e7844a0771
10 changed files with 1470 additions and 753 deletions

View file

@ -30,6 +30,11 @@
namespace ircd {
namespace db {
struct cell;
struct row;
struct column;
struct database;
// Errors for the database subsystem. The exceptions that use _HIDENAME
// are built from RocksDB errors which already have an info string with
// an included name.
@ -55,11 +60,14 @@ extern struct log::log log;
} // namespace db
} // namespace ircd
//
// These are forward declarations to objects we may carry a pointer to.
// Users of ircd::db should not be dealing with these types.
//
namespace rocksdb
{
struct DB;
struct Slice;
struct Options;
struct DBOptions;
struct ColumnFamilyOptions;
@ -71,22 +79,34 @@ namespace rocksdb
struct Snapshot;
}
#include "db/opts.h"
#include "db/delta.h"
#include "db/database.h"
#include "db/column.h"
#include "db/const_iterator.h"
#include "db/row.h"
//
// Misc utils
//
namespace ircd {
namespace db {
rocksdb::Slice slice(const string_view &);
string_view slice(const rocksdb::Slice &);
bool valid(const rocksdb::Iterator &);
string_view key(const rocksdb::Iterator &);
string_view val(const rocksdb::Iterator &);
std::string path(const std::string &name);
std::vector<std::string> available();
void log_rdb_perf_context(const bool &all = true);
} // namespace db
} // namespace ircd
#include "db/delta.h"
#include "db/database.h"
#include "db/opts.h"
#include "db/column.h"
#include "db/cell.h"
#include "db/row.h"
namespace ircd {
namespace db {
@ -94,3 +114,9 @@ std::string merge_operator(const string_view &, const std::pair<string_view, str
} // namespace db
} // namespace ircd
namespace ircd {
using database = db::database;
} // namespace ircd

126
include/ircd/db/cell.h Normal file
View file

@ -0,0 +1,126 @@
/*
* Copyright (C) 2016 Charybdis Development Team
* Copyright (C) 2016 Jason Volk <jason@zemos.net>
*
* 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_CELL_H
namespace ircd {
namespace db {
struct cell
{
struct delta;
column c;
string_view index;
database::snapshot ss;
std::unique_ptr<rocksdb::Iterator> it;
public:
operator const rocksdb::Iterator &() const { return *it; }
operator const database::snapshot &() const { return ss; }
explicit operator const column &() const { return c; }
operator rocksdb::Iterator &() { return *it; }
operator database::snapshot &() { return ss; }
explicit operator column &() { return c; }
bool valid() const; // cell exists
operator bool() const { return valid(); }
bool operator!() const { return !valid(); }
// [GET] read from cell (zero-copy)
string_view col() const { return name(c); /* always column name */ }
string_view key() const; // key == index or empty on invalid
string_view val() const; // empty on !valid()
string_view key(); // reload then key == index or empty on invalid
string_view val(); // reload then empty on !valid()
// [GET] read from cell (zero-copy)
explicit operator string_view() const; // empty on !valid()
explicit operator string_view(); // reload then empty on !valid()
// [SET] assign cell
cell &operator=(const string_view &);
// [GET] -> [SET] assign cell (atomic)
bool compare_exchange(string_view &expected, const string_view &desired);
string_view exchange(const string_view &desired);
bool load(gopts = {});
cell(column, const string_view &index, std::unique_ptr<rocksdb::Iterator>);
cell(column, const string_view &index, gopts = {});
cell(database &, const string_view &column, const string_view &index, gopts = {});
cell();
cell(cell &&) noexcept;
cell(const cell &) = delete;
cell &operator=(cell &&) noexcept;
cell &operator=(const cell &) = delete;
~cell() noexcept;
friend std::ostream &operator<<(std::ostream &s, const cell &c);
};
struct cell::delta
:std::tuple<op, cell &, string_view>
{
delta(const enum op &op, cell &c, const string_view &val = {})
:std::tuple<enum op, cell &, string_view>{op, c, val}
{}
delta(cell &c, const string_view &val, const enum op &op = op::SET)
:std::tuple<enum op, cell &, string_view>{op, c, val}
{}
};
// [SET] Perform operations in a sequence as a single transaction.
void write(const cell::delta &, const sopts & = {});
void write(const std::initializer_list<cell::delta> &, const sopts & = {});
void write(const sopts &, const std::initializer_list<cell::delta> &);
const std::string &name(const cell &);
uint64_t sequence(const cell &);
} // namespace db
} // namespace ircd
inline
uint64_t
ircd::db::sequence(const cell &c)
{
const database::snapshot &ss(c);
return sequence(ss);
}
inline
const std::string &
ircd::db::name(const cell &c)
{
return name(c.c);
}
inline std::ostream &
ircd::db::operator<<(std::ostream &s, const cell &c)
{
s << string_view{c};
return s;
}

View file

@ -37,6 +37,7 @@ namespace db {
//
struct column
{
struct delta;
struct const_iterator;
using key_type = string_view;
using mapped_type = string_view;
@ -47,16 +48,14 @@ struct column
using iterator = const_iterator;
protected:
using ColumnFamilyHandle = rocksdb::ColumnFamilyHandle;
database::column *c;
std::shared_ptr<database::column> c;
public:
operator const database &() const { return database::get(*c); }
operator const database::column &() const { return *c; }
explicit operator const database &() const;
explicit operator const database::column &() const;
operator database &() { return database::get(*c); }
operator database::column &() { return *c; }
explicit operator database &();
explicit operator database::column &();
operator bool() const { return bool(c); }
bool operator!() const { return !c; }
@ -70,30 +69,90 @@ struct column
const_iterator lower_bound(const string_view &key, const gopts & = {});
const_iterator upper_bound(const string_view &key, const gopts & = {});
// [GET] Get cell
cell operator[](const string_view &key) const;
// [GET] Perform a get into a closure. This offers a reference to the data with zero-copy.
using view_closure = std::function<void (const string_view &)>;
void operator()(const string_view &key, const view_closure &func, const gopts & = {});
void operator()(const string_view &key, const gopts &, const view_closure &func);
// [SET] Perform operations in a sequence as a single transaction.
void operator()(const delta &, const sopts & = {});
void operator()(const std::initializer_list<delta> &, const sopts & = {});
void operator()(const sopts &, const std::initializer_list<delta> &);
void operator()(const op &, const string_view &key, const string_view &val = {}, const sopts & = {});
explicit column(std::shared_ptr<database::column> c);
column(database::column &c);
column(database &, const string_view &column);
column(database::column &c)
:c{&c}
{}
column() = default;
};
// Get property data of a db column (column).
struct column::delta
:std::tuple<op, string_view, string_view>
{
delta(const enum op &op, const string_view &key, const string_view &val = {})
:std::tuple<enum op, string_view, string_view>{op, key, val}
{}
delta(const string_view &key, const string_view &val, const enum op &op = op::SET)
:std::tuple<enum op, string_view, string_view>{op, key, val}
{}
};
struct column::const_iterator
{
using value_type = column::value_type;
using iterator_category = std::bidirectional_iterator_tag;
private:
gopts opts;
std::shared_ptr<database::column> c;
std::unique_ptr<rocksdb::Iterator> it;
mutable value_type val;
friend class column;
const_iterator(std::shared_ptr<database::column>, std::unique_ptr<rocksdb::Iterator> &&, gopts = {});
public:
operator const database::column &() const { return *c; }
operator const database::snapshot &() const { return opts.snapshot; }
explicit operator const gopts &() const { return opts; }
operator database::column &() { return *c; }
explicit operator database::snapshot &() { return opts.snapshot; }
operator bool() const;
bool operator!() const;
const value_type *operator->() const;
const value_type &operator*() const;
const_iterator &operator++();
const_iterator &operator--();
const_iterator();
const_iterator(const_iterator &&) noexcept;
const_iterator &operator=(const_iterator &&) noexcept;
~const_iterator() noexcept;
friend bool operator==(const const_iterator &, const const_iterator &);
friend bool operator!=(const const_iterator &, const const_iterator &);
friend bool operator<(const const_iterator &, const const_iterator &);
friend bool operator>(const const_iterator &, const const_iterator &);
template<class pos> friend void seek(column::const_iterator &, const pos &);
friend void seek(column::const_iterator &, const string_view &key);
};
// Get property data of a db column.
// R can optionally be uint64_t for some values.
template<class R = std::string> R property(column &, const string_view &name);
template<> std::string property(column &, const string_view &name);
template<> uint64_t property(column &, const string_view &name);
// Information about a column (column)
// Information about a column
const std::string &name(const column &);
size_t file_count(column &);
size_t bytes(column &);
@ -121,18 +180,27 @@ void flush(column &, const bool &blocking = false);
} // namespace ircd
inline
ircd::db::column::column(database &d,
const string_view &column_name)
try
:column
ircd::db::column::operator database::column &()
{
*d.columns.at(column_name)
return *c;
}
inline
ircd::db::column::operator database &()
{
return database::get(*c);
}
catch(const std::out_of_range &e)
inline
ircd::db::column::operator const database::column &()
const
{
log.error("'%s' failed to open non-existent column '%s'",
d.name,
column_name);
return *c;
}
inline
ircd::db::column::operator const database &()
const
{
return database::get(*c);
}

View file

@ -1,83 +0,0 @@
/*
* Copyright (C) 2016 Charybdis Development Team
* Copyright (C) 2016 Jason Volk <jason@zemos.net>
*
* 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_CONST_ITERATOR_H
namespace ircd {
namespace db {
struct column::const_iterator
{
struct state;
using key_type = string_view;
using mapped_type = string_view;
using value_type = std::pair<key_type, mapped_type>;
using pointer = value_type *;
using reference = value_type &;
using difference_type = size_t;
using iterator_category = std::bidirectional_iterator_tag;
private:
gopts opts;
database::column *c;
std::unique_ptr<rocksdb::Iterator> it;
mutable value_type val;
friend class column;
const_iterator(database::column &, std::unique_ptr<rocksdb::Iterator> &&, gopts = {});
public:
operator const database::column &() const { return *c; }
operator const database::snapshot &() const { return opts.snapshot; }
explicit operator const gopts &() const { return opts; }
operator database::column &() { return *c; }
explicit operator database::snapshot &() { return opts.snapshot; }
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();
const_iterator(const_iterator &&) noexcept;
const_iterator &operator=(const_iterator &&) noexcept;
~const_iterator() noexcept;
template<class pos> friend void seek(column::const_iterator &, const pos &);
friend void seek(column::const_iterator &, const string_view &key);
};
} // namespace db
} // namespace ircd

View file

@ -38,16 +38,6 @@ struct database
struct comparator;
struct column;
struct descriptor
{
using typing = std::pair<std::type_index, std::type_index>;
std::string name;
typing type { typeid(string_view), typeid(string_view) };
std::string options {};
db::comparator cmp {};
};
static std::map<string_view, database *> dbs; // open databases
std::string name;
@ -61,6 +51,20 @@ struct database
custom_ptr<rocksdb::DB> d;
public:
struct descriptor
{
using typing = std::pair<std::type_index, std::type_index>;
std::string name;
std::string explain;
typing type { typeid(string_view), typeid(string_view) };
std::string options {};
db::comparator cmp {};
};
using description = std::initializer_list<descriptor>;
operator std::shared_ptr<database>() { return shared_from_this(); }
operator const rocksdb::DB &() const { return *d; }
operator rocksdb::DB &() { return *d; }
@ -69,7 +73,7 @@ struct database
database(const std::string &name,
const std::string &options = {},
std::initializer_list<descriptor> = {});
description = {});
database() = default;
database(database &&) = delete;
@ -143,21 +147,24 @@ struct database::snapshot
~snapshot() noexcept;
};
// Linkage to get shared_ptr of database::column
std::shared_ptr<const database::column> shared_from(const database::column &);
std::shared_ptr<database::column> shared_from(database::column &);
// Get property data from all columns in DB. Only integer properties supported.
template<class R = uint64_t> R property(database &, const string_view &name);
template<> uint64_t property(database &, const string_view &name);
const std::string &name(const database &);
const std::string &name(const database::column &);
uint32_t id(const database::column &);
void drop(database::column &); // Request to erase column from db
uint64_t sequence(const database::snapshot &); // Sequence of a snapshot
uint64_t sequence(const database &); // Latest sequence number
uint32_t id(const database::column &);
void drop(database::column &); // Request to erase column from db
void sync(database &); // Sync the write log (all columns)
} // namespace db
using database = db::database;
} // namespace ircd

View file

@ -36,22 +36,9 @@ enum op
SINGLE_DELETE,
};
struct delta
:std::tuple<op, string_view, string_view>
{
delta(const enum op &op, const string_view &key, const string_view &val = {})
:std::tuple<enum op, string_view, string_view>{op, key, val}
{}
delta(const string_view &key, const string_view &val, const enum op &op = op::SET)
:std::tuple<enum op, string_view, string_view>{op, key, val}
{}
};
using merge_delta = std::pair<string_view, string_view>;
using merge_closure = std::function<std::string (const string_view &key, const merge_delta &)>;
using update_closure = std::function<std::string (const string_view &key, merge_delta &)>;
using view_closure = std::function<void (const string_view &)>;
struct comparator
{

View file

@ -23,22 +23,24 @@
#pragma once
#define HAVE_IRCD_DB_OBJECT_H
// handler register(username):
//
// (let database value registered = 0)
//
// context A | context B
// |
//0 enter |
//1 if(registered) | enter ; A yields on cache-miss/IO read
//2 | if(registered) ; B resumes hitting cached value A fetched
//3 | bnt return; ; B continues without yield
//4 | registered = time(nullptr); ; B assigns B's value to database
//5 b?t return; | leave ; A resumes [what does if() see?]
//6 registered = time(nullptr); | ; A overwrites B's value
//7 leave | ; ???
namespace ircd {
namespace db {
template<database *const &d>
struct transaction
{
string_view index;
database::snapshot snapshot;
//something transaction;
transaction(const string_view &index = {})
:index{index}
,snapshot{*d}
{}
};
template<class T,
database *const &d>
struct value
@ -47,186 +49,99 @@ struct value
template<database *const &d>
struct value<void, d>
:cell
{
mutable column h;
transaction<d> *t;
value(const string_view &name,
transaction<d> &t)
:h{!name.empty()? column{*d, name} : column{}}
,t{&t}
const string_view &index)
:cell{*d, name, index}
{}
value()
:t{nullptr}
{}
using cell::cell;
};
template<database *const &d,
const char *const &prefix>
template<database *const &d>
struct object
:row
{
struct iterator;
struct const_iterator;
using key_type = string_view;
using mapped_type = value<void, d>;
using value_type = std::pair<key_type, mapped_type>;
using pointer = value_type *;
using reference = value_type &;
using size_type = size_t;
using difference_type = ptrdiff_t;
string_view prefix;
string_view index;
transaction<d> *t;
iterator begin();
iterator end();
object(transaction<d> &t)
:t{&t}
{}
object()
:t{nullptr}
{}
object(const string_view &prefix, const string_view &index);
object() = default;
};
template<database *const &d,
const char *const &prefix>
struct object<d, prefix>::iterator
template<database *const &d>
object<d>::object(const string_view &prefix,
const string_view &index)
:row{[&prefix, &index]() -> row
{
using key_type = string_view;
using mapped_type = value<void, d>;
using value_type = std::pair<key_type, mapped_type>;
using pointer = value_type *;
using reference = value_type &;
using size_type = size_t;
using difference_type = ptrdiff_t;
// The prefix is the name of the object we want to find members in.
// This function has to find columns starting with the prefix but not
// containing any additional '.' except the one directly after the prefix,
// as more '.' indicates sub-members which we don't fetch here.
friend class object<d, prefix>;
protected:
transaction<d> *t;
decltype(database::columns)::iterator it;
value_type last;
value_type val;
void seek_next();
public:
const value_type *operator->() const { return &val; }
const value_type &operator*() const { return *operator->(); }
bool operator==(const iterator &o) const { return it == o.it; }
bool operator!=(const iterator &o) const { return it != o.it; }
bool operator<(const iterator &o) const { return it < o.it; }
iterator &operator++()
auto &columns(d->columns);
auto low(columns.lower_bound(prefix)), hi(low);
for(; hi != std::end(columns); ++hi)
{
++it;
seek_next();
return *this;
const auto &name(hi->first);
if(!startswith(name, prefix))
break;
}
iterator(transaction<d> &t)
:t{&t}
{}
iterator()
:t{nullptr}
{}
};
template<database *const &d,
const char *const &prefix>
typename object<d, prefix>::iterator
object<d, prefix>::end()
{
iterator ret{};
ret.it = std::end(d->columns);
return ret;
}
template<database *const &d,
const char *const &prefix>
typename object<d, prefix>::iterator
object<d, prefix>::begin()
{
iterator ret{*t};
ret.it = std::begin(d->columns);
ret.seek_next();
return ret;
}
template<database *const &d,
const char *const &prefix>
void
object<d, prefix>::iterator::seek_next()
{
const auto ptc(tokens_count(prefix, "."));
while(it != std::end(d->columns))
string_view names[std::distance(low, hi)];
std::transform(low, hi, names, [&prefix](const auto &pair)
{
const auto &pair(*it);
if(!startswith(pair.first, prefix))
{
++it;
continue;
}
const auto &path(pair.first);
const auto ktc(tokens_count(pair.first, "."));
if(ktc != ptc + 1)
{
const auto com(std::min(tokens_count(last.first, "."), ptc + 1));
if(!com || token(last.first, ".", com - 1) == token(pair.first, ".", com - 1))
{
++it;
continue;
}
}
// Find members of this object by removing the prefix and then removing
// any members which have a '.' indicating they are not at this level.
string_view name(path);
name = lstrip(name, prefix);
name = lstrip(name, '.');
if(tokens_count(name, ".") != 1)
return string_view{};
bool bad(false);
const auto com(std::min(ktc, ptc));
if(com)
for(size_t i(0); i < com - 1 && !bad; i++)
if(token(prefix, ".", i) != token(pair.first, ".", i))
bad = true;
if(bad)
{
++it;
continue;
}
return string_view{path};
});
val.first = pair.first;
last.first = pair.first;
val.first = lstrip(val.first, prefix);
val.first = lstrip(val.first, '.');
val.first = split(val.first, '.').first;
val.second = value<void, d>{pair.first, *t};
break;
}
// Clear empty names from the array before passing up to row{}
const auto end(std::remove(names, names + std::distance(low, hi), string_view{}));
const auto count(std::distance(names, end));
return row
{
*d, index, vector_view<string_view>(names, count)
};
}()}
,index{index}
{
}
/*
template<database *const &d>
struct value<string_view ,d>
:value<void, d>
{
// hold iterator
operator string_view() const
{
std::cout << "read [" << this->name << "] " << std::endl;
return {};
return string_view{static_cast<const cell &>(*this)};
}
operator string_view()
{
return string_view{static_cast<cell &>(*this)};
}
value &operator=(const string_view &val)
{
std::cout << "write [" << this->name << "] " << val << std::endl;
static_cast<cell &>(*this) = val;
return *this;
}
value(const string_view &name)
:value<void, d>{name}
value(const string_view &col,
const string_view &row)
:value<void, d>{col, row}
{}
friend std::ostream &operator<<(std::ostream &s, const value<string_view, d> &v)
@ -235,37 +150,76 @@ struct value<string_view ,d>
return s;
}
};
*/
template<database *const &d>
struct value<int64_t, d>
template<class T,
database *const &d>
struct arithmetic_value
:value<void, d>
{
int64_t def;
bool compare_exchange(T &expected, const T &desired)
{
const auto ep(reinterpret_cast<const char *>(&expected));
const auto dp(reinterpret_cast<const char *>(&desired));
operator int64_t() const try
{
const auto val(read(this->h, this->t->index));
return lex_cast<int64_t>(val);
}
catch(const not_found &e)
{
return def;
string_view s{ep, expected? sizeof(T) : 0};
const auto ret(cell::compare_exchange(s, string_view{dp, sizeof(T)}));
expected = !s.empty()? *reinterpret_cast<const T *>(s.data()) : 0;
return ret;
}
value &operator=(const int64_t &val)
T exchange(const T &desired)
{
write(this->h, this->t->index, lex_cast(val));
const auto dp(reinterpret_cast<const char *>(&desired));
const auto ret(cell::exchange(string_view{dp, desired? sizeof(T) : 0}));
return !ret.empty()? *reinterpret_cast<const T *>(ret.data()) : 0;
}
operator T() const
{
const auto val(this->val());
return !val.empty()? *reinterpret_cast<const T *>(val.data()) : 0;
}
operator T()
{
const auto val(this->val());
return !val.empty()? *reinterpret_cast<const T *>(val.data()) : 0;
}
arithmetic_value &operator=(const T &val)
{
cell &cell(*this);
const auto ptr(reinterpret_cast<const char *>(&val));
cell = string_view{ptr, val? sizeof(T) : 0};
return *this;
}
value(const string_view &name,
transaction<d> &t,
const int64_t &def = 0)
:value<void, d>{name, t}
,def{def}
friend std::ostream &operator<<(std::ostream &s, const arithmetic_value &v)
{
s << T(v);
return s;
}
arithmetic_value(const string_view &col,
const string_view &row)
:value<void, d>{col, row}
{}
};
#define IRCD_ARITHMETIC_VALUE(_type_) \
template<database *const &d> \
struct value<_type_, d> \
:arithmetic_value<_type_, d> \
{ \
using arithmetic_value<_type_, d>::arithmetic_value; \
}
IRCD_ARITHMETIC_VALUE(uint64_t);
IRCD_ARITHMETIC_VALUE(int64_t);
IRCD_ARITHMETIC_VALUE(uint32_t);
IRCD_ARITHMETIC_VALUE(int32_t);
IRCD_ARITHMETIC_VALUE(uint16_t);
IRCD_ARITHMETIC_VALUE(int16_t);
} // namespace db
} // namespace ircd

View file

@ -58,6 +58,7 @@ enum class get
NO_SNAPSHOT, // This iterator will have the latest data (tailing)
NO_CHECKSUM, // Integrity of data will be checked unless this is specified
READAHEAD, // Pair with a size in bytes for prefetching additional data
NO_EMPTY, // Option for db::row to not include unassigned cells in the row
};
struct gopts

View file

@ -26,41 +26,185 @@
namespace ircd {
namespace db {
struct cell
{
explicit
cell(database &,
column,
const string_view &key,
gopts opts = {});
};
struct row
{
using key_type = column;
using mapped_type = std::unique_ptr<rocksdb::Iterator>;
using value_type = std::pair<key_type, mapped_type>;
struct delta;
struct iterator;
struct const_iterator;
using value_type = cell &;
using reference = cell &;
using pointer = cell *;
using difference_type = size_t;
gopts opts;
std::vector<value_type> its;
private:
std::vector<cell> its;
template<class pos> friend void seek(row &, const pos &);
friend void seek(row &, const string_view &key);
public:
auto begin() const { return std::begin(its); }
auto end() const { return std::end(its); }
auto begin() { return std::begin(its); }
auto end() { return std::end(its); }
// [GET] Iterations
const_iterator begin() const;
const_iterator end() const;
iterator begin();
iterator end();
string_view operator[](const string_view &column);
// [GET] Get iterator to cell
const_iterator find(const string_view &column) const;
iterator find(const string_view &column);
row(database &, const string_view &key = {}, gopts = {});
row() = default;
row(row &&) noexcept;
row &operator=(row &&) noexcept;
~row() noexcept;
auto empty() const { return its.empty(); }
auto size() const { return its.size(); }
// [GET] Get cell
const cell &operator[](const string_view &column) const;
cell &operator[](const string_view &column);
// [SET] Perform operation
void operator()(const op &, const string_view &col, const string_view &val = {}, const sopts & = {});
row(std::vector<cell> cells = {})
:its{std::move(cells)}
{}
row(database &,
const string_view &key = {},
const vector_view<string_view> &columns = {},
const gopts &opts = {});
friend size_t trim(row &, const std::function<bool (cell &)> &);
friend size_t trim(row &, const string_view &key); // remove invalid or not equal
friend size_t trim(row &); // remove invalid
};
struct row::const_iterator
{
using value_type = const cell &;
using reference = const cell &;
using pointer = const cell *;
using iterator_category = std::bidirectional_iterator_tag;
private:
friend class row;
decltype(row::its)::const_iterator it;
const_iterator(decltype(row::its)::const_iterator it)
:it{std::move(it)}
{}
public:
reference operator*() const { return it.operator*(); }
pointer operator->() const { return it.operator->(); }
const_iterator &operator++() { ++it; return *this; }
const_iterator &operator--() { --it; return *this; }
const_iterator() = default;
friend bool operator==(const const_iterator &, const const_iterator &);
friend bool operator!=(const const_iterator &, const const_iterator &);
};
struct row::iterator
{
using value_type = cell &;
using reference = cell &;
using pointer = cell *;
using iterator_category = std::bidirectional_iterator_tag;
private:
friend class row;
decltype(row::its)::iterator it;
iterator(decltype(row::its)::iterator it)
:it{std::move(it)}
{}
public:
reference operator*() const { return it.operator*(); }
pointer operator->() const { return it.operator->(); }
iterator &operator++() { ++it; return *this; }
iterator &operator--() { --it; return *this; }
iterator() = default;
friend bool operator==(const iterator &, const iterator &);
friend bool operator!=(const iterator &, const iterator &);
};
} // namespace db
} // namespace ircd
inline ircd::db::cell &
ircd::db::row::operator[](const string_view &column)
{
const auto it(find(column));
if(unlikely(it == end()))
throw not_found("column '%s' does not exist", column);
return *it;
}
inline const ircd::db::cell &
ircd::db::row::operator[](const string_view &column)
const
{
const auto it(find(column));
if(unlikely(it == end()))
throw not_found("column '%s' does not exist", column);
return *it;
}
inline ircd::db::row::iterator
ircd::db::row::end()
{
return { std::end(its) };
}
inline ircd::db::row::iterator
ircd::db::row::begin()
{
return { std::begin(its) };
}
inline ircd::db::row::const_iterator
ircd::db::row::end()
const
{
return { std::end(its) };
}
inline ircd::db::row::const_iterator
ircd::db::row::begin()
const
{
return { std::begin(its) };
}
inline bool
ircd::db::operator!=(const row::iterator &a, const row::iterator &b)
{
return a.it != b.it;
}
inline bool
ircd::db::operator==(const row::iterator &a, const row::iterator &b)
{
return a.it == b.it;
}
inline bool
ircd::db::operator!=(const row::const_iterator &a, const row::const_iterator &b)
{
return a.it != b.it;
}
inline bool
ircd::db::operator==(const row::const_iterator &a, const row::const_iterator &b)
{
return a.it == b.it;
}

1311
ircd/db.cc

File diff suppressed because it is too large Load diff