/************************************************************************* * * 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 filemap* dbmap::flist; mutex_t dbmap::mutex; opmap dbmap::M; /////////////////////////////////////////////////////////////////////// dbmap::dbmap(): wok(0),fatal(0),index(0), compname(),file(0),tmap(),recs() { minor=0; major=0; } dbmap::~dbmap() { Close(); } /////////////////////////////////////////////////////////////////////// void dbmap::remap_tabs() { fatal=head()->fatal.get(); tmap.clear(); for(int i=0;itabs[i]),i); } void dbmap::remap_recs() { major=head()->major.get(); recs.clear(); int p=file->recs(); while(file->size(p)) { record_t* rec=(record_t*)file->at(p); if(rec->caps.get()) recs.push_back(idx_t(rec->at(index),rec)); p+=rec->mem.get(); } recs.sort(CompOperator(compname)); } int dbmap::remap() { int state=0; if(fatal!=head()->fatal.get()) { remap_tabs(); state|=4; } if(major!=head()->major.get()) { remap_recs(); state|=2; } if(minor!=head()->minor.get()) { minor=head()->minor.get(); state|=1; } return state; } /////////////////////////////////////////////////////////////////////// void Open(const mstring& path,int update=0,int prot=0600) throw(merror_t); void Saveas(const mstring& path,int prot=0600) throw(merror_t); void Close(); void dbmap::Open(const mstring& path,int update,int prot) throw(merror_t) { Close(); wok=update?1:0; { MLOCK(mutex); for(filemap* p=flist;p;p=p->next) if(p->Pathname()==path&&p->writable()==wok) { (file=p)->pushref(); break; } if(!file) { filemap* fm=new filemap(flist); try { fm->open(path,wok,prot); fm->check(); file=flist=fm; } catch(...) { delete fm; wok=0; throw; } } } index=head()->index.get(); compname=head()->compname; remap_tabs(); remap_recs(); minor=head()->minor.get(); } void dbmap::Saveas(const mstring& path,int prot) throw(merror_t) { file->save(path,prot); } void dbmap::Close() { wok=0; minor=0; major=0; fatal=0; index=0; compname.clear(); recs.clear(); tmap.clear(); if(file) { MLOCK(mutex); if(file->reference()) file->popref(); else { if(flist==file) flist=file->next; else for(filemap* p=flist;p;p=p->next) if(p->next==file) { p->next=file->next; break; } delete file; } file=0; } } void dbmap::Sync() { MLOCK(mutex); for(filemap* p=flist;p;p=p->next) { if(p->writable()) p->sync(); } } /////////////////////////////////////////////////////////////////////// void dbmap::SetTable(int col,const sref& name) throw(merror_t) { check(); if(!wok) THROW("db: cannot set table - readonly"); if(col<0||col>=Tables()) THROW("db: bad column"); HEADLOCK(file); head()->set(col,name); remap(); } void dbmap::InsertTable(int col,const sref& name) throw(merror_t) { check(); if(!wok) THROW("db: cannot insert table - readonly"); if(Tables()+1>file->maxtabs) THROW("db: too many tables"); if(col<0||col>Tables()) THROW("db: bad column"); { HEADLOCK(file); head()->insert(col,name); int p=file->recs(); while(file->size(p)) { record_t* rec=(record_t*)file->at(p); if(rec->caps.get()) rec->insert(col); p+=rec->mem.get(); } head()->major.add(1); } index=head()->index.get(); compname=head()->compname; remap(); } void dbmap::RemTable(int col) throw(merror_t) { check(); if(!wok) THROW("db: cannot remove table - readonly"); if(col<0||col>=Tables()) THROW("db: bad column"); if(col==head()->index.get()) THROW("db: cannot remove index table"); { HEADLOCK(file); head()->remove(col); int p=file->recs(); while(file->size(p)) { record_t* rec=(record_t*)file->at(p); if(rec->caps.get()) rec->remove(col); p+=rec->mem.get(); } head()->major.add(1); } index=head()->index.get(); compname=head()->compname; remap(); } /////////////////////////////////////////////////////////////////////// void dbmap::Get(int row,spile& list) throw(merror_t) { check(); if(row<0||row>=recs.size()) THROW("db: not a valid record"); list.resize(Tables()); recs[row].rec->get(list); } void dbmap::Set(int row,int col,const sref& s) throw(merror_t) { check(); if(!wok) THROW("db: cannot set - readonly"); if(row<0||row>=recs.size()) THROW("db: not a valid record"); if(col==index) THROW("db: cannot set index"); HEADLOCK(file); record_t* rec=recs[row].rec; int dim=rec->setreq(col,s); if(dim>rec->caps.get()) { rec=new(file->add(dim)) record_t(*rec); file->rem(recs[row].rec); recs[row].rec=rec; head()->major.add(1); major++; } rec->set(col,s); head()->minor.add(1); minor++; } void dbmap::Set(int row,const spile& list) throw(merror_t) { check(); if(!wok) THROW("db: cannot set - readonly"); if(row<0||row>=recs.size()) THROW("db: not a valid record"); if(list.size()!=Tables()) THROW("db: wrong number of tables - "<at(index)!=list[index]) THROW("db: cannot set index"); int dim=record_t::req(list); if(dim>rec->caps.get()) { rec=new(file->add(dim)) record_t(*rec); file->rem(recs[row].rec); recs[row].rec=rec; head()->major.add(1); major++; } rec->set(list); head()->minor.add(1); minor++; } /////////////////////////////////////////////////////////////////////// void dbmap::Rem(int row) throw(merror_t) { if(!wok) THROW("db: cannot delete - readonly"); if(row<0||row>=recs.size()) THROW("db: not a valid record"); HEADLOCK(file); file->rem(recs[row].rec); recs.erase(recs.begin()+row); head()->major.add(1); major++; } int dbmap::Insert(const spile& list,int unique) throw(merror_t) { check(); if(!wok) THROW("db: cannot insert - readonly"); if(index!=head()->index.get()) THROW("db: can only insert under normal order"); HEADLOCK(file); remap(); int row=recs.get(list[index]); if(row<0) { record_t* rec=new(file->add(record_t::req(list))) record_t(list); row=recs.add(rec->at(index),rec); head()->major.add(1); major++; } return row; }