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