ARB
adindex.cxx
Go to the documentation of this file.
1 // =============================================================== //
2 // //
3 // File : adindex.cxx //
4 // Purpose : //
5 // //
6 // Institute of Microbiology (Technical University Munich) //
7 // http://www.arb-home.de/ //
8 // //
9 // =============================================================== //
10 
11 #include "gb_key.h"
12 #include "gb_undo.h"
13 #include "gb_index.h"
14 #include "gb_hashindex.h"
15 #include "gb_ts.h"
16 
17 #include <arb_strbuf.h>
18 
19 #include <cctype>
20 
21 #define GB_INDEX_FIND(gbf, ifs, quark) \
22  for (ifs = GBCONTAINER_IFS(gbf); \
23  ifs; \
24  ifs = GB_INDEX_FILES_NEXT(ifs)) \
25  { \
26  if (ifs->key == quark) break; \
27  }
28 
30  // write field in index table
31 
32  GBCONTAINER *gfather = GB_GRANDPA(this);
33  if (gfather) {
34  GBQUARK quark = GB_KEY_QUARK(this);
35  gb_index_files *ifs;
36  GB_INDEX_FIND(gfather, ifs, quark);
37 
38  if (ifs) { // if key is indexed
39  if (is_indexable()) {
40  if (flags2.is_indexed) {
41  GB_internal_error("Double checked in");
42  }
43  else {
44  GB_CSTR content = GB_read_char_pntr(this);
45  unsigned long idx;
46  GB_CALC_HASH_INDEX(content, idx, ifs->hash_table_size, ifs->case_sens);
47  ifs->nr_of_elements++;
48 
49  {
50  GB_REL_IFES *entries = GB_INDEX_FILES_ENTRIES(ifs);
52 
53  SET_GB_IF_ENTRIES_NEXT(ifes, GB_ENTRIES_ENTRY(entries, idx));
54  SET_GB_IF_ENTRIES_GBD(ifes, this);
55  SET_GB_ENTRIES_ENTRY(entries, idx, ifes);
56  }
58  flags2.is_indexed = 1;
59  }
60  }
61  }
62  }
63 }
64 
66  // remove entry from index table
67  if (flags2.is_indexed) {
68  GBCONTAINER *gfather = GB_GRANDPA(this);
69  GBQUARK quark = GB_KEY_QUARK(this);
70 
71  flags2.is_indexed = 0;
72 
73  gb_index_files *ifs;
74  GB_INDEX_FIND(gfather, ifs, quark);
75 
77  if (!ifs) error = "key is not indexed";
78  else {
79  error = GB_push_transaction(this);
80  if (!error) {
81  GB_CSTR content = GB_read_char_pntr(this);
82 
83  if (!content) {
84  error = GBS_global_string("can't read key value (%s)", GB_await_error());
85  }
86  else {
87  unsigned long idx;
88  GB_CALC_HASH_INDEX(content, idx, ifs->hash_table_size, ifs->case_sens);
89 
90  gb_if_entries *ifes2 = NULp;
91  GB_REL_IFES *entries = GB_INDEX_FILES_ENTRIES(ifs);
92  gb_if_entries *ifes;
93 
94  for (ifes = GB_ENTRIES_ENTRY(entries, idx); ifes; ifes = GB_IF_ENTRIES_NEXT(ifes)) {
95  if (this == GB_IF_ENTRIES_GBD(ifes)) { // entry found
96  if (ifes2) SET_GB_IF_ENTRIES_NEXT(ifes2, GB_IF_ENTRIES_NEXT(ifes));
97  else SET_GB_ENTRIES_ENTRY(entries, idx, GB_IF_ENTRIES_NEXT(ifes));
98 
99  ifs->nr_of_elements--;
100  gbm_free_mem(ifes, sizeof(gb_if_entries), GB_GBM_INDEX(this));
101  break;
102  }
103  ifes2 = ifes;
104  }
105  }
106  }
107  error = GB_end_transaction(this, error);
108  }
109 
110  if (error) {
111  error = GBS_global_string("GBENTRY::index_check_out failed for key '%s' (%s)\n", GB_KEY(this), error);
112  GB_internal_error(error);
113  }
114  }
115 }
116 
117 GB_ERROR GB_create_index(GBDATA *gbd, const char *key, GB_CASE case_sens, long estimated_size) { // goes to header: __ATTR__USERESULT
118  /* Create an index for a database.
119  * Uses hash tables - collisions are avoided by using linked lists.
120  */
121  GB_ERROR error = NULp;
122 
123  if (gbd->is_entry()) {
124  error = "GB_create_index used on non CONTAINER Type";
125  }
126  else if (GB_read_clients(gbd)<0) {
127  error = "No index tables in DB clients allowed";
128  }
129  else {
130  GBCONTAINER *gbc = gbd->as_container();
131  GBQUARK key_quark = GB_find_or_create_quark(gbd, key);
132 
133  gb_index_files *ifs;
134  GB_INDEX_FIND(gbc, ifs, key_quark);
135 
136  if (!ifs) { // if not already have index (e.g. if fast-loaded)
137  ifs = (gb_index_files *)gbm_get_mem(sizeof(gb_index_files), GB_GBM_INDEX(gbc));
139  SET_GBCONTAINER_IFS(gbc, ifs);
140 
141  ifs->key = key_quark;
142  ifs->hash_table_size = gbs_get_a_prime(estimated_size);
143  ifs->nr_of_elements = 0;
144  ifs->case_sens = case_sens;
145 
146  SET_GB_INDEX_FILES_ENTRIES(ifs, (gb_if_entries **)gbm_get_mem(sizeof(void *)*(int)ifs->hash_table_size, GB_GBM_INDEX(gbc)));
147 
148  for (GBDATA *gbf = GB_find_sub_by_quark(gbd, -1, NULp, 0);
149  gbf;
150  gbf = GB_find_sub_by_quark(gbd, -1, gbf, 0))
151  {
152  if (gbf->is_container()) {
153  for (GBDATA *gb2 = GB_find_sub_by_quark(gbf, key_quark, NULp, 0);
154  gb2;
155  gb2 = GB_find_sub_by_quark(gbf, key_quark, gb2, 0))
156  {
157  if (gb2->is_indexable()) gb2->as_entry()->index_check_in();
158  }
159  }
160  }
161  }
162  }
163  RETURN_ERROR(error);
164 }
165 
167  gb_index_files *ifs = GBCONTAINER_IFS(gbc);
168 
169  while (ifs) {
170  GB_REL_IFES *if_entries = GB_INDEX_FILES_ENTRIES(ifs);
171 
172  for (int index = 0; index<ifs->hash_table_size; index++) {
173  gb_if_entries *ifes = GB_ENTRIES_ENTRY(if_entries, index);
174 
175  while (ifes) {
176  gb_if_entries *ifes_next = GB_IF_ENTRIES_NEXT(ifes);
177 
178  gbm_free_mem(ifes, sizeof(*ifes), GB_GBM_INDEX(gbc));
179  ifes = ifes_next;
180  }
181  }
182  gbm_free_mem(if_entries, sizeof(void *)*(int)ifs->hash_table_size, GB_GBM_INDEX(gbc));
183 
184  gb_index_files *ifs_next = GB_INDEX_FILES_NEXT(ifs);
185  gbm_free_mem(ifs, sizeof(gb_index_files), GB_GBM_INDEX(gbc));
186  ifs = ifs_next;
187  }
188 }
189 
190 #if defined(DEBUG)
191 
192 NOT4PERL void GB_dump_indices(GBDATA *gbd) { // used for debugging
193  // dump indices of container
194 
195  char *db_path = ARB_strdup(GB_get_db_path(gbd));
196  if (gbd->is_entry()) {
197  fprintf(stderr, "'%s' (%s) is no container.\n", db_path, GB_get_type_name(gbd));
198  }
199  else {
200  gb_index_files *ifs;
201  int index_count = 0;
202 
203  GBCONTAINER *gbc = gbd->as_container();
204  GB_MAIN_TYPE *Main = GBCONTAINER_MAIN(gbc);
205 
206  for (ifs = GBCONTAINER_IFS(gbc); ifs; ifs = GB_INDEX_FILES_NEXT(ifs)) {
207  index_count++;
208  }
209 
210  if (index_count == 0) {
211  fprintf(stderr, "Container '%s' has no index.\n", db_path);
212  }
213  else {
214  int pass;
215 
216  fprintf(stderr, "Indices for '%s':\n", db_path);
217  for (pass = 1; pass <= 2; pass++) {
218  if (pass == 2) {
219  fprintf(stderr, "\nDetailed index contents:\n\n");
220  }
221  index_count = 0;
222  for (ifs = GBCONTAINER_IFS(gbc); ifs; ifs = GB_INDEX_FILES_NEXT(ifs)) {
223  fprintf(stderr,
224  "* Index %i for key=%s (%i), entries=%li, %s\n",
225  index_count,
226  quark2key(Main, ifs->key),
227  ifs->key,
228  ifs->nr_of_elements,
229  ifs->case_sens == GB_MIND_CASE
230  ? "Case sensitive"
231  : (ifs->case_sens == GB_IGNORE_CASE
232  ? "Case insensitive"
233  : "<Error in case_sens>")
234  );
235 
236  if (pass == 2) {
237  gb_if_entries *ifes;
238  int index;
239 
240  fprintf(stderr, "\n");
241  for (index = 0; index<ifs->hash_table_size; index++) {
242  for (ifes = GB_ENTRIES_ENTRY(GB_INDEX_FILES_ENTRIES(ifs), index);
243  ifes;
244  ifes = GB_IF_ENTRIES_NEXT(ifes))
245  {
246  GBDATA *igbd = GB_IF_ENTRIES_GBD(ifes);
247  const char *data = GB_read_char_pntr(igbd);
248 
249  fprintf(stderr, " - '%s' (@idx=%i)\n", data, index);
250  }
251  }
252  fprintf(stderr, "\n");
253  }
254  index_count++;
255  }
256  }
257  }
258  }
259 
260  free(db_path);
261 }
262 
263 #endif // DEBUG
264 
265 
266 // find an entry in an hash table
267 GBDATA *gb_index_find(GBCONTAINER *gbf, gb_index_files *ifs, GBQUARK quark, const char *val, GB_CASE case_sens, int after_index) {
268  unsigned long index;
269  GB_CSTR data;
270  gb_if_entries *ifes;
271  GBDATA *result = NULp;
272  long min_index;
273 
274  if (!ifs) {
275  GB_INDEX_FIND(gbf, ifs, quark);
276  if (!ifs) {
277  GB_internal_error("gb_index_find called, but no index table found");
278  return NULp;
279  }
280  }
281 
282  if (ifs->case_sens != case_sens) {
283  GB_internal_error("case mismatch between index and search");
284  return NULp;
285  }
286 
287  GB_CALC_HASH_INDEX(val, index, ifs->hash_table_size, ifs->case_sens);
288  min_index = gbf->d.nheader;
289 
290  for (ifes = GB_ENTRIES_ENTRY(GB_INDEX_FILES_ENTRIES(ifs), index);
291  ifes;
292  ifes = GB_IF_ENTRIES_NEXT(ifes))
293  {
294  GBDATA *igbd = GB_IF_ENTRIES_GBD(ifes);
295  GBCONTAINER *ifather = GB_FATHER(igbd);
296 
297  if (ifather->index < after_index) continue;
298  if (ifather->index >= min_index) continue;
299  data = GB_read_char_pntr(igbd);
300  if (GBS_string_matches(data, val, case_sens)) { // entry found
301  result = igbd;
302  min_index = ifather->index;
303  }
304  }
305  return result;
306 }
307 
308 
309 /* UNDO functions
310  *
311  * There are three undo stacks:
312  *
313  * GB_UNDO_NONE no undo
314  * GB_UNDO_UNDO normal undo stack
315  * GB_UNDO_REDO redo stack
316  */
317 
319  GB_MAIN_TYPE *Main = GB_MAIN(gb_main);
320  Main->undo_type = type;
321  return NULp;
322 }
323 
324 static void g_b_add_size_to_undo_entry(g_b_undo_entry *ue, long size) {
325  ue->sizeof_this += size; // undo entry
326  ue->father->sizeof_this += size; // one undo
327  ue->father->father->sizeof_this += size; // all undos
328 }
329 
332 
333  ue->next = u->entries;
334  ue->father = u;
335  u->entries = ue;
336 
338 
339  return ue;
340 }
341 
342 
343 
344 void gb_init_undo_stack(GB_MAIN_TYPE *Main) { // @@@ move into GB_MAIN_TYPE-ctor
345  ARB_calloc(Main->undo, 1);
346 
348 
349  ARB_calloc(Main->undo->u, 1);
350  ARB_calloc(Main->undo->r, 1);
351 }
352 
354  switch (entry->type) {
357  if (entry->d.ts) {
359  }
360  }
361  default:
362  break;
363  }
364  gbm_free_mem(entry, sizeof(g_b_undo_entry), GBM_UNDO);
365 }
366 
368  g_b_undo_entry *a, *next;
369  for (a = u->entries; a; a = next) {
370  next = a->next;
372  }
373  free(u);
374 }
375 
377  g_b_undo_list *next = NULp;
378  for (g_b_undo_list *a = uh->stack; a; a = next) {
379  next = a->next;
381  }
382  free(uh);
383 }
384 
385 static char *g_b_check_undo_size2(g_b_undo_header *uhs, long size, long max_cnt) {
386  long csize = 0;
387  long ccnt = 0;
388  g_b_undo_list *us;
389 
390  for (us = uhs->stack; us && us->next; us = us->next) {
391  csize += us->sizeof_this;
392  ccnt ++;
393  if (((csize + us->next->sizeof_this) > size) ||
394  (ccnt >= max_cnt)) { // delete the rest
395  g_b_undo_list *next = NULp;
396 
397  for (g_b_undo_list *a = us->next; a; a = next) {
398  next = a->next;
400  }
401  us->next = NULp;
402  uhs->sizeof_this = csize;
403  break;
404  }
405  }
406  return NULp;
407 }
408 
409 static char *g_b_check_undo_size(GB_MAIN_TYPE *Main) {
410  long maxsize = Main->undo->max_size_of_all_undos;
411  char *error = g_b_check_undo_size2(Main->undo->u, maxsize/2, GB_MAX_UNDO_CNT);
412  if (!error) error = g_b_check_undo_size2(Main->undo->r, maxsize/2, GB_MAX_REDO_CNT);
413  return error;
414 }
415 
416 
418  delete_g_b_undo_header(Main->undo->u);
419  delete_g_b_undo_header(Main->undo->r);
420  free(Main->undo);
421 }
422 
423 // -------------------------
424 // real undo (redo)
425 
427  GB_ERROR error = NULp;
428  switch (ue->type) {
430  error = GB_delete(ue->source);
431  break;
432 
434  GBDATA *gbd = ue->d.gs.gbd;
435  if (gbd->is_container()) {
436  gbd = gb_make_pre_defined_container(ue->source->as_container(), gbd->as_container(), -1, ue->d.gs.key);
437  }
438  else {
439  gbd = gb_make_pre_defined_entry(ue->source->as_container(), gbd, -1, ue->d.gs.key);
440  }
441  GB_ARRAY_FLAGS(gbd).flags = ue->flag;
444  break;
445  }
448  GBDATA *gbd = ue->source;
449  if (gbd->is_entry()) {
450  GBENTRY *gbe = gbd->as_entry();
451  gb_save_extern_data_in_ts(gbe); // check out and free string
452 
453  if (ue->d.ts) { // nothing to undo (e.g. if undoing GB_touch)
454  gbe->flags = ue->d.ts->flags;
455  gbe->flags2.extern_data = ue->d.ts->flags2.extern_data;
456 
457  memcpy(&gbe->info, &ue->d.ts->info, sizeof(gbe->info)); // restore old information
458  if (gbe->type() >= GB_BITS) {
459  if (gbe->stored_external()) {
460  gbe->info.ex.set_data(ue->d.ts->info.ex.data);
461  }
462 
464  ue->d.ts = NULp;
465 
466  gbe->index_re_check_in();
467  }
468  }
469  }
470  {
471  gb_header_flags *pflags = &GB_ARRAY_FLAGS(gbd);
472  if (pflags->flags != (unsigned)ue->flag) {
473  GBCONTAINER *gb_father = GB_FATHER(gbd);
474  gbd->flags.saved_flags = pflags->flags;
475  pflags->flags = ue->flag;
476  if (GB_FATHER(gb_father)) {
477  gb_touch_header(gb_father); // don't touch father of main
478  }
479  }
480  }
482  break;
483  }
484  default:
485  GB_internal_error("Undo stack corrupt:!!!");
486  error = GB_export_error("shit 34345");
487  break;
488  }
489 
490  return error;
491 }
492 
493 
494 
495 static GB_ERROR g_b_undo(GBDATA *gb_main, g_b_undo_header *uh) { // goes to header: __ATTR__USERESULT
496  GB_ERROR error = NULp;
497 
498  if (!uh->stack) {
499  error = "Sorry no more undos/redos available";
500  }
501  else {
502  g_b_undo_list *u = uh->stack;
503  g_b_undo_entry *ue, *next;
504 
505  error = GB_begin_transaction(gb_main);
506 
507  for (ue=u->entries; ue && !error; ue = next) {
508  next = ue->next;
509  error = undo_entry(ue);
511  u->entries = next;
512  }
513  uh->sizeof_this -= u->sizeof_this; // remove undo from list
514  uh->stack = u->next;
515 
517  error = GB_end_transaction(gb_main, error);
518  }
519  return error;
520 }
521 
523  return quark2key(Main, ue->d.gs.key);
524 }
525 
526 static char *g_b_undo_info(GB_MAIN_TYPE *Main, g_b_undo_header *uh) {
527  char *info = NULp;
528  g_b_undo_list *u = uh->stack;
529  if (!u) {
530  info = ARB_strdup("No more undos available");
531  }
532  else {
533  GBS_strstruct res(1024);
534  for (g_b_undo_entry *ue = u->entries; ue; ue = ue->next) {
535  switch (ue->type) {
537  res.cat("Delete new entry: ");
538  res.cat(gb_read_key_pntr(ue->source));
539  break;
540 
542  res.cat("Rebuild deleted entry: ");
543  res.cat(g_b_read_undo_key_pntr(Main, ue));
544  break;
545 
548  res.cat("Undo modified entry: ");
549  res.cat(gb_read_key_pntr(ue->source));
550  break;
551  }
552  res.put('\n');
553  }
554  info = res.release();
555  }
556  return info;
557 }
558 
560  // Remove all existing undos/redos
561  GB_MAIN_TYPE *Main = GB_MAIN(gb_main);
562  g_b_undo_list *a, *next;
563 
564  for (a = Main->undo->r->stack; a; a = next) {
565  next = a->next;
567  }
568  Main->undo->r->stack = NULp;
569  Main->undo->r->sizeof_this = 0;
570 
571  for (a = Main->undo->u->stack; a; a = next) {
572  next = a->next;
574  }
575  Main->undo->u->stack = NULp;
576  Main->undo->u->sizeof_this = 0;
577 
578  return NULp;
579 }
580 
581 
583  // start a new undoable transaction
584  GB_MAIN_TYPE *Main = GB_MAIN(gb_main);
585  char *error = g_b_check_undo_size(Main);
586  g_b_undo_header *uhs;
587 
588  if (error) return error;
589  switch (Main->requested_undo_type) { // init the target undo stack
590  case GB_UNDO_UNDO: // that will undo but delete all redos
591  uhs = Main->undo->u;
592  break;
593  case GB_UNDO_UNDO_REDO: uhs = Main->undo->u; break;
594  case GB_UNDO_REDO: uhs = Main->undo->r; break;
595  case GB_UNDO_KILL: gb_free_all_undos(gb_main);
596  FALLTHROUGH;
597  default: uhs = NULp;
598  }
599  if (uhs) {
600  g_b_undo_list *u = ARB_calloc<g_b_undo_list>(1);
601  u->next = uhs->stack;
602  u->father = uhs;
603  uhs->stack = u;
604  Main->undo->valid_u = u;
605  }
606 
607  return gb_set_undo_type(gb_main, Main->requested_undo_type);
608 }
609 
611  // called to finish an undoable section, called at end of gb_commit_transaction
612  GB_MAIN_TYPE *Main = GB_MAIN(gb_main);
613  g_b_undo_list *u = Main->undo->valid_u;
614 
615  if (!u) return NULp;
616  if (!u->entries) { // nothing to undo, just a read transaction
617  u->father->stack = u->next;
619  }
620  else {
621  if (Main->requested_undo_type == GB_UNDO_UNDO) { // remove all redos
622  g_b_undo_list *a, *next;
623 
624  for (a = Main->undo->r->stack; a; a = next) {
625  next = a->next;
627  }
628  Main->undo->r->stack = NULp;
629  Main->undo->r->sizeof_this = 0;
630  }
631  }
632  Main->undo->valid_u = NULp;
633  return gb_set_undo_type(gb_main, GB_UNDO_NONE);
634 }
635 
637  if (Main->undo->valid_u) {
639 
641  ue->source = gbd;
642  ue->gbm_index = GB_GBM_INDEX(gbd);
643  ue->flag = 0;
644  }
645 }
646 
648  if (!Main->undo->valid_u) {
650  }
651  else {
652  gb_transaction_save *old = gbd->get_oldData();
654 
655  ue->source = gbd;
656  ue->gbm_index = GB_GBM_INDEX(gbd);
658  ue->flag = gbd->flags.saved_flags;
659 
660  if (gbd->is_entry()) {
661  ue->d.ts = old;
662  if (old) {
664  if (gbd->type() >= GB_BITS && old->stored_external() && old->info.ex.data) {
666  // move external array from ts to undo entry struct
668  }
669  }
670  }
671  }
672 }
673 
675  if (!Main->undo->valid_u) {
676  gb_delete_entry(gbd);
677  return;
678  }
679 
680  if (gbd->is_container()) {
681  GBCONTAINER *gbc = gbd->as_container();
682  for (int index = 0; (index < gbc->d.nheader); index++) {
683  GBDATA *gbd2 = GBCONTAINER_ELEM(gbc, index);
684  if (gbd2) gb_check_in_undo_delete(Main, gbd2);
685  }
686  }
687  else {
688  gbd->as_entry()->index_check_out();
689  gbd->flags2.should_be_indexed = 0; // do not re-checkin
690  }
691  gb_abort_entry(gbd); // get old version
692 
694 
696  ue->source = GB_FATHER(gbd);
697  ue->gbm_index = GB_GBM_INDEX(gbd);
698  ue->flag = GB_ARRAY_FLAGS(gbd).flags;
699 
700  ue->d.gs.gbd = gbd;
701  ue->d.gs.key = GB_KEY_QUARK(gbd);
702 
703  gb_pre_delete_entry(gbd); // get the core of the entry
704 
705  if (gbd->is_container()) {
707  }
708  else {
709  if (gbd->type() >= GB_BITS && gbd->as_entry()->stored_external()) {
710  /* we have copied the data structures, now
711  mark the old as deleted !!! */
713  }
714  g_b_add_size_to_undo_entry(ue, sizeof(GBENTRY));
715  }
716 }
717 
718 // ----------------------------------------
719 // UNDO functions exported to USER
720 
721 GB_ERROR GB_request_undo_type(GBDATA *gb_main, GB_UNDO_TYPE type) { // goes to header: __ATTR__USERESULT_TODO
735  GB_MAIN_TYPE *Main = GB_MAIN(gb_main);
736  GB_ERROR error = NULp;
737 
738  if (Main->is_client()) {
739  enum gb_undo_commands cmd = (type == GB_UNDO_NONE || type == GB_UNDO_KILL)
742  error = gbcmc_send_undo_commands(gb_main, cmd);
743  }
744  if (!error) Main->requested_undo_type = type;
745 
746  return error;
747 }
748 
750  GB_MAIN_TYPE *Main = GB_MAIN(gb_main);
751  return Main->requested_undo_type;
752 }
753 
754 
755 GB_ERROR GB_undo(GBDATA *gb_main, GB_UNDO_TYPE type) { // goes to header: __ATTR__USERESULT
756  // undo/redo the last transaction
757 
758  GB_MAIN_TYPE *Main = GB_MAIN(gb_main);
759  GB_ERROR error = NULp;
760 
761  if (Main->is_client()) {
762  switch (type) {
763  case GB_UNDO_UNDO:
765  break;
766 
767  case GB_UNDO_REDO:
769  break;
770 
771  default:
772  GB_internal_error("unknown undo type in GB_undo");
773  error = "Internal UNDO error";
774  break;
775  }
776  }
777  else {
778  GB_UNDO_TYPE old_type = GB_get_requested_undo_type(gb_main);
779  switch (type) {
780  case GB_UNDO_UNDO:
781  error = GB_request_undo_type(gb_main, GB_UNDO_REDO);
782  if (!error) {
783  error = g_b_undo(gb_main, Main->undo->u);
784  ASSERT_NO_ERROR(GB_request_undo_type(gb_main, old_type));
785  }
786  break;
787 
788  case GB_UNDO_REDO:
789  error = GB_request_undo_type(gb_main, GB_UNDO_UNDO_REDO);
790  if (!error) {
791  error = g_b_undo(gb_main, Main->undo->r);
792  ASSERT_NO_ERROR(GB_request_undo_type(gb_main, old_type));
793  }
794  break;
795 
796  default:
797  error = "GB_undo: unknown undo type specified";
798  break;
799  }
800  }
801 
802  return error;
803 }
804 
805 
807  // get some information about the next undo
808  // returns NULp in case of exported error
809 
810  GB_MAIN_TYPE *Main = GB_MAIN(gb_main);
811  if (Main->is_client()) {
812  switch (type) {
813  case GB_UNDO_UNDO:
815  case GB_UNDO_REDO:
817  default:
818  GB_export_error("GB_undo_info: unknown undo type specified");
819  return NULp;
820  }
821  }
822  switch (type) {
823  case GB_UNDO_UNDO:
824  return g_b_undo_info(Main, Main->undo->u);
825  case GB_UNDO_REDO:
826  return g_b_undo_info(Main, Main->undo->r);
827  default:
828  GB_export_error("GB_undo_info: unknown undo type specified");
829  return NULp;
830  }
831 }
832 
833 GB_ERROR GB_set_undo_mem(GBDATA *gbd, long memsize) {
834  // set the maximum memory used for undoing
835 
836  GB_MAIN_TYPE *Main = GB_MAIN(gbd);
837  if (memsize < _GBCMC_UNDOCOM_SET_MEM) {
838  return GB_export_errorf("Not enough UNDO memory specified: should be more than %i",
840  }
841  Main->undo->max_size_of_all_undos = memsize;
842  if (Main->is_client()) {
843  return gbcmc_send_undo_commands(gbd, (enum gb_undo_commands)memsize);
844  }
845  g_b_check_undo_size(Main);
846  return NULp;
847 }
848 
849 
850 #ifdef UNIT_TESTS
851 #include <test_unit.h>
852 #include <map>
853 #include <ad_cb_prot.h>
854 
855 class cb_counter : virtual Noncopyable {
856  GBDATA *gbd;
857  int deletes, changes, creates;
858  bool do_trace;
859 public:
860  static void count_swapped(GBDATA* gbd, cb_counter* counter, GB_CB_TYPE t ) {
861  // CB system cannot swap parameters, we need to wrap
862  // And yes... fixed parameters are added *in the middle*, not at the end.
863  counter->count(gbd, t);
864  }
865 
866  cb_counter(GBDATA* gbd_) : gbd(gbd_), deletes(0), changes(0), creates(0), do_trace(false) {
867  GB_add_callback(gbd, GB_CB_ALL, makeDatabaseCallback(cb_counter::count_swapped, this));
868  }
869 
870  ~cb_counter() {
871  // CB system cannot auto-destroy callbacks, nor are there CB handles
872  if (deletes == 0) { // (GB_delete destroys CBs I think)
873  GB_remove_callback(gbd, GB_CB_ALL, makeDatabaseCallback(cb_counter::count_swapped, this));
874  // above must be exact copy of GB_add_callback copy
875  }
876  }
877 
878  void count(GBDATA*, GB_CB_TYPE t) {
879  if (t & GB_CB_DELETE) deletes ++;
880  if (t & GB_CB_SON_CREATED) creates ++;
881  if (t & GB_CB_CHANGED) changes ++;
882  if (do_trace) printf("counts: %p d=%i c=%i n=%i\n", gbd, deletes, changes, creates);
883  }
884 
885  void trace(bool t) {
886  do_trace = t;
887  }
888 
889  int get_deletes() {
890  int res = deletes;
891  deletes = 0;
892  return res;
893  }
894 
895  int get_creates() {
896  int res = creates;
897  creates = 0;
898  return res;
899  }
900 
901  int get_changes() {
902  int res = changes;
903  changes = 0;
904  return res;
905  }
906 };
907 
908 
909 
910 void TEST_GB_undo__basic() {
911  GB_shell shell;
912  // GB_ERROR err;
913 
914  GBDATA *main = GB_open("nosuch.arb", "c");
915  GB_begin_transaction(main);
916  cb_counter main_counter(main);
917  GB_commit_transaction(main);
918 
919  GBDATA *gbd;
920  cb_counter *gbd_counter;
921 
922  GB_set_undo_mem(main, 10000);
924 
925  // Notes:
926  // - CB_CHANGED == CB_SON_CREATED
927  // Both are called on creating sons as well as just writing strings.
928  // - GB_SON_CREATED also called if "SON_DELETED"
929  // - It's possible to get CB_SON_CREATED on GBENTRY if the CB is
930  // registered within the running transaction.
931  // - CBs are triggered at the end of the transaction.
932 
933 
934  // test undo create empty string entry
935  GB_begin_transaction(main);
936  gbd = GB_create(main, "test", GB_STRING);
937  gbd_counter = new cb_counter(gbd);
938  GB_commit_transaction(main);
939 
940  TEST_EXPECT_EQUAL( main_counter.get_creates(), 1);
941  TEST_EXPECT_EQUAL( main_counter.get_changes(), 1);
942  TEST_EXPECT_EQUAL( main_counter.get_deletes(), 0);
943  TEST_EXPECT_EQUAL( gbd_counter->get_creates(), 1);
944  TEST_EXPECT_EQUAL( gbd_counter->get_changes(), 1);
945  TEST_EXPECT_EQUAL( gbd_counter->get_deletes(), 0);
946  // string initialises as empty
947  TEST_EXPECT_EQUAL( GB_read_pntr(GB_find(main, "test", SEARCH_CHILD)), "");
949  TEST_EXPECT_EQUAL( main_counter.get_creates(), 1); // BROKEN -- should be 0
950  TEST_EXPECT_EQUAL( main_counter.get_changes(), 1);
951  TEST_EXPECT_EQUAL( main_counter.get_deletes(), 0); // BROKEN -- should be 1
952  TEST_EXPECT_EQUAL( gbd_counter->get_creates(), 0);
953  TEST_EXPECT_EQUAL( gbd_counter->get_changes(), 0);
954  TEST_EXPECT_EQUAL( gbd_counter->get_deletes(), 1);
955  TEST_EXPECT_NULL( GB_find(main, "test", SEARCH_CHILD) );
957  TEST_EXPECT_EQUAL( main_counter.get_creates(), 1);
958  TEST_EXPECT_EQUAL( main_counter.get_changes(), 1);
959  TEST_EXPECT_EQUAL( main_counter.get_deletes(), 0);
960  TEST_REJECT_NULL( gbd = GB_find(main, "test", SEARCH_CHILD) );
961  TEST_EXPECT_EQUAL( GB_read_pntr(GB_find(main, "test", SEARCH_CHILD)), "");
962 
963  // re-establish counter
964  GB_begin_transaction(main);
965  delete gbd_counter;
966  gbd_counter = new cb_counter(gbd);
967  GB_commit_transaction(main);
968 
969  // test undo delete empty string
970  GB_begin_transaction(main);
971  GB_delete(gbd);
972  GB_commit_transaction(main);
973  TEST_EXPECT_EQUAL( main_counter.get_creates(), 1); // BROKEN -- should be 0
974  TEST_EXPECT_EQUAL( main_counter.get_changes(), 1);
975  TEST_EXPECT_EQUAL( main_counter.get_deletes(), 0);
976  TEST_EXPECT_EQUAL( gbd_counter->get_creates(), 0);
977  TEST_EXPECT_EQUAL( gbd_counter->get_changes(), 0);
978  TEST_EXPECT_EQUAL( gbd_counter->get_deletes(), 1);
979  TEST_EXPECT_NULL( GB_find(main, "test", SEARCH_CHILD) );
981  TEST_EXPECT_EQUAL( main_counter.get_creates(), 1);
982  TEST_EXPECT_EQUAL( main_counter.get_changes(), 1);
983  TEST_EXPECT_EQUAL( main_counter.get_deletes(), 0);
984  TEST_EXPECT_EQUAL( GB_read_pntr(GB_find(main, "test", SEARCH_CHILD)), "" );
986  TEST_EXPECT_EQUAL( main_counter.get_creates(), 1); // BROKEN -- should be 0
987  TEST_EXPECT_EQUAL( main_counter.get_changes(), 1);
988  TEST_EXPECT_EQUAL( main_counter.get_deletes(), 0);
989  TEST_EXPECT_NULL( GB_find(main, "test", SEARCH_CHILD) );
991  TEST_REJECT_NULL( gbd = GB_find(main, "test", SEARCH_CHILD) );
992  TEST_EXPECT_EQUAL( gbd_counter->get_creates(), 0);
993  TEST_EXPECT_EQUAL( gbd_counter->get_changes(), 0);
994  TEST_EXPECT_EQUAL( gbd_counter->get_deletes(), 0);
995 
996  // re-establish counter
997  GB_begin_transaction(main);
998  delete gbd_counter;
999  gbd_counter = new cb_counter(gbd);
1000  GB_commit_transaction(main);
1001 
1002  // test undo write short string
1003  const char* str = "testtest9012345";
1004  GB_begin_transaction(main);
1005  GB_write_string(gbd, str);
1006  GB_commit_transaction(main);
1007  TEST_EXPECT_EQUAL( gbd_counter->get_creates(), 1); // BROKEN?
1008  TEST_EXPECT_EQUAL( gbd_counter->get_changes(), 1);
1009  TEST_EXPECT_EQUAL( gbd_counter->get_deletes(), 0);
1010  TEST_EXPECT_EQUAL( GB_read_pntr(GB_find(main, "test", SEARCH_CHILD)), str);
1012  TEST_EXPECT_EQUAL( gbd_counter->get_creates(), 1); // BROKEN?
1013  TEST_EXPECT_EQUAL( gbd_counter->get_changes(), 1);
1014  TEST_EXPECT_EQUAL( gbd_counter->get_deletes(), 0);
1015  TEST_EXPECT_EQUAL( GB_read_pntr(GB_find(main, "test", SEARCH_CHILD)), "");
1017  TEST_EXPECT_EQUAL( gbd_counter->get_creates(), 1); // BROKEN?
1018  TEST_EXPECT_EQUAL( gbd_counter->get_changes(), 1);
1019  TEST_EXPECT_EQUAL( gbd_counter->get_deletes(), 0);
1020  TEST_EXPECT_EQUAL( GB_read_pntr(GB_find(main, "test", SEARCH_CHILD)), str);
1021 
1022  delete gbd_counter;
1023 
1024  // test undo delete short string
1025  GB_begin_transaction(main);
1026  GB_delete(gbd);
1027  GB_commit_transaction(main);
1028  TEST_EXPECT_NULL( GB_find(main, "test", SEARCH_CHILD) );
1030 
1032  TEST_EXPECT_EQUAL__BROKEN( GB_read_pntr(GB_find(main, "test", SEARCH_CHILD)), str, (char*)NULp);
1033  GB_close(main);
1034  return; // remainder will fail now
1035 
1036 
1038  TEST_EXPECT_NULL( GB_find(main, "test", SEARCH_CHILD) );
1040  TEST_REJECT_NULL( gbd = GB_find(main, "test", SEARCH_CHILD) );
1041 
1042  // test undo write "" and delete short string
1043  GB_begin_transaction(main);
1044  GB_write_string(gbd, str);
1045  GB_delete(gbd);
1046  GB_commit_transaction(main);
1047  TEST_EXPECT_NULL( GB_find(main, "test", SEARCH_CHILD) );
1049  TEST_EXPECT_EQUAL( GB_read_pntr(GB_find(main, "test", SEARCH_CHILD)), str);
1051  TEST_EXPECT_NULL( GB_find(main, "test", SEARCH_CHILD) );
1053  TEST_REJECT_NULL( gbd = GB_find(main, "test", SEARCH_CHILD) );
1054 
1055  //err = GB_write_string(gbd, "testtest9012345");
1056 
1057  GB_close(main);
1058 }
1059 TEST_PUBLISH(TEST_GB_undo__basic);
1060 
1061 
1062 #endif // UNIT_TESTS
GB_ERROR GB_begin_transaction(GBDATA *gbd)
Definition: arbdb.cxx:2528
void gb_init_undo_stack(GB_MAIN_TYPE *Main)
Definition: adindex.cxx:344
const char * GB_ERROR
Definition: arb_core.h:25
static char * g_b_undo_info(GB_MAIN_TYPE *Main, g_b_undo_header *uh)
Definition: adindex.cxx:526
string result
GBDATA * GB_open(const char *path, const char *opent)
Definition: ad_load.cxx:1363
GB_TYPES type
g_b_undo_gbd gs
Definition: gb_undo.h:44
gb_flag_types2 flags2
Definition: gb_ts.h:43
GB_ERROR GB_commit_transaction(GBDATA *gbd)
Definition: arbdb.cxx:2551
#define GB_GBM_INDEX(gbd)
Definition: gb_data.h:127
g_b_undo_mgr * undo
Definition: gb_main.h:147
unsigned int saved_flags
Definition: gb_data.h:74
long max_size_of_all_undos
Definition: gb_undo.h:63
g_b_undo_list * stack
Definition: gb_undo.h:49
gb_undo_commands
Definition: gb_local.h:61
void gb_check_in_undo_create(GB_MAIN_TYPE *Main, GBDATA *gbd)
Definition: adindex.cxx:636
GB_ERROR gbcmc_send_undo_commands(GBDATA *gbd, enum gb_undo_commands command)
Definition: adcomm.cxx:1824
Definition: arbdb.h:69
GB_ERROR GB_create_index(GBDATA *gbd, const char *key, GB_CASE case_sens, long estimated_size)
Definition: adindex.cxx:117
GB_ERROR GB_write_string(GBDATA *gbd, const char *s)
Definition: arbdb.cxx:1387
void gb_touch_header(GBCONTAINER *gbc)
Definition: ad_core.cxx:108
const char * quark2key(GB_MAIN_TYPE *Main, GBQUARK key_quark)
Definition: gb_key.h:45
GB_ERROR GB_add_callback(GBDATA *gbd, GB_CB_TYPE type, const DatabaseCallback &dbcb)
Definition: ad_cb.cxx:356
gb_flag_types2 flags2
Definition: gb_data.h:135
#define ASSERT_NO_ERROR(errorExpr)
Definition: arb_assert.h:360
GB_ERROR GB_undo(GBDATA *gb_main, GB_UNDO_TYPE type)
Definition: adindex.cxx:755
gb_data_base_type_union info
Definition: gb_data.h:204
void SET_GB_IF_ENTRIES_GBD(gb_if_entries *ie, GBDATA *gbd)
Definition: gb_index.h:39
GBDATA * GB_find(GBDATA *gbd, const char *key, GB_SEARCH_TYPE gbs)
Definition: adquery.cxx:295
GB_MAIN_TYPE * GB_MAIN(GBDATA *gbd)
Definition: gb_data.h:291
g_b_undo_header * r
Definition: gb_undo.h:66
GB_ERROR GB_set_undo_mem(GBDATA *gbd, long memsize)
Definition: adindex.cxx:833
gb_extern_data2 ex
Definition: gb_ts.h:38
void gb_del_ref_and_extern_gb_transaction_save(gb_transaction_save *ts)
Definition: ad_core.cxx:606
GB_ERROR GB_end_transaction(GBDATA *gbd, GB_ERROR error)
Definition: arbdb.cxx:2561
int main(int argc, char **argv)
Definition: aisc.c:359
size_t memsize() const
Definition: gb_data.h:215
GBDATA * gb_index_find(GBCONTAINER *gbf, gb_index_files *ifs, GBQUARK quark, const char *val, GB_CASE case_sens, int after_index)
Definition: adindex.cxx:267
short type
Definition: gb_undo.h:36
static char * g_b_check_undo_size(GB_MAIN_TYPE *Main)
Definition: adindex.cxx:409
const char * GB_get_type_name(GBDATA *gbd)
Definition: arbdb.cxx:72
char * ARB_strdup(const char *str)
Definition: arb_string.h:27
static void delete_g_b_undo_list(g_b_undo_list *u)
Definition: adindex.cxx:367
CONSTEXPR_INLINE GBCONTAINER * GB_GRANDPA(GBDATA *gbd)
Definition: gb_data.h:272
GBDATA * gb_make_pre_defined_entry(GBCONTAINER *father, GBDATA *gbd, long index_pos, GBQUARK keyq)
Definition: ad_core.cxx:327
const char * GBS_global_string(const char *templat,...)
Definition: arb_msg.cxx:203
char * release()
Definition: arb_strbuf.h:129
void gb_add_ref_gb_transaction_save(gb_transaction_save *ts)
Definition: ad_core.cxx:586
GB_UNDO_TYPE GB_get_requested_undo_type(GBDATA *gb_main)
Definition: adindex.cxx:749
gb_header_flags & GB_ARRAY_FLAGS(GBDATA *gbd)
Definition: gb_header.h:49
g_b_undo_entry * next
Definition: gb_undo.h:35
void cat(const char *from)
Definition: arb_strbuf.h:199
void index_check_in()
Definition: adindex.cxx:29
g_b_undo_list * next
Definition: gb_undo.h:57
gb_index_files * GB_INDEX_FILES_NEXT(gb_index_files *ixf)
Definition: gb_index.h:87
g_b_undo_list * father
Definition: gb_undo.h:34
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
static g_b_undo_entry * new_g_b_undo_entry(g_b_undo_list *u)
Definition: adindex.cxx:330
GBDATA * GB_IF_ENTRIES_GBD(gb_if_entries *ie)
Definition: gb_index.h:36
static char * gb_set_undo_type(GBDATA *gb_main, GB_UNDO_TYPE type)
Definition: adindex.cxx:318
const int GB_MAX_REDO_CNT
Definition: adtune.cxx:32
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 GB_push_transaction(GBDATA *gbd)
Definition: arbdb.cxx:2494
#define GB_INDEX_FIND(gbf, ifs, quark)
Definition: adindex.cxx:21
#define NOT4PERL
Definition: arbdb_base.h:23
GB_ERROR GB_delete(GBDATA *&source)
Definition: arbdb.cxx:1916
NOT4PERL void GB_dump_indices(GBDATA *gbd)
GB_UNDO_TYPE
Definition: arbdb.h:107
GB_UNDO_TYPE undo_type
Definition: gb_main.h:145
#define TEST_PUBLISH(testfunction)
Definition: test_unit.h:1517
const int GB_MAX_UNDO_CNT
Definition: adtune.cxx:33
GB_ERROR GB_export_error(const char *error)
Definition: arb_msg.cxx:257
GB_ERROR GB_await_error()
Definition: arb_msg.cxx:342
gb_flag_types flags
Definition: gb_data.h:134
char * gb_set_undo_sync(GBDATA *gb_main)
Definition: adindex.cxx:582
GBDATA * GB_create(GBDATA *father, const char *key, GB_TYPES type)
Definition: arbdb.cxx:1781
bool is_indexable() const
Definition: gb_data.h:145
void SET_GB_INDEX_FILES_ENTRIES(gb_index_files *ixf, gb_if_entries **entries)
Definition: gb_index.h:83
GB_CSTR GB_read_pntr(GBDATA *gbd)
Definition: arbdb.cxx:877
void gb_pre_delete_entry(GBDATA *gbd)
Definition: ad_core.cxx:445
#define TEST_EXPECT_EQUAL__BROKEN(expr, want, got)
Definition: test_unit.h:1295
gb_data_base_type_union2 info
Definition: gb_ts.h:44
#define false
Definition: ureadseq.h:13
#define RETURN_ERROR(err)
Definition: arb_msg.h:27
static char * gb_free_all_undos(GBDATA *gb_main)
Definition: adindex.cxx:559
char * gb_disable_undo(GBDATA *gb_main)
Definition: adindex.cxx:610
bool is_container() const
Definition: gb_data.h:147
#define TEST_REJECT_NULL(n)
Definition: test_unit.h:1325
GBCONTAINER * gb_make_pre_defined_container(GBCONTAINER *father, GBCONTAINER *gbc, long index_pos, GBQUARK keyq)
Definition: ad_core.cxx:395
static void error(const char *msg)
Definition: mkptypes.cxx:96
bool is_client() const
Definition: gb_main.h:204
GB_UNDO_TYPE requested_undo_type
Definition: gb_main.h:144
void index_check_out()
Definition: adindex.cxx:65
GBQUARK GB_find_or_create_quark(GBDATA *gbd, const char *key)
Definition: arbdb.cxx:1695
union g_b_undo_entry::@5 d
unsigned int extern_data
Definition: gb_data.h:84
GBQUARK key
Definition: gb_index.h:49
void index_re_check_in()
Definition: gb_data.h:235
void SET_GB_INDEX_FILES_NEXT(gb_index_files *ixf, gb_index_files *next)
Definition: gb_index.h:90
static void delete_g_b_undo_entry(g_b_undo_entry *entry)
Definition: adindex.cxx:353
long GB_read_clients(GBDATA *gbd)
Definition: adcomm.cxx:1682
GBCONTAINER * as_container() const
Definition: gb_data.h:155
unsigned int should_be_indexed
Definition: gb_data.h:87
gb_transaction_save * get_oldData() const
Definition: gb_data.h:196
GBDATA * GB_find_sub_by_quark(GBDATA *father, GBQUARK key_quark, GBDATA *after, size_t skip_over)
Definition: adquery.cxx:174
void * gbm_get_mem(size_t size, long index)
Definition: gb_memory.h:130
CONSTEXPR_INLINE GBCONTAINER * GB_FATHER(GBDATA *gbd)
Definition: gb_data.h:271
void gb_destroy_indices(GBCONTAINER *gbc)
Definition: adindex.cxx:166
long sizeof_this
Definition: gb_undo.h:41
void SET_GB_IF_ENTRIES_NEXT(gb_if_entries *ie, gb_if_entries *next)
Definition: gb_index.h:32
long memsize
Definition: gb_ts.h:31
const int GB_MAX_UNDO_SIZE
Definition: adtune.cxx:34
unsigned int is_indexed
Definition: gb_data.h:88
static void delete_g_b_undo_header(g_b_undo_header *uh)
Definition: adindex.cxx:376
gb_index_files * GBCONTAINER_IFS(GBCONTAINER *gbc)
Definition: gb_index.h:94
GB_CASE
Definition: arb_core.h:30
bool stored_external() const
Definition: gb_ts.h:47
gb_extern_data ex
Definition: gb_data.h:51
gb_if_entries * GB_IF_ENTRIES_NEXT(gb_if_entries *ie)
Definition: gb_index.h:29
char * gbcmc_send_undo_info_commands(GBDATA *gbd, enum gb_undo_commands command)
Definition: adcomm.cxx:1847
long sizeof_this
Definition: gb_undo.h:59
static GB_ERROR undo_entry(g_b_undo_entry *ue)
Definition: adindex.cxx:426
static char * g_b_check_undo_size2(g_b_undo_header *uhs, long size, long max_cnt)
Definition: adindex.cxx:385
GB_ERROR GB_export_errorf(const char *templat,...)
Definition: arb_msg.cxx:262
void GB_internal_error(const char *message)
Definition: arb_msg.cxx:481
GBQUARK GB_KEY_QUARK(GBDATA *gbd)
Definition: gb_key.h:48
GB_CASE case_sens
Definition: gb_index.h:52
TYPE * ARB_calloc(size_t nelem)
Definition: arb_mem.h:81
#define TEST_EXPECT_NULL(n)
Definition: test_unit.h:1322
#define SET_GB_ENTRIES_ENTRY(entries, idx, ie)
Definition: gb_index.h:67
bool stored_external() const
Definition: gb_data.h:211
g_b_undo_list * valid_u
Definition: gb_undo.h:64
char * gb_abort_entry(GBDATA *gbd)
Definition: ad_core.cxx:768
long GB_REL_IFES
Definition: gb_memory.h:59
int gbm_index
Definition: gb_undo.h:40
void gb_save_extern_data_in_ts(GBENTRY *gbe)
Definition: ad_core.cxx:639
void SET_GBCONTAINER_IFS(GBCONTAINER *gbc, gb_index_files *ifs)
Definition: gb_index.h:97
bool is_entry() const
Definition: gb_data.h:148
long index
Definition: gb_data.h:133
GB_CSTR gb_read_key_pntr(GBDATA *gbd)
Definition: arbdb.cxx:1664
GB_ERROR GB_request_undo_type(GBDATA *gb_main, GB_UNDO_TYPE type)
Definition: adindex.cxx:721
void GB_remove_callback(GBDATA *gbd, GB_CB_TYPE type, const DatabaseCallback &dbcb)
Definition: ad_cb.cxx:360
gb_transaction_save * ts
Definition: gb_undo.h:43
const char * GB_get_db_path(GBDATA *gbd)
Definition: adTest.cxx:14
char * GB_undo_info(GBDATA *gb_main, GB_UNDO_TYPE type)
Definition: adindex.cxx:806
g_b_undo_entry * entries
Definition: gb_undo.h:56
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
void gb_free_undo_stack(GB_MAIN_TYPE *Main)
Definition: adindex.cxx:417
#define GB_CALC_HASH_INDEX(string, index, size, caseSens)
Definition: gb_hashindex.h:70
short flag
Definition: gb_undo.h:37
static void g_b_add_size_to_undo_entry(g_b_undo_entry *ue, long size)
Definition: adindex.cxx:324
static GB_ERROR g_b_undo(GBDATA *gb_main, g_b_undo_header *uh)
Definition: adindex.cxx:495
void gb_check_in_undo_modify(GB_MAIN_TYPE *Main, GBDATA *gbd)
Definition: adindex.cxx:647
GBQUARK key
Definition: gb_undo.h:29
char * data
Definition: gb_ts.h:30
GB_REL_IFES * GB_INDEX_FILES_ENTRIES(gb_index_files *ifs)
Definition: gb_index.h:80
#define FALLTHROUGH
Definition: cxxforward.h:130
long nr_of_elements
Definition: gb_index.h:51
long sizeof_this
Definition: gb_undo.h:50
g_b_undo_header * u
Definition: gb_undo.h:65
void gb_del_ref_gb_transaction_save(gb_transaction_save *ts)
Definition: ad_core.cxx:591
GB_CSTR GB_read_char_pntr(GBDATA *gbd)
Definition: arbdb.cxx:904
GBDATA * gb_main
Definition: adname.cxx:32
void gbm_free_mem(void *block, size_t size, long index)
Definition: gb_memory.h:131
GBDATA * gbd
Definition: gb_undo.h:30
void GB_FREE_TRANSACTION_SAVE(GBDATA *gbd)
Definition: gb_ts.h:55
bool GBS_string_matches(const char *str, const char *expr, GB_CASE case_sens)
Definition: admatch.cxx:193
long hash_table_size
Definition: gb_index.h:50
static GB_CSTR g_b_read_undo_key_pntr(GB_MAIN_TYPE *Main, g_b_undo_entry *ue)
Definition: adindex.cxx:522
const char * GB_KEY(GBDATA *gbd)
Definition: gb_key.h:49
GBDATA * source
Definition: gb_undo.h:39
int nheader
Definition: gb_data.h:102
void gb_touch_entry(GBDATA *gbd, GB_CHANGE val)
Definition: ad_core.cxx:83
#define GB_ENTRIES_ENTRY(entries, idx)
Definition: gb_index.h:64
GB_CB_TYPE
Definition: arbdb_base.h:46
static int info[maxsites+1]
size_t gbs_get_a_prime(size_t above_or_equal_this)
Definition: adhash.cxx:193
const char * GB_CSTR
Definition: arbdb_base.h:25
int GBQUARK
Definition: arbdb_base.h:30
Definition: gb_undo.h:33
#define TEST_EXPECT_EQUAL(expr, want)
Definition: test_unit.h:1294
g_b_undo_header * father
Definition: gb_undo.h:55
void GB_close(GBDATA *gbd)
Definition: arbdb.cxx:655
void put(char c)
Definition: arb_strbuf.h:174
void set_data(char *data)
Definition: gb_data.h:33
unsigned int flags
Definition: gb_header.h:20