/
BlockStorage.h
299 lines (233 loc) · 8.9 KB
/
BlockStorage.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
/*****************************************************************************/
/* Milliways - B+ trees and key-value store C++ library */
/* */
/* Copyright 2016 Marco Pantaleoni and J CUBE Inc. Tokyo, Japan. */
/* */
/* Author: Marco Pantaleoni <marco.pantaleoni@gmail.com> */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); */
/* you may not use this file except in compliance with the License. */
/* You may obtain a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/*****************************************************************************/
#ifndef MILLIWAYS_BLOCKSTORAGE_H
#define MILLIWAYS_BLOCKSTORAGE_H
#include <iostream>
#include <fstream>
#include <string>
#include <array>
#include <vector>
#include <functional>
#include <stdint.h>
#include <assert.h>
#include "LRUCache.h"
#include "Utils.h"
namespace milliways {
typedef uint32_t block_id_t;
static const block_id_t BLOCK_ID_INVALID = static_cast<block_id_t>(-1);
inline bool block_id_valid(block_id_t block_id) { return (block_id != BLOCK_ID_INVALID); }
template <size_t BLOCKSIZE>
class Block
{
public:
static const size_t BlockSize = BLOCKSIZE;
typedef size_t size_type;
Block(block_id_t index) :
m_index(index), m_dirty(false) { memset(m_data, 0, sizeof(m_data)); }
Block(const Block<BLOCKSIZE>& other) : m_index(other.m_index), m_data(other.m_data), m_dirty(other.m_dirty) { }
Block& operator= (const Block<BLOCKSIZE>& rhs) { assert(this != &rhs); m_index = rhs.index(); memcpy(m_data, rhs.m_data, sizeof(m_data)); m_dirty = rhs.m_dirty; return *this; }
virtual ~Block() {}
block_id_t index() const { return m_index; }
block_id_t index(block_id_t value) { block_id_t old = m_index; m_index = value; return old; }
char* data() { return m_data; }
const char* data() const { return m_data; }
size_type size() const { return BlockSize; }
bool valid() const { return m_index != BLOCK_ID_INVALID; }
bool dirty() const { return m_dirty; }
bool dirty(bool value) { bool old = m_dirty; m_dirty = value; return old; }
private:
Block();
block_id_t m_index;
char m_data[BlockSize];
bool m_dirty;
};
template <size_t BLOCKSIZE>
class BlockStorage
{
public:
static const int MAJOR_VERSION = 0;
static const int MINOR_VERSION = 1;
static const size_t MAX_USER_HEADER_LEN = 240;
static const size_t BlockSize = BLOCKSIZE;
typedef Block<BLOCKSIZE> block_t;
typedef size_t size_type;
BlockStorage() :
m_header_block_id(BLOCK_ID_INVALID) {}
virtual ~BlockStorage() { /* call close() from the most derived class, and BEFORE destruction */ }
/* -- General I/O ---------------------------------------------- */
virtual bool isOpen() const = 0;
virtual bool open();
virtual bool close();
virtual bool flush() = 0;
virtual bool created() const = 0;
virtual bool openHelper() = 0;
virtual bool closeHelper() = 0;
/* -- Misc ----------------------------------------------------- */
virtual size_type count() = 0;
/* -- Header --------------------------------------------------- */
virtual bool readHeader();
virtual bool writeHeader();
int allocUserHeader() { int uid = m_user_header.size(); m_user_header.push_back(""); return uid; }
void setUserHeader(int uid, const std::string& userHeader) { m_user_header[uid] = userHeader; }
std::string getUserHeader(int uid) { return m_user_header[uid]; }
/* -- Block I/O ------------------------------------------------ */
virtual bool hasId(block_id_t block_id) = 0;
virtual block_id_t allocId(int n_blocks = 1) = 0;
virtual block_id_t firstId() = 0;
block_id_t allocBlock(block_t& dst);
virtual bool dispose(block_id_t block_id, int count = 1) = 0;
bool dispose(block_t& block);
virtual bool read(block_t& dst) = 0;
virtual bool write(block_t& src) = 0;
private:
BlockStorage(const BlockStorage& other);
BlockStorage& operator= (const BlockStorage& other);
block_id_t m_header_block_id;
std::vector<std::string> m_user_header;
};
template <size_t BLOCKSIZE, size_t CACHESIZE>
class LRUBlockCache : public LRUCache< CACHESIZE, block_id_t, shptr< Block<BLOCKSIZE> > >
{
public:
typedef block_id_t key_type;
typedef Block<BLOCKSIZE> block_type;
typedef shptr<block_type> block_ptr_type;
typedef block_ptr_type mapped_type;
typedef std::pair<key_type, mapped_type> value_type;
typedef ordered_map<key_type, mapped_type> ordered_map_type;
typedef LRUCache< CACHESIZE, block_id_t, shptr<block_type> > base_type;
typedef typename base_type::size_type size_type;
typedef BlockStorage<BLOCKSIZE>* storage_ptr_type;
static const size_type Size = CACHESIZE;
static const size_type BlockSize = BLOCKSIZE;
static const block_id_t InvalidCacheKey = BLOCK_ID_INVALID;
LRUBlockCache(storage_ptr_type storage) :
base_type(LRUBlockCache::InvalidCacheKey), m_storage(storage) {}
bool on_miss(typename base_type::op_type op, const key_type& key, mapped_type& value)
{
// std::cerr << "block miss id:" << key << " op:" << (int)op << "\n";
block_id_t block_id = key;
if (m_storage->hasId(block_id)) {
/* allocate block object and read block data from disk */
block_type* block = new block_type(block_id);
if (! block) return false;
switch (op)
{
case base_type::op_get:
if (! m_storage->read(*block)) return false;
block->dirty(false);
value.reset(block);
break;
case base_type::op_set:
assert(value);
*block = *value;
break;
case base_type::op_sub:
//assert(value);
bool rv = m_storage->read(*block);
assert(rv || block->dirty());
value.reset(block);
return rv;
break;
}
return true;
}
return false;
}
bool on_set(const key_type& key, const mapped_type& value)
{
return true;
}
//bool on_delete(const key_type& key);
bool on_eviction(const key_type& key, mapped_type& value)
{
/* write back block */
/* block_id_t block_id = key; */
block_type* block = value.get();
if (block)
{
if (block->valid())
{
bool ok = m_storage->write(*block);
assert(ok);
// if (ok) block->dirty(false);
}
// block->dirty(true);
// block->index(BLOCK_ID_INVALID);
// value.reset();
}
return true;
}
private:
storage_ptr_type m_storage;
};
template <size_t BLOCKSIZE, int CACHE_SIZE>
class FileBlockStorage : public BlockStorage<BLOCKSIZE>
{
public:
static const size_t BlockSize = BLOCKSIZE;
static const int CacheSize = CACHE_SIZE;
typedef Block<BLOCKSIZE> block_t;
typedef size_t size_type;
typedef ssize_t ssize_type;
typedef BlockStorage<BLOCKSIZE> base_type;
typedef LRUBlockCache<BLOCKSIZE, CACHE_SIZE> cache_t;
FileBlockStorage(const std::string& pathname) :
BlockStorage<BLOCKSIZE>(),
m_pathname(pathname), m_created(false), m_count(-1), m_next_block_id(BLOCK_ID_INVALID), m_lru(this) {}
~FileBlockStorage(); /* call close() before destruction! */
/* -- General I/O ---------------------------------------------- */
bool isOpen() const { return m_stream.is_open(); }
bool open() { return base_type::open(); }
bool close() { return base_type::close(); }
bool openHelper();
bool closeHelper();
bool flush();
bool created() const { return m_created; }
/* -- Misc ----------------------------------------------------- */
size_type count();
const std::string& pathname() const { return m_pathname; }
/* -- Block I/O ------------------------------------------------ */
bool hasId(block_id_t block_id) { return (block_id != BLOCK_ID_INVALID) && (block_id < nextId()); }
block_id_t nextId();
block_id_t allocId(int n_blocks = 1);
block_id_t firstId() { return 0; }
bool dispose(block_id_t block_id, int count = 1);
bool read(block_t& dst);
bool write(block_t& src);
/* cached I/O */
shptr<block_t> get(block_id_t block_id);
bool put(const block_t& src);
protected:
void _updateCount();
private:
FileBlockStorage();
FileBlockStorage(const FileBlockStorage& other);
FileBlockStorage& operator= (const FileBlockStorage& other);
std::string m_pathname;
std::fstream m_stream;
bool m_created;
ssize_t m_count;
block_id_t m_next_block_id;
cache_t m_lru;
};
} /* end of namespace milliways */
#include "BlockStorage.impl.hpp"
#endif /* MILLIWAYS_BLOCKSTORAGE_H */