source: trunk/flatfile_pool.cpp

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

willem

File size: 5.9 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  bool rectoolong = 0;
124
125  buf = buf + this->exists + dbsep + k + dbsep + r;
126
127  if (buf.size() >= this->reclen) // >= because we need place for
128                                  // end-of-string zero
129  {
130    rectoolong = 1;
131    buf.resize(reclen-1);
132  }
133
134  off_t p = this->strtoslot(l)*reclen;
135
136  int rc =  this->write_string(buf,p);
137  if (!rectoolong)
138    return rc;
139  return RECORDTOOLONG;
140}
141
142int flatfile_pool::remove_record(const std::string &k, const std::string &l)
143{
144  int rc;
145
146  off_t p = this->strtoslot(l)*reclen;
147
148  std::string r;
149  rc = this->read_string(r,p);
150  if (rc != 0)
151    return rc;
152
153  rc = haskey(r,k);
154  if (rc != 0)
155    return rc;
156
157  r = this->deleted;
158
159  if (status.extra == slottostr(0))
160    r = r + dbsep + slottostr(0);
161  else
162    r = r + dbsep + status.extra;
163  status.extra = l;
164
165  return this->write_string(r,p);
166}
167
168int flatfile_pool::read_string(std::string &r, off_t p)
169{
170
171  char b[this->reclen];
172  off_t rc;
173  rc = lseek(this->ff, p, SEEK_SET);
174  if (rc == -1)
175    return FETCHERROR;
176
177  ssize_t rc1;
178  rc1 = read(this->ff, b, this->reclen);
179  if (rc1 != this->reclen)
180    return FETCHERROR;
181
182  r = b;
183
184  return 0;
185}
186
187
188int flatfile_pool::write_string(const std::string &r, off_t p)
189{
190  int rc;
191  char b[this->reclen];
192
193  rc = lseek(this->ff,p,SEEK_SET);
194  if (rc == -1)
195    return STOREERROR;
196
197  bzero(b, this->reclen);
198  strncpy(b,r.c_str(),r.size());
199  ssize_t first = 0;
200  ssize_t togo  = this->reclen;
201  ssize_t written;
202
203  do
204  {
205    written = write(ff,&b[first],togo);
206    if (written == -1)
207    {
208      perror("write:");
209      return 2;
210    }
211    togo   -= written;
212    first  += written;
213  } while(togo !=0);
214
215  return 0;
216}
217
218
219int flatfile_pool::create_db(const std::string &dbname)
220{
221  int rc; 
222
223  rc = this->purge_db();
224  if (rc != 0)
225    return rc;
226
227  // The db_name can be composed of parts separated with '/'
228  // we try to create this path until the last '/'
229 
230  size_t p = dbname.find_last_of('/');
231  rc = mkdir_p(dbname.substr(0,p+1),0755);
232  if (rc != 0)
233    return CREATEERROR;
234
235  rc = this->open_db(O_CREAT|O_RDWR);
236  if (rc != 0)
237    return rc;
238  this->close_db();
239
240  this->status.extra = stopos_key::NumberToKey(0);
241
242  return 0;
243}
244
245int flatfile_pool::purge_db(void)
246{
247  if (this->db_name == 0)
248    return NOFILENAME;
249
250  this->close_db();
251
252  unlink(this->db_name);
253  return 0;
254}
255
256int flatfile_pool::open_db()
257{
258  int rc;
259  rc = this->open_db(O_RDWR);
260  return rc;
261}
262
263int flatfile_pool::open_db(int flags)
264{
265  int rc;
266
267  if (this->db_name == 0)
268    return NOFILENAME;
269
270  if (this->db_open)
271    return 0;
272
273  this->ff = open(this->db_name, flags,0644);
274  if (this->ff < 0)
275    return OPENERROR;
276
277  struct flock lock;
278  lock.l_type   = F_RDLCK|F_WRLCK;
279  lock.l_whence = SEEK_SET;
280  lock.l_start  = 0;
281  lock.l_len    = 0;
282
283  rc = fcntl(this->ff,F_SETLKW,&lock);
284  if (rc < 0)
285    return LOCKERROR;
286
287  this->db_open = 1;
288
289  return 0;
290}
291
292int flatfile_pool::close_db(void)
293{
294  if (!this->db_open)
295     return 0;
296
297  int rc;
298
299  struct flock lock;
300  lock.l_type   = F_UNLCK;
301  lock.l_whence = SEEK_SET;
302  lock.l_start  = 0;
303  lock.l_len    = 0;
304
305  rc = fcntl(this->ff,F_SETLKW,&lock);
306  if (rc < 0)
307    return UNLOCKERROR;
308
309  rc = close(this->ff);
310  if (rc == -1)
311    return CLOSEERROR;
312
313  this->db_open = 0;
314
315  return 0;
316}
317
Note: See TracBrowser for help on using the repository browser.