source: tags/0.5/stopos_pool.cpp @ 9

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

willem

File size: 12.9 KB
Line 
1#include "stopos_pool.h"
2#include "stopos.h"
3#include "wutils.h"
4#include <iostream>
5#include <string.h>
6#include <stdlib.h>
7int stopos_pool::get_status(void)
8  // non-sense example implementation, you have to overwrite this in a derived class
9{
10  std::cerr << __FILE__<<":"<<__LINE__<<"stopos_pool::getstatus must be overwritten in a derived class"<<std::endl;
11  this->status.next  = this->statuskey;
12  this->status.first = this->statuskey;
13  this->status.last  = this->statuskey;
14  this->status.count = StringToNumber<longuint>(0);
15  return NOTIMPLEMENTED;
16}
17int stopos_pool::put_status(void)
18  // non-sense example implementation, you have to overwrite this in a derived class
19{
20  std::cerr << __FILE__<<":"<<__LINE__<<"stopos_pool::putstatus must be overwritten in a derived class"<<std::endl;
21  std::cout << this->status.next.str();
22  std::cout << this->status.first.str();
23  std::cout << this->status.last.str();
24  std::cout << this->status.count;
25  return NOTIMPLEMENTED;
26}
27
28int stopos_pool::get_record(datarecord &r, const stopos_key &k)
29  // non-sense example implementation, you have to overwrite this in a derived class
30{
31  std::cerr << __FILE__<<":"<<__LINE__<<"stopos_pool::get_record must be overwritten in a derived class"<<std::endl;
32  r.prev      = stopos_key("the key of the record preceding r,"
33                            "this->statuskey if r is the first record");
34  r.next      = stopos_key("the key of the record following r,"
35                             "this->statuskey if r is the last record");
36  r.retrieved = 5; // the number of times this record has been
37                   // retrieved until now (not including this
38                   // retrieval)
39  r.value     = "the value stored in this record";
40
41  return 0;
42}
43
44int stopos_pool::put_record(datarecord &r, const stopos_key &k)
45  // non-sense example implementation, you have to overwrite this in a derived class
46{
47  std::cerr << __FILE__<<":"<<__LINE__<<"stopos_pool::put_record must be overwritten in a derived class"<<std::endl;
48  std::cout <<r.next.str()<<"/"<<r.prev.str()<<"/"<<r.retrieved<<r.value<<std::endl;
49  return 0;
50  // all fields of r must have been filled in properly:
51  // next: key of next record  (this->statuskey if there is no next record)
52  // prev: key of previous record (this->statuskey if there is no previous record)
53  // retrieved: the number of times the record has been retrieved
54  // r.value: the value
55  //
56  // record r must be stored such that get_record() retrieves it using k
57  //
58}
59
60int stopos_pool::remove_record(const stopos_key &k)
61  // non-sense example implementation, you have to overwrite this in a derived class
62{
63  std::cerr << __FILE__<<":"<<__LINE__<<"stopos_pool::remove_record must be overwritten in a derived class"<<std::endl;
64  std::cout << "Please forget the existence of the record with the following key:"<<k.str()<<std::endl;
65  return 0;
66}
67
68int stopos_pool::create_db(void)
69  // non-sense example implementation, you have to overwrite this in a derived class
70{
71  std::cerr << __FILE__<<":"<<__LINE__<<"stopos_pool::create_db must be overwritten in a derived class"<<std::endl;
72  std::cout << "Please create file " << this->db_name<< std::endl;
73  return 0;
74}
75
76int stopos_pool::purge_db(void)
77  // non-sense example implementation, you have to overwrite this in a derived class
78{
79  std::cerr << __FILE__<<":"<<__LINE__<<"stopos_pool::purge_db must be overwritten in a derived class"<<std::endl;
80  std::cout << "Please purge file " << this->db_name<< std::endl;
81  return 0;
82}
83
84int stopos_pool::open_db(void)
85  // non-sense example implementation, you have to overwrite this in a derived class
86{
87  std::cerr << __FILE__<<":"<<__LINE__<<"stopos_pool::open_db must be overwritten in a derived class"<<std::endl;
88  std::cout << "Please open file " << this->db_name<<" and assign the result to an handle in your class" << std::endl;
89
90  this->db_open = 1;
91  return 0;
92}
93
94int stopos_pool::close_db(void)
95  // non-sense example implementation, you have to overwrite this in a derived class
96{
97  std::cerr << __FILE__<<":"<<__LINE__<<"stopos_pool::close_db must be overwritten in a derived class"<<std::endl;
98  std::cout << "Please close file " << this->db_name<<std::endl;
99
100  db_open = 0;
101  return 0;
102}
103
104void stopos_pool::dump_db(void)
105  // non-sense example implementation, you have to overwrite this in a derived class
106{
107  std::cerr << __FILE__<<":"<<__LINE__<<"stopos_pool::dump_db must be overwritten in a derived class"<<std::endl;
108  std::cout << "Please dump file " << this->db_name<<std::endl;
109}
110
111// constructor:
112stopos_pool::stopos_pool()
113{
114  this->kvp         = 0;
115  this->statuskey   = stopos_key();
116  this->db_name     = 0;
117  this->db_open     = 0;
118}
119
120// destructor
121stopos_pool::~stopos_pool()
122{
123  if(db_name)
124    free (db_name);
125}
126
127void stopos_pool::set_db_name(std::string filename)
128{
129  this->sdb_name = filename;
130  this->db_name = strdup(filename.c_str());
131}
132
133std::string stopos_pool::get_db_name(void)
134{
135  return this->sdb_name;
136}
137
138int stopos_pool::add_line(const std::string line, std::string &key)
139{
140  if (!this->db_open)
141    return DBNOTOPEN;
142
143  datarecord d;
144  stopos_key dkey;
145  int rc;
146  rc = get_status();
147  if (rc != 0)
148    return rc;
149
150  //dkey is the key of the inserted record
151  dkey = status.last;
152  dkey.set(status.count + 1);
153
154  // if status.last != 0, modify 'next' of last record
155  if (status.last != this->statuskey)
156  {
157    datarecord l;
158    rc = this->get_record(l,this->status.last);
159    if (rc != 0)
160      return rc;
161    l.next = dkey;
162    rc = this->put_record(l,this->status.last);
163    if (rc !=0)
164      return rc;
165  }
166
167  // if status.next points to nothing
168  //   or
169  // if status.next points to a record that has been committed,
170  //   then
171  // status.next should point to the record just added
172
173  // modify status record
174
175  if (this->status.next == this->statuskey) // status.next points to nothing
176    this->status.next = dkey;
177  else  // look if status.next points to a record that has already been committed
178  {
179    datarecord r;
180    int rc;
181
182    rc = this->get_record(r,this->status.next);
183    if (rc != 0)
184      return FETCHERROR;
185
186    if (r.retrieved != 0)
187      this->status.next = dkey;
188  }
189
190  if (this->status.first == this->statuskey)
191    this->status.first = dkey;
192
193  d.prev            = status.last; 
194  this->status.last = dkey;
195
196  this->status.count++;
197
198  rc = this->put_status();
199  if (rc != 0)
200    return this->STOREERROR;
201
202  d.value     = zstrtohex(line);
203  d.next      = this->statuskey;
204  d.retrieved = 0;
205
206  rc = put_record(d,dkey);
207
208  if (rc != 0)
209    return this->STOREERROR;
210
211  key = dkey.str();
212  return 0;
213}
214
215int stopos_pool::get_line(std::string &line, unsigned int &retrieved, std::string &key)
216{
217  if (!this->db_open)
218    return DBNOTOPEN;
219
220  int rc;
221  rc = this->get_status();
222  if (rc != 0)
223    return FETCHERROR;
224
225  if (this->status.next == this->statuskey)
226  {
227    if (!this->kvp)
228      return  NOTFOUND;
229    // wrapping around ...
230    status.next = status.first;
231
232    if (this->status.next == this->statuskey)
233      return NOTFOUND;
234  }
235
236  datarecord r;
237 
238  rc = this->get_record(r,this->status.next);
239  if (rc != 0)
240    return FETCHERROR;
241
242  retrieved = r.retrieved;
243  if (!this->kvp)
244    if (r.retrieved !=0)
245      return NOTFOUND;
246  key = this->status.next.str();
247
248  line = zhextostr(r.value);
249
250  // adjust the 'retrieved' field of r, and write it
251
252  r.retrieved++;
253
254  rc = this->put_record(r,status.next);
255  if (rc != 0)
256    return STOREERROR;
257
258  // adjust the 'next' field of status. this must be equal
259  // to the 'next' field of r
260
261  this->status.next = r.next;
262
263  this->put_status();
264
265  return 0;
266}
267
268int stopos_pool::remove_line(const std::string &k)
269{
270  if (!this->db_open)
271    return DBNOTOPEN;
272
273  int rc;
274  datarecord r;
275  stopos_key key(k);
276
277  rc = this->get_record(r,key);
278  if (rc !=0)
279    return rc;
280
281  // remove this record from the linked lists.
282
283  rc=this->get_status();
284  if (rc != 0)
285    return rc;
286
287  bool status_changed = 0;
288
289  //
290  //remove_line
291
292  // r = record to remove
293  //
294  // situations we have to deal with:
295  //
296  // r.next = 0  ( = key to status)
297  // r.next = data ( = key to data)
298  //
299  // r.prev = 0
300  // r.prev = data
301  //
302  // if (r.prev != 0)
303  //    get p(r.prev)
304  //
305  // if (r.next != 0)
306  //    get n(r.next)
307  //
308  // if (r.next = 0)    //r is last record
309  //   {
310  //      if r.prev = data
311  //      {
312  //          p.next = r.next     (=0)
313  //          if (key == s.next)
314  //             s.next = r.next  ( = 0)
315  //          if (key == s.last)     // must be true, r is last record
316  //             s.last = r.prev
317  //          if (key == s.first)
318  //             impossible, because there is a previous record
319  //      }
320  //      else  // r.prev = 0 // this is the only record
321  //      {
322  //          s.next = r.next ( =r.prev =0)
323  //          s.first = r.prev ( = r.next =0)
324  //          s.last  = r.prev ( = r.next = 0)
325  //      }
326  //   }
327  // else    // r has a follower
328  //  {
329  //      if r.prev = datarecord
330  //      {
331  //          p.next = r.next
332  //          n.prev = r.prev
333  //          if (key == s.next)
334  //             s.next = r.next
335  //          if (key == s.last)
336  //             impossible, there is a follower
337  //          if (key == s.first)
338  //             impossible, there is a predecessor
339  //      }
340  //      else  // r.prev = 0: r is the first record
341  //      {
342  //          n.prev = r.prev (=0)
343  //          if (key == s.next)
344  //             s.next = r.next
345  //          if (key == s.last)
346  //             impossible, there is a follower
347  //          if (key == s.first)  // must be
348  //             s.first = r.next
349  //      }
350  //  }
351
352  // remove record r
353  //
354
355  this->get_record(r,key); 
356  //
357  // situations we have to deal with:
358  //
359  // r.next = 0  ( = key to status)
360  // r.next = data ( = key to data)
361  //
362  // r.prev = 0
363  // r.prev = data
364  //
365
366  datarecord p,n;
367
368  if (r.prev != this->statuskey)
369    this->get_record(p,r.prev);
370 
371  if (r.next != this->statuskey)
372    this->get_record(n,r.next);
373 
374  if (r.next == this->statuskey)  // r is last record
375    {
376      if (r.prev != this->statuskey)  // r is last record and has a predecessor
377        {
378          p.next = r.next;
379          this->put_record(p,r.prev);
380          status_changed = 1;
381
382          if (key == status.next)
383            status.next = r.next;
384
385          // if (key == status.last)  // always the case here
386          status.last = r.prev;
387
388          // if (key == status.first)
389          //   impossible, because there is a previous record
390        }
391      else  // r is the only record
392      {
393        status_changed = 1;
394        status.next  = r.next;
395        status.first = r.prev;
396        status.last  = r.prev;
397      }
398    }
399    else   // r has a follower
400    {
401      if (r.prev != this->statuskey)  // r has a predecessor and a follower
402      {
403        p.next = r.next;
404        this->put_record(p,r.prev);
405
406        n.prev = r.prev;
407        this->put_record(n,r.next);
408
409        if (key == status.next)
410        { status.next = r.next; status_changed = 1;}
411        // if (key == status.last)
412        //   impossible, r has a follower
413        // if (key == s.first)
414        //   impossible, r has a predecessor
415      }
416      else  // r is first record and has a follower
417      {
418        n.prev = r.prev;
419        this->put_record(n,r.next);
420
421        status_changed = 1;
422
423        if (key == status.next)
424          status.next = r.next;
425
426        // if (key == status.last)
427        //   impossible, r has a follower
428       
429        // if (key == status.first)  // always true here
430        status.first = r.next;
431      }
432    }
433
434  // finally, remove the record
435
436  rc = this->remove_record(key);
437  if (rc != 0)
438    return rc;
439
440  // and rewrite status, if necessary
441
442  if (status_changed)
443  {
444    rc = this->put_status();
445    if (rc != 0)
446      return rc;
447  }
448
449  return 0;
450}
451
452void stopos_pool::set_kvp(bool v)
453{
454  this->kvp = v;
455}
456
457bool stopos_pool::get_kvp(void)
458{
459  return this->kvp;
460}
461
462datarecord::datarecord()
463{
464  this->retrieved = 0;
465}
466
467datarecord::datarecord(const std::string &s,char sep)
468{
469  std::vector <std::string> v;
470  split(v,s,sep);
471
472  this->prev      = stopos_key(v[0]);
473  this->next      = stopos_key(v[1]);
474  this->retrieved = StringToNumber<longuint>(v[2]);
475  this->value     = v[3];
476}
477
478std::string datarecord::str(char dbsep)
479{
480  std::string r;
481  r = this->prev.str()                + dbsep
482    + this->next.str()                + dbsep
483    + NumberToString(this->retrieved) + dbsep
484    + this->value
485    ;
486
487  return r;
488}
489
490statusrecord::statusrecord(void)
491{
492  this->init();
493}
494
495statusrecord::statusrecord(const std::string & s, char dbsep)
496{
497  std:: vector <std::string> v;
498
499  split(v,s,dbsep);
500  this->next  = stopos_key(v[0]);
501  this->first = stopos_key(v[1]);
502  this->last  = stopos_key(v[2]);
503  this->count = StringToNumber<longuint>(v[3]);
504
505}
506void statusrecord::init(void)
507{
508  this->next  = stopos_key();
509  this->first = stopos_key();
510  this->last  = stopos_key();
511  this->count = 0;
512}
513
514std::string statusrecord::str(char dbsep)
515{
516  std::string r;
517  r = this->next.str()  + dbsep
518    + this->first.str() + dbsep
519    + this->last.str()  + dbsep
520    + NumberToString(this->count) 
521    ;
522  return r;
523}
524
Note: See TracBrowser for help on using the repository browser.