blob: 526ea4e2e29bb475c5104beb379da441fb0048a6 [file] [log] [blame]
Zhenkai Zhu772c7072012-12-30 12:40:23 -08001#include "object-db-file.h"
2#include <assert.h>
3
4void
5writeBytes(ostream &out, const Bytes &bytes)
6{
7 int size = bytes.size();
8 writeInt(out, size);
9 out.write(head(bytes), size);
10}
11
12void
13readBytes(istream &in, Bytes &bytes)
14{
15 int size;
16 readInt(in, size);
17 bytes.reserve(size);
18 in.read(head(bytes), size);
19}
20
21ObjectDBFile::ObjectDBFile(const string &filename)
22 : m_size(0)
23 , m_cap(0)
24 , m_index(0)
25 , m_initialized(false)
Zhenkai Zhu772c7072012-12-30 12:40:23 -080026 , m_filename(filename)
Zhenkai Zhu427bed42012-12-30 23:57:48 -080027 // This ensures file with filename exists (assuming having write permission)
28 // This is needed as file_lock only works with existing file
29 , m_ostream(m_filename, ios_base::binary | ios_base::app)
30 , m_istream(m_filename, ios_base::binary | ios_base::in)
31 , m_filelock(m_filename)
Zhenkai Zhu772c7072012-12-30 12:40:23 -080032{
Zhenkai Zhu772c7072012-12-30 12:40:23 -080033 int magic;
Zhenkai Zhu427bed42012-12-30 23:57:48 -080034 ReadLock(m_filelock);
Zhenkai Zhu772c7072012-12-30 12:40:23 -080035 readInt(m_istream, magic);
36 if (magic == MAGIC_NUM)
37 {
38 m_initialized = true;
39 readInt(m_istream, m_cap);
40 readInt(m_istream, m_size);
41 m_istream.seekg( (3 + m_cap) * sizeof(int), ios::beg);
42 }
43}
44
45ObjectDBFile::~ObjectDBFile()
46{
47 m_istream.close();
Zhenkai Zhu427bed42012-12-30 23:57:48 -080048 m_ostream.close();
Zhenkai Zhu772c7072012-12-30 12:40:23 -080049}
50
51void
52ObjectDBFile::init(int capacity)
53{
Zhenkai Zhu427bed42012-12-30 23:57:48 -080054 WriteLock(m_filelock);
Zhenkai Zhu772c7072012-12-30 12:40:23 -080055 if (m_initialized)
56 {
57 throwException("Trying to init already initialized ObjectDBFile object" + m_filename);
58 }
59
Zhenkai Zhu772c7072012-12-30 12:40:23 -080060 m_cap = capacity;
61 m_size = 0;
62
63 int magic = MAGIC_NUM;
64 writeInt(m_ostream, magic);
65 writeInt(m_ostream, m_cap);
66 writeInt(m_ostream, m_size);
67 m_initialized = true;
68
69 int count = size;
70 int offset = 0;
71 while (count-- > 0)
72 {
73 writeInt(m_ostream, offset);
74 }
75
76 // prepare read pos
77 m_istream.seekg(m_ostream.tellp(), ios::beg);
78
79 // DEBUG
80 assert(m_ostream.tellp() == ((3 + m_cap) * sizeof(int)));
81
82}
83
84// Append is not super efficient as it needs to seek and update the pos for the
85// Content object. However, in our app, it is the case the these objects are wrote
86// once and read multiple times, so it's not a big problem.
87void
88ObjectDBFile::append(const Bytes &co)
89{
Zhenkai Zhu427bed42012-12-30 23:57:48 -080090 WriteLock(m_filelock);
Zhenkai Zhu772c7072012-12-30 12:40:23 -080091 checkInit("Trying to append to un-initialized ObjectDBFile: " + m_filename);
92
Zhenkai Zhu772c7072012-12-30 12:40:23 -080093 if (m_size >= m_cap)
94 {
95 throwException("Exceed Maximum capacity: " + boost::lexical_cast<string>(m_cap));
96 }
97
98 // pos for this CO
99 int coPos = m_ostream.tellp();
100 // index field for this CO
101 int indexPos = (3 + m_size) * sizeof(int);
102
103 m_size++;
104
105 // Update size (is it necessary?) We'll do it for now anyway
106 m_ostream.seekp( 2 * sizeof(int), ios::beg);
107 writeInt(m_ostream, m_size);
108
109 // Write the pos for the CO
110 m_ostream.seekp(indexPos, ios::beg);
111 writeInt(m_ostream, coPos);
112
113 // write the content object
114 m_ostream.seekp(coPos, ios::beg);
115 writeBytes(m_ostream, co);
116
117 // By the end, the write pos is at the end of the file
118}
119
Zhenkai Zhu8a75ea92012-12-31 00:14:04 -0800120// forget about caching for now; but ideally, we should cache the next few COs in memory
121// and the request for COs tends to be sequential
Zhenkai Zhu772c7072012-12-30 12:40:23 -0800122Bytes
123ObjectDBFile::next()
124{
Zhenkai Zhu9bcbd542012-12-31 01:01:25 -0800125 // Scoped shared lock for cache
Zhenkai Zhud8569c92012-12-31 00:53:25 -0800126 {
Zhenkai Zhu9bcbd542012-12-31 01:01:25 -0800127 SLock(m_cacheLock);
128 // no need to read file if found in cache
129 if (m_dummyCache.find(m_index) != map::end)
130 {
131 int index = m_index;
132 m_index++;
133 return m_dummyCache[index];
134 }
Zhenkai Zhud8569c92012-12-31 00:53:25 -0800135 }
136
Zhenkai Zhu9bcbd542012-12-31 01:01:25 -0800137 ReadLock(m_filelock);
138
Zhenkai Zhud8569c92012-12-31 00:53:25 -0800139 // m_index not found in cache
Zhenkai Zhu8a75ea92012-12-31 00:14:04 -0800140 Bytes co;
141 if (m_index >= m_size)
142 {
Zhenkai Zhud8569c92012-12-31 00:53:25 -0800143 // at the end of file, return empty
Zhenkai Zhu8a75ea92012-12-31 00:14:04 -0800144 return co;
145 }
Zhenkai Zhud8569c92012-12-31 00:53:25 -0800146
Zhenkai Zhu8a75ea92012-12-31 00:14:04 -0800147 readBytes(m_istream, co);
148 m_index++;
Zhenkai Zhud8569c92012-12-31 00:53:25 -0800149
150 // fill dummy cache with the next CACHE_SIZE COs
151 fillDummyCache();
152
Zhenkai Zhu8a75ea92012-12-31 00:14:04 -0800153 return co;
Zhenkai Zhu772c7072012-12-30 12:40:23 -0800154}
155
156void
Zhenkai Zhud8569c92012-12-31 00:53:25 -0800157ObjectDBFile::fillDummyCache()
Zhenkai Zhu772c7072012-12-30 12:40:23 -0800158{
Zhenkai Zhu9bcbd542012-12-31 01:01:25 -0800159 ULock(m_cacheLock);
Zhenkai Zhud8569c92012-12-31 00:53:25 -0800160 m_dummyCache.clear();
161 int stop = (m_index + CACHE_SIZE < m_size) ? m_index + CACHE_SIZE : m_size;
162 // the m_index should not change
163 int index = m_index;
164 while (index < stop)
Zhenkai Zhu8a75ea92012-12-31 00:14:04 -0800165 {
166 Bytes co;
167 readBytes(m_istream, co);
Zhenkai Zhud8569c92012-12-31 00:53:25 -0800168 m_dummyCache.insert(make_pair(index, co));
169 index++;
Zhenkai Zhu8a75ea92012-12-31 00:14:04 -0800170 }
Zhenkai Zhu772c7072012-12-30 12:40:23 -0800171}
172
173int
174ObjectDBFile::size() const
175{
176 return m_size;
177}
178
179void
180ObjectDBFile::updateSzie()
181{
182 int pos = m_istream.tellg();
183 m_istream.seekg(2 * sizeof(int), ios::beg);
184 readInt(m_istream, m_size);
185 // recover the original pos
186 m_istream.seekg(pos, ios::beg);
187}
188
189int
190ObjectDBFile::fSize()
191{
Zhenkai Zhu427bed42012-12-30 23:57:48 -0800192 ReadLock(m_filelock);
Zhenkai Zhu772c7072012-12-30 12:40:23 -0800193 updateSize();
194 return m_size;
195}
196
197int
198ObjectDBFile::index()
199{
Zhenkai Zhu427bed42012-12-30 23:57:48 -0800200 ReadLock(m_filelock);
Zhenkai Zhu772c7072012-12-30 12:40:23 -0800201 return m_index;
202}
203
204bool
205ObjectDBFile::seek(int index)
206{
Zhenkai Zhu427bed42012-12-30 23:57:48 -0800207 ReadLock(m_filelock);
Zhenkai Zhu772c7072012-12-30 12:40:23 -0800208 updateSize();
209 if (m_size <= index)
210 {
211 return false;
212 }
213 m_index = index;
214 m_istream.seekg( (3 + m_index) * sizeof(int), ios::beg);
215 int pos;
216 readInt(m_istream, pos);
217 m_istream.seekg(pos, ios::beg);
218 return true;
219}
220
221void
222rewind()
223{
Zhenkai Zhu427bed42012-12-30 23:57:48 -0800224 ReadLock(m_filelock);
Zhenkai Zhu772c7072012-12-30 12:40:23 -0800225 m_index = 0;
226 // point to the start of the CO fields
227 m_istream.seekg( (3 + m_cap) * sizeof(int), ios::beg);
228}
229
230void
231ObjectDBFile::checkInit(const string &msg)
232{
233 if (!m_initialized)
234 {
235 throwException(msg);
236 }
237}