blob: 02991a9fbe3a47473ef7da04a6db85ba945d2dfa [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 Zhu8a75ea92012-12-31 00:14:04 -0800125 ReadLock(m_filelock);
Zhenkai Zhud8569c92012-12-31 00:53:25 -0800126 // We are been lazy here; just use file lock as mutex
127 // for the access to the cache too
128 if (m_dummyCache.find(m_index) != map::end)
129 {
130 int index = m_index;
131 m_index++;
132 return m_dummyCache[index];
133 }
134
135 // m_index not found in cache
Zhenkai Zhu8a75ea92012-12-31 00:14:04 -0800136 Bytes co;
137 if (m_index >= m_size)
138 {
Zhenkai Zhud8569c92012-12-31 00:53:25 -0800139 // at the end of file, return empty
Zhenkai Zhu8a75ea92012-12-31 00:14:04 -0800140 return co;
141 }
Zhenkai Zhud8569c92012-12-31 00:53:25 -0800142
Zhenkai Zhu8a75ea92012-12-31 00:14:04 -0800143 readBytes(m_istream, co);
144 m_index++;
Zhenkai Zhud8569c92012-12-31 00:53:25 -0800145
146 // fill dummy cache with the next CACHE_SIZE COs
147 fillDummyCache();
148
Zhenkai Zhu8a75ea92012-12-31 00:14:04 -0800149 return co;
Zhenkai Zhu772c7072012-12-30 12:40:23 -0800150}
151
152void
Zhenkai Zhud8569c92012-12-31 00:53:25 -0800153ObjectDBFile::fillDummyCache()
Zhenkai Zhu772c7072012-12-30 12:40:23 -0800154{
Zhenkai Zhud8569c92012-12-31 00:53:25 -0800155 m_dummyCache.clear();
156 int stop = (m_index + CACHE_SIZE < m_size) ? m_index + CACHE_SIZE : m_size;
157 // the m_index should not change
158 int index = m_index;
159 while (index < stop)
Zhenkai Zhu8a75ea92012-12-31 00:14:04 -0800160 {
161 Bytes co;
162 readBytes(m_istream, co);
Zhenkai Zhud8569c92012-12-31 00:53:25 -0800163 m_dummyCache.insert(make_pair(index, co));
164 index++;
Zhenkai Zhu8a75ea92012-12-31 00:14:04 -0800165 }
Zhenkai Zhu772c7072012-12-30 12:40:23 -0800166}
167
168int
169ObjectDBFile::size() const
170{
171 return m_size;
172}
173
174void
175ObjectDBFile::updateSzie()
176{
177 int pos = m_istream.tellg();
178 m_istream.seekg(2 * sizeof(int), ios::beg);
179 readInt(m_istream, m_size);
180 // recover the original pos
181 m_istream.seekg(pos, ios::beg);
182}
183
184int
185ObjectDBFile::fSize()
186{
Zhenkai Zhu427bed42012-12-30 23:57:48 -0800187 ReadLock(m_filelock);
Zhenkai Zhu772c7072012-12-30 12:40:23 -0800188 updateSize();
189 return m_size;
190}
191
192int
193ObjectDBFile::index()
194{
Zhenkai Zhu427bed42012-12-30 23:57:48 -0800195 ReadLock(m_filelock);
Zhenkai Zhu772c7072012-12-30 12:40:23 -0800196 return m_index;
197}
198
199bool
200ObjectDBFile::seek(int index)
201{
Zhenkai Zhu427bed42012-12-30 23:57:48 -0800202 ReadLock(m_filelock);
Zhenkai Zhu772c7072012-12-30 12:40:23 -0800203 updateSize();
204 if (m_size <= index)
205 {
206 return false;
207 }
208 m_index = index;
209 m_istream.seekg( (3 + m_index) * sizeof(int), ios::beg);
210 int pos;
211 readInt(m_istream, pos);
212 m_istream.seekg(pos, ios::beg);
213 return true;
214}
215
216void
217rewind()
218{
Zhenkai Zhu427bed42012-12-30 23:57:48 -0800219 ReadLock(m_filelock);
Zhenkai Zhu772c7072012-12-30 12:40:23 -0800220 m_index = 0;
221 // point to the start of the CO fields
222 m_istream.seekg( (3 + m_cap) * sizeof(int), ios::beg);
223}
224
225void
226ObjectDBFile::checkInit(const string &msg)
227{
228 if (!m_initialized)
229 {
230 throwException(msg);
231 }
232}