9#ifndef PSTSDK_NDB_NODE_H
10#define PSTSDK_NDB_NODE_H
16#include <boost/iterator/transform_iterator.hpp>
17#include <boost/iostreams/concepts.hpp>
20#pragma warning(disable:4244)
22#include <boost/iostreams/stream.hpp>
34#pragma warning(disable:4250)
62class node_impl :
public std::enable_shared_from_this<node_impl>
71 : m_id(
info.id), m_original_data_id(
info.data_bid), m_original_sub_id(
info.sub_bid), m_original_parent_id(
info.parent_id), m_parent_id(
info.parent_id), m_db(
db) { }
90 { m_pdata =
other.m_pdata; m_psub =
other.m_psub;
return *
this; }
117 { ensure_data_block();
return m_pdata; }
121 { ensure_sub_block();
return m_psub; }
138 template<
typename T> T
read(
ulong offset)
const;
220 mutable std::shared_ptr<data_block> m_pdata;
221 mutable std::shared_ptr<subnode_block> m_psub;
224 std::shared_ptr<node_impl> m_pcontainer_node;
251 std::shared_ptr<node_impl> m_parent;
273 std::streamsize
write(
const char*
pbuffer, std::streamsize
n);
280 std::streampos
seek(boost::iostreams::stream_offset
off, std::ios_base::seekdir
way);
287 std::streamsize m_pos;
288 std::shared_ptr<node_impl> m_pnode;
324 typedef boost::transform_iterator<subnode_transform_info, const_subnodeinfo_iterator>
subnode_iterator;
354 : m_pimpl(
other.m_pimpl) { }
356#ifndef BOOST_NO_RVALUE_REFERENCES
365 { *m_pimpl = *(
other.m_pimpl);
return *
this; }
381 {
return m_pimpl->get_data_block(); }
384 {
return m_pimpl->get_subnode_block(); }
388 {
return m_pimpl->read(
buffer, offset); }
391 {
return m_pimpl->read<T>(offset); }
397 {
return m_pimpl->read<T>(
page_num, offset); }
401 {
return m_pimpl->write(
buffer, offset); }
402 template<
typename T>
void write(
const T& obj,
ulong offset)
403 {
return m_pimpl->write<T>(obj, offset); }
404 size_t write(std::vector<byte>& buffer,
uint page_num,
ulong offset)
405 {
return m_pimpl->write(buffer, page_num, offset); }
406 template<
typename T>
void write(
const T& obj,
uint page_num,
ulong offset)
407 {
return m_pimpl->write<T>(obj, page_num, offset); }
408 size_t resize(
size_t size)
409 {
return m_pimpl->resize(
size); }
425 size_t size()
const {
return m_pimpl->size(); }
428 {
return m_pimpl->get_page_size(
page_num); }
435 {
return m_pimpl->subnode_info_begin(); }
438 {
return m_pimpl->subnode_info_end(); }
462 {
return m_pimpl->lookup(
id); }
465 std::shared_ptr<node_impl> m_pimpl;
576 template<
typename T> T
read(
ulong offset)
const;
607 virtual size_t resize(
size_t size, std::shared_ptr<data_block>&
presult) = 0;
628 public std::enable_shared_from_this<extended_block>
640#ifndef BOOST_NO_RVALUE_REFERENCES
650#ifndef BOOST_NO_RVALUE_REFERENCES
651 extended_block(
const shared_db_ptr& db,
ushort level,
size_t total_size,
size_t child_max_total_size,
ulong page_max_count,
ulong child_page_max_count, std::vector<std::shared_ptr<data_block> > child_blocks)
652 : data_block(db, block_info(), total_size), m_child_max_total_size(child_max_total_size), m_child_max_page_count(child_page_max_count), m_max_page_count(page_max_count), m_level(level), m_child_blocks(std::move(child_blocks))
653 { m_block_info.resize(m_child_blocks.size()); touch(); }
655 extended_block(
const shared_db_ptr& db,
ushort level,
size_t total_size,
size_t child_max_total_size,
ulong page_max_count,
ulong child_page_max_count,
const std::vector<std::shared_ptr<data_block> >& child_blocks)
656 :
data_block(db, block_info(), total_size), m_child_max_total_size(child_max_total_size), m_child_max_page_count(child_page_max_count), m_max_page_count(page_max_count), m_level(level), m_child_blocks(child_blocks)
657 { m_block_info.resize(m_child_blocks.size()); touch(); }
662 size_t read_raw(
byte* pdest_buffer,
size_t size,
ulong offset)
const;
664 size_t write_raw(
const byte* psrc_buffer,
size_t size,
ulong offset, std::shared_ptr<data_block>& presult);
668 std::shared_ptr<external_block>
get_page(
uint page_num)
const;
671 size_t resize(
size_t size, std::shared_ptr<data_block>& presult);
686 const size_t m_child_max_total_size;
687 const ulong m_child_max_page_count;
688 const ulong m_max_page_count;
691 size_t get_max_size()
const {
return m_child_max_total_size * m_max_page_count; }
694 std::vector<block_id> m_block_info;
695 mutable std::vector<std::shared_ptr<data_block> > m_child_blocks;
707 public std::enable_shared_from_this<external_block>
715#ifndef BOOST_NO_RVALUE_REFERENCES
725 external_block(
const shared_db_ptr& db,
size_t max_size,
size_t current_size)
726 : data_block(db, block_info(), current_size), m_max_size(max_size), m_buffer(current_size)
730 size_t read_raw(
byte* pdest_buffer,
size_t size,
ulong offset)
const;
732 size_t write_raw(
const byte* psrc_buffer,
size_t size,
ulong offset, std::shared_ptr<data_block>& presult);
739 size_t resize(
size_t size, std::shared_ptr<data_block>&
presult);
747 const size_t m_max_size;
748 size_t get_max_size()
const {
return m_max_size; }
750 std::vector<byte> m_buffer;
766 public virtual btree_node<node_id, subnode_info>
803 public std::enable_shared_from_this<subnode_nonleaf_block>
810#ifndef BOOST_NO_RVALUE_REFERENCES
820 {
return m_subnode_info[
pos].first; }
826 std::vector<std::pair<node_id, block_id> > m_subnode_info;
827 mutable std::vector<std::shared_ptr<subnode_block> > m_child_blocks;
840 public std::enable_shared_from_this<subnode_leaf_block>
847#ifndef BOOST_NO_RVALUE_REFERENCES
857 {
return m_subnodes[
pos].second; }
859 {
return m_subnodes[
pos].first; }
861 {
return m_subnodes.size(); }
864 std::vector<std::pair<node_id, subnode_info> > m_subnodes;
877 return m_pdata->get_id();
879 return m_original_data_id;
885 return m_psub->get_id();
887 return m_original_sub_id;
892 return ensure_data_block()->get_total_size();
897 return ensure_data_block()->get_page(
page_num)->get_total_size();
902 return ensure_data_block()->get_page_count();
907 return ensure_data_block()->read(
buffer, offset);
912 return ensure_data_block()->read_raw(
pdest_buffer, size, offset);
918 return ensure_data_block()->read<T>(offset);
923 return ensure_data_block()->get_page(
page_num)->read(
buffer, offset);
929 return ensure_data_block()->get_page(
page_num)->read<T>(offset);
933inline size_t pstsdk::node_impl::write(
const std::vector<byte>&
buffer,
ulong offset)
935 return ensure_data_block()->write(
buffer, offset, m_pdata);
938inline size_t pstsdk::node_impl::write_raw(
const byte* pdest_buffer,
size_t size,
ulong offset)
941 return m_pdata->write_raw(pdest_buffer, size, offset, m_pdata);
945inline void pstsdk::node_impl::write(
const T& obj,
ulong offset)
947 return ensure_data_block()->write<T>(obj, offset, m_pdata);
950inline size_t pstsdk::node_impl::write(
const std::vector<byte>& buffer,
uint page_num,
ulong offset)
952 return ensure_data_block()->write(buffer, page_num * get_page_size(0) + offset, m_pdata);
956inline void pstsdk::node_impl::write(
const T& obj,
uint page_num,
ulong offset)
958 return ensure_data_block()->write<T>(obj, page_num * get_page_size(0) + offset, m_pdata);
961inline size_t pstsdk::node_impl::resize(
size_t size)
963 return ensure_data_block()->resize(size, m_pdata);
970 m_pdata = m_db->read_data_block(m_original_data_id);
972 return m_pdata.get();
978 m_psub = m_db->read_subnode_block(m_original_sub_id);
984inline void pstsdk::block::touch()
991 m_id = get_db_ptr()->alloc_bid(is_internal());
998 size_t read = m_pnode->read_raw(
reinterpret_cast<byte*
>(
pbuffer),
static_cast<size_t>(
n),
static_cast<size_t>(m_pos));
1008inline std::streamsize pstsdk::node_stream_device::write(
const char*
pbuffer, std::streamsize
n)
1010 size_t written = m_pnode->write_raw(
reinterpret_cast<const byte*
>(
pbuffer),
static_cast<size_t>(
n),
static_cast<size_t>(m_pos));
1018#if defined(_MSC_VER) && (_MSC_VER < 1600)
1019#pragma warning(push)
1020#pragma warning(disable:4244)
1022 if(
way == std::ios_base::beg)
1024 else if(
way == std::ios_base::end)
1025 m_pos = m_pnode->size() +
off;
1028#if defined(_MSC_VER) && (_MSC_VER < 1600)
1034 else if(
static_cast<size_t>(m_pos) > m_pnode->size())
1035 m_pos = m_pnode->size();
1042 if(m_child_blocks[
pos] ==
NULL)
1044 m_child_blocks[
pos] = get_db_ptr()->read_subnode_block(m_subnode_info[
pos].
second);
1047 return m_child_blocks[
pos].get();
1052 if(m_child_blocks[
pos] ==
NULL)
1054 m_child_blocks[
pos] = get_db_ptr()->read_subnode_block(m_subnode_info[
pos].
second);
1057 return m_child_blocks[
pos].get();
1066 if(offset >= get_total_size())
1067 throw std::out_of_range(
"offset >= size()");
1078 if(offset >= get_total_size())
1079 throw std::out_of_range(
"offset >= size()");
1080 if(
sizeof(T) + offset > get_total_size())
1081 throw std::out_of_range(
"sizeof(T) + offset >= size()");
1084 read_raw(
reinterpret_cast<byte*
>(&
t),
sizeof(T), offset);
1090inline size_t pstsdk::data_block::write(
const std::vector<byte>&
buffer,
ulong offset, std::shared_ptr<data_block>&
presult)
1096 if(offset >= get_total_size())
1097 throw std::out_of_range(
"offset >= size()");
1106void pstsdk::data_block::write(
const T& buffer,
ulong offset, std::shared_ptr<data_block>& presult)
1108 if(offset >= get_total_size())
1109 throw std::out_of_range(
"offset >= size()");
1110 if(
sizeof(T) + offset > get_total_size())
1111 throw std::out_of_range(
"sizeof(T) + offset >= size()");
1113 (void)write_raw(
reinterpret_cast<const byte*
>(&buffer),
sizeof(T), offset, presult);
1119 assert(m_child_max_total_size % m_child_max_page_count == 0);
1120 uint page_size = m_child_max_total_size / m_child_max_page_count;
1121 uint page_count = (get_total_size() / page_size) + ((get_total_size() % page_size) != 0 ? 1 : 0);
1132 if(total_size % m_child_max_total_size != 0)
1144 if(index >= m_child_blocks.size())
1145 throw std::out_of_range(
"index >= m_child_blocks.size()");
1147 if(m_child_blocks[index] == NULL)
1149 if(m_block_info[index] == 0)
1151 if(get_level() == 1)
1152 m_child_blocks[index] = get_db_ptr()->create_external_block(m_child_max_total_size);
1154 m_child_blocks[index] = get_db_ptr()->create_extended_block(m_child_max_total_size);
1157 m_child_blocks[index] = get_db_ptr()->read_data_block(m_block_info[index]);
1160 return m_child_blocks[index].get();
1166 return get_child_block(
page)->get_page(
page_num % m_child_max_page_count);
1172 throw std::out_of_range(
"index > 0");
1181 assert(offset <= get_total_size());
1183 if(offset + size > get_total_size())
1192inline size_t pstsdk::external_block::write_raw(
const byte*
psrc_buffer,
size_t size,
ulong offset, std::shared_ptr<data_block>&
presult)
1195 if(
pblock.use_count() > 2)
1202 assert(offset <= get_total_size());
1204 size_t write_size = size;
1206 if(offset + size > get_total_size())
1207 write_size = get_total_size() - offset;
1209 memcpy(&m_buffer[0]+offset, psrc_buffer, write_size);
1212#ifndef BOOST_NO_RVALUE_REFERENCES
1213 presult = std::move(pblock);
1224 assert(offset <= get_total_size());
1226 if(offset + size > get_total_size())
1227 size = get_total_size() - offset;
1257inline size_t pstsdk::extended_block::write_raw(
const byte*
psrc_buffer,
size_t size,
ulong offset, std::shared_ptr<data_block>&
presult)
1260 if(
pblock.use_count() > 2)
1267 assert(offset <= get_total_size());
1269 if(offset + size > get_total_size())
1270 size = get_total_size() - offset;
1272 const byte* pend = psrc_buffer + size;
1273 size_t total_bytes_written = 0;
1275 while(psrc_buffer != pend)
1278 uint child_pos = offset / m_child_max_total_size;
1280 ulong child_offset = offset % m_child_max_total_size;
1283 size_t bytes_written = get_child_block(child_pos)->write_raw(psrc_buffer, size, child_offset, m_child_blocks[child_pos]);
1284 assert(bytes_written <= size);
1287 psrc_buffer += bytes_written;
1288 offset += bytes_written;
1289 size -= bytes_written;
1290 total_bytes_written += bytes_written;
1292 assert(psrc_buffer <= pend);
1296#ifndef BOOST_NO_RVALUE_REFERENCES
1297 presult = std::move(pblock);
1302 return total_bytes_written;
1305inline size_t pstsdk::external_block::resize(
size_t size, std::shared_ptr<data_block>& presult)
1307 std::shared_ptr<external_block> pblock = shared_from_this();
1308 if(pblock.use_count() > 2)
1310 std::shared_ptr<external_block> pnewblock(
new external_block(*
this));
1311 return pnewblock->resize(size, presult);
1315 m_buffer.resize(size > m_max_size ? m_max_size : size);
1316 m_total_size = m_buffer.size();
1318 if(size > get_max_size())
1321 std::shared_ptr<extended_block> pnewxblock = get_db_ptr()->create_extended_block(pblock);
1322 return pnewxblock->resize(size, presult);
1326#ifndef BOOST_NO_RVALUE_REFERENCES
1327 presult = std::move(pblock);
1335inline size_t pstsdk::extended_block::resize(
size_t size, std::shared_ptr<data_block>& presult)
1338 uint old_num_subblocks = m_block_info.size();
1339 uint num_subblocks = size / m_child_max_total_size;
1341 if(size % m_child_max_total_size != 0)
1344 if(num_subblocks > m_max_page_count)
1345 num_subblocks = m_max_page_count;
1348 assert(!m_child_blocks.empty());
1349 if(num_subblocks < 2)
1350 return get_child_block(0)->resize(size, presult);
1352 std::shared_ptr<extended_block> pblock = shared_from_this();
1353 if(pblock.use_count() > 2)
1355 std::shared_ptr<extended_block> pnewblock(
new extended_block(*
this));
1356 return pnewblock->resize(size, presult);
1361 m_block_info.resize(num_subblocks, 0);
1362 m_child_blocks.resize(num_subblocks);
1364 if(old_num_subblocks < num_subblocks)
1365 get_child_block(old_num_subblocks-1)->resize(m_child_max_total_size, m_child_blocks[old_num_subblocks-1]);
1368 size_t last_child_size = size - (num_subblocks-1) * m_child_max_total_size;
1369 get_child_block(num_subblocks-1)->resize(last_child_size, m_child_blocks[num_subblocks-1]);
1371 if(size > get_max_size())
1373 m_total_size = get_max_size();
1375 if(get_level() == 2)
1376 throw can_not_resize(
"size > max_size");
1379 std::shared_ptr<extended_block> pnewxblock = get_db_ptr()->create_extended_block(pblock);
1380 return pnewxblock->resize(size, presult);
1384 m_total_size = size;
1385#ifndef BOOST_NO_RVALUE_REFERENCES
1386 presult = std::move(pblock);
1409 return node(std::const_pointer_cast<node_impl>(
shared_from_this()), ensure_sub_block()->lookup(
id));
Generic BTree implementation.
The base class of the block class hierarchy.
shared_db_ptr get_db_ptr() const
bool m_modified
True if this block has been modified and needs to be saved.
block(const shared_db_ptr &db, const block_info &info)
Basic block constructor.
virtual bool is_internal() const =0
Returns the blocks internal/external state.
ulonglong m_address
The address of this specific block on disk, 0 if unknown.
block_id get_id() const
Get the block_id of this block.
block_id m_id
The id of this block.
size_t get_disk_size() const
Get the last known size of this block on disk.
size_t m_size
The size of this specific block on disk at last save.
ulonglong get_address() const
Get the address of this block on disk.
Contains references to other bth_node allocations.
Represents a leaf node in a BTree structure.
Represents a non-leaf node in a BTree structure.
const_iterator end() const
Returns a STL style iterator positioned at the "end" entry.
const_iterator begin() const
Returns a STL style iterator positioned at the first entry.
A block which represents end user data.
size_t m_total_size
the total or logical size (sum of all external child blocks)
virtual std::shared_ptr< external_block > get_page(uint page_num) const =0
Get a specific page of this data_block.
virtual size_t read_raw(byte *pdest_buffer, size_t size, ulong offset) const =0
Read data from this block.
size_t get_total_size() const
Get the total logical size of this block.
size_t read(std::vector< byte > &buffer, ulong offset) const
Read data from this block.
virtual uint get_page_count() const =0
Get the number of physical pages in this data_block.
data_block(const shared_db_ptr &db, const block_info &info, size_t total_size)
Constructor for a data_block.
A data block which refers to other data blocks, in order to extend the physical size limit (8k) to a ...
extended_block(const shared_db_ptr &db, const block_info &info, ushort level, size_t total_size, size_t child_max_total_size, ulong page_max_count, ulong child_page_max_count, std::vector< block_id > bi)
Construct an extended_block from disk.
uint get_page_count() const
Get the number of physical pages in this data_block.
ushort get_level() const
Get the "level" of this extended_block.
std::shared_ptr< external_block > get_page(uint page_num) const
Get a specific page of this data_block.
size_t read_raw(byte *pdest_buffer, size_t size, ulong offset) const
Read data from this block.
bool is_internal() const
Returns the blocks internal/external state.
bool is_internal() const
Returns the blocks internal/external state.
std::shared_ptr< external_block > get_page(uint page_num) const
Get a specific page of this data_block.
uint get_page_count() const
Get the number of physical pages in this data_block.
size_t read_raw(byte *pdest_buffer, size_t size, ulong offset) const
Read data from this block.
external_block(const shared_db_ptr &db, const block_info &info, size_t max_size, std::vector< byte > buffer)
Construct an external_block from disk.
size_t read(std::vector< byte > &buffer, ulong offset) const
Read data from this node.
size_t get_page_size(uint page_num) const
Returns the size of a page in this node.
block_id get_data_id() const
Get the block_id of the data block of this node.
bool is_subnode()
Tells you if this is a subnode.
node_id get_id() const
Get the id of this node.
node_impl(const std::shared_ptr< node_impl > &container_node, const subnode_info &info)
Constructor for subnodes.
size_t size() const
Returns the size of this node.
node_impl & operator=(const node_impl &other)
Set one node equal to another.
block_id get_sub_id() const
Get the block_id of the subnode block of this node.
std::shared_ptr< subnode_block > get_subnode_block() const
Returns the subnode block associated with this node.
node_id get_parent_id() const
Get the parent id.
std::shared_ptr< data_block > get_data_block() const
Returns the data block associated with this node.
node_impl(const shared_db_ptr &db, const node_info &info)
Constructor for top level nodes.
uint get_page_count() const
Returns the number of pages in this node.
node lookup(node_id id) const
Lookup a subnode by node id.
const_subnodeinfo_iterator subnode_info_begin() const
Returns an iterator positioned at first subnodeinfo.
const_subnodeinfo_iterator subnode_info_end() const
Returns an iterator positioned past the last subnodeinfo.
size_t read_raw(byte *pdest_buffer, size_t size, ulong offset) const
Read data from this node.
Defines a stream device for a node for use by boost iostream.
node_stream_device()
Default construct the node stream device.
std::streamsize read(char *pbuffer, std::streamsize n)
Read data from this node into the buffer at the current position.
std::streampos seek(boost::iostreams::stream_offset off, std::ios_base::seekdir way)
Move the current position in the stream.
An in memory representation of the "node" concept in a PST data file.
node_stream_device open_as_stream()
Creates a stream device over this node.
subnode_iterator subnode_begin() const
Returns a proxy iterator for the first subnode.
uint get_page_count() const
Returns the number of pages in this node.
node & operator=(const node &other)
Set one node equal to another.
size_t read(std::vector< byte > &buffer, uint page_num, ulong offset) const
Read data from this node.
node(const node &container_node, const subnode_info &info)
Constructor for subnodes.
subnode_iterator subnode_end() const
Returns a proxy iterator positioned past the last subnode.
node(const std::shared_ptr< node_impl > &container_node, const subnode_info &info)
Constructor for subnodes.
size_t get_page_size(uint page_num) const
Returns the size of a page in this node.
size_t read(std::vector< byte > &buffer, ulong offset) const
Read data from this node.
bool is_subnode()
Tells you if this is a subnode.
boost::transform_iterator< subnode_transform_info, const_subnodeinfo_iterator > subnode_iterator
A transform iterator, so we can expose the subnodes as a collection of nodes rather than subnode_info...
size_t size() const
Returns the size of this node.
node(const node &other)
Copy construct this node.
block_id get_data_id() const
Get the block_id of the data block of this node.
const_subnodeinfo_iterator subnode_info_end() const
Returns an iterator positioned past the last subnodeinfo.
block_id get_sub_id() const
Get the block_id of the subnode block of this node.
std::shared_ptr< subnode_block > get_subnode_block() const
Returns the subnode block associated with this node.
std::shared_ptr< data_block > get_data_block() const
Returns the data block associated with this node.
node(const shared_db_ptr &db, const node_info &info)
Constructor for top level nodes.
node_id get_parent_id() const
Get the parent id.
T read(ulong offset) const
Read data from this node.
T read(uint page_num, ulong offset) const
Read data from a specific block on this node.
node(const node &other, alias_tag)
Alias constructor.
node(node &&other)
Move constructor.
node lookup(node_id id) const
Lookup a subnode by node id.
const_subnodeinfo_iterator subnode_info_begin() const
Returns an iterator positioned at first subnodeinfo.
node_id get_id() const
Get the id of this node.
Generic base class for all page typesA page which forms a node in the NBT or BBT.
A block which contains information about subnodes.
bool is_internal() const
Returns the blocks internal/external state.
ushort get_level() const
Get the level of this subnode_block.
ushort m_level
Level of this subnode_block.
subnode_block(const shared_db_ptr &db, const block_info &info, ushort level)
Construct a block from disk.
Contains the actual subnode information.
uint num_values() const
Returns the number of entries in this btree_node.
const node_id & get_key(uint pos) const
Returns the key at the specified position.
subnode_leaf_block(const shared_db_ptr &db, const block_info &info, std::vector< std::pair< node_id, subnode_info > > subnodes)
Construct a subnode_leaf_block from disk.
const subnode_info & get_value(uint pos) const
Returns the value at the associated position on this leaf node.
Contains references to subnode_leaf_blocks.
subnode_block * get_child(uint pos)
Returns the child btree_node at the requested location.
const node_id & get_key(uint pos) const
Returns the key at the specified position.
subnode_nonleaf_block(const shared_db_ptr &db, const block_info &info, std::vector< std::pair< node_id, block_id > > subblocks)
Construct a subnode_nonleaf_block from disk.
uint num_values() const
Returns the number of entries in this btree_node.
boost::uint64_t ulonglong
Contains the definition of all in memory representations of disk structures.
std::weak_ptr< db_context > weak_db_ptr
std::shared_ptr< db_context > shared_db_ptr
Tag structure used to indicate a copy constructed class should be an alias (shallow copy) rather than...
An in memory, database format agnostic version of disk::bbt_leaf_entry.
An in memory, database format agnostic version of disk::nbt_leaf_entry.
An in memory, database format agnostic version of disk::sub_leaf_entry.
General utility functions and classes.