diff --git a/Makefile b/Makefile index 13a69dd..fb3afe2 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,7 @@ SOURCE=\ space_map.cc \ space_map_disk.cc \ space_map_recursive.cc \ + space_map_transactional.cc \ thin_pool.cc \ transaction_manager.cc \ xml_format.cc diff --git a/space_map_transactional.cc b/space_map_transactional.cc new file mode 100644 index 0000000..dfbec48 --- /dev/null +++ b/space_map_transactional.cc @@ -0,0 +1,96 @@ +#include "space_map_transactional.h" + +//---------------------------------------------------------------- + +namespace { + class sm_transactional : public checked_space_map { + public: + typedef shared_ptr ptr; + + sm_transactional(checked_space_map::ptr sm) + : sm_(sm), + committed_(sm_->clone()), + allocated_(0), + search_start_(0) { + } + + virtual block_address get_nr_blocks() const { + return committed_->get_nr_blocks(); + } + + virtual block_address get_nr_free() const { + return committed_->get_nr_free() - allocated_; + } + + virtual ref_t get_count(block_address b) const { + return sm_->get_count(b); + } + + virtual void set_count(block_address b, ref_t c) { + sm_->set_count(b, c); + } + + virtual void commit() { + sm_->commit(); + committed_ = sm_->clone(); + allocated_ = 0; + search_start_ = 0; + } + + virtual void inc(block_address b) { + // FIXME: this may do an implicit allocation, so + // search_start_ and allocated_ will be wrong. + sm_->inc(b); + } + + virtual void dec(block_address b) { + sm_->dec(b); + } + + virtual maybe_block new_block() { + return new_block(0, sm_->get_nr_blocks()); + } + + virtual maybe_block new_block(block_address begin, block_address end) { + if (end <= search_start_) + return maybe_block(); + + maybe_block mb = sm_->new_block(max(search_start_, begin), end); + if (mb) { + allocated_++; + search_start_ = *mb + 1; + } else + search_start_ = end; + + return mb; + } + + virtual bool count_possibly_greater_than_one(block_address b) const { + return sm_->count_possibly_greater_than_one(b); + } + + virtual void extend(block_address extra_blocks) { + return sm_->extend(extra_blocks); + } + + virtual size_t root_size() const { + return sm_->root_size(); + } + + virtual void copy_root(void *dest, size_t len) const { + return sm_->copy_root(dest, len); + } + + virtual checked_space_map::ptr clone() const { + return checked_space_map::ptr(new sm_transactional(sm_)); + } + + private: + checked_space_map::ptr sm_; + checked_space_map::ptr committed_; + block_address allocated_; + block_address search_start_; + }; +} + +//---------------------------------------------------------------- diff --git a/space_map_transactional.h b/space_map_transactional.h new file mode 100644 index 0000000..4cd502b --- /dev/null +++ b/space_map_transactional.h @@ -0,0 +1,19 @@ +#ifndef SPACE_MAP_TRANSACTIONAL_H +#define SPACE_MAP_TRANSACTIONAL_H + +#include "space_map.h" + +//---------------------------------------------------------------- + +namespace persistent_data { + + // FIXME: change name 'transactional' is so vague. + + // This space map ensures no blocks are allocated which have been + // freed within the current transaction. + checked_space_map::ptr create_transactional_sm(checked_space_map::ptr sm); +} + +//---------------------------------------------------------------- + +#endif