blob: fb9ca91532764c1891a39f72b242c4564574e33e [file] [log] [blame]
Zhenkai Zhu772c7072012-12-30 12:40:23 -08001#ifndef OBJECT_DB_FILE_H
2#define OBJECT_DB_FILE_H
3
4#include "object-db.h"
5#include <stdio.h>
6#include <fstream>
7#include <ifstream>
8#include <ofstream>
9#include <sstream>
10#include <boost/thread/locks.hpp>
11#include <boost/thread/recursive_mutex.hpp>
12#include <boost/lexical_cast.hpp>
13
14#define _OVERRIDE
15#ifdef __GNUC__
16#if __GNUC_MAJOR >= 4 && __GNUC_MINOR__ >= 7
17 #undef _OVERRIDE
18 #define _OVERRIDE override
19#endif // __GNUC__ version
20#endif // __GNUC__
21
22using namespace std;
23
24// This is a file based ObjectDB implementation
25// The assumption is, the Content Objects will be stored sequentially
26
27// To provide random access, we will have a table of "address" for each
28// ContentObject at the beginning of the file.
29// This also requires another assumption, that is the number of COs must
30// be know a priori. This requirement is reasonable for our dropbox-like
31// System, as the file we publish is static file and we can easily know
32// the number of COs before we store them into ObjectDB.
33
34/* How file looks like:
35 * |MAGIC_NUM|capacity|size|pos for each CO ...|1st CO|2nd CO| ... |
36 */
37
38class ObjectDBFile
39{
40public:
41 typedef boost::shared_mutex Lock;
42 typedef boost::unique_lock<Lock> WriteLock;
43 typedef boost::shared_lock<Lock> ReadLock;
44
45 ObjectDBFile(const string &filename);
46 virtual ~ObjectDBFile(){}
47
48 // reserve the "address" table for n COs; must reserve before
49 // write anything (unless reserved quota has not be consumed yet)
50 void
51 init(int capacity);
52
53 bool
54 initialized() const { return m_initialized; }
55
56 // assume sequential
57 virtual void
58 append(const Bytes &co) _OVERRIDE;
59
60 // get next CO
61 virtual Bytes
62 next() _OVERRIDE;
63
64 // get n COs; if the remaining number of COs < n, return all;
65 virtual void
66 read(vector<Bytes> &vco, int n) _OVERRIDE;
67
68 // size in terms of number of COs
69 // This is the lazy form of size, i.e. it returns the size cached in this object
70 // but that may not necessarily equal to the actual size kept in file
71 // This is enough if the caller knows for sure that no other thread is changing the
72 // file or the caller does not care about the new size.
73 virtual int
74 size() const _OVERRIDE;
75
76 // this returns the actual size (also update the size cache in this object), but it is more costly, and requires file IO
77 int
78 fSize();
79
80 // the index of the CO to be read
81 int
82 index();
83
84 // set the pos to be the desired CO
85 // return true if success
86 bool
87 seek(int index);
88
89 // reset pos to be zero
90 void
91 rewind();
92
93protected:
94 // write lock should have been grabbed already before the call
95 void
96 prepareWrite();
97
98 // read or write lock should have been grabbed already before the call
99 void
100 checkInit(const string &msg);
101
102 // read lock should have been grabbed already before the call
103 void
104 updateSize();
105
106 #define MAGIC_NUM 0xAAAAAAAA
107
108protected:
109 string m_filename;
110 ifstream m_istream;
111 ofstream m_ostream;
112 Lock m_lock;
113 bool m_writable;
114 bool m_initialized;
115 // capacity in terms of number of COs
116 int m_cap;
117 int m_size;
118 // the index (or seq) of the CO to be read
119 int m_index;
120};
121
122void inline
123writeInt(ostream &out, const int &x)
124{
125 out.write((const char *)&x, sizeof(int));
126}
127
128void inline
129readInt(istream &in, int &x)
130{
131 in.read((char *)&x, sizeof(int));
132}
133
134// write size and then the actual bytes
135// operator << overloading is not used to avoid confusion
136void
137writeBytes(ostream &out, const Bytes &bytes);
138
139// read size and then the actual bytes
140void
141readBytes(istream &in, Bytes &bytes);
142
143#endif