blob: 26f8fb31d36e263c67deab67ca0f1d9c90bffcb4 [file] [log] [blame]
Zhenkai Zhu772c7072012-12-30 12:40:23 -08001#include "object-db-file.h"
2#include <assert.h>
3
Zhenkai Zhu6204d472013-01-02 13:16:22 -08004char *
5head(const Bytes &bytes)
6{
7 return (char *)&bytes[0];
8}
9
Zhenkai Zhu772c7072012-12-30 12:40:23 -080010void
11writeBytes(ostream &out, const Bytes &bytes)
12{
13 int size = bytes.size();
14 writeInt(out, size);
15 out.write(head(bytes), size);
16}
17
18void
19readBytes(istream &in, Bytes &bytes)
20{
21 int size;
22 readInt(in, size);
23 bytes.reserve(size);
24 in.read(head(bytes), size);
25}
26
27ObjectDBFile::ObjectDBFile(const string &filename)
28 : m_size(0)
29 , m_cap(0)
30 , m_index(0)
31 , m_initialized(false)
Zhenkai Zhu772c7072012-12-30 12:40:23 -080032 , m_filename(filename)
Zhenkai Zhu427bed42012-12-30 23:57:48 -080033 // This ensures file with filename exists (assuming having write permission)
34 // This is needed as file_lock only works with existing file
Zhenkai Zhu6204d472013-01-02 13:16:22 -080035 , m_ostream(m_filename.c_str(), ios_base::binary | ios_base::app)
36 , m_istream(m_filename.c_str(), ios_base::binary | ios_base::binary)
37 , m_filelock(m_filename.c_str())
Zhenkai Zhu772c7072012-12-30 12:40:23 -080038{
Zhenkai Zhu772c7072012-12-30 12:40:23 -080039 int magic;
Zhenkai Zhu427bed42012-12-30 23:57:48 -080040 ReadLock(m_filelock);
Zhenkai Zhu772c7072012-12-30 12:40:23 -080041 readInt(m_istream, magic);
42 if (magic == MAGIC_NUM)
43 {
44 m_initialized = true;
45 readInt(m_istream, m_cap);
46 readInt(m_istream, m_size);
47 m_istream.seekg( (3 + m_cap) * sizeof(int), ios::beg);
48 }
49}
50
51ObjectDBFile::~ObjectDBFile()
52{
53 m_istream.close();
Zhenkai Zhu427bed42012-12-30 23:57:48 -080054 m_ostream.close();
Zhenkai Zhu772c7072012-12-30 12:40:23 -080055}
56
57void
58ObjectDBFile::init(int capacity)
59{
Zhenkai Zhu6204d472013-01-02 13:16:22 -080060 WriteLock(*m_filelock);
Zhenkai Zhu772c7072012-12-30 12:40:23 -080061 if (m_initialized)
62 {
63 throwException("Trying to init already initialized ObjectDBFile object" + m_filename);
64 }
65
Zhenkai Zhu772c7072012-12-30 12:40:23 -080066 m_cap = capacity;
67 m_size = 0;
68
69 int magic = MAGIC_NUM;
70 writeInt(m_ostream, magic);
71 writeInt(m_ostream, m_cap);
72 writeInt(m_ostream, m_size);
73 m_initialized = true;
74
Zhenkai Zhu6204d472013-01-02 13:16:22 -080075 int count = m_cap;
Zhenkai Zhu772c7072012-12-30 12:40:23 -080076 int offset = 0;
77 while (count-- > 0)
78 {
79 writeInt(m_ostream, offset);
80 }
81
82 // prepare read pos
83 m_istream.seekg(m_ostream.tellp(), ios::beg);
84
85 // DEBUG
86 assert(m_ostream.tellp() == ((3 + m_cap) * sizeof(int)));
87
88}
89
90// Append is not super efficient as it needs to seek and update the pos for the
91// Content object. However, in our app, it is the case the these objects are wrote
92// once and read multiple times, so it's not a big problem.
93void
94ObjectDBFile::append(const Bytes &co)
95{
Zhenkai Zhu427bed42012-12-30 23:57:48 -080096 WriteLock(m_filelock);
Zhenkai Zhu772c7072012-12-30 12:40:23 -080097 checkInit("Trying to append to un-initialized ObjectDBFile: " + m_filename);
98
Zhenkai Zhu772c7072012-12-30 12:40:23 -080099 if (m_size >= m_cap)
100 {
101 throwException("Exceed Maximum capacity: " + boost::lexical_cast<string>(m_cap));
102 }
103
104 // pos for this CO
105 int coPos = m_ostream.tellp();
106 // index field for this CO
107 int indexPos = (3 + m_size) * sizeof(int);
108
109 m_size++;
110
111 // Update size (is it necessary?) We'll do it for now anyway
112 m_ostream.seekp( 2 * sizeof(int), ios::beg);
113 writeInt(m_ostream, m_size);
114
115 // Write the pos for the CO
116 m_ostream.seekp(indexPos, ios::beg);
117 writeInt(m_ostream, coPos);
118
119 // write the content object
120 m_ostream.seekp(coPos, ios::beg);
121 writeBytes(m_ostream, co);
122
123 // By the end, the write pos is at the end of the file
124}
125
Zhenkai Zhu8a75ea92012-12-31 00:14:04 -0800126// forget about caching for now; but ideally, we should cache the next few COs in memory
127// and the request for COs tends to be sequential
Zhenkai Zhu772c7072012-12-30 12:40:23 -0800128Bytes
129ObjectDBFile::next()
130{
Zhenkai Zhu9bcbd542012-12-31 01:01:25 -0800131 // Scoped shared lock for cache
Zhenkai Zhud8569c92012-12-31 00:53:25 -0800132 {
Zhenkai Zhu9bcbd542012-12-31 01:01:25 -0800133 SLock(m_cacheLock);
134 // no need to read file if found in cache
Zhenkai Zhu6204d472013-01-02 13:16:22 -0800135 if (m_dummyCache.find(m_index) != m_dummyCache.end())
Zhenkai Zhu9bcbd542012-12-31 01:01:25 -0800136 {
137 int index = m_index;
138 m_index++;
139 return m_dummyCache[index];
140 }
Zhenkai Zhud8569c92012-12-31 00:53:25 -0800141 }
142
Zhenkai Zhu9bcbd542012-12-31 01:01:25 -0800143 ReadLock(m_filelock);
144
Zhenkai Zhud8569c92012-12-31 00:53:25 -0800145 // m_index not found in cache
Zhenkai Zhu8a75ea92012-12-31 00:14:04 -0800146 Bytes co;
147 if (m_index >= m_size)
148 {
Zhenkai Zhud8569c92012-12-31 00:53:25 -0800149 // at the end of file, return empty
Zhenkai Zhu8a75ea92012-12-31 00:14:04 -0800150 return co;
151 }
Zhenkai Zhud8569c92012-12-31 00:53:25 -0800152
Zhenkai Zhu8a75ea92012-12-31 00:14:04 -0800153 readBytes(m_istream, co);
154 m_index++;
Zhenkai Zhud8569c92012-12-31 00:53:25 -0800155
156 // fill dummy cache with the next CACHE_SIZE COs
157 fillDummyCache();
158
Zhenkai Zhu8a75ea92012-12-31 00:14:04 -0800159 return co;
Zhenkai Zhu772c7072012-12-30 12:40:23 -0800160}
161
162void
Zhenkai Zhud8569c92012-12-31 00:53:25 -0800163ObjectDBFile::fillDummyCache()
Zhenkai Zhu772c7072012-12-30 12:40:23 -0800164{
Zhenkai Zhu9bcbd542012-12-31 01:01:25 -0800165 ULock(m_cacheLock);
Zhenkai Zhud8569c92012-12-31 00:53:25 -0800166 m_dummyCache.clear();
167 int stop = (m_index + CACHE_SIZE < m_size) ? m_index + CACHE_SIZE : m_size;
168 // the m_index should not change
169 int index = m_index;
170 while (index < stop)
Zhenkai Zhu8a75ea92012-12-31 00:14:04 -0800171 {
172 Bytes co;
173 readBytes(m_istream, co);
Zhenkai Zhud8569c92012-12-31 00:53:25 -0800174 m_dummyCache.insert(make_pair(index, co));
175 index++;
Zhenkai Zhu8a75ea92012-12-31 00:14:04 -0800176 }
Zhenkai Zhu772c7072012-12-30 12:40:23 -0800177}
178
179int
180ObjectDBFile::size() const
181{
182 return m_size;
183}
184
185void
Zhenkai Zhu6204d472013-01-02 13:16:22 -0800186ObjectDBFile::updateSize()
Zhenkai Zhu772c7072012-12-30 12:40:23 -0800187{
188 int pos = m_istream.tellg();
189 m_istream.seekg(2 * sizeof(int), ios::beg);
190 readInt(m_istream, m_size);
191 // recover the original pos
192 m_istream.seekg(pos, ios::beg);
193}
194
195int
196ObjectDBFile::fSize()
197{
Zhenkai Zhu427bed42012-12-30 23:57:48 -0800198 ReadLock(m_filelock);
Zhenkai Zhu772c7072012-12-30 12:40:23 -0800199 updateSize();
200 return m_size;
201}
202
203int
204ObjectDBFile::index()
205{
Zhenkai Zhu427bed42012-12-30 23:57:48 -0800206 ReadLock(m_filelock);
Zhenkai Zhu772c7072012-12-30 12:40:23 -0800207 return m_index;
208}
209
210bool
211ObjectDBFile::seek(int index)
212{
Zhenkai Zhu427bed42012-12-30 23:57:48 -0800213 ReadLock(m_filelock);
Zhenkai Zhu772c7072012-12-30 12:40:23 -0800214 updateSize();
215 if (m_size <= index)
216 {
217 return false;
218 }
219 m_index = index;
220 m_istream.seekg( (3 + m_index) * sizeof(int), ios::beg);
221 int pos;
222 readInt(m_istream, pos);
223 m_istream.seekg(pos, ios::beg);
224 return true;
225}
226
227void
Zhenkai Zhu6204d472013-01-02 13:16:22 -0800228ObjectDBFile::rewind()
Zhenkai Zhu772c7072012-12-30 12:40:23 -0800229{
Zhenkai Zhu427bed42012-12-30 23:57:48 -0800230 ReadLock(m_filelock);
Zhenkai Zhu772c7072012-12-30 12:40:23 -0800231 m_index = 0;
232 // point to the start of the CO fields
233 m_istream.seekg( (3 + m_cap) * sizeof(int), ios::beg);
234}
235
236void
237ObjectDBFile::checkInit(const string &msg)
238{
239 if (!m_initialized)
240 {
241 throwException(msg);
242 }
243}