source: tags/0.58/stopos_pool.cpp @ 9

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

willem

File size: 14.8 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>
7
8int stopos_pool::get_record(std::string &r, const std::string &k, const std::string &l)
9  // non-sense example implementation, you have to overwrite this in a derived class
10{
11  std::cerr << __FILE__<<":"<<__LINE__<<"stopos_pool::get_record must be overwritten in a derived class"<<std::endl;
12  return 0;
13}
14
15int stopos_pool::put_record(const std::string &r, const std::string &k,const std::string &l)
16  // non-sense example implementation, you have to overwrite this in a derived class
17{
18  std::cerr << __FILE__<<":"<<__LINE__<<"stopos_pool::put_record must be overwritten in a derived class"<<std::endl;
19  std::cout <<r<<std::endl;
20  return 0;
21  //
22  // record r must be stored such that get_record() retrieves it using k
23  //
24}
25
26int stopos_pool::remove_record(const std::string &k, const std::string &l)
27  // non-sense example implementation, you have to overwrite this in a derived class
28{
29  std::cerr << __FILE__<<":"<<__LINE__<<"stopos_pool::remove_record must be overwritten in a derived class"<<std::endl;
30  std::cout << "Please forget the existence of the record with the following key:"<<k<<std::endl;
31  return 0;
32}
33
34int stopos_pool::create_db(const std::string &db)
35  // non-sense example implementation, you have to overwrite this in a derived class
36{
37  std::cerr << __FILE__<<":"<<__LINE__<<"stopos_pool::create_db must be overwritten in a derived class"<<std::endl;
38  std::cout << "Please create file " << db<< std::endl;
39  return 0;
40}
41
42int stopos_pool::purge_db(void)
43  // non-sense example implementation, you have to overwrite this in a derived class
44{
45  std::cerr << __FILE__<<":"<<__LINE__<<"stopos_pool::purge_db must be overwritten in a derived class"<<std::endl;
46  std::cout << "Please purge file " << this->db_name<< std::endl;
47  return 0;
48}
49
50int stopos_pool::open_db(void)
51  // non-sense example implementation, you have to overwrite this in a derived class
52{
53  std::cerr << __FILE__<<":"<<__LINE__<<"stopos_pool::open_db must be overwritten in a derived class"<<std::endl;
54  std::cout << "Please open file " << this->db_name<<" and assign the result to an handle in your class" << std::endl;
55
56  this->db_open = 1;
57  return 0;
58}
59
60int stopos_pool::close_db(void)
61  // non-sense example implementation, you have to overwrite this in a derived class
62{
63  std::cerr << __FILE__<<":"<<__LINE__<<"stopos_pool::close_db must be overwritten in a derived class"<<std::endl;
64  std::cout << "Please close file " << this->db_name<<std::endl;
65
66  db_open = 0;
67  return 0;
68}
69
70// constructor:
71stopos_pool::stopos_pool()
72{
73  this->kvp         = 0;
74  this->statuskey   = stopos_key();  // full key
75  this->db_name     = 0;
76  this->db_open     = 0;
77}
78
79// destructor
80stopos_pool::~stopos_pool()
81{
82  if(db_name)
83    free (db_name);
84}
85
86int stopos_pool::create_db(void)
87{
88  int rc;
89  rc = this->create_db(this->sdb_name);
90  if(rc != 0)
91    return rc;
92
93  this->status.init();
94  rc = this->open_db();
95  if (rc != 0)
96    return rc;
97  rc =  this->put_status();
98  this->close_db();
99  return rc;
100}
101
102int stopos_pool::get_record(datarecord       &r,
103                            const stopos_key &k)
104{
105  std::string s;
106  int rc;
107  rc = this->get_record(s, k.get_key(),k.get_slot());
108  if (rc != 0)
109    return rc;
110  r = datarecord(s,dbsep);
111  return 0;
112}
113
114int stopos_pool::put_record(const datarecord &r,
115                            const stopos_key &k)
116{
117  std::string b;
118  int rc;
119
120  b = r.str(dbsep);
121
122  rc = this->put_record(b,k.get_key(),k.get_slot());
123
124  return rc;
125}
126
127int stopos_pool::remove_record(const stopos_key &k)
128{
129  return this->remove_record(k.get_key(),k.get_slot());
130}
131
132void stopos_pool::set_db_name(std::string filename)
133{
134  this->sdb_name = filename;
135  this->db_name  = strdup(filename.c_str());
136}
137
138std::string stopos_pool::get_db_name(void)
139{
140  return this->sdb_name;
141}
142
143int stopos_pool::put_status(void)
144{
145  std::string buf;
146  buf = this->status.str(dbsep);
147
148  return this->put_record(buf,this->statuskey.get_key(),this->statuskey.get_slot());
149}
150
151int stopos_pool::get_status(void)
152{
153  std::string buf;
154  int rc =this->get_record(buf,this->statuskey.get_key(),this->statuskey.get_slot());
155  if (rc != 0) 
156    return rc;
157
158  this->status = statusrecord(buf,dbsep);
159  return 0;
160}
161
162int stopos_pool::add_line(const std::string line, 
163                                std::string &key)
164{
165  if (!this->db_open)
166    return DBNOTOPEN;
167
168  datarecord d;
169  stopos_key dkey;
170  int rc;
171  rc = get_status();
172  if (rc != 0)
173    return rc;
174
175  //dkey is the key of the inserted record
176  //dkey = status.last;
177  std::string slot = this->key_to_slot(stopos_key::NumberToKey(status.count +1));
178  dkey.set(status.count + 1,slot);
179
180  // if status.last != 0, modify 'next' of last record
181  if (status.last != this->statuskey)
182  {
183    datarecord l;
184    rc = this->get_record(l,this->status.last);
185    if (rc != 0)
186      return rc;
187    l.next = dkey;
188    rc = this->put_record(l,this->status.last);
189    if (rc !=0)
190      return rc;
191  }
192
193  // if status.next points to nothing
194  //   or
195  // if status.next points to a record that has been committed,
196  //   then
197  // status.next should point to the record just added
198
199  // modify status record
200
201  if (this->status.next == this->statuskey) // status.next points to nothing
202    this->status.next = dkey;
203  else  // look if status.next points to a record that has already been committed
204  {
205    datarecord r;
206    int rc;
207
208    rc = this->get_record(r,this->status.next);
209    if (rc != 0)
210      return FETCHERROR;
211
212    if (r.retrieved != 0)
213      this->status.next = dkey;
214  }
215
216  if (this->status.first == this->statuskey)
217    this->status.first = dkey;
218
219  d.prev            = status.last; 
220  this->status.last = dkey;
221
222  this->status.count++;
223  this->status.present++;
224  this->status.present0++;
225
226  rc = this->put_status();
227  if (rc != 0)
228    return this->STOREERROR;
229
230  d.value     = zstrtohex(line);
231  d.next      = this->statuskey;
232  d.retrieved = 0;
233
234  rc = put_record(d,dkey);
235
236  if (rc != 0)
237    return this->STOREERROR;
238
239  key = dkey.str();
240  return 0;
241}
242
243int stopos_pool::get_line(std::string      &line, 
244                          longuint         &retrieved, 
245                          std::string      &key)
246{
247  if (!this->db_open)
248    return DBNOTOPEN;
249
250  int rc;
251  rc = this->get_status();
252  if (rc != 0)
253    return FETCHERROR;
254
255  if (this->status.next == this->statuskey)
256  {
257    if (!this->kvp)
258      return  NOTFOUND;
259    // wrapping around ...
260    status.next = status.first;
261
262    if (this->status.next == this->statuskey)
263      return NOTFOUND;
264  }
265
266  datarecord r;
267 
268  rc = this->get_record(r,this->status.next);
269  if (rc != 0)
270    return FETCHERROR;
271
272  retrieved = r.retrieved;
273  if (!this->kvp)
274    if (r.retrieved !=0)
275      return NOTFOUND;
276  key = this->status.next.str();
277
278  line = zhextostr(r.value);
279
280  // adjust the 'retrieved' field of r, and write it
281
282  r.retrieved++;
283
284  rc = this->put_record(r,status.next);
285  if (rc != 0)
286    return STOREERROR;
287
288  // adjust the 'next' field of status. this must be equal
289  // to the 'next' field of r
290
291  this->status.next = r.next;
292
293  if (r.retrieved == 1)
294    this->status.present0--;
295
296  this->put_status();
297
298  return 0;
299}
300
301int stopos_pool::remove_line(const std::string &k)
302{
303  if (!this->db_open)
304    return DBNOTOPEN;
305
306  int rc;
307  datarecord r;
308  stopos_key key(k);
309
310  rc = this->get_record(r,key);
311  if (rc !=0)
312    return rc;
313
314  // remove this record from the linked lists.
315
316  rc=this->get_status();
317  if (rc != 0)
318    return rc;
319
320  //
321  //remove_line
322
323  // r = record to remove
324  //
325  // situations we have to deal with:
326  //
327  // r.next = 0  ( = key to status)
328  // r.next = data ( = key to data)
329  //
330  // r.prev = 0
331  // r.prev = data
332  //
333  // if (r.prev != 0)
334  //    get p(r.prev)
335  //
336  // if (r.next != 0)
337  //    get n(r.next)
338  //
339  // if (r.next = 0)    //r is last record
340  //   {
341  //      if r.prev = data
342  //      {
343  //          p.next = r.next     (=0)
344  //          if (key == s.next)
345  //             s.next = r.next  ( = 0)
346  //          if (key == s.last)     // must be true, r is last record
347  //             s.last = r.prev
348  //          if (key == s.first)
349  //             impossible, because there is a previous record
350  //      }
351  //      else  // r.prev = 0 // this is the only record
352  //      {
353  //          s.next = r.next ( =r.prev =0)
354  //          s.first = r.prev ( = r.next =0)
355  //          s.last  = r.prev ( = r.next = 0)
356  //      }
357  //   }
358  // else    // r has a follower
359  //  {
360  //      if r.prev = datarecord
361  //      {
362  //          p.next = r.next
363  //          n.prev = r.prev
364  //          if (key == s.next)
365  //             s.next = r.next
366  //          if (key == s.last)
367  //             impossible, there is a follower
368  //          if (key == s.first)
369  //             impossible, there is a predecessor
370  //      }
371  //      else  // r.prev = 0: r is the first record
372  //      {
373  //          n.prev = r.prev (=0)
374  //          if (key == s.next)
375  //             s.next = r.next
376  //          if (key == s.last)
377  //             impossible, there is a follower
378  //          if (key == s.first)  // must be
379  //             s.first = r.next
380  //      }
381  //  }
382
383  // remove record r
384  //
385
386  this->get_record(r,key); 
387  //
388  // situations we have to deal with:
389  //
390  // r.next = 0  ( = key to status)
391  // r.next = data ( = key to data)
392  //
393  // r.prev = 0
394  // r.prev = data
395  //
396
397  datarecord p,n;
398
399  if (r.prev != this->statuskey)
400    this->get_record(p,r.prev);
401 
402  if (r.next != this->statuskey)
403    this->get_record(n,r.next);
404//
405// and what to do if the next record to be dumped is
406// exactly this record?
407//
408// I think, status.nextd should become r.next,
409// whatever r.next is pointing to
410// However, if r.next is pointing to nothing,
411// we should give status.nextd an impossible value
412//
413 
414  if (this->status.nextd == key)
415  {
416    if (r.next == this->statuskey)
417      this->status.nextd.impossible();
418    else
419      this->status.nextd = r.next;
420  }
421
422  if (r.next == this->statuskey)  // r is last record
423  {
424    if (r.prev != this->statuskey)  // r is last record and has a predecessor
425      {
426        p.next = r.next;
427        this->put_record(p,r.prev);
428
429        if (key == status.next)
430          status.next = r.next;
431
432        // if (key == status.last)  // always the case here
433        status.last = r.prev;
434
435        // if (key == status.first)
436        //   impossible, because there is a previous record
437      }
438    else  // r is the only record
439    {
440      status.next  = r.next;
441      status.first = r.prev;
442      status.last  = r.prev;
443    }
444  }
445  else   // r has a follower
446  {
447    if (r.prev != this->statuskey)  // r has a predecessor and a follower
448    {
449      p.next = r.next;
450      this->put_record(p,r.prev);
451
452      n.prev = r.prev;
453      this->put_record(n,r.next);
454
455      if (key == status.next)
456        status.next = r.next;
457      // if (key == status.last)
458      //   impossible, r has a follower
459      // if (key == s.first)
460      //   impossible, r has a predecessor
461    }
462    else  // r is first record and has a follower
463    {
464      n.prev = r.prev;
465      this->put_record(n,r.next);
466
467      if (key == status.next)
468        status.next = r.next;
469
470      // if (key == status.last)
471      //   impossible, r has a follower
472     
473      // if (key == status.first)  // always true here
474      status.first = r.next;
475    }
476  }
477
478  // finally, remove the record
479
480
481  rc = this->remove_record(key);
482  if (rc != 0)
483    return rc;
484
485  // and rewrite status
486
487  this->status.present--;
488  if (r.retrieved == 0) 
489    this->status.present0--;
490
491  rc = this->put_status();
492  if (rc != 0)
493    return rc;
494
495  return 0;
496}
497
498bool stopos_pool::is_statusrecord(const std::string &k)
499{
500  return stopos_key::KeyToNumber(k) == 0;
501}
502
503void stopos_pool::set_kvp(bool v)
504{
505  this->kvp = v;
506}
507
508bool stopos_pool::get_kvp(void)
509{
510  return this->kvp;
511}
512
513int stopos_pool::get_counts(longuint &count, 
514                            longuint &present, 
515                            longuint &present0)
516{
517  int rc = get_status();
518  if (rc != 0) 
519    return rc;
520
521  count    = status.count;
522  present  = status.present;
523  present0 = status.present0;
524  return 0;
525}
526
527int stopos_pool::dump_line(std::string  &line, 
528                           longuint     &retrieved, 
529                           std::string  &key)
530{
531  if (!this->db_open)
532    return DBNOTOPEN;
533
534  int rc;
535  rc = this->get_status();
536  if (rc != 0)
537    return FETCHERROR;
538
539  //
540  // if status.nextd is pointing to nothing,
541  // we assume that one is starting the dump,
542  // and let nextd point to the first record
543  //
544
545  if (this->status.nextd == this->statuskey)
546    this->status.nextd = this->status.first;
547
548  // if nextd is still pointing to nothing,
549  // there is nothing
550
551  if (this->status.nextd == this->statuskey)
552    return NOTFOUND;
553
554  datarecord r;
555
556  rc = this->get_record(r,this->status.nextd);
557  if (rc != 0)
558  {
559    this->status.nextd = this->status.first;
560    this->put_status();
561    return NOTFOUND;
562  }
563
564  key                = this->status.nextd.str();
565
566  retrieved          = r.retrieved;
567
568  line               = zhextostr(r.value);
569
570  this->status.nextd = r.next;
571
572  if (this->status.nextd == this->statuskey) // we signal that we reached eoi
573    this->status.nextd.impossible();         // at the next call
574
575  this->put_status();
576
577  return 0;
578}
579 
580datarecord::datarecord()
581{
582  this->retrieved = 0;
583}
584
585datarecord::datarecord(const std::string &s,
586                       char              sep)
587{
588  std::vector <std::string> v;
589  split(v,s,sep);
590
591  this->prev      = stopos_key(v[0]);
592  this->next      = stopos_key(v[1]);
593  this->retrieved = StringToNumber<longuint>(v[2]);
594  this->value     = v[3];
595}
596
597std::string datarecord::str(char sep) const
598{
599  std::string r;
600  r = this->prev.str()                + sep
601    + this->next.str()                + sep
602    + NumberToString(this->retrieved) + sep
603    + this->value
604    ;
605
606  return r;
607}
608
609statusrecord::statusrecord(void)
610{
611  this->init();
612}
613
614statusrecord::statusrecord(const std::string &s, 
615                           char              sep)
616{
617  std:: vector <std::string> v;
618
619  split(v,s,sep);
620  this->next     = stopos_key(v[0]);
621  this->first    = stopos_key(v[1]);
622  this->last     = stopos_key(v[2]);
623  this->nextd    = stopos_key(v[3]);
624  this->count    = StringToNumber<longuint>(v[4]);
625  this->present  = StringToNumber<longuint>(v[5]);
626  this->present0 = StringToNumber<longuint>(v[6]);
627  this->extra    = v[7];
628
629}
630void statusrecord::init(void)
631{
632  this->next     = stopos_key();
633  this->first    = stopos_key();
634  this->last     = stopos_key();
635  this->nextd    = stopos_key();
636  this->count    = 0;
637  this->present  = 0;
638  this->present0 = 0;
639  // note: extra is not initialized here, that is
640  // something for a derived class
641}
642
643std::string statusrecord::str(char sep)
644{
645  std::string r;
646  r = this->next.str()               + sep
647    + this->first.str()              + sep
648    + this->last.str()               + sep
649    + this->nextd.str()              + sep
650    + NumberToString(this->count)    + sep
651    + NumberToString(this->present)  + sep
652    + NumberToString(this->present0) + sep
653    + this->extra
654    ;
655  return r;
656}
657
Note: See TracBrowser for help on using the repository browser.