#include "stopos_pool.h" #include "flatfile_pool.h" #include #include #include #include #include #include "wutils.h" #include #include #include #include #include "stopos.h" // // this->status.extra is always pointing to // the first free slot // // records are stored thusly: // character to denote if this record exists or is deleted // dbsep // // for a not deleted record, next fields: // key for this record // dbsep // 1st parameter of put_record // // for a deleted record: // pointer to next deleted record // // constructor flatfile_pool::flatfile_pool() { this->whoami = "flat"; this->statuskey.set_slot(this->statuskey.get_key()); } std::string flatfile_pool::key_to_slot(const std::string &k) { if (strtoslot(this->status.extra) == 0) return k; std::string slot = this->status.extra; std::string r; off_t p = strtoslot(slot)*this->reclen; this->read_string(r, p); this->status.extra = r.substr(2); return slot; } off_t flatfile_pool::strtoslot(const std::string &s) { return stopos_key::KeyToNumber(s); } std::string flatfile_pool::slottostr(off_t l) { return stopos_key::NumberToKey(l); } int flatfile_pool::haskey(std::string &r, const std::string &k) { size_t q1 = 1; // find second separator. The first one is on postion 1 size_t q2 = r.find(dbsep,2); std::string key = r.substr(q1+1,q2-q1-1); if (key != k) return this->NOTFOUND; r.erase(0,q2+1); return 0; } int flatfile_pool::get_record(std::string &r, const std::string &k, const std::string &l) { int rc; off_t p = this->strtoslot(l)*reclen; rc = this->read_string(r,p); if (rc !=0 ) return rc; if (r[0] == this->deleted) return this->NOTFOUND; // this record was not deleted, but it could be that // the key does not match // rc = this->haskey(r,k); if (rc != 0) return rc; return 0; } int flatfile_pool::put_record(const std::string &r, const std::string &k, const std::string &l) { std::string buf; buf = buf + this->exists + dbsep + k + dbsep + r; if (buf.size() >= this->reclen) // >= because we need place for // end-of-string zero return RECORDTOOLONG; off_t p = this->strtoslot(l)*reclen; return this->write_string(buf,p); } int flatfile_pool::remove_record(const std::string &k, const std::string &l) { int rc; off_t p = this->strtoslot(l)*reclen; std::string r; rc = this->read_string(r,p); if (rc != 0) return rc; rc = haskey(r,k); if (rc != 0) return rc; r = this->deleted; if (status.extra == slottostr(0)) r = r + dbsep + slottostr(0); else r = r + dbsep + status.extra; status.extra = l; return this->write_string(r,p); } int flatfile_pool::read_string(std::string &r, off_t p) { char b[this->reclen]; off_t rc; rc = lseek(this->ff, p, SEEK_SET); if (rc == -1) return FETCHERROR; ssize_t rc1; rc1 = read(this->ff, b, this->reclen); if (rc1 != this->reclen) return FETCHERROR; r = b; return 0; } int flatfile_pool::write_string(const std::string &r, off_t p) { int rc; char b[this->reclen]; rc = lseek(this->ff,p,SEEK_SET); if (rc == -1) return STOREERROR; bzero(b, this->reclen); strncpy(b,r.c_str(),r.size()); ssize_t first = 0; ssize_t togo = this->reclen; ssize_t written; do { written = write(ff,&b[first],togo); if (written == -1) { perror("write:"); return 2; } togo -= written; first += written; } while(togo !=0); return 0; } int flatfile_pool::create_db(const std::string &dbname) { int rc; rc = this->purge_db(); if (rc != 0) return rc; // The db_name can be composed of parts separated with '/' // we try to create this path until the last '/' size_t p = dbname.find_last_of('/'); rc = mkdir_p(dbname.substr(0,p+1),0755); if (rc != 0) return CREATEERROR; rc = this->open_db(); if (rc != 0) return rc; this->close_db(); this->status.extra = stopos_key::NumberToKey(0); return 0; } int flatfile_pool::purge_db(void) { if (this->db_name == 0) return NOFILENAME; this->close_db(); unlink(this->db_name); return 0; } int flatfile_pool::open_db(void) { int rc; if (this->db_name == 0) return NOFILENAME; if (this->db_open) return 0; this->ff = open(this->db_name, O_CREAT|O_RDWR,0644); if (this->ff < 0) return OPENERROR; struct flock lock; lock.l_type = F_RDLCK|F_WRLCK; lock.l_whence = SEEK_SET; lock.l_start = 0; lock.l_len = 0; rc = fcntl(this->ff,F_SETLKW,&lock); if (rc < 0) return LOCKERROR; this->db_open = 1; return 0; } int flatfile_pool::close_db(void) { if (!this->db_open) return 0; int rc; struct flock lock; lock.l_type = F_UNLCK; lock.l_whence = SEEK_SET; lock.l_start = 0; lock.l_len = 0; rc = fcntl(this->ff,F_SETLKW,&lock); if (rc < 0) return UNLOCKERROR; rc = close(this->ff); if (rc == -1) return CLOSEERROR; this->db_open = 0; return 0; } void flatfile_pool::dump_db(void) { std::string r; off_t n = 1; while (read_string(r,n*this->reclen)==0) { std::cerr << r << std::endl; n++; } }