blob: 9fe62de093c16b40ed7f114ee695e1db644b3469 [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);
126 Bytes co;
127 if (m_index >= m_size)
128 {
129 return co;
130 }
131 readBytes(m_istream, co);
132 m_index++;
133 return co;
Zhenkai Zhu772c7072012-12-30 12:40:23 -0800134}
135
Zhenkai Zhu8a75ea92012-12-31 00:14:04 -0800136// Caching is not so useful here, as its sequentially reading anyway
Zhenkai Zhu772c7072012-12-30 12:40:23 -0800137void
138ObjectDBFile::read(vector<Bytes> &vco, int n)
139{
Zhenkai Zhu8a75ea92012-12-31 00:14:04 -0800140 ReadLock(m_filelock);
141 int stop = (m_index + n < m_size ) ? m_index + n : m_size;
142 while (m_index < stop)
143 {
144 Bytes co;
145 readBytes(m_istream, co);
146 vco.push_back(co);
147 m_index++;
148 }
Zhenkai Zhu772c7072012-12-30 12:40:23 -0800149}
150
151int
152ObjectDBFile::size() const
153{
154 return m_size;
155}
156
157void
158ObjectDBFile::updateSzie()
159{
160 int pos = m_istream.tellg();
161 m_istream.seekg(2 * sizeof(int), ios::beg);
162 readInt(m_istream, m_size);
163 // recover the original pos
164 m_istream.seekg(pos, ios::beg);
165}
166
167int
168ObjectDBFile::fSize()
169{
Zhenkai Zhu427bed42012-12-30 23:57:48 -0800170 ReadLock(m_filelock);
Zhenkai Zhu772c7072012-12-30 12:40:23 -0800171 updateSize();
172 return m_size;
173}
174
175int
176ObjectDBFile::index()
177{
Zhenkai Zhu427bed42012-12-30 23:57:48 -0800178 ReadLock(m_filelock);
Zhenkai Zhu772c7072012-12-30 12:40:23 -0800179 return m_index;
180}
181
182bool
183ObjectDBFile::seek(int index)
184{
Zhenkai Zhu427bed42012-12-30 23:57:48 -0800185 ReadLock(m_filelock);
Zhenkai Zhu772c7072012-12-30 12:40:23 -0800186 updateSize();
187 if (m_size <= index)
188 {
189 return false;
190 }
191 m_index = index;
192 m_istream.seekg( (3 + m_index) * sizeof(int), ios::beg);
193 int pos;
194 readInt(m_istream, pos);
195 m_istream.seekg(pos, ios::beg);
196 return true;
197}
198
199void
200rewind()
201{
Zhenkai Zhu427bed42012-12-30 23:57:48 -0800202 ReadLock(m_filelock);
Zhenkai Zhu772c7072012-12-30 12:40:23 -0800203 m_index = 0;
204 // point to the start of the CO fields
205 m_istream.seekg( (3 + m_cap) * sizeof(int), ios::beg);
206}
207
208void
209ObjectDBFile::checkInit(const string &msg)
210{
211 if (!m_initialized)
212 {
213 throwException(msg);
214 }
215}