source: trunk/stopos_pool.cpp @ 17

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

willem

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