source: tags/0.9/flatfile_pool.cpp @ 9

Last change on this file since 9 was 9, checked in by willem, 11 years ago

willem

File size: 5.7 KB
Line 
1
2/*
3   Copyright 2013 Willem Vermin, SURFsara
4
5   Licensed under the Apache License, Version 2.0 (the "License");
6   you may not use this file except in compliance with the License.
7   You may obtain a copy of the License at
8
9       http://www.apache.org/licenses/LICENSE-2.0
10
11   Unless required by applicable law or agreed to in writing, software
12   distributed under the License is distributed on an "AS IS" BASIS,
13   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   See the License for the specific language governing permissions and
15   limitations under the License.
16 */
17#include "stopos_pool.h"
18#include "flatfile_pool.h"
19#include <sys/types.h>
20#include <sys/stat.h>
21#include <errno.h>
22#include <fcntl.h>
23#include <stdlib.h>
24#include "wutils.h"
25#include <string.h>
26#include <strings.h>
27#include <stdio.h>
28#include <algorithm>
29#include "stopos.h"
30
31//
32// this->status.extra is always pointing to
33// the first free slot
34//
35// records are stored thusly:
36// character to denote if this record exists or is deleted
37// dbsep
38//
39//   for a not deleted record, next fields:
40//   key for this record
41//   dbsep
42//   1st parameter of put_record
43//
44//   for a deleted record:
45//   pointer to next deleted record
46//
47
48// constructor
49flatfile_pool::flatfile_pool()
50{
51  this->whoami = "flat";
52  this->statuskey.set_slot(this->statuskey.get_key());
53}
54
55std::string flatfile_pool::key_to_slot(const std::string &k)
56{
57
58  if (strtoslot(this->status.extra) == 0)
59    return k;
60
61  std::string slot = this->status.extra;
62  std::string r;
63  off_t p = strtoslot(slot)*this->reclen;
64  this->read_string(r, p);
65  this->status.extra = r.substr(2);
66
67  return slot;
68}
69
70off_t flatfile_pool::strtoslot(const std::string &s)
71{
72  return stopos_key::KeyToNumber(s);
73}
74
75std::string flatfile_pool::slottostr(off_t l)
76{
77  return stopos_key::NumberToKey(l);
78}
79
80int flatfile_pool::haskey(std::string &r, const std::string &k)
81{
82  size_t q1 = 1; 
83  // find second separator. The first one is on postion 1
84  size_t q2 = r.find(dbsep,2);
85
86  std::string key = r.substr(q1+1,q2-q1-1);
87  if (key != k)
88    return this->NOTFOUND;
89  r.erase(0,q2+1);
90  return 0;
91}
92
93int flatfile_pool::get_record(std::string &r, const std::string &k, const std::string &l)
94{
95  int rc;
96
97  off_t p = this->strtoslot(l)*reclen;
98
99  rc = this->read_string(r,p);
100  if (rc !=0 )
101    return rc;
102
103  if (r[0] == this->deleted)
104    return this->NOTFOUND;
105
106  // this record was not deleted, but it could be that
107  // the key does not match
108  //
109
110  rc = this->haskey(r,k);
111  if (rc != 0)
112    return rc;
113
114  return 0;
115}
116
117int flatfile_pool::put_record(const std::string &r, 
118                              const std::string &k,
119                              const std::string &l)
120{
121  std::string buf;
122
123  buf = buf + this->exists + dbsep + k + dbsep + r;
124
125  if (buf.size() >= this->reclen) // >= because we need place for
126                                  // end-of-string zero
127    return RECORDTOOLONG;
128
129  off_t p = this->strtoslot(l)*reclen;
130
131  return this->write_string(buf,p);
132}
133
134int flatfile_pool::remove_record(const std::string &k, const std::string &l)
135{
136  int rc;
137
138  off_t p = this->strtoslot(l)*reclen;
139
140  std::string r;
141  rc = this->read_string(r,p);
142  if (rc != 0)
143    return rc;
144
145  rc = haskey(r,k);
146  if (rc != 0)
147    return rc;
148
149  r = this->deleted;
150
151  if (status.extra == slottostr(0))
152    r = r + dbsep + slottostr(0);
153  else
154    r = r + dbsep + status.extra;
155  status.extra = l;
156
157  return this->write_string(r,p);
158}
159
160int flatfile_pool::read_string(std::string &r, off_t p)
161{
162
163  char b[this->reclen];
164  off_t rc;
165  rc = lseek(this->ff, p, SEEK_SET);
166  if (rc == -1)
167    return FETCHERROR;
168
169  ssize_t rc1;
170  rc1 = read(this->ff, b, this->reclen);
171  if (rc1 != this->reclen)
172    return FETCHERROR;
173
174  r = b;
175
176  return 0;
177}
178
179
180int flatfile_pool::write_string(const std::string &r, off_t p)
181{
182  int rc;
183  char b[this->reclen];
184
185  rc = lseek(this->ff,p,SEEK_SET);
186  if (rc == -1)
187    return STOREERROR;
188
189  bzero(b, this->reclen);
190  strncpy(b,r.c_str(),r.size());
191  ssize_t first = 0;
192  ssize_t togo  = this->reclen;
193  ssize_t written;
194
195  do
196  {
197    written = write(ff,&b[first],togo);
198    if (written == -1)
199    {
200      perror("write:");
201      return 2;
202    }
203    togo   -= written;
204    first  += written;
205  } while(togo !=0);
206
207  return 0;
208}
209
210
211int flatfile_pool::create_db(const std::string &dbname)
212{
213  int rc; 
214
215  rc = this->purge_db();
216  if (rc != 0)
217    return rc;
218
219  // The db_name can be composed of parts separated with '/'
220  // we try to create this path until the last '/'
221 
222  size_t p = dbname.find_last_of('/');
223  rc = mkdir_p(dbname.substr(0,p+1),0755);
224  if (rc != 0)
225    return CREATEERROR;
226
227  rc = this->open_db(O_CREAT|O_RDWR);
228  if (rc != 0)
229    return rc;
230  this->close_db();
231
232  this->status.extra = stopos_key::NumberToKey(0);
233
234  return 0;
235}
236
237int flatfile_pool::purge_db(void)
238{
239  if (this->db_name == 0)
240    return NOFILENAME;
241
242  this->close_db();
243
244  unlink(this->db_name);
245  return 0;
246}
247
248int flatfile_pool::open_db()
249{
250  int rc;
251  rc = this->open_db(O_RDWR);
252  return rc;
253}
254
255int flatfile_pool::open_db(int flags)
256{
257  int rc;
258
259  if (this->db_name == 0)
260    return NOFILENAME;
261
262  if (this->db_open)
263    return 0;
264
265  this->ff = open(this->db_name, flags,0644);
266  if (this->ff < 0)
267    return OPENERROR;
268
269  struct flock lock;
270  lock.l_type   = F_RDLCK|F_WRLCK;
271  lock.l_whence = SEEK_SET;
272  lock.l_start  = 0;
273  lock.l_len    = 0;
274
275  rc = fcntl(this->ff,F_SETLKW,&lock);
276  if (rc < 0)
277    return LOCKERROR;
278
279  this->db_open = 1;
280
281  return 0;
282}
283
284int flatfile_pool::close_db(void)
285{
286  if (!this->db_open)
287     return 0;
288
289  int rc;
290
291  struct flock lock;
292  lock.l_type   = F_UNLCK;
293  lock.l_whence = SEEK_SET;
294  lock.l_start  = 0;
295  lock.l_len    = 0;
296
297  rc = fcntl(this->ff,F_SETLKW,&lock);
298  if (rc < 0)
299    return UNLOCKERROR;
300
301  rc = close(this->ff);
302  if (rc == -1)
303    return CLOSEERROR;
304
305  this->db_open = 0;
306
307  return 0;
308}
309
Note: See TracBrowser for help on using the repository browser.