summaryrefslogtreecommitdiff
path: root/src/hdb/filemap.cc
diff options
context:
space:
mode:
authorHenrik Rydberg <rydberg@euromail.se>2011-10-08 20:30:28 +0200
committerHenrik Rydberg <rydberg@euromail.se>2011-10-08 20:30:28 +0200
commit5df79c53745fde5d6c3340a2979b1429cd5892c1 (patch)
tree1a81af141708b826e9c61e8a04019994fcca8298 /src/hdb/filemap.cc
Initial import of htcd system 1.0
Signed-off-by: Henrik Rydberg <rydberg@euromail.se>
Diffstat (limited to 'src/hdb/filemap.cc')
-rw-r--r--src/hdb/filemap.cc302
1 files changed, 302 insertions, 0 deletions
diff --git a/src/hdb/filemap.cc b/src/hdb/filemap.cc
new file mode 100644
index 0000000..b40644f
--- /dev/null
+++ b/src/hdb/filemap.cc
@@ -0,0 +1,302 @@
1/*************************************************************************
2 *
3 * HTCd - Copyright (C) 1998-2006 Henrik Rydberg
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include <hdb/filemap.h>
21#include <mt/split.h>
22#include <fcntl.h>
23#include <sys/stat.h>
24#include <sys/mman.h>
25#include <new>
26using namespace std;
27
28const int PAGESIZE=getpagesize();
29const filemap::char32 HEADNAME="HDB/1.2\n";
30const filemap::char32 COMPNAME="lt";
31const mstring dev_tag="/dev/";
32
33const int TIMEOUT=20;
34
35///////////////////////////////////////////////////
36
37filemap::head_t::head_t()
38{
39 memcpy(ident,HEADNAME,sizeof(char32));
40 lock.set(0);
41 minor.set(0);
42 major.set(0);
43 fatal.set(0);
44 filesize.set(PAGESIZE);
45 filetop.set(sizeof(head_t));
46 tables.set(0);
47 index.set(0);
48 memcpy(compname,COMPNAME,sizeof(char32));
49 memset(tabs,0,maxtabs*sizeof(char32));
50 frame.set(sizeof(head_t));
51}
52
53filemap::head_t::head_t(const head_t* hd,int mem)
54{
55 memcpy(ident,HEADNAME,sizeof(char32));
56 lock.set(0);
57 minor.set(0);
58 major.set(0);
59 fatal.set(0);
60 filetop.set(sizeof(head_t)+mem);
61 filesize.set(PAGESIZE*int((filetop.get()+PAGESIZE)/PAGESIZE));
62 tables=hd->tables;
63 index=hd->index;
64 memcpy(compname,hd->compname,sizeof(char32));
65 memset(tabs,0,maxtabs*sizeof(char32));
66 for(int i=0;i<tables.get();i++)
67 memcpy(tabs[i],hd->tabs[i],sizeof(char32));
68 frame.set(sizeof(head_t));
69}
70
71void filemap::head_t::setcomp(int idx,const sref& s)
72{
73 index.set(idx);
74 s.copyto(compname,sizeof(char32));
75 fatal.add(1);
76}
77
78void filemap::head_t::set(int col,const sref& s)
79{
80 s.copyto(tabs[col],sizeof(char32));
81 fatal.add(1);
82}
83
84void filemap::head_t::insert(int col,const sref& s)
85{
86 for(int i=maxtabs-1;i>col;i--)
87 memcpy(tabs[i],tabs[i-1],sizeof(char32));
88 if(index.get()>=col&&index.get()<tables.get())
89 index.add(1);
90 s.copyto(tabs[col],sizeof(char32));
91 tables.add(1);
92 fatal.add(1);
93}
94
95void filemap::head_t::remove(int col)
96{
97 if(index.get()!=col) {
98 for(int i=col;i<maxtabs-1;i++)
99 memcpy(tabs[i],tabs[i+1],sizeof(char32));
100 if(index.get()>col) index.set(index.get()-1);
101 tables.add(-1);
102 fatal.add(1);
103 }
104}
105
106///////////////////////////////////////////////////////
107
108filemap::chunk_t::chunk_t(chunk_t* p,int fd,int wok,int off,int size)
109{
110 next=p;
111 end=(begin=off)+size;
112 map=(char*)mmap(0,size,PROT_READ|(wok?PROT_WRITE:0),MAP_SHARED,fd,off);
113 if(map==MAP_FAILED) { map=0; THROW("filemap: could not map chunk") }
114}
115
116filemap::chunk_t::~chunk_t()
117{
118 if(map) munmap(map,end-begin);
119}
120
121int filemap::chunk_t::fill(int off)
122{
123 if(own(off)) {
124 at(off)->mem.set(end-off);
125 at(off)->caps.set(0);
126 return end;
127 }
128 else return off;
129}
130
131void filemap::chunk_t::sync()
132{
133 msync(map,end-begin,MS_SYNC);
134}
135
136///////////////////////////////////////////////////////
137
138void filemap::remap()
139{
140 while(mem->end<hd->filesize.get()) {
141 mem=new chunk_t(mem,fd,wok,mem->end,mem->size()<<1);
142 }
143}
144
145filemap::rec_t* filemap::add(int n)
146{
147 int caps=sizeof(rec_t),dim=caps+n;
148 while(caps<dim) caps<<=1;
149 remap();
150 if(hd->filesize.get()<mem->end) {
151 ftruncate(fd,mem->end);
152 hd->filesize.set(mem->end);
153 }
154 while(hd->filetop.get()+caps>mem->end) {
155 hd->filetop.set(mem->fill(hd->filetop.get()));
156 mem=new chunk_t(mem,fd,wok,mem->end,mem->size()<<1);
157 ftruncate(fd,mem->end);
158 hd->filesize.set(mem->end);
159 }
160 rec_t* rec=at(hd->filetop.get());
161 hd->filetop.add(caps);
162 rec->mem.set(caps);
163 rec->caps.set(n);
164 return rec;
165}
166
167void filemap::rem(rec_t* rec)
168{
169 rec->caps.set(0);
170}
171
172///////////////////////////////////////////////////////
173
174filemap::filemap(filemap* p):
175 next(p),fd(-1),wok(0),refs(0),pathname(),hd(0),mem(0),nodelock(0)
176{
177 memset(&mutex,0,sizeof(mutex_t));
178}
179
180filemap::filemap(filemap* p,const mstring& path,int update,int prot):
181 next(p),fd(-1),wok(0),refs(0),pathname(),hd(0),mem(0),nodelock(0)
182{
183 memset(&mutex,0,sizeof(mutex_t));
184 open(path,update,prot);
185}
186
187filemap::~filemap()
188{
189 close();
190}
191
192///////////////////////////////////////////////////////
193
194void filemap::open(const mstring& path,int update,int prot) throw(merror_t)
195{
196 close();
197 if(update) {
198 if(path.left(5)!=dev_tag) nodelock=new nodelock_t(path);
199 else nodelock=0;
200 wok=1;
201 }
202 else {
203 nodelock=0;
204 wok=0;
205 }
206 fd=::open(path.c_str(),wok?O_RDWR|O_CREAT:O_RDONLY,prot);
207 if(fd<0) THROW("filemap: could not open "<<path);
208 int fsize=lseek(fd,0,SEEK_END);
209 int mapsize=PAGESIZE*int((fsize+PAGESIZE)/PAGESIZE);
210 hd=(head_t*)(mem=new chunk_t(0,fd,wok,0,mapsize))->map;
211 if(fsize<sizeof(head_t)) {
212 if(wok) { ftruncate(fd,fsize=mapsize); new(hd) head_t(); }
213 else THROW("filemap: not a HDB file");
214 }
215 if(First(sref(hd->ident))!=First(sref(HEADNAME))) THROW("filemap: bad version");
216 remap();
217 if(fsize!=hd->filesize.get())
218 THROW("filemap: "<<path<<" has bad filesize - run hdbfix");
219 pathname=path;
220}
221
222void filemap::check() throw(merror_t)
223{
224 // Make a consistency test, but NEVER change filetop!!!
225 // Severe loss of data may occur if you do
226 // Use hdbfix in case the db seems corrupted
227 int p=recs(),ft=hd->filetop.get();
228 while(size(p)) {
229 rec_t* rec=at(p);
230 p+=rec->mem.get();
231 }
232 if(p<ft) THROW("filemap: "<<pathname<<" is corrupted - run hdbfix");
233 // OK, at least no data is missing. Usually p==ft,
234 // but since no locking is done here, another process
235 // may make changes that turn p>ft.
236}
237
238void filemap::save(const mstring& path,int prot) throw(merror_t)
239{
240 if(path==pathname) THROW("filemap: cannot overwrite current file");
241 int mfd=::open(path.c_str(),O_RDWR|O_CREAT|O_TRUNC,prot);
242 if(mfd<0) THROW("filemap: could not open "<<path<<" for writing");
243 int caps=0,p=recs();
244 while(size(p)) {
245 rec_t* rec=at(p);
246 if(rec->caps.get()) caps+=rec->mem.get();
247 p+=rec->mem.get();
248 }
249 head_t mhd(hd,caps);
250 ::write(mfd,&mhd,sizeof(head_t));
251 p=recs();
252 while(size(p)) {
253 rec_t* rec=at(p);
254 if(rec->caps.get()) ::write(mfd,rec,rec->mem.get());
255 p+=rec->mem.get();
256 }
257 ftruncate(mfd,mhd.filesize.get());
258 ::close(mfd);
259}
260
261void filemap::close()
262{
263 while(mem) { chunk_t* p=mem->next; delete mem; mem=p; }
264 hd=0;
265 wok=0;
266 refs=0;
267 if(fd>=0) { ::close(fd); fd=-1; }
268 delete nodelock; nodelock=0;
269 pathname.clear();
270}
271
272void filemap::sync()
273{
274 for(chunk_t* p=mem;p;p=p->next) p->sync();
275}
276
277///////////////////////////////////////////////////////
278
279void filemap::lock()
280{
281 if(hd) {
282 MLOCK(mutex);
283 if((volatile long&)hd->lock) {
284 time_t end=time(0)+TIMEOUT;
285 while((volatile long&)hd->lock&&time(0)<end);
286 }
287 hd->lock.set(1);
288 }
289}
290
291void filemap::unlock()
292{
293 if(hd) hd->lock.set(0);
294}
295
296///////////////////////////////////////////////////////
297
298time_t filemap::Lastmod() const
299{
300 struct stat fs; fstat(fd,&fs); return fs.st_mtime;
301}
302