#ifndef DB_H #define DB_H #define MALLOC_ALIGN_MASK (2*sizeof(size_t) - 1) class PgfDB; #if defined(_MSC_VER) extern PGF_INTERNAL_DECL __declspec( thread ) unsigned char* current_base; extern PGF_INTERNAL_DECL __declspec( thread ) PgfDB* current_db; #else extern PGF_INTERNAL_DECL __thread unsigned char* current_base __attribute__((tls_model("initial-exec"))); extern PGF_INTERNAL_DECL __thread PgfDB* current_db __attribute__((tls_model("initial-exec"))); #endif struct block_descr; struct malloc_state; template class PGF_INTERNAL_DECL ref { private: object offset; friend class PgfDB; public: ref() { } ref(object o) { offset = o; } A* operator->() const { return (A*) (current_base+offset); } operator A*() const { return (A*) (current_base+offset); } bool operator ==(ref& other) const { return offset==other.as_object(); } bool operator !=(ref& other) const { return offset!=other.as_object(); } bool operator ==(object other_offset) const { return offset==other_offset; } bool operator !=(object other_offset) const { return offset!=other_offset; } ref& operator= (const ref& r) { offset = r.offset; return *this; } static ref from_ptr(A *ptr) { return (((uint8_t*) ptr) - current_base); } object as_object() const { return offset; } object tagged() { assert(A::tag < MALLOC_ALIGN_MASK + 1); return (offset | A::tag); } static ref untagged(object v) { return (v & ~MALLOC_ALIGN_MASK); } static uint8_t get_tag(object v) { return (v & MALLOC_ALIGN_MASK); } }; enum DB_scope_mode {READER_SCOPE, WRITER_SCOPE}; typedef size_t txn_t; class PgfDB { private: int fd; const char *filepath; malloc_state* ms; unsigned char* base; unsigned long int seed; // The following four fields are normally equal to // the corresponding fields in the malloc_state. // The exception is when a transaction is active. object top; object transaction_object; object free_blocks; object free_descriptors[3]; object last_free_block; size_t last_free_block_size; txn_t last_free_block_txn_id; size_t mmap_size; size_t page_size; #ifndef _WIN32 pid_t pid; #else DWORD pid; HANDLE hMap; HANDLE hRevMutex; HANDLE hWriteMutex; HANDLE hRWEvent; #endif friend class PgfReader; public: // Here we count to how many revisions the client has access. // When the count is zero we release the database. size_t ref_count; PGF_INTERNAL_DECL PgfDB(const char* filepath, int flags, int mode, size_t init_size); PGF_INTERNAL_DECL ~PgfDB(); PGF_INTERNAL_DECL static txn_t get_txn_id(); PGF_INTERNAL_DECL const char *get_file_path() { return filepath; }; template static ref malloc(size_t extra_bytes=0) { return current_db->malloc_internal(sizeof(A)+extra_bytes); } template static ref realloc(ref r, size_t old_extra_bytes, size_t new_extra_bytes, txn_t txn_id) { return current_db->realloc_internal(r.as_object(), sizeof(A)+old_extra_bytes, sizeof(A)+new_extra_bytes, txn_id); } template static void free(ref o, size_t extra_bytes=0) { current_db->free_internal(o.as_object(), sizeof(A)+extra_bytes); } PGF_INTERNAL_DECL object get_active_revision(); PGF_INTERNAL_DECL object register_revision(object o, txn_t txn_id); PGF_INTERNAL_DECL void unregister_revision(object o); PGF_INTERNAL_DECL ref revision2pgf(PgfRevision revision, size_t *p_txn_id = NULL); PGF_INTERNAL_DECL ref revision2concr(PgfConcrRevision revision, size_t *p_txn_id = NULL); PGF_INTERNAL_DECL void start_transaction(); PGF_INTERNAL_DECL void set_transaction_object(object o); PGF_INTERNAL_DECL void commit(object o); PGF_INTERNAL_DECL void rollback(object o); PGF_INTERNAL_DECL bool is_transient_object(object o); PGF_INTERNAL_DECL static int rand() { current_db->seed = current_db->seed * 1103515245 + 12345; return (unsigned int)(current_db->seed/65536) % 32768; } private: PGF_INTERNAL_DECL int init_rev_mutex(); PGF_INTERNAL_DECL int init_write_mutex(); PGF_INTERNAL_DECL int init_rwlock_mutex(); PGF_INTERNAL_DECL int init_state(); PGF_INTERNAL_DECL void cleanup_state(); PGF_INTERNAL_DECL size_t block_descr_size(object map); PGF_INTERNAL_DECL object new_block_descr(object o, size_t size, txn_t txn_id); PGF_INTERNAL_DECL object upd_block_descr(object map, object left, object right); PGF_INTERNAL_DECL object balanceL_block_descriptor(object map); PGF_INTERNAL_DECL object balanceR_block_descriptor(object map); PGF_INTERNAL_DECL object pop_first_block_descriptor(object map, object *res); PGF_INTERNAL_DECL object pop_last_block_descriptor(object map, object *res); PGF_INTERNAL_DECL object insert_block_descriptor(object map, object o, size_t size, txn_t txn_id); PGF_INTERNAL_DECL object delete_block_descriptor(object map, object *po, size_t *psize, txn_t *ptxn_id); #ifdef DEBUG_MEMORY_ALLOCATOR PGF_INTERNAL_DECL void dump_free_blocks(object map); #endif PGF_INTERNAL_DECL object malloc_internal(size_t bytes); PGF_INTERNAL_DECL object realloc_internal(object oldo, size_t old_bytes, size_t new_bytes, txn_t txn_id); PGF_INTERNAL_DECL void free_internal(object o, size_t bytes); PGF_INTERNAL_DECL void lock(DB_scope_mode m); PGF_INTERNAL_DECL void unlock(); PGF_INTERNAL_DECL void resize_map(size_t new_size, bool writeable); friend class DB_scope; }; class PGF_INTERNAL_DECL DB_scope { public: DB_scope(PgfDB *db, DB_scope_mode m); ~DB_scope(); private: DB_scope_mode mode; PgfDB* save_db; DB_scope* next_scope; }; #if defined(_MSC_VER) extern PGF_INTERNAL_DECL __declspec( thread ) DB_scope *last_db_scope; #else extern PGF_INTERNAL_DECL __thread DB_scope *last_db_scope __attribute__((tls_model("initial-exec"))); #endif #endif