source: tags/0.55/stopos_pool.cpp @ 9

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

willem

File size: 14.7 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  this->status.present++;
198  this->status.present0++;
199
200  rc = this->put_status();
201  if (rc != 0)
202    return this->STOREERROR;
203
204  d.value     = zstrtohex(line);
205  d.next      = this->statuskey;
206  d.retrieved = 0;
207
208  rc = put_record(d,dkey);
209
210  if (rc != 0)
211    return this->STOREERROR;
212
213  key = dkey.str();
214  return 0;
215}
216
217int stopos_pool::get_line(std::string &line, longuint &retrieved, std::string &key)
218{
219  if (!this->db_open)
220    return DBNOTOPEN;
221
222  int rc;
223  rc = this->get_status();
224  if (rc != 0)
225    return FETCHERROR;
226
227  if (this->status.next == this->statuskey)
228  {
229    if (!this->kvp)
230      return  NOTFOUND;
231    // wrapping around ...
232    status.next = status.first;
233
234    if (this->status.next == this->statuskey)
235      return NOTFOUND;
236  }
237
238  datarecord r;
239 
240  rc = this->get_record(r,this->status.next);
241  if (rc != 0)
242    return FETCHERROR;
243
244  retrieved = r.retrieved;
245  if (!this->kvp)
246    if (r.retrieved !=0)
247      return NOTFOUND;
248  key = this->status.next.str();
249
250  line = zhextostr(r.value);
251
252  // adjust the 'retrieved' field of r, and write it
253
254  r.retrieved++;
255
256  rc = this->put_record(r,status.next);
257  if (rc != 0)
258    return STOREERROR;
259
260  // adjust the 'next' field of status. this must be equal
261  // to the 'next' field of r
262
263  this->status.next = r.next;
264
265  if (r.retrieved == 1)
266    this->status.present0--;
267
268  this->put_status();
269
270  return 0;
271}
272
273int stopos_pool::remove_line(const std::string &k)
274{
275  if (!this->db_open)
276    return DBNOTOPEN;
277
278  int rc;
279  datarecord r;
280  stopos_key key(k);
281
282  rc = this->get_record(r,key);
283  if (rc !=0)
284    return rc;
285
286  // remove this record from the linked lists.
287
288  rc=this->get_status();
289  if (rc != 0)
290    return rc;
291
292  //
293  //remove_line
294
295  // r = record to remove
296  //
297  // situations we have to deal with:
298  //
299  // r.next = 0  ( = key to status)
300  // r.next = data ( = key to data)
301  //
302  // r.prev = 0
303  // r.prev = data
304  //
305  // if (r.prev != 0)
306  //    get p(r.prev)
307  //
308  // if (r.next != 0)
309  //    get n(r.next)
310  //
311  // if (r.next = 0)    //r is last record
312  //   {
313  //      if r.prev = data
314  //      {
315  //          p.next = r.next     (=0)
316  //          if (key == s.next)
317  //             s.next = r.next  ( = 0)
318  //          if (key == s.last)     // must be true, r is last record
319  //             s.last = r.prev
320  //          if (key == s.first)
321  //             impossible, because there is a previous record
322  //      }
323  //      else  // r.prev = 0 // this is the only record
324  //      {
325  //          s.next = r.next ( =r.prev =0)
326  //          s.first = r.prev ( = r.next =0)
327  //          s.last  = r.prev ( = r.next = 0)
328  //      }
329  //   }
330  // else    // r has a follower
331  //  {
332  //      if r.prev = datarecord
333  //      {
334  //          p.next = r.next
335  //          n.prev = r.prev
336  //          if (key == s.next)
337  //             s.next = r.next
338  //          if (key == s.last)
339  //             impossible, there is a follower
340  //          if (key == s.first)
341  //             impossible, there is a predecessor
342  //      }
343  //      else  // r.prev = 0: r is the first record
344  //      {
345  //          n.prev = r.prev (=0)
346  //          if (key == s.next)
347  //             s.next = r.next
348  //          if (key == s.last)
349  //             impossible, there is a follower
350  //          if (key == s.first)  // must be
351  //             s.first = r.next
352  //      }
353  //  }
354
355  // remove record r
356  //
357
358  this->get_record(r,key); 
359  //
360  // situations we have to deal with:
361  //
362  // r.next = 0  ( = key to status)
363  // r.next = data ( = key to data)
364  //
365  // r.prev = 0
366  // r.prev = data
367  //
368
369  datarecord p,n;
370
371  if (r.prev != this->statuskey)
372    this->get_record(p,r.prev);
373 
374  if (r.next != this->statuskey)
375    this->get_record(n,r.next);
376//
377// and what to do if the next record to be dumped is
378// exactly this record?
379//
380// I think, status.nextd should become r.next,
381// whatever r.next is pointing to
382// However, if r.next is pointing to nothing,
383// we should give status.nextd an impossible value
384//
385 
386  if (this->status.nextd == key)
387  {
388    if (r.next == this->statuskey)
389      this->status.nextd.impossible();
390    else
391      this->status.nextd = r.next;
392  }
393
394  if (r.next == this->statuskey)  // r is last record
395  {
396    if (r.prev != this->statuskey)  // r is last record and has a predecessor
397      {
398        p.next = r.next;
399        this->put_record(p,r.prev);
400
401        if (key == status.next)
402          status.next = r.next;
403
404        // if (key == status.last)  // always the case here
405        status.last = r.prev;
406
407        // if (key == status.first)
408        //   impossible, because there is a previous record
409      }
410    else  // r is the only record
411    {
412      status.next  = r.next;
413      status.first = r.prev;
414      status.last  = r.prev;
415    }
416  }
417  else   // r has a follower
418  {
419    if (r.prev != this->statuskey)  // r has a predecessor and a follower
420    {
421      p.next = r.next;
422      this->put_record(p,r.prev);
423
424      n.prev = r.prev;
425      this->put_record(n,r.next);
426
427      if (key == status.next)
428        status.next = r.next;
429      // if (key == status.last)
430      //   impossible, r has a follower
431      // if (key == s.first)
432      //   impossible, r has a predecessor
433    }
434    else  // r is first record and has a follower
435    {
436      n.prev = r.prev;
437      this->put_record(n,r.next);
438
439      if (key == status.next)
440        status.next = r.next;
441
442      // if (key == status.last)
443      //   impossible, r has a follower
444     
445      // if (key == status.first)  // always true here
446      status.first = r.next;
447    }
448  }
449
450  // finally, remove the record
451
452
453  rc = this->remove_record(key);
454  if (rc != 0)
455    return rc;
456
457  // and rewrite status
458
459  this->status.present--;
460  if (r.retrieved == 0) 
461    this->status.present0--;
462
463  rc = this->put_status();
464  if (rc != 0)
465    return rc;
466
467  return 0;
468}
469
470void stopos_pool::set_kvp(bool v)
471{
472  this->kvp = v;
473}
474
475bool stopos_pool::get_kvp(void)
476{
477  return this->kvp;
478}
479
480int stopos_pool::get_counts(longuint &count, 
481               longuint &present, 
482               longuint &present0)
483{
484  int rc = get_status();
485  if (rc != 0) 
486    return rc;
487
488  count    = status.count;
489  present  = status.present;
490  present0 = status.present0;
491  return 0;
492}
493
494int stopos_pool::dump_line(std::string  &line, 
495                           longuint     &retrieved, 
496                           std::string  &key)
497{
498  if (!this->db_open)
499    return DBNOTOPEN;
500
501  int rc;
502  rc = this->get_status();
503  if (rc != 0)
504    return FETCHERROR;
505
506  //
507  // if status.nextd is pointing to nothing,
508  // we assume that one is starting the dump,
509  // and let nextd point to the first record
510  //
511
512  if (this->status.nextd == this->statuskey)
513    this->status.nextd = this->status.first;
514
515  datarecord r;
516
517  rc = this->get_record(r,this->status.nextd);
518  if (rc != 0)
519  {
520    this->status.nextd = this->status.first;
521    this->put_status();
522    return NOTFOUND;
523  }
524
525  key = this->status.nextd.str();
526
527  line = zhextostr(r.value);
528
529  this->status.nextd = r.next;
530
531  if (this->status.nextd == this->statuskey) // we signal that we reached eoi
532    this->status.nextd.impossible();         // at the next call
533
534  this->put_status();
535
536  return 0;
537}
538 
539datarecord::datarecord()
540{
541  this->retrieved = 0;
542}
543
544datarecord::datarecord(const std::string &s,char sep)
545{
546  std::vector <std::string> v;
547  split(v,s,sep);
548
549  this->prev      = stopos_key(v[0]);
550  this->next      = stopos_key(v[1]);
551  this->retrieved = StringToNumber<longuint>(v[2]);
552  this->value     = v[3];
553}
554
555std::string datarecord::str(char sep)
556{
557  std::string r;
558  r = this->prev.str()                + sep
559    + this->next.str()                + sep
560    + NumberToString(this->retrieved) + sep
561    + this->value
562    ;
563
564  return r;
565}
566
567statusrecord::statusrecord(void)
568{
569  this->init();
570}
571
572statusrecord::statusrecord(const std::string & s, char sep)
573{
574  std:: vector <std::string> v;
575
576  split(v,s,sep);
577  this->next     = stopos_key(v[0]);
578  this->first    = stopos_key(v[1]);
579  this->last     = stopos_key(v[2]);
580  this->nextd    = stopos_key(v[3]);
581  this->count    = StringToNumber<longuint>(v[4]);
582  this->present  = StringToNumber<longuint>(v[5]);
583  this->present0 = StringToNumber<longuint>(v[6]);
584
585}
586void statusrecord::init(void)
587{
588  this->next     = stopos_key();
589  this->first    = stopos_key();
590  this->last     = stopos_key();
591  this->nextd    = stopos_key();
592  this->count    = 0;
593  this->present  = 0;
594  this->present0 = 0;
595}
596
597std::string statusrecord::str(char sep)
598{
599  std::string r;
600  r = this->next.str()              + sep
601    + this->first.str()             + sep
602    + this->last.str()              + sep
603    + this->nextd.str()             + sep
604    + NumberToString(this->count)   + sep
605    + NumberToString(this->present) + sep
606    + NumberToString(this->present0)
607    ;
608  return r;
609}
610
Note: See TracBrowser for help on using the repository browser.