mirror of
https://github.com/matrix-construct/construct
synced 2025-03-31 23:11:33 +02:00
ircd::db: Database system developments.
This commit is contained in:
parent
397d1dd3dd
commit
e7844a0771
10 changed files with 1470 additions and 753 deletions
|
@ -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
126
include/ircd/db/cell.h
Normal 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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
1311
ircd/db.cc
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue