1 #include "common/platform.h"
2 
3 #include <cassert>
4 #include <cstdlib>
5 #include <cstring>
6 #include <stdexcept>
7 
8 #include "master/hstring_bdbstorage.h"
9 
10 using namespace hstorage;
11 
12 static const int kGigabyte = (1024 * 1024 * 1024);
13 
BDBStorage(const std::string & path,uint64_t cachesize,int ncache,uint32_t pagesize)14 BDBStorage::BDBStorage(const std::string &path, uint64_t cachesize, int ncache, uint32_t pagesize)
15 		: path_(path) {
16 
17 	int err;
18 
19 	err = db_create(&dbp_, NULL, 0);
20 	if (err) {
21 		throw std::runtime_error("Could not create database");
22 	}
23 
24 	if (pagesize != 0) {
25 		err = dbp_->set_pagesize(dbp_, pagesize);
26 		if (err) {
27 			throw std::runtime_error("Could not set pagesize for database");
28 		}
29 	}
30 
31 	err = dbp_->set_cachesize(dbp_, cachesize / kGigabyte, cachesize % kGigabyte , ncache);
32 	if (err) {
33 		throw std::runtime_error("Could not set cachesize for database");
34 	}
35 
36 	err = dbp_->open(dbp_, NULL, path.c_str(), NULL, DB_HEAP, DB_CREATE | DB_TRUNCATE, 0);
37 	if (err) {
38 		throw std::runtime_error("Could not open database");
39 	}
40 }
41 
~BDBStorage()42 BDBStorage::~BDBStorage() {
43 	if (dbp_) {
44 		dbp_->close(dbp_, DB_NOSYNC);
45 		dbp_ = nullptr;
46 	}
47 }
48 
compare(const Handle & handle,const HString & str)49 bool BDBStorage::compare(const Handle &handle, const HString &str) {
50 	if (hash(handle) == static_cast<HashType>(str.hash())) {
51 		return str == get(handle);
52 	}
53 	return false;
54 }
55 
get(const Handle & handle)56 ::std::string BDBStorage::get(const Handle &handle) {
57 	int err;
58 	DBT key, data;
59 	DB_HEAP_RID rid = decode(handle);
60 
61 	memset(&key, 0, sizeof(DBT));
62 	memset(&data, 0, sizeof(DBT));
63 
64 	key.data = &rid;
65 	key.size = sizeof(rid);
66 	key.ulen = sizeof(rid);
67 	key.flags = DB_DBT_USERMEM;
68 
69 	err = dbp_->get(dbp_, 0, &key, &data, 0);
70 
71 	if (err) {
72 		throw std::runtime_error("Getting from database failed");
73 	}
74 
75 	return static_cast<const char *>(data.data);
76 }
77 
copy(Handle & handle,const Handle & other)78 void BDBStorage::copy(Handle &handle, const Handle &other) {
79 	bind(handle, get(other), hash(other));
80 }
81 
bind(Handle & handle,const HString & str)82 void BDBStorage::bind(Handle &handle, const HString &str) {
83 	bind(handle, str, str.hash());
84 }
85 
bind(Handle & handle,const std::string & str,HashType hash)86 void BDBStorage::bind(Handle &handle, const std::string &str, HashType hash) {
87 	int err;
88 	DBT key, data;
89 	DB_HEAP_RID rid;
90 	memset(&key, 0, sizeof(DBT));
91 	memset(&data, 0, sizeof(DBT));
92 	memset(&rid, 0, sizeof(rid));
93 
94 	data.size = (str.size() + 1) * sizeof(char);
95 	data.data = const_cast<char *>(str.c_str());
96 	data.flags = DB_DBT_USERMEM;
97 
98 	key.data = &rid;
99 	key.size = key.ulen = sizeof(rid);
100 	key.flags = DB_DBT_USERMEM;
101 
102 	err = dbp_->put(dbp_, nullptr, &key, &data, DB_APPEND);
103 	if (err) {
104 		throw std::runtime_error("Putting to database failed");
105 	}
106 
107 	handle.data() = encode(rid, hash);
108 }
109 
encode(const DB_HEAP_RID & rid,HashType hash) const110 BDBStorage::ValueType BDBStorage::encode(const DB_HEAP_RID &rid, HashType hash) const {
111 	ValueType ret = static_cast<ValueType>(hash) << 48;
112 	ret += static_cast<ValueType>(rid.pgno + kSalt) << 16;
113 	ret += rid.indx;
114 	return ret;
115 }
116 
decode(const Handle & handle) const117 DB_HEAP_RID BDBStorage::decode(const Handle &handle) const {
118 	/*
119 	 * Structure of DB_HEAP_RID is
120 	 * {
121 	 *    db_pgno_t pgno;
122 	 *    db_indx_t indx;
123 	 * }
124 	 */
125 	return {static_cast<db_pgno_t>(((handle.data() << 16) >> 32) - kSalt),
126 			static_cast<db_indx_t>((handle.data() << 48) >> 48)};
127 }
128 
unbind(Handle & handle)129 void BDBStorage::unbind(Handle &handle) {
130 	DBT key, data;
131 	DB_HEAP_RID rid = decode(handle);
132 
133 	memset(&key, 0, sizeof(DBT));
134 	memset(&data, 0, sizeof(DBT));
135 
136 	key.data = &rid;
137 	key.size = sizeof(rid);
138 	key.ulen = sizeof(rid);
139 	key.flags = DB_DBT_USERMEM;
140 
141 	/* Ignore errors, unbind is used in the destructor */
142 	dbp_->del(dbp_, nullptr, &key, 0);
143 }
144 
name() const145 ::std::string BDBStorage::name() const {
146 	return kName;
147 }
148