blob: dea8582482d39bedcb687a5ae0c06bfc9e76e48f [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>
Zhenkai Zhud8569c92012-12-31 00:53:25 -080010#include <deque>
Zhenkai Zhu772c7072012-12-30 12:40:23 -080011#include <boost/thread/locks.hpp>
Zhenkai Zhu772c7072012-12-30 12:40:23 -080012#include <boost/lexical_cast.hpp>
Zhenkai Zhu9bcbd542012-12-31 01:01:25 -080013#include <boost/thread/shared_mutex.hpp>
Zhenkai Zhu427bed42012-12-30 23:57:48 -080014#include <boost/interprocess/sync/file_lock.hpp>
15#include <boost/interprocess/sync/sharable_lock.hpp>
16#include <boost/interprocess/sync/scoped_lock.hpp>
Zhenkai Zhu772c7072012-12-30 12:40:23 -080017
18#define _OVERRIDE
19#ifdef __GNUC__
20#if __GNUC_MAJOR >= 4 && __GNUC_MINOR__ >= 7
21 #undef _OVERRIDE
22 #define _OVERRIDE override
23#endif // __GNUC__ version
24#endif // __GNUC__
25
26using namespace std;
27
28// This is a file based ObjectDB implementation
29// The assumption is, the Content Objects will be stored sequentially
30
31// To provide random access, we will have a table of "address" for each
32// ContentObject at the beginning of the file.
33// This also requires another assumption, that is the number of COs must
34// be know a priori. This requirement is reasonable for our dropbox-like
35// System, as the file we publish is static file and we can easily know
36// the number of COs before we store them into ObjectDB.
37
38/* How file looks like:
39 * |MAGIC_NUM|capacity|size|pos for each CO ...|1st CO|2nd CO| ... |
40 */
41
42class ObjectDBFile
43{
44public:
Zhenkai Zhu427bed42012-12-30 23:57:48 -080045 typedef boost::interprocess::file_lock Filelock;
46 typedef boost::interprocess::scoped_lock<Filelock> WriteLock;
47 typedef boost::interprocess::sharable_lock<Filelock> ReadLock;
Zhenkai Zhu9bcbd542012-12-31 01:01:25 -080048 typedef boost::shared_mutex Mutex;
49 typedef boost::shared_lock<Mutex> SLock;
50 typedef boost::unique_lock<Mutex> ULock;
Zhenkai Zhu772c7072012-12-30 12:40:23 -080051
52 ObjectDBFile(const string &filename);
53 virtual ~ObjectDBFile(){}
54
55 // reserve the "address" table for n COs; must reserve before
56 // write anything (unless reserved quota has not be consumed yet)
57 void
58 init(int capacity);
59
60 bool
61 initialized() const { return m_initialized; }
62
63 // assume sequential
64 virtual void
65 append(const Bytes &co) _OVERRIDE;
66
67 // get next CO
68 virtual Bytes
69 next() _OVERRIDE;
70
Zhenkai Zhu772c7072012-12-30 12:40:23 -080071 // size in terms of number of COs
72 // This is the lazy form of size, i.e. it returns the size cached in this object
73 // but that may not necessarily equal to the actual size kept in file
74 // This is enough if the caller knows for sure that no other thread is changing the
75 // file or the caller does not care about the new size.
76 virtual int
77 size() const _OVERRIDE;
78
79 // this returns the actual size (also update the size cache in this object), but it is more costly, and requires file IO
80 int
81 fSize();
82
83 // the index of the CO to be read
84 int
85 index();
86
87 // set the pos to be the desired CO
88 // return true if success
89 bool
90 seek(int index);
91
92 // reset pos to be zero
93 void
94 rewind();
95
96protected:
Zhenkai Zhu772c7072012-12-30 12:40:23 -080097 // read or write lock should have been grabbed already before the call
98 void
99 checkInit(const string &msg);
100
101 // read lock should have been grabbed already before the call
102 void
103 updateSize();
104
Zhenkai Zhud8569c92012-12-31 00:53:25 -0800105 // read lock should have been grabbed already before the call
106 void
107 fillDummyCache();
108
Zhenkai Zhu772c7072012-12-30 12:40:23 -0800109 #define MAGIC_NUM 0xAAAAAAAA
110
111protected:
112 string m_filename;
113 ifstream m_istream;
114 ofstream m_ostream;
Zhenkai Zhu427bed42012-12-30 23:57:48 -0800115 Filelock m_filelock;
Zhenkai Zhu772c7072012-12-30 12:40:23 -0800116 bool m_initialized;
117 // capacity in terms of number of COs
118 int m_cap;
119 int m_size;
120 // the index (or seq) of the CO to be read
121 int m_index;
Zhenkai Zhud8569c92012-12-31 00:53:25 -0800122
123 // A dummy Cache that holds the next 10 (or all remaining if less than 10)
124 // COs after a next() operation
125 // If needed and time allows, we can have more complex cache
126 #define CACHE_SIZE 10
127 map<int, Bytes> m_dummyCache;
Zhenkai Zhu9bcbd542012-12-31 01:01:25 -0800128 Mutex m_cacheMutex;
Zhenkai Zhu772c7072012-12-30 12:40:23 -0800129};
130
131void inline
132writeInt(ostream &out, const int &x)
133{
134 out.write((const char *)&x, sizeof(int));
135}
136
137void inline
138readInt(istream &in, int &x)
139{
140 in.read((char *)&x, sizeof(int));
141}
142
143// write size and then the actual bytes
144// operator << overloading is not used to avoid confusion
145void
146writeBytes(ostream &out, const Bytes &bytes);
147
148// read size and then the actual bytes
149void
150readBytes(istream &in, Bytes &bytes);
151
152#endif