From 5df79c53745fde5d6c3340a2979b1429cd5892c1 Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Sat, 8 Oct 2011 20:30:28 +0200 Subject: Initial import of htcd system 1.0 Signed-off-by: Henrik Rydberg --- src/hdb/filemap.cc | 302 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 302 insertions(+) create mode 100644 src/hdb/filemap.cc (limited to 'src/hdb/filemap.cc') 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 @@ +/************************************************************************* + * + * HTCd - Copyright (C) 1998-2006 Henrik Rydberg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +using namespace std; + +const int PAGESIZE=getpagesize(); +const filemap::char32 HEADNAME="HDB/1.2\n"; +const filemap::char32 COMPNAME="lt"; +const mstring dev_tag="/dev/"; + +const int TIMEOUT=20; + +/////////////////////////////////////////////////// + +filemap::head_t::head_t() +{ + memcpy(ident,HEADNAME,sizeof(char32)); + lock.set(0); + minor.set(0); + major.set(0); + fatal.set(0); + filesize.set(PAGESIZE); + filetop.set(sizeof(head_t)); + tables.set(0); + index.set(0); + memcpy(compname,COMPNAME,sizeof(char32)); + memset(tabs,0,maxtabs*sizeof(char32)); + frame.set(sizeof(head_t)); +} + +filemap::head_t::head_t(const head_t* hd,int mem) +{ + memcpy(ident,HEADNAME,sizeof(char32)); + lock.set(0); + minor.set(0); + major.set(0); + fatal.set(0); + filetop.set(sizeof(head_t)+mem); + filesize.set(PAGESIZE*int((filetop.get()+PAGESIZE)/PAGESIZE)); + tables=hd->tables; + index=hd->index; + memcpy(compname,hd->compname,sizeof(char32)); + memset(tabs,0,maxtabs*sizeof(char32)); + for(int i=0;itabs[i],sizeof(char32)); + frame.set(sizeof(head_t)); +} + +void filemap::head_t::setcomp(int idx,const sref& s) +{ + index.set(idx); + s.copyto(compname,sizeof(char32)); + fatal.add(1); +} + +void filemap::head_t::set(int col,const sref& s) +{ + s.copyto(tabs[col],sizeof(char32)); + fatal.add(1); +} + +void filemap::head_t::insert(int col,const sref& s) +{ + for(int i=maxtabs-1;i>col;i--) + memcpy(tabs[i],tabs[i-1],sizeof(char32)); + if(index.get()>=col&&index.get()col) index.set(index.get()-1); + tables.add(-1); + fatal.add(1); + } +} + +/////////////////////////////////////////////////////// + +filemap::chunk_t::chunk_t(chunk_t* p,int fd,int wok,int off,int size) +{ + next=p; + end=(begin=off)+size; + map=(char*)mmap(0,size,PROT_READ|(wok?PROT_WRITE:0),MAP_SHARED,fd,off); + if(map==MAP_FAILED) { map=0; THROW("filemap: could not map chunk") } +} + +filemap::chunk_t::~chunk_t() +{ + if(map) munmap(map,end-begin); +} + +int filemap::chunk_t::fill(int off) +{ + if(own(off)) { + at(off)->mem.set(end-off); + at(off)->caps.set(0); + return end; + } + else return off; +} + +void filemap::chunk_t::sync() +{ + msync(map,end-begin,MS_SYNC); +} + +/////////////////////////////////////////////////////// + +void filemap::remap() +{ + while(mem->endfilesize.get()) { + mem=new chunk_t(mem,fd,wok,mem->end,mem->size()<<1); + } +} + +filemap::rec_t* filemap::add(int n) +{ + int caps=sizeof(rec_t),dim=caps+n; + while(capsfilesize.get()end) { + ftruncate(fd,mem->end); + hd->filesize.set(mem->end); + } + while(hd->filetop.get()+caps>mem->end) { + hd->filetop.set(mem->fill(hd->filetop.get())); + mem=new chunk_t(mem,fd,wok,mem->end,mem->size()<<1); + ftruncate(fd,mem->end); + hd->filesize.set(mem->end); + } + rec_t* rec=at(hd->filetop.get()); + hd->filetop.add(caps); + rec->mem.set(caps); + rec->caps.set(n); + return rec; +} + +void filemap::rem(rec_t* rec) +{ + rec->caps.set(0); +} + +/////////////////////////////////////////////////////// + +filemap::filemap(filemap* p): + next(p),fd(-1),wok(0),refs(0),pathname(),hd(0),mem(0),nodelock(0) +{ + memset(&mutex,0,sizeof(mutex_t)); +} + +filemap::filemap(filemap* p,const mstring& path,int update,int prot): + next(p),fd(-1),wok(0),refs(0),pathname(),hd(0),mem(0),nodelock(0) +{ + memset(&mutex,0,sizeof(mutex_t)); + open(path,update,prot); +} + +filemap::~filemap() +{ + close(); +} + +/////////////////////////////////////////////////////// + +void filemap::open(const mstring& path,int update,int prot) throw(merror_t) +{ + close(); + if(update) { + if(path.left(5)!=dev_tag) nodelock=new nodelock_t(path); + else nodelock=0; + wok=1; + } + else { + nodelock=0; + wok=0; + } + fd=::open(path.c_str(),wok?O_RDWR|O_CREAT:O_RDONLY,prot); + if(fd<0) THROW("filemap: could not open "<map; + if(fsizeident))!=First(sref(HEADNAME))) THROW("filemap: bad version"); + remap(); + if(fsize!=hd->filesize.get()) + THROW("filemap: "<filetop.get(); + while(size(p)) { + rec_t* rec=at(p); + p+=rec->mem.get(); + } + if(pft. +} + +void filemap::save(const mstring& path,int prot) throw(merror_t) +{ + if(path==pathname) THROW("filemap: cannot overwrite current file"); + int mfd=::open(path.c_str(),O_RDWR|O_CREAT|O_TRUNC,prot); + if(mfd<0) THROW("filemap: could not open "<caps.get()) caps+=rec->mem.get(); + p+=rec->mem.get(); + } + head_t mhd(hd,caps); + ::write(mfd,&mhd,sizeof(head_t)); + p=recs(); + while(size(p)) { + rec_t* rec=at(p); + if(rec->caps.get()) ::write(mfd,rec,rec->mem.get()); + p+=rec->mem.get(); + } + ftruncate(mfd,mhd.filesize.get()); + ::close(mfd); +} + +void filemap::close() +{ + while(mem) { chunk_t* p=mem->next; delete mem; mem=p; } + hd=0; + wok=0; + refs=0; + if(fd>=0) { ::close(fd); fd=-1; } + delete nodelock; nodelock=0; + pathname.clear(); +} + +void filemap::sync() +{ + for(chunk_t* p=mem;p;p=p->next) p->sync(); +} + +/////////////////////////////////////////////////////// + +void filemap::lock() +{ + if(hd) { + MLOCK(mutex); + if((volatile long&)hd->lock) { + time_t end=time(0)+TIMEOUT; + while((volatile long&)hd->lock&&time(0)lock.set(1); + } +} + +void filemap::unlock() +{ + if(hd) hd->lock.set(0); +} + +/////////////////////////////////////////////////////// + +time_t filemap::Lastmod() const +{ + struct stat fs; fstat(fd,&fs); return fs.st_mtime; +} + -- cgit v1.2.3