source: tags/0.9/stopos_pool.cpp @ 9

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

willem

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