ARB
ad_core.cxx
Go to the documentation of this file.
1 // =============================================================== //
2 // //
3 // File : ad_core.cxx //
4 // Purpose : //
5 // //
6 // Institute of Microbiology (Technical University Munich) //
7 // http://www.arb-home.de/ //
8 // //
9 // =============================================================== //
10 
11 #include "gb_ts.h"
12 #include "gb_index.h"
13 #include "gb_localdata.h"
14 #include "ad_hcb.h"
15 
16 // Copy all info + external data mem to an one step undo buffer
17 // (needed to abort transactions)
18 
19 inline void _GB_CHECK_IN_UNDO_DELETE(GB_MAIN_TYPE *Main, GBDATA *& gbd) {
20  if (Main->undo_type) gb_check_in_undo_delete(Main, gbd);
21  else gb_delete_entry(gbd);
22 }
23 inline void _GB_CHECK_IN_UNDO_CREATE(GB_MAIN_TYPE *Main, GBDATA *gbd) {
24  if (Main->undo_type) gb_check_in_undo_create(Main, gbd);
25 }
26 inline void _GB_CHECK_IN_UNDO_MODIFY(GB_MAIN_TYPE *Main, GBDATA *gbd) {
27  if (Main->undo_type) gb_check_in_undo_modify(Main, gbd);
28 }
29 
30 // ---------------------------
31 // trigger callbacks
32 // (i.e. add them to pending callbacks)
33 
34 void GB_MAIN_TYPE::callback_group::trigger(GBDATA *gbd, GB_CB_TYPE type, gb_callback_list *dataCBs) {
35  gb_assert(implicated(!gbd->ext, gbd->is_container())); // expect old data was saved in ext (for normal data entries)
36  if (hierarchy_cbs) {
37  for (gb_hierarchy_callback_list::itertype cb = hierarchy_cbs->callbacks.begin(); cb != hierarchy_cbs->callbacks.end(); ++cb) {
38  if ((cb->spec.get_type() & type) && cb->triggered_by(gbd)) {
39  pending.add_unchecked(gb_triggered_callback(gbd, gbd->get_oldData(), cb->spec));
40  }
41  }
42  }
43  if (dataCBs) {
44  for (gb_callback_list::itertype cb = dataCBs->callbacks.begin(); cb != dataCBs->callbacks.end(); ++cb) {
45  if (cb->spec.get_type() & type) {
46  pending.add_unchecked(gb_triggered_callback(gbd, gbd->get_oldData(), cb->spec));
47  }
48  }
49  }
50 }
51 
53  changeCBs.trigger(gbd, type, gbd->get_callbacks());
54 }
55 
57  gb_callback_list *cbl = gbd->get_callbacks();
58  if (cbl || deleteCBs.hierarchy_cbs) {
59  gb_assert(implicated(cbl, gbd->ext)); // gbd->ext may be NULp if gbd has no callback installed
60 
61  if (gbd->ext) {
62  gbd->ext->callback = NULp;
63  if (!gbd->ext->old && gbd->type() != GB_DB) {
65  }
66  }
67  else if (gbd->type() != GB_DB) {
68  gbd->create_extended();
69  // gbd->ext->old always NULp here
71  }
72 
73  gb_assert(implicated(!gbd->ext, gbd->is_container()));
74  deleteCBs.trigger(gbd, GB_CB_DELETE, cbl);
75 
76  gb_assert(implicated(gbd->ext, !gbd->ext->callback));
77  delete cbl;
78  }
79 }
80 // ---------------------------
81 // GB data management
82 
83 void gb_touch_entry(GBDATA *gbd, GB_CHANGE val) {
84  gbd->flags2.update_in_server = 0;
85  GB_ARRAY_FLAGS(gbd).inc_change(val);
86 
87  GBCONTAINER *gbc = GB_FATHER(gbd);
88  gbc->set_touched_idx(gbd->index);
89 
90  while (1) {
91  GBCONTAINER *gbc_father = GB_FATHER(gbc);
92  if (!gbc_father) break;
93 
94  gbc_father->set_touched_idx(gbc->index);
95 
96  if (gbc->flags2.update_in_server) {
97  gbc->flags2.update_in_server = 0;
98  }
99  else {
100  if (GB_ARRAY_FLAGS(gbc).changed >= GB_SON_CHANGED)
101  return;
102  }
104  gbc = gbc_father;
105  }
106 }
107 
109  gbc->flags2.header_changed = 1;
111 }
112 
113 
115  GBDATA *gbd;
116  int index, start, end;
117  GB_CHANGE changed;
118  gb_header_list *header = GB_DATA_LIST_HEADER(gbc->d);
119 
120  if (gbc->index_of_touched_one_son > 0) {
121  start = (int)gbc->index_of_touched_one_son-1;
122  end = start + 1;
123  }
124  else {
125  if (!gbc->index_of_touched_one_son) {
126  start = end = 0;
127  }
128  else {
129  start = 0;
130  end = gbc->d.nheader;
131  }
132  }
133 
134  for (index = start; index < end; index++) {
135  if ((gbd = GB_HEADER_LIST_GBD(header[index]))) {
136  changed = (GB_CHANGE)header[index].flags.changed;
137  if (changed != GB_UNCHANGED && changed < GB_DELETED) {
138  header[index].flags.changed = GB_UNCHANGED;
139  if (gbd->is_container()) {
141  }
142  }
143  gbd->flags2.update_in_server = 0;
144  }
145  }
146  gbc->index_of_touched_one_son = 0;
147 }
148 
149 void gb_untouch_me(GBENTRY *gbe) {
151 }
152 inline void gb_untouch_me(GBCONTAINER *gbc) {
154 
155  gbc->flags2.header_changed = 0;
156  gbc->index_of_touched_one_son = 0;
157 }
158 
160  gb_untouch_children(gbc);
161  gb_untouch_me(gbc);
162 }
163 
165  for (int index = 0; index < gbc->d.nheader; index++) {
166  GBDATA *gbd = GBCONTAINER_ELEM(gbc, index);
167  if (gbd) {
168  if (gbd->is_container()) {
170  }
171  gbd->flags2.update_in_server = 1;
172  }
173  }
174 }
175 
176 void gb_create_header_array(GBCONTAINER *gbc, int size) {
177  // creates or resizes an old array to children
178  gb_header_list *nl, *ol;
179 
180  if (size <= gbc->d.headermemsize) return;
181  if (!size) return;
182  if (size > 10) size++;
183  if (size > 30) size = size*3/2;
185 
186  if ((ol=GB_DATA_LIST_HEADER(gbc->d))) {
187  int idx;
188  int maxidx = gbc->d.headermemsize; // ???: oder ->d.nheader
189 
190  for (idx=0; idx<maxidx; idx++) {
191  GBDATA *gbd = GB_HEADER_LIST_GBD(ol[idx]);
192  nl[idx].flags = ol[idx].flags;
193 
194  if (gbd) {
195  gb_assert(gbd->server_id==GBTUM_MAGIC_NUMBER || GB_read_clients(gbd)<0); // or I am a client
196  SET_GB_HEADER_LIST_GBD(nl[idx], gbd);
197  }
198  }
199 
201  }
202 
203  gbc->d.headermemsize = size;
204  SET_GB_DATA_LIST_HEADER(gbc->d, nl);
205 }
206 
207 static void gb_link_entry(GBCONTAINER* father, GBDATA *gbd, long index_pos) {
208  /* if index_pos == -1 -> to end of data;
209  else special index position; error when data already exists in index pos */
210 
211  SET_GB_FATHER(gbd, father);
212  if (!father) return; // do not link 'main'-entry!
213 
214  if (index_pos < 0) {
215  index_pos = father->d.nheader++;
216  }
217  else {
218  if (index_pos >= father->d.nheader) {
219  father->d.nheader = (int)index_pos+1;
220  }
221  }
222 
223  gb_create_header_array(father, (int)index_pos+1);
224 
225  if (GBCONTAINER_ELEM(father, index_pos)) {
226  GB_internal_error("Index of Databaseentry used twice");
227  index_pos = father->d.nheader++;
228  gb_create_header_array(father, (int)index_pos+1);
229  }
230 
231  /* the following code skips just-deleted index position, while searching for an unused
232  index position. I'm unsure whether this works w/o problems (ralf 2004-Oct-08) */
233 
234  while (GB_DATA_LIST_HEADER(father->d)[index_pos].flags.changed >= GB_DELETED) {
235 #if defined(DEBUG)
236  fprintf(stderr, "Warning: index_pos %li of father(%p) contains just-deleted entry -> using next index_pos..\n", index_pos, father);
237 #endif // DEBUG
238  index_pos = father->d.nheader++;
239  gb_create_header_array(father, (int)index_pos+1);
240  }
241 
242  gbd->index = index_pos;
243  SET_GBCONTAINER_ELEM(father, index_pos, gbd);
244  father->d.size++;
245 }
246 
247 static void gb_unlink_entry(GBDATA * gbd) {
248  GBCONTAINER *father = GB_FATHER(gbd);
249 
250  if (father) {
251  int index_pos = (int)gbd->index;
252  gb_header_list *hls = &(GB_DATA_LIST_HEADER(father->d)[index_pos]);
253 
255  hls->flags.key_quark = 0;
256  hls->flags.set_change(GB_DELETED);
257  father->d.size--;
258  SET_GB_FATHER(gbd, NULp);
259  }
260 }
261 
262 GB_MAIN_TYPE::GB_MAIN_TYPE(const char *db_path)
263  : transaction_level(0),
264  aborted_transaction(0),
265  i_am_server(false),
266  c_link(NULp),
267  server_data(NULp),
268  dummy_father(NULp),
269  root_container(NULp),
270  gb_key_data(NULp),
271  path(nulldup(db_path)),
272  opentype(gb_open_all),
273  disabled_path(NULp),
274  allow_corrupt_file_recovery(0),
275  compression_mask(-1), // allow all compressions
276  keycnt(0),
277  sizeofkeys(0),
278  first_free_key(0),
279  keys(NULp),
280  key_2_index_hash(GBS_create_hash(ALLOWED_KEYS, GB_MIND_CASE)),
281  key_clock(0),
282  mapped(false),
283  last_updated(0),
284  last_saved_time(0),
285  last_saved_transaction(0),
286  last_main_saved_transaction(0),
287  requested_undo_type(GB_UNDO_NONE),
288  undo_type(GB_UNDO_NONE),
289  undo(NULp),
290  security_level(0),
291  clock(0),
292  remote_hash(NULp),
293  close_callbacks(NULp),
294  this_user(NULp)
295 {
296  for (int i = 0; i<ALLOWED_DATES; ++i) dates[i] = NULp;
297  for (int i = 0; i<GB_MAX_USERS; ++i) users[i] = NULp;
298 
299  gb_init_undo_stack(this);
300  gb_local->announce_db_open(this);
301 }
302 
306 
308 
310 
311  free_all_keys();
312 
314  freenull(keys);
315 
316  gb_free_undo_stack(this);
317 
318  for (int j = 0; j<ALLOWED_DATES; ++j) freenull(dates[j]);
319 
320  free(path);
321  free(disabled_path);
322  free(qs.quick_save_disabled);
323 
325 }
326 
328  // inserts an object into the dabase hierarchy
329  GB_MAIN_TYPE *Main = GBCONTAINER_MAIN(father);
330 
331  SET_GB_FATHER(gbd, father);
332  if (Main->is_server()) {
334  }
335  if (Main->clock) {
336  gbd->create_extended();
337  gbd->touch_creation(Main->clock);
338  }
339 
340  gb_link_entry(father, gbd, index_pos);
341  gb_write_index_key(father, gbd->index, keyq);
342 
343  return gbd;
344 }
345 
346 static void gb_write_key(GBDATA *gbd, const char *s) {
347  GB_MAIN_TYPE *Main = GB_MAIN(gbd);
348  GBQUARK new_index = GBS_read_hash(Main->key_2_index_hash, s);
349  if (!new_index) new_index = (int)gb_create_key(Main, s, true); // create new index
350  gb_write_index_key(GB_FATHER(gbd), gbd->index, new_index);
351 }
352 
353 GBENTRY *gb_make_entry(GBCONTAINER *father, const char *key, long index_pos, GBQUARK keyq, GB_TYPES type) {
354  // creates a terminal database object
355  GB_MAIN_TYPE *Main = GBCONTAINER_MAIN(father);
356 
357  if (!keyq) keyq = gb_find_or_create_quark(Main, key);
358 
359  long gbm_index = quark2gbmindex(Main, keyq);
360  GBENTRY *gbe = (GBENTRY*)gbm_get_mem(sizeof(GBENTRY), gbm_index);
361 
362  GB_GBM_INDEX(gbe) = gbm_index;
363  SET_GB_FATHER(gbe, father);
364 
365  switch (type) {
366  case GB_STRING_SHRT:
367  type = GB_STRING;
368  // fall-through
369  case GB_STRING:
370  gbe->insert_data("", 0, 1);
371  break;
372  case GB_OBSOLETE:
373  gbe->flags.temporary = 1; // exclude obsolete type from next save
374  break;
375  default:
376  break;
377  }
378  gbe->flags.type = type;
379 
380  if (Main->is_server()) {
382  }
383  if (Main->clock) {
384  gbe->create_extended();
385  gbe->touch_creation(Main->clock);
386  }
387 
388  gb_link_entry(father, gbe, index_pos);
389  if (key) gb_write_key(gbe, key);
390  else gb_write_index_key(father, gbe->index, keyq);
391 
392  return gbe;
393 }
394 
396  // inserts an object into the dabase hierarchy
397  GB_MAIN_TYPE *Main = GBCONTAINER_MAIN(father);
398 
399  SET_GB_FATHER(gbc, father);
400  gbc->main_idx = father->main_idx;
401 
402  if (Main->is_server()) gbc->server_id = GBTUM_MAGIC_NUMBER;
403  if (Main->clock) {
404  gbc->create_extended();
405  gbc->touch_creation(Main->clock);
406  }
407  gb_link_entry(father, gbc, index_pos);
408  gb_write_index_key(father, gbc->index, keyq);
409 
410  return gbc;
411 }
412 
413 
414 GBCONTAINER *gb_make_container(GBCONTAINER *father, const char *key, long index_pos, GBQUARK keyq) {
415  GBCONTAINER *gbc;
416 
417  if (father) {
418  GB_MAIN_TYPE *Main = GBCONTAINER_MAIN(father);
419 
420  if (!keyq) keyq = gb_find_or_create_NULL_quark(Main, key);
421  long gbm_index = quark2gbmindex(Main, keyq);
422  gbc = (GBCONTAINER *)gbm_get_mem(sizeof(GBCONTAINER), gbm_index);
423  GB_GBM_INDEX(gbc) = gbm_index;
424 
425  SET_GB_FATHER(gbc, father);
426  gbc->flags.type = GB_DB;
427  gbc->main_idx = father->main_idx;
428  if (Main->is_server()) gbc->server_id = GBTUM_MAGIC_NUMBER;
429  if (Main->clock) {
430  gbc->create_extended();
431  gbc->touch_creation(Main->clock);
432  }
433  gb_link_entry(father, gbc, index_pos);
434  if (key) gb_write_key(gbc, key);
435  else gb_write_index_key(father, gbc->index, keyq);
436  }
437  else { // main entry
438  gbc = (GBCONTAINER *) gbm_get_mem(sizeof(GBCONTAINER), 0);
439  gbc->flags.type = GB_DB;
440  }
441 
442  return gbc;
443 }
444 
446  // Reduce an entry to its absolute minimum and remove it from database
447  GB_MAIN_TYPE *Main = GB_MAIN_NO_FATHER(gbd);
448  GB_TYPES type = gbd->type();
449 
450  Main->trigger_delete_callbacks(gbd);
451 
452  {
453  GBCONTAINER *gb_father = GB_FATHER(gbd);
454  if (gb_father) gb_write_index_key(gb_father, gbd->index, 0);
455  }
456  gb_unlink_entry(gbd);
457 
458  /* as soon as an entry is deleted, there is
459  * no need to keep track of the database entry
460  * within the server at the client side
461  */
462  if (Main->is_client() && gbd->server_id) {
463  if (Main->remote_hash) GBS_write_numhash(Main->remote_hash, gbd->server_id, 0);
464  }
465 
466  if (type >= GB_BITS && type < GB_DB) {
467  gb_free_cache(Main, gbd->as_entry()); // cant use gb_uncache (since entry is already unlinked!)
468  }
470  gbd->destroy_extended();
471 }
472 
473 static void gb_delete_entry(GBCONTAINER*& gbc) {
474  long gbm_index = GB_GBM_INDEX(gbc);
475 
476  gb_assert(gbc->type() == GB_DB);
477 
478  for (long index = 0; index < gbc->d.nheader; index++) {
479  GBDATA *gbd = GBCONTAINER_ELEM(gbc, index);
480  if (gbd) {
481  gb_delete_entry(gbd);
482  SET_GBCONTAINER_ELEM(gbc, index, NULp);
483  }
484  }
485 
486  gb_pre_delete_entry(gbc);
487 
488  // what is left now, is the core database entry!
489 
490  gb_destroy_indices(gbc);
491  gb_header_list *hls;
492 
493  if ((hls=GB_DATA_LIST_HEADER(gbc->d))) {
495  }
496  gbm_free_mem(gbc, sizeof(GBCONTAINER), gbm_index);
497 
498  gbc = NULp; // avoid further usage
499 }
500 
501 static void gb_delete_entry(GBENTRY*& gbe) {
502  long gbm_index = GB_GBM_INDEX(gbe);
503 
504  gb_pre_delete_entry(gbe);
505  if (gbe->type() >= GB_BITS) gbe->free_data();
506  gbm_free_mem(gbe, sizeof(GBENTRY), gbm_index);
507 
508  gbe = NULp; // avoid further usage
509 }
510 
511 void gb_delete_entry(GBDATA*& gbd) {
512  if (gbd->is_container()) {
513  gb_delete_entry(reinterpret_cast<GBCONTAINER*&>(gbd));
514  }
515  else {
516  gb_delete_entry(reinterpret_cast<GBENTRY*&>(gbd));
517  }
518 }
519 
521  GBQUARK sys_quark = key2quark(GB_MAIN(gb_main), GB_SYSTEM_FOLDER);
522 
523  // Note: sys_quark may be 0 (happens when destroying client db which never established a connection).
524  // In this case no system folder/quark has been created (and we do no longer try to create it)
525  // Nothing will happen in pass 2 below.
526 
527  for (int pass = 1; pass <= 2; pass++) {
528  for (int index = 0; index < gb_main->d.nheader; index++) {
529  GBDATA *gbd = GBCONTAINER_ELEM(gb_main, index);
530  if (gbd) {
531  // delay deletion of system folder to pass 2:
532  if (pass == 2 || GB_KEY_QUARK(gbd) != sys_quark) {
533  gb_delete_entry(gbd);
534  SET_GBCONTAINER_ELEM(gb_main, index, NULp);
535  }
536  }
537  }
538  }
539  gb_delete_entry(gb_main);
540 }
541 
543  gb_assert(!GB_FATHER(gbc));
544 
545  GB_MAIN_TYPE *Main = GB_MAIN(gbc);
546  for (int index = 0; index < gbc->d.nheader; index++) {
547  GBDATA *gbd = GBCONTAINER_ELEM(gbc, index);
548  if (gbd) {
549  // dummy fathers should only have one element (which is the root_container)
550  GBCONTAINER *gb_main = gbd->as_container();
551  gb_assert(gb_main == Main->root_container);
552 
553  gb_delete_main_entry(gb_main);
554  SET_GBCONTAINER_ELEM(gbc, index, NULp);
555  Main->root_container = NULp;
556  }
557  }
558 
559  gb_delete_entry(gbc);
560 }
561 
562 // ---------------------
563 // Data Storage
564 
566  // Note: does not increment the refcounter
568 
569  ts->flags = gbe->flags;
570  ts->flags2 = gbe->flags2;
571 
572  if (gbe->stored_external()) {
573  ts->info.ex.data = gbe->info.ex.get_data();
574  ts->info.ex.memsize = gbe->info.ex.memsize;
575  ts->info.ex.size = gbe->info.ex.size;
576  }
577  else {
578  memcpy(&(ts->info), &(gbe->info), sizeof(gbe->info));
579  }
580 
581  ts->refcount = 1;
582 
583  return ts;
584 }
585 
587  if (!ts) return;
588  ts->refcount ++;
589 }
590 
592  if (!ts) return;
593  ts->refcount --;
594  if (ts->refcount <= 0) { // no more references !!!!
595  if (ts->stored_external()) {
596  if (ts->info.ex.data) {
597  gbm_free_mem(ts->info.ex.data,
598  ts->info.ex.memsize,
599  ts->flags2.gbm_index);
600  }
601  }
603  }
604 }
605 
607  // remove reference to undo entry and set extern pointer to zero
608  if (ts->stored_external()) {
609  ts->info.ex.data = NULp;
610  }
612 }
613 
614 static void gb_abortdata(GBENTRY *gbe) {
615  gb_transaction_save *old;
616 
617  gbe->index_check_out();
618  old = gbe->ext->old;
619  gb_assert(old);
620 
621  gbe->flags = old->flags;
622  gbe->flags2 = old->flags2;
623 
624  if (old->stored_external()) {
625  gbe->info.ex.set_data(old->info.ex.data);
626  gbe->info.ex.memsize = old->info.ex.memsize;
627  gbe->info.ex.size = old->info.ex.size;
628  }
629  else {
630  memcpy(&(gbe->info), &(old->info), sizeof(old->info));
631  }
633  gbe->ext->old = NULp;
634 
635  gbe->index_re_check_in();
636 }
637 
638 
640  /* Saves gbe->info into gbe->ext->old
641  * Destroys gbe->info!
642  * Don't call with GBCONTAINER
643  */
644 
645  gbe->create_extended();
646  gbe->index_check_out();
647  if (gbe->ext->old || (GB_ARRAY_FLAGS(gbe).changed == GB_CREATED)) {
648  gbe->free_data();
649  }
650  else {
651  gbe->ext->old = gb_new_gb_transaction_save(gbe);
652  gbe->info.ex.set_data(NULp);
653  }
654 }
655 
656 
657 // -----------------------
658 // Key Management
659 
660 void gb_write_index_key(GBCONTAINER *father, long index, GBQUARK new_index) {
661  // Set the key quark of an database field.
662  // Check for indexing data field.
663 
664  GB_MAIN_TYPE *Main = GBCONTAINER_MAIN(father);
665  gb_header_list *hls = GB_DATA_LIST_HEADER(father->d);
666  GBQUARK old_index = hls[index].flags.key_quark;
667 
668  Main->keys[old_index].nref--;
669  Main->keys[new_index].nref++;
670 
671  if (Main->is_server()) {
672  GBDATA *gbd = GB_HEADER_LIST_GBD(hls[index]);
673 
674  if (gbd && gbd->is_indexable()) {
675  GBENTRY *gbe = gbd->as_entry();
676  gb_index_files *ifs = NULp;
677 
678  gbe->index_check_out();
679  gbe->flags2.should_be_indexed = 0; // do not re-checkin
680 
681  GBCONTAINER *gfather = GB_FATHER(father);
682  if (gfather) {
683  for (ifs = GBCONTAINER_IFS(gfather); ifs; ifs = GB_INDEX_FILES_NEXT(ifs)) {
684  if (ifs->key == new_index) break;
685  }
686  }
687  hls[index].flags.key_quark = new_index;
688  if (ifs) gbe->index_check_in();
689 
690  return;
691  }
692  }
693 
694  hls[index].flags.key_quark = new_index;
695 }
696 
697 void gb_create_key_array(GB_MAIN_TYPE *Main, int index) {
698  if (index >= Main->sizeofkeys) {
699  Main->sizeofkeys = Main->keys ? index*3/2+1 : 1000;
700  ARB_recalloc(Main->keys, Main->keycnt, Main->sizeofkeys);
701  for (int i = Main->keycnt; i < Main->sizeofkeys; i++) {
702  Main->keys[i].compression_mask = -1;
703  }
704  }
705  gb_assert(index<Main->sizeofkeys);
706 }
707 
708 long gb_create_key(GB_MAIN_TYPE *Main, const char *key, bool create_gb_key) {
709  long index;
710  if (Main->first_free_key) {
711  index = Main->first_free_key;
712  Main->first_free_key = Main->keys[index].next_free_key;
713  Main->keys[index].next_free_key = 0;
714  }
715  else {
716  index = Main->keycnt++;
717  gb_create_key_array(Main, (int)index+1);
718  }
719  if (Main->is_client()) {
720  long test_index = gbcmc_key_alloc(Main->gb_main(), key);
721  if (test_index != index) {
722  if (test_index == 0) { // comm error
723  GBK_terminatef("Allocating quark for '%s' failed (Reason: %s)", key, GB_await_error());
724  }
725  else {
726  GBK_terminatef("Database corrupt (allocating quark '%s' in server failed)", key);
727  }
728  }
729  }
730  Main->keys[index].nref = 0;
731 
732  if (key) {
733  if (!key[0]) GBK_terminate("Attempt to allocate empty key");
734 
735  Main->keys[index].key = ARB_strdup(key);
736  GBS_write_hash(Main->key_2_index_hash, key, index);
738  if (Main->gb_key_data && create_gb_key) {
739  gb_load_single_key_data(Main->gb_main(), (GBQUARK)index);
740  // Warning: starts a big recursion
741  if (Main->is_client()) { // send new gb_key to server, needed for searching
743  }
744  }
745  }
746 
747 
748  Main->key_clock = Main->clock;
749  return index;
750 }
751 
753  if (keys) {
754  for (long index = 1; index < keycnt; index++) {
755  if (keys[index].key) {
756  GBS_write_hash(key_2_index_hash, keys[index].key, 0);
757  freenull(keys[index].key);
758  }
759  keys[index].nref = 0;
760  keys[index].next_free_key = 0;
761  }
762  freenull(keys[0].key); // "main"
763  first_free_key = 0;
764  keycnt = 1;
765  }
766 }
767 
768 char *gb_abort_entry(GBDATA *gbd) { // @@@ result is always NULp -> remove return value
770 
771  if (gbd->is_entry()) {
772  GBENTRY *gbe = gbd->as_entry();
773  if (gbe->get_oldData()) {
774  if (gbe->type() >= GB_BITS) {
775  gb_uncache(gbe);
776  gbe->free_data();
777  }
778  gb_abortdata(gbe);
779  }
780  }
781  return NULp;
782 }
783 
784 // ---------------------
785 // Transactions
786 
788  // delete created, undo changed
789  GB_CHANGE change = (GB_CHANGE)GB_ARRAY_FLAGS(gbd).changed;
790 
791  switch (change) {
792  case GB_UNCHANGED:
793  break;
794 
795  case GB_CREATED:
796  GB_PUT_SECURITY_DELETE(gbd, 0);
797  gb_delete_entry(gbd);
798  break;
799 
800  case GB_DELETED:
802  // fall-through
803  default:
804  if (gbd->is_container()) {
805  GBCONTAINER *gbc = gbd->as_container();
806  gb_header_list *hls = GB_DATA_LIST_HEADER(gbc->d);
807 
808  for (int index = 0; index < gbc->d.nheader; index++) {
809  GBDATA *gb = GB_HEADER_LIST_GBD(hls[index]);
810  if (gb) gb_abort_transaction_local_rek(gb);
811  }
812  }
813  gb_abort_entry(gbd);
814  break;
815  }
816 }
817 
818 GB_ERROR gb_commit_transaction_local_rek(GBDATA*& gbd, long mode, int *pson_created) {
819  // goes to header: __ATTR__USERESULT
820 
821  /* commit created / delete deleted
822  * mode 0 local = server or
823  * begin trans in client or
824  * commit_client_in_server
825  * mode 1 remote = client
826  * mode 2 remote = client (only send updated data)
827  */
828 
829  GB_MAIN_TYPE *Main = GB_MAIN(gbd);
830  GB_CHANGE change = (GB_CHANGE)GB_ARRAY_FLAGS(gbd).changed;
831  int son_created = 0;
832  GB_ERROR error;
833 
834  switch (change) {
835  case GB_UNCHANGED:
836  return NULp;
837 
838  case GB_DELETED:
839  GB_PUT_SECURITY_DELETE(gbd, 0);
840  if (mode) {
841  if (!gbd->flags2.update_in_server) {
842  error = gbcmc_sendupdate_delete(gbd);
843  if (error)
844  return error;
845  gbd->flags2.update_in_server = 1;
846  }
847  if (mode == 2) return NULp;
848  }
849  else {
851  _GB_CHECK_IN_UNDO_DELETE(Main, gbd);
852  return NULp;
853  }
854  gb_delete_entry(gbd);
855  return NULp;
856 
857  case GB_CREATED:
858  if (mode) {
859  if (!gbd->flags2.update_in_server) {
860  if (gbd->server_id) goto gb_changed_label;
861  // already created, do only a change
862  error = gbcmc_sendupdate_create(gbd);
863  if (gbd->is_container()) {
865  // set all children update_in_server flags
866  }
867  gbd->flags2.update_in_server = 1;
868  if (error) return error;
869  }
870  if (mode == 2) return NULp;
871  }
872  else {
873  _GB_CHECK_IN_UNDO_CREATE(Main, gbd);
874  }
875  if (pson_created) {
876  *pson_created = 1;
877  }
878 
879  if (gbd->flags2.header_changed == 1) {
880  gbd->as_container()->header_update_date = Main->clock;
881  }
882  goto gb_commit_do_callbacks;
883 
884  case GB_NORMAL_CHANGE:
885  if (mode) {
886  if (!gbd->flags2.update_in_server) {
887  gb_changed_label:
888  int send_header = gbd->flags2.header_changed ? 1 : 0;
889  error = gbcmc_sendupdate_update(gbd, send_header);
890  if (error) return error;
891  gbd->flags2.update_in_server = 1;
892  }
893  }
894  else {
895  _GB_CHECK_IN_UNDO_MODIFY(Main, gbd);
896  }
897  // fall-through
898 
899  default: // means GB_SON_CHANGED + GB_NORMAL_CHANGE
900 
901  if (gbd->is_container()) {
902  GBCONTAINER *gbc = gbd->as_container();
903  gb_header_list *hls = GB_DATA_LIST_HEADER(gbc->d);
904 
905  int start, end;
906 
907  if (gbc->index_of_touched_one_son>0) {
908  start = (int)gbc->index_of_touched_one_son-1;
909  end = start+1;
910  }
911  else {
912  if (!gbc->index_of_touched_one_son) {
913  start = end = 0;
914  }
915  else {
916  start = 0;
917  end = gbc->d.nheader;
918  }
919  }
920 
921  for (int index = start; index < end; index++) {
922  GBDATA *gb = GB_HEADER_LIST_GBD(hls[index]);
923  if (gb) {
924  if (!hls[index].flags.changed) continue;
925  error = gb_commit_transaction_local_rek(gb, mode, &son_created);
926  if (error) return error;
927  }
928  }
929 
930  if (mode) gbd->flags2.update_in_server = 1;
931  }
932  gb_commit_do_callbacks :
933  if (mode == 2) { // update server; no callbacks
934  gbd->flags2.update_in_server = 1;
935  }
936  else {
938  gbd->create_extended();
939  gbd->touch_update(Main->clock);
940  if (gbd->flags2.header_changed) {
941  gbd->as_container()->header_update_date = Main->clock;
942  }
943 
944  Main->trigger_change_callbacks(gbd, cbtype);
945 
947  }
948  }
949 
950  return NULp;
951 }
void free_data()
Definition: gb_data.h:223
GB_CHANGE
Definition: gb_local.h:73
long memsize
Definition: gb_data.h:29
void gb_init_undo_stack(GB_MAIN_TYPE *Main)
Definition: adindex.cxx:344
const char * GB_ERROR
Definition: arb_core.h:25
#define GB_SYSTEM_FOLDER
Definition: arbdb.h:27
gb_quick_save qs
Definition: gb_main.h:127
void SET_GB_DATA_LIST_HEADER(gb_data_list &dl, gb_header_list *head)
Definition: gb_data.h:108
GB_TYPES type
void GBK_terminate_on_error(const char *error)
Definition: arb_msg.h:75
gb_flag_types2 flags2
Definition: gb_ts.h:43
#define GB_GBM_INDEX(gbd)
Definition: gb_data.h:127
unsigned int saved_flags
Definition: gb_data.h:74
char * path
Definition: gb_main.h:122
listtype::iterator itertype
Definition: gb_cb.h:64
void SET_GBCONTAINER_ELEM(GBCONTAINER *gbc, int idx, GBDATA *gbd)
Definition: gb_header.h:60
void free_all_keys()
Definition: ad_core.cxx:752
#define implicated(hypothesis, conclusion)
Definition: arb_assert.h:289
char * dates[ALLOWED_DATES]
Definition: gb_main.h:149
void gb_check_in_undo_create(GB_MAIN_TYPE *Main, GBDATA *gbd)
Definition: adindex.cxx:636
long GBS_write_hash(GB_HASH *hs, const char *key, long val)
Definition: adhash.cxx:454
__ATTR__USERESULT GB_ERROR send_update_to_server(GBDATA *gbd) __ATTR__USERESULT
Definition: arbdb.cxx:2468
Definition: arbdb.h:69
void gb_touch_header(GBCONTAINER *gbc)
Definition: ad_core.cxx:108
static void gb_unlink_entry(GBDATA *gbd)
Definition: ad_core.cxx:247
gb_flag_types2 flags2
Definition: gb_data.h:135
gb_data_base_type_union info
Definition: gb_data.h:204
void _GB_CHECK_IN_UNDO_DELETE(GB_MAIN_TYPE *Main, GBDATA *&gbd)
Definition: ad_core.cxx:19
GB_MAIN_TYPE * GB_MAIN(GBDATA *gbd)
Definition: gb_data.h:291
gb_extern_data2 ex
Definition: gb_ts.h:38
void insert_data(const char *Data, long Size, long Memsize)
Definition: gb_storage.h:60
long nref
Definition: gb_key.h:31
gb_user * users[GB_MAX_USERS]
Definition: gb_main.h:156
void gb_del_ref_and_extern_gb_transaction_save(gb_transaction_save *ts)
Definition: ad_core.cxx:606
long server_id
Definition: gb_data.h:130
long gb_create_key(GB_MAIN_TYPE *Main, const char *key, bool create_gb_key)
Definition: ad_core.cxx:708
static void gb_set_update_in_server_flags(GBCONTAINER *gbc)
Definition: ad_core.cxx:164
unsigned int type
Definition: gb_data.h:66
static gb_transaction_save * gb_new_gb_transaction_save(GBENTRY *gbe)
Definition: ad_core.cxx:565
long key_clock
Definition: gb_main.h:136
void inc_change(GB_CHANGE val)
Definition: gb_header.h:29
long GBS_write_numhash(GB_NUMHASH *hs, long key, long val)
Definition: adhash.cxx:687
static void gb_delete_main_entry(GBCONTAINER *&gb_main)
Definition: ad_core.cxx:520
char * ARB_strdup(const char *str)
Definition: arb_string.h:27
void touch_update(long udate)
Definition: gb_data.h:189
GBDATA * gb_make_pre_defined_entry(GBCONTAINER *father, GBDATA *gbd, long index_pos, GBQUARK keyq)
Definition: ad_core.cxx:327
void GBK_terminatef(const char *templat,...)
Definition: arb_msg.cxx:523
static void gb_abortdata(GBENTRY *gbe)
Definition: ad_core.cxx:614
GBDATA * GB_HEADER_LIST_GBD(gb_header_list &hl)
Definition: gb_header.h:42
void gb_write_index_key(GBCONTAINER *father, long index, GBQUARK new_index)
Definition: ad_core.cxx:660
CONSTEXPR_INLINE gb_header_list * GB_DATA_LIST_HEADER(gb_data_list &dl)
Definition: gb_data.h:105
void gb_add_ref_gb_transaction_save(gb_transaction_save *ts)
Definition: ad_core.cxx:586
GB_ERROR gb_commit_transaction_local_rek(GBDATA *&gbd, long mode, int *pson_created)
Definition: ad_core.cxx:818
gb_header_flags & GB_ARRAY_FLAGS(GBDATA *gbd)
Definition: gb_header.h:49
char * get_data()
Definition: gb_data.h:32
void GBS_free_hash(GB_HASH *hs)
Definition: adhash.cxx:538
void index_check_in()
Definition: adindex.cxx:29
GBQUARK gb_find_or_create_quark(GB_MAIN_TYPE *Main, const char *key)
Definition: arbdb.cxx:1668
gb_index_files * GB_INDEX_FILES_NEXT(gb_index_files *ixf)
Definition: gb_index.h:87
gb_flag_types flags
Definition: gb_ts.h:42
GB_TYPES type() const
Definition: gb_data.h:139
GB_MAIN_TYPE * GBCONTAINER_MAIN(GBCONTAINER *gbc)
Definition: gb_data.h:289
GBCONTAINER * root_container
Definition: gb_main.h:120
void _GB_CHECK_IN_UNDO_MODIFY(GB_MAIN_TYPE *Main, GBDATA *gbd)
Definition: ad_core.cxx:26
static void gb_delete_entry(GBCONTAINER *&gbc)
Definition: ad_core.cxx:473
void gb_check_in_undo_delete(GB_MAIN_TYPE *Main, GBDATA *&gbd)
Definition: adindex.cxx:674
GB_ERROR gbcmc_sendupdate_update(GBDATA *gbd, int send_headera)
Definition: adcomm.cxx:1415
long clock
Definition: gb_main.h:151
void _GB_CHECK_IN_UNDO_CREATE(GB_MAIN_TYPE *Main, GBDATA *gbd)
Definition: ad_core.cxx:23
#define cb(action)
GB_MAIN_TYPE(const char *db_path)
Definition: ad_core.cxx:262
#define GB_MAX_USERS
Definition: gb_local.h:23
static HelixNrInfo * start
POS_TREE1 * father
Definition: probe_tree.h:39
GB_UNDO_TYPE undo_type
Definition: gb_main.h:145
void SET_GB_HEADER_LIST_GBD(gb_header_list &hl, GBDATA *gbd)
Definition: gb_header.h:45
uchar flags
Definition: probe_tree.h:38
GB_ERROR GB_await_error()
Definition: arb_msg.cxx:342
gb_flag_types flags
Definition: gb_data.h:134
Definition: arbdb.h:78
GB_MAIN_TYPE * GB_MAIN_NO_FATHER(GBDATA *gbd)
Definition: gb_data.h:294
void gb_untouch_children_and_me(GBCONTAINER *gbc)
Definition: ad_core.cxx:159
bool is_indexable() const
Definition: gb_data.h:145
long header_update_date
Definition: gb_data.h:253
GB_HASH * key_2_index_hash
Definition: gb_main.h:135
char * quick_save_disabled
Definition: gb_main.h:42
void gb_pre_delete_entry(GBDATA *gbd)
Definition: ad_core.cxx:445
void GBK_terminate(const char *error) __ATTR__NORETURN
Definition: arb_msg.cxx:509
bool is_server() const
Definition: gb_main.h:203
short refcount
Definition: gb_ts.h:45
gb_data_base_type_union2 info
Definition: gb_ts.h:44
GBCONTAINER * gb_key_data
Definition: gb_main.h:121
void destroy_extended()
Definition: gb_data.h:181
#define false
Definition: ureadseq.h:13
GB_ERROR gbcmc_sendupdate_create(GBDATA *gbd)
Definition: adcomm.cxx:1389
void gb_abort_transaction_local_rek(GBDATA *&gbd)
Definition: ad_core.cxx:787
GBQUARK key2quark(GB_MAIN_TYPE *Main, const char *key)
Definition: gb_key.h:42
unsigned int key_quark
Definition: gb_header.h:21
bool is_container() const
Definition: gb_data.h:147
void announce_db_close(GB_MAIN_TYPE *Main)
Definition: arbdb.cxx:562
GBCONTAINER * gb_make_pre_defined_container(GBCONTAINER *father, GBCONTAINER *gbc, long index_pos, GBQUARK keyq)
Definition: ad_core.cxx:395
static void gb_write_key(GBDATA *gbd, const char *s)
Definition: ad_core.cxx:346
static void error(const char *msg)
Definition: mkptypes.cxx:96
static void gb_link_entry(GBCONTAINER *father, GBDATA *gbd, long index_pos)
Definition: ad_core.cxx:207
bool is_client() const
Definition: gb_main.h:204
void index_check_out()
Definition: adindex.cxx:65
GBQUARK key
Definition: gb_index.h:49
void set_touched_idx(int idx)
Definition: gb_data.h:258
size_t GBS_hash_elements(const GB_HASH *hs)
Definition: adhash.cxx:570
gb_db_extended * ext
Definition: gb_data.h:132
void gb_free_cache(GB_MAIN_TYPE *Main, GBENTRY *gbe)
Definition: adcache.cxx:204
unsigned int update_in_server
Definition: gb_data.h:83
GB_ERROR gbcms_add_to_delete_list(GBDATA *gbd)
Definition: adcomm.cxx:1635
void index_re_check_in()
Definition: gb_data.h:235
void gb_untouch_me(GBENTRY *gbe)
Definition: ad_core.cxx:149
long GB_read_clients(GBDATA *gbd)
Definition: adcomm.cxx:1682
static void gb_uncache(GBCONTAINER *gbc)
Definition: adcache.cxx:221
GBCONTAINER * as_container() const
Definition: gb_data.h:155
unsigned int should_be_indexed
Definition: gb_data.h:87
GB_write_int const char GB_write_autoconv_string WRITE_SKELETON(write_pointer, GBDATA *,"%p", GB_write_pointer) char *AW_awa if)(!gb_var) return strdup("")
Definition: AW_awar.cxx:163
void ARB_recalloc(TYPE *&tgt, size_t oelem, size_t nelem)
Definition: arb_mem.h:49
gb_transaction_save * get_oldData() const
Definition: gb_data.h:196
void * gbm_get_mem(size_t size, long index)
Definition: gb_memory.h:130
void gb_create_header_array(GBCONTAINER *gbc, int size)
Definition: ad_core.cxx:176
long first_free_key
Definition: gb_main.h:133
long index_of_touched_one_son
Definition: gb_data.h:248
int compression_mask
Definition: gb_key.h:38
CONSTEXPR_INLINE GBCONTAINER * GB_FATHER(GBDATA *gbd)
Definition: gb_data.h:271
void gb_destroy_indices(GBCONTAINER *gbc)
Definition: adindex.cxx:166
long memsize
Definition: gb_ts.h:31
char * key
Definition: gb_key.h:29
GBDATA * gb_main() const
Definition: gb_main.h:179
void nl()
Definition: test_unit.h:415
gb_index_files * GBCONTAINER_IFS(GBCONTAINER *gbc)
Definition: gb_index.h:94
void GBS_free_numhash(GB_NUMHASH *hs)
Definition: adhash.cxx:742
bool stored_external() const
Definition: gb_ts.h:47
unsigned int temporary
Definition: gb_data.h:73
void gb_untouch_children(GBCONTAINER *gbc)
Definition: ad_core.cxx:114
GB_ERROR gbcmc_sendupdate_delete(GBDATA *gbd)
Definition: adcomm.cxx:1406
gb_extern_data ex
Definition: gb_data.h:51
GBENTRY * gb_make_entry(GBCONTAINER *father, const char *key, long index_pos, GBQUARK keyq, GB_TYPES type)
Definition: ad_core.cxx:353
GBQUARK gb_find_or_create_NULL_quark(GB_MAIN_TYPE *Main, const char *key)
Definition: arbdb.cxx:1678
gb_callback_list * callback
Definition: gb_data.h:59
void touch_creation(long cdate)
Definition: gb_data.h:188
#define ALLOWED_DATES
Definition: gb_main.h:85
void GB_internal_error(const char *message)
Definition: arb_msg.cxx:481
CONSTEXPR_INLINE_Cxx14 void SET_GB_FATHER(GBDATA *gbd, GBCONTAINER *father)
Definition: gb_data.h:274
GBQUARK GB_KEY_QUARK(GBDATA *gbd)
Definition: gb_key.h:48
GBCONTAINER * gb_make_container(GBCONTAINER *father, const char *key, long index_pos, GBQUARK keyq)
Definition: ad_core.cxx:414
#define GBTUM_MAGIC_NUMBER
Definition: gb_local.h:25
#define gb_assert(cond)
Definition: arbdbt.h:11
bool stored_external() const
Definition: gb_data.h:211
char * gb_abort_entry(GBDATA *gbd)
Definition: ad_core.cxx:768
void trigger_change_callbacks(GBDATA *gbd, GB_CB_TYPE type)
Definition: ad_core.cxx:52
void gb_save_extern_data_in_ts(GBENTRY *gbe)
Definition: ad_core.cxx:639
bool is_entry() const
Definition: gb_data.h:148
long index
Definition: gb_data.h:133
long quark2gbmindex(GB_MAIN_TYPE *Main, GBQUARK key_quark)
Definition: gb_key.h:46
gb_transaction_save * old
Definition: gb_data.h:60
listtype callbacks
Definition: gb_cb.h:67
long sizeofkeys
Definition: gb_main.h:132
void create_extended()
Definition: gb_data.h:176
unsigned int changed
Definition: gb_header.h:22
#define GB_PUT_SECURITY_DELETE(gb, i)
Definition: gb_data.h:307
gb_Key * keys
Definition: gb_main.h:134
void announce_db_open(GB_MAIN_TYPE *Main)
Definition: arbdb.cxx:550
GBENTRY * as_entry() const
Definition: gb_data.h:150
GBDATA * GBCONTAINER_ELEM(GBCONTAINER *gbc, int idx)
Definition: gb_header.h:57
#define NULp
Definition: cxxforward.h:116
gb_data_list d
Definition: gb_data.h:246
long gbcmc_key_alloc(GBDATA *gbd, const char *key)
Definition: adcomm.cxx:1788
void gb_free_undo_stack(GB_MAIN_TYPE *Main)
Definition: adindex.cxx:417
int keycnt
Definition: gb_main.h:131
gb_header_flags flags
Definition: gb_header.h:35
void release_main_idx()
Definition: ad_load.cxx:947
void gb_check_in_undo_modify(GB_MAIN_TYPE *Main, GBDATA *gbd)
Definition: adindex.cxx:647
GB_TYPES
Definition: arbdb.h:62
char * data
Definition: gb_ts.h:30
void gb_del_ref_gb_transaction_save(gb_transaction_save *ts)
Definition: ad_core.cxx:591
GBDATA * gb_main
Definition: adname.cxx:32
void gbm_free_mem(void *block, size_t size, long index)
Definition: gb_memory.h:131
unsigned int gbm_index
Definition: gb_data.h:86
void GB_FREE_TRANSACTION_SAVE(GBDATA *gbd)
Definition: gb_ts.h:55
void gb_load_single_key_data(GBDATA *gb_main, GBQUARK q)
Definition: adsystem.cxx:112
char * disabled_path
Definition: gb_main.h:124
GB_NUMHASH * remote_hash
Definition: gb_main.h:152
int nheader
Definition: gb_data.h:102
void gb_touch_entry(GBDATA *gbd, GB_CHANGE val)
Definition: ad_core.cxx:83
GB_CB_TYPE
Definition: arbdb_base.h:46
void gb_create_key_array(GB_MAIN_TYPE *Main, int index)
Definition: ad_core.cxx:697
GB_MAIN_IDX main_idx
Definition: gb_data.h:255
void trigger_delete_callbacks(GBDATA *gbd)
Definition: ad_core.cxx:56
unsigned int header_changed
Definition: gb_data.h:85
int GBQUARK
Definition: arbdb_base.h:30
gb_local_data * gb_local
Definition: arbdb.cxx:33
long GBS_read_hash(const GB_HASH *hs, const char *key)
Definition: adhash.cxx:392
gb_callback_list * get_callbacks() const
Definition: gb_data.h:195
long next_free_key
Definition: gb_key.h:32
GBCONTAINER * dummy_father
Definition: gb_main.h:119
#define ALLOWED_KEYS
Definition: gb_main.h:84
GB_HASH * GBS_create_hash(long estimated_elements, GB_CASE case_sens)
Definition: adhash.cxx:253
int headermemsize
Definition: gb_data.h:100
long size
Definition: gb_ts.h:32
void set_data(char *data)
Definition: gb_data.h:33
void gb_delete_dummy_father(GBCONTAINER *&gbc)
Definition: ad_core.cxx:542
unsigned int flags
Definition: gb_header.h:20
GB_write_int const char s
Definition: AW_awar.cxx:154