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  GBS_strstruct *res = GBS_stropen(1024);
528  g_b_undo_list *u;
529  g_b_undo_entry *ue;
530 
531  u = uh->stack;
532  if (!u) return ARB_strdup("No more undos available");
533  for (ue=u->entries; ue; ue = ue->next) {
534  switch (ue->type) {
536  GBS_strcat(res, "Delete new entry: ");
538  break;
540  GBS_strcat(res, "Rebuild deleted entry: ");
541  GBS_strcat(res, g_b_read_undo_key_pntr(Main, ue));
542  break;
545  GBS_strcat(res, "Undo modified entry: ");
547  break;
548  default:
549  break;
550  }
551  GBS_chrcat(res, '\n');
552  }
553  return GBS_strclose(res);
554 }
555 
557  // Remove all existing undos/redos
558  GB_MAIN_TYPE *Main = GB_MAIN(gb_main);
559  g_b_undo_list *a, *next;
560 
561  for (a = Main->undo->r->stack; a; a = next) {
562  next = a->next;
564  }
565  Main->undo->r->stack = NULp;
566  Main->undo->r->sizeof_this = 0;
567 
568  for (a = Main->undo->u->stack; a; a = next) {
569  next = a->next;
571  }
572  Main->undo->u->stack = NULp;
573  Main->undo->u->sizeof_this = 0;
574 
575  return NULp;
576 }
577 
578 
580  // start a new undoable transaction
581  GB_MAIN_TYPE *Main = GB_MAIN(gb_main);
582  char *error = g_b_check_undo_size(Main);
583  g_b_undo_header *uhs;
584 
585  if (error) return error;
586  switch (Main->requested_undo_type) { // init the target undo stack
587  case GB_UNDO_UNDO: // that will undo but delete all redos
588  uhs = Main->undo->u;
589  break;
590  case GB_UNDO_UNDO_REDO: uhs = Main->undo->u; break;
591  case GB_UNDO_REDO: uhs = Main->undo->r; break;
592  case GB_UNDO_KILL: gb_free_all_undos(gb_main);
593  FALLTHROUGH;
594  default: uhs = NULp;
595  }
596  if (uhs) {
597  g_b_undo_list *u = ARB_calloc<g_b_undo_list>(1);
598  u->next = uhs->stack;
599  u->father = uhs;
600  uhs->stack = u;
601  Main->undo->valid_u = u;
602  }
603 
604  return gb_set_undo_type(gb_main, Main->requested_undo_type);
605 }
606 
608  // called to finish an undoable section, called at end of gb_commit_transaction
609  GB_MAIN_TYPE *Main = GB_MAIN(gb_main);
610  g_b_undo_list *u = Main->undo->valid_u;
611 
612  if (!u) return NULp;
613  if (!u->entries) { // nothing to undo, just a read transaction
614  u->father->stack = u->next;
616  }
617  else {
618  if (Main->requested_undo_type == GB_UNDO_UNDO) { // remove all redos
619  g_b_undo_list *a, *next;
620 
621  for (a = Main->undo->r->stack; a; a = next) {
622  next = a->next;
624  }
625  Main->undo->r->stack = NULp;
626  Main->undo->r->sizeof_this = 0;
627  }
628  }
629  Main->undo->valid_u = NULp;
630  return gb_set_undo_type(gb_main, GB_UNDO_NONE);
631 }
632 
634  if (Main->undo->valid_u) {
636 
638  ue->source = gbd;
639  ue->gbm_index = GB_GBM_INDEX(gbd);
640  ue->flag = 0;
641  }
642 }
643 
645  if (!Main->undo->valid_u) {
647  }
648  else {
649  gb_transaction_save *old = gbd->get_oldData();
651 
652  ue->source = gbd;
653  ue->gbm_index = GB_GBM_INDEX(gbd);
655  ue->flag = gbd->flags.saved_flags;
656 
657  if (gbd->is_entry()) {
658  ue->d.ts = old;
659  if (old) {
661  if (gbd->type() >= GB_BITS && old->stored_external() && old->info.ex.data) {
663  // move external array from ts to undo entry struct
665  }
666  }
667  }
668  }
669 }
670 
672  if (!Main->undo->valid_u) {
673  gb_delete_entry(gbd);
674  return;
675  }
676 
677  if (gbd->is_container()) {
678  GBCONTAINER *gbc = gbd->as_container();
679  for (int index = 0; (index < gbc->d.nheader); index++) {
680  GBDATA *gbd2 = GBCONTAINER_ELEM(gbc, index);
681  if (gbd2) gb_check_in_undo_delete(Main, gbd2);
682  }
683  }
684  else {
685  gbd->as_entry()->index_check_out();
686  gbd->flags2.should_be_indexed = 0; // do not re-checkin
687  }
688  gb_abort_entry(gbd); // get old version
689 
691 
693  ue->source = GB_FATHER(gbd);
694  ue->gbm_index = GB_GBM_INDEX(gbd);
695  ue->flag = GB_ARRAY_FLAGS(gbd).flags;
696 
697  ue->d.gs.gbd = gbd;
698  ue->d.gs.key = GB_KEY_QUARK(gbd);
699 
700  gb_pre_delete_entry(gbd); // get the core of the entry
701 
702  if (gbd->is_container()) {
704  }
705  else {
706  if (gbd->type() >= GB_BITS && gbd->as_entry()->stored_external()) {
707  /* we have copied the data structures, now
708  mark the old as deleted !!! */
710  }
711  g_b_add_size_to_undo_entry(ue, sizeof(GBENTRY));
712  }
713 }
714 
715 // ----------------------------------------
716 // UNDO functions exported to USER
717 
718 GB_ERROR GB_request_undo_type(GBDATA *gb_main, GB_UNDO_TYPE type) { // goes to header: __ATTR__USERESULT_TODO
732  GB_MAIN_TYPE *Main = GB_MAIN(gb_main);
733  GB_ERROR error = NULp;
734 
735  if (Main->is_client()) {
736  enum gb_undo_commands cmd = (type == GB_UNDO_NONE || type == GB_UNDO_KILL)
739  error = gbcmc_send_undo_commands(gb_main, cmd);
740  }
741  if (!error) Main->requested_undo_type = type;
742 
743  return error;
744 }
745 
747  GB_MAIN_TYPE *Main = GB_MAIN(gb_main);
748  return Main->requested_undo_type;
749 }
750 
751 
752 GB_ERROR GB_undo(GBDATA *gb_main, GB_UNDO_TYPE type) { // goes to header: __ATTR__USERESULT
753  // undo/redo the last transaction
754 
755  GB_MAIN_TYPE *Main = GB_MAIN(gb_main);
756  GB_ERROR error = NULp;
757 
758  if (Main->is_client()) {
759  switch (type) {
760  case GB_UNDO_UNDO:
762  break;
763 
764  case GB_UNDO_REDO:
766  break;
767 
768  default:
769  GB_internal_error("unknown undo type in GB_undo");
770  error = "Internal UNDO error";
771  break;
772  }
773  }
774  else {
775  GB_UNDO_TYPE old_type = GB_get_requested_undo_type(gb_main);
776  switch (type) {
777  case GB_UNDO_UNDO:
778  error = GB_request_undo_type(gb_main, GB_UNDO_REDO);
779  if (!error) {
780  error = g_b_undo(gb_main, Main->undo->u);
781  ASSERT_NO_ERROR(GB_request_undo_type(gb_main, old_type));
782  }
783  break;
784 
785  case GB_UNDO_REDO:
786  error = GB_request_undo_type(gb_main, GB_UNDO_UNDO_REDO);
787  if (!error) {
788  error = g_b_undo(gb_main, Main->undo->r);
789  ASSERT_NO_ERROR(GB_request_undo_type(gb_main, old_type));
790  }
791  break;
792 
793  default:
794  error = "GB_undo: unknown undo type specified";
795  break;
796  }
797  }
798 
799  return error;
800 }
801 
802 
804  // get some information about the next undo
805  // returns NULp in case of exported error
806 
807  GB_MAIN_TYPE *Main = GB_MAIN(gb_main);
808  if (Main->is_client()) {
809  switch (type) {
810  case GB_UNDO_UNDO:
812  case GB_UNDO_REDO:
814  default:
815  GB_export_error("GB_undo_info: unknown undo type specified");
816  return NULp;
817  }
818  }
819  switch (type) {
820  case GB_UNDO_UNDO:
821  return g_b_undo_info(Main, Main->undo->u);
822  case GB_UNDO_REDO:
823  return g_b_undo_info(Main, Main->undo->r);
824  default:
825  GB_export_error("GB_undo_info: unknown undo type specified");
826  return NULp;
827  }
828 }
829 
830 GB_ERROR GB_set_undo_mem(GBDATA *gbd, long memsize) {
831  // set the maximum memory used for undoing
832 
833  GB_MAIN_TYPE *Main = GB_MAIN(gbd);
834  if (memsize < _GBCMC_UNDOCOM_SET_MEM) {
835  return GB_export_errorf("Not enough UNDO memory specified: should be more than %i",
837  }
838  Main->undo->max_size_of_all_undos = memsize;
839  if (Main->is_client()) {
840  return gbcmc_send_undo_commands(gbd, (enum gb_undo_commands)memsize);
841  }
842  g_b_check_undo_size(Main);
843  return NULp;
844 }
845 
846 
847 #ifdef UNIT_TESTS
848 #include <test_unit.h>
849 #include <map>
850 #include <ad_cb_prot.h>
851 
852 class cb_counter : virtual Noncopyable {
853  GBDATA *gbd;
854  int deletes, changes, creates;
855  bool do_trace;
856 public:
857  static void count_swapped(GBDATA* gbd, cb_counter* counter, GB_CB_TYPE t ) {
858  // CB system cannot swap parameters, we need to wrap
859  // And yes... fixed parameters are added *in the middle*, not at the end.
860  counter->count(gbd, t);
861  }
862 
863  cb_counter(GBDATA* gbd_) : gbd(gbd_), deletes(0), changes(0), creates(0), do_trace(false) {
864  GB_add_callback(gbd, GB_CB_ALL, makeDatabaseCallback(cb_counter::count_swapped, this));
865  }
866 
867  ~cb_counter() {
868  // CB system cannot auto-destroy callbacks, nor are there CB handles
869  if (deletes == 0) { // (GB_delete destroys CBs I think)
870  GB_remove_callback(gbd, GB_CB_ALL, makeDatabaseCallback(cb_counter::count_swapped, this));
871  // above must be exact copy of GB_add_callback copy
872  }
873  }
874 
875  void count(GBDATA*, GB_CB_TYPE t) {
876  if (t & GB_CB_DELETE) deletes ++;
877  if (t & GB_CB_SON_CREATED) creates ++;
878  if (t & GB_CB_CHANGED) changes ++;
879  if (do_trace) printf("counts: %p d=%i c=%i n=%i\n", gbd, deletes, changes, creates);
880  }
881 
882  void trace(bool t) {
883  do_trace = t;
884  }
885 
886  int get_deletes() {
887  int res = deletes;
888  deletes = 0;
889  return res;
890  }
891 
892  int get_creates() {
893  int res = creates;
894  creates = 0;
895  return res;
896  }
897 
898  int get_changes() {
899  int res = changes;
900  changes = 0;
901  return res;
902  }
903 };
904 
905 
906 
907 void TEST_GB_undo__basic() {
908  GB_shell shell;
909  // GB_ERROR err;
910 
911  GBDATA *main = GB_open("nosuch.arb", "c");
912  GB_begin_transaction(main);
913  cb_counter main_counter(main);
914  GB_commit_transaction(main);
915 
916  GBDATA *gbd;
917  cb_counter *gbd_counter;
918 
919  GB_set_undo_mem(main, 10000);
921 
922 
923  // Notes:
924  // - CB_CHANGED == CB_SON_CREATED
925  // Both are called on creating sons as well as just writing strings.
926  // - GB_SON_CREATED also called if "SON_DELETED"
927  // - It's possible to get CB_SON_CREATED on GBENTRY if the CB is
928  // registered within the running transaction.
929  // - CBs are triggered at the end of the transaction.
930 
931 
932  // test undo create empty string entry
933  GB_begin_transaction(main);
934  gbd = GB_create(main, "test", GB_STRING);
935  gbd_counter = new cb_counter(gbd);
936  GB_commit_transaction(main);
937 
938  TEST_EXPECT_EQUAL( main_counter.get_creates(), 1);
939  TEST_EXPECT_EQUAL( main_counter.get_changes(), 1);
940  TEST_EXPECT_EQUAL( main_counter.get_deletes(), 0);
941  TEST_EXPECT_EQUAL( gbd_counter->get_creates(), 1);
942  TEST_EXPECT_EQUAL( gbd_counter->get_changes(), 1);
943  TEST_EXPECT_EQUAL( gbd_counter->get_deletes(), 0);
944  // string initialises as empty
945  TEST_EXPECT_EQUAL( GB_read_pntr(GB_find(main, "test", SEARCH_CHILD)), "");
947  TEST_EXPECT_EQUAL( main_counter.get_creates(), 1); // BROKEN -- should be 0
948  TEST_EXPECT_EQUAL( main_counter.get_changes(), 1);
949  TEST_EXPECT_EQUAL( main_counter.get_deletes(), 0); // BROKEN -- should be 1
950  TEST_EXPECT_EQUAL( gbd_counter->get_creates(), 0);
951  TEST_EXPECT_EQUAL( gbd_counter->get_changes(), 0);
952  TEST_EXPECT_EQUAL( gbd_counter->get_deletes(), 1);
953  TEST_EXPECT_NULL( GB_find(main, "test", SEARCH_CHILD) );
955  TEST_EXPECT_EQUAL( main_counter.get_creates(), 1);
956  TEST_EXPECT_EQUAL( main_counter.get_changes(), 1);
957  TEST_EXPECT_EQUAL( main_counter.get_deletes(), 0);
958  TEST_REJECT_NULL( gbd = GB_find(main, "test", SEARCH_CHILD) );
959  TEST_EXPECT_EQUAL( GB_read_pntr(GB_find(main, "test", SEARCH_CHILD)), "");
960 
961  // re-establish counter
962  GB_begin_transaction(main);
963  delete gbd_counter;
964  gbd_counter = new cb_counter(gbd);
965  GB_commit_transaction(main);
966 
967  // test undo delete empty string
968  GB_begin_transaction(main);
969  GB_delete(gbd);
970  GB_commit_transaction(main);
971  TEST_EXPECT_EQUAL( main_counter.get_creates(), 1); // BROKEN -- should be 0
972  TEST_EXPECT_EQUAL( main_counter.get_changes(), 1);
973  TEST_EXPECT_EQUAL( main_counter.get_deletes(), 0);
974  TEST_EXPECT_EQUAL( gbd_counter->get_creates(), 0);
975  TEST_EXPECT_EQUAL( gbd_counter->get_changes(), 0);
976  TEST_EXPECT_EQUAL( gbd_counter->get_deletes(), 1);
977  TEST_EXPECT_NULL( GB_find(main, "test", SEARCH_CHILD) );
979  TEST_EXPECT_EQUAL( main_counter.get_creates(), 1);
980  TEST_EXPECT_EQUAL( main_counter.get_changes(), 1);
981  TEST_EXPECT_EQUAL( main_counter.get_deletes(), 0);
982  TEST_EXPECT_EQUAL( GB_read_pntr(GB_find(main, "test", SEARCH_CHILD)), "" );
984  TEST_EXPECT_EQUAL( main_counter.get_creates(), 1); // BROKEN -- should be 0
985  TEST_EXPECT_EQUAL( main_counter.get_changes(), 1);
986  TEST_EXPECT_EQUAL( main_counter.get_deletes(), 0);
987  TEST_EXPECT_NULL( GB_find(main, "test", SEARCH_CHILD) );
989  TEST_REJECT_NULL( gbd = GB_find(main, "test", SEARCH_CHILD) );
990  TEST_EXPECT_EQUAL( gbd_counter->get_creates(), 0);
991  TEST_EXPECT_EQUAL( gbd_counter->get_changes(), 0);
992  TEST_EXPECT_EQUAL( gbd_counter->get_deletes(), 0);
993 
994  // re-establish counter
995  GB_begin_transaction(main);
996  delete gbd_counter;
997  gbd_counter = new cb_counter(gbd);
998  GB_commit_transaction(main);
999 
1000  // test undo write short string
1001  const char* str = "testtest9012345";
1002  GB_begin_transaction(main);
1003  GB_write_string(gbd, str);
1004  GB_commit_transaction(main);
1005  TEST_EXPECT_EQUAL( gbd_counter->get_creates(), 1); // BROKEN?
1006  TEST_EXPECT_EQUAL( gbd_counter->get_changes(), 1);
1007  TEST_EXPECT_EQUAL( gbd_counter->get_deletes(), 0);
1008  TEST_EXPECT_EQUAL( GB_read_pntr(GB_find(main, "test", SEARCH_CHILD)), str);
1010  TEST_EXPECT_EQUAL( gbd_counter->get_creates(), 1); // BROKEN?
1011  TEST_EXPECT_EQUAL( gbd_counter->get_changes(), 1);
1012  TEST_EXPECT_EQUAL( gbd_counter->get_deletes(), 0);
1013  TEST_EXPECT_EQUAL( GB_read_pntr(GB_find(main, "test", SEARCH_CHILD)), "");
1015  TEST_EXPECT_EQUAL( gbd_counter->get_creates(), 1); // BROKEN?
1016  TEST_EXPECT_EQUAL( gbd_counter->get_changes(), 1);
1017  TEST_EXPECT_EQUAL( gbd_counter->get_deletes(), 0);
1018  TEST_EXPECT_EQUAL( GB_read_pntr(GB_find(main, "test", SEARCH_CHILD)), str);
1019 
1020  delete gbd_counter;
1021 
1022  // test undo delete short string
1023  GB_begin_transaction(main);
1024  GB_delete(gbd);
1025  GB_commit_transaction(main);
1026  TEST_EXPECT_NULL( GB_find(main, "test", SEARCH_CHILD) );
1028 
1030  TEST_EXPECT_EQUAL__BROKEN( GB_read_pntr(GB_find(main, "test", SEARCH_CHILD)), str, (char*)NULp);
1031  GB_close(main);
1032  return; // remainder will fail now
1033 
1034 
1036  TEST_EXPECT_NULL( GB_find(main, "test", SEARCH_CHILD) );
1038  TEST_REJECT_NULL( gbd = GB_find(main, "test", SEARCH_CHILD) );
1039 
1040  // test undo write "" and delete short string
1041  GB_begin_transaction(main);
1042  GB_write_string(gbd, str);
1043  GB_delete(gbd);
1044  GB_commit_transaction(main);
1045  TEST_EXPECT_NULL( GB_find(main, "test", SEARCH_CHILD) );
1047  TEST_EXPECT_EQUAL( GB_read_pntr(GB_find(main, "test", SEARCH_CHILD)), str);
1049  TEST_EXPECT_NULL( GB_find(main, "test", SEARCH_CHILD) );
1051  TEST_REJECT_NULL( gbd = GB_find(main, "test", SEARCH_CHILD) );
1052 
1053  //err = GB_write_string(gbd, "testtest9012345");
1054 
1055  GB_close(main);
1056 }
1057 TEST_PUBLISH(TEST_GB_undo__basic);
1058 
1059 
1060 #endif // UNIT_TESTS
GB_ERROR GB_begin_transaction(GBDATA *gbd)
Definition: arbdb.cxx:2492
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:2515
#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:633
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:1361
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:752
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:830
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:2525
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:65
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:204
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:746
gb_header_flags & GB_ARRAY_FLAGS(GBDATA *gbd)
Definition: gb_header.h:49
g_b_undo_entry * next
Definition: gb_undo.h:35
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:671
GB_ERROR GB_push_transaction(GBDATA *gbd)
Definition: arbdb.cxx:2458
#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:1880
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:1484
const int GB_MAX_UNDO_CNT
Definition: adtune.cxx:33
GB_ERROR GB_export_error(const char *error)
Definition: arb_msg.cxx:259
GBS_strstruct * GBS_stropen(long init_size)
Definition: arb_strbuf.cxx:39
GB_ERROR GB_await_error()
Definition: arb_msg.cxx:353
gb_flag_types flags
Definition: gb_data.h:134
char * gb_set_undo_sync(GBDATA *gb_main)
Definition: adindex.cxx:579
GBDATA * GB_create(GBDATA *father, const char *key, GB_TYPES type)
Definition: arbdb.cxx:1755
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:847
void gb_pre_delete_entry(GBDATA *gbd)
Definition: ad_core.cxx:445
#define TEST_EXPECT_EQUAL__BROKEN(expr, want, got)
Definition: test_unit.h:1284
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:556
char * gb_disable_undo(GBDATA *gb_main)
Definition: adindex.cxx:607
bool is_container() const
Definition: gb_data.h:147
#define TEST_REJECT_NULL(n)
Definition: test_unit.h:1309
GBCONTAINER * gb_make_pre_defined_container(GBCONTAINER *father, GBCONTAINER *gbc, long index_pos, GBQUARK keyq)
Definition: ad_core.cxx:395
void GBS_strcat(GBS_strstruct *strstr, const char *ptr)
Definition: arb_strbuf.cxx:108
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:1669
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
void GBS_chrcat(GBS_strstruct *strstr, char ch)
Definition: arb_strbuf.cxx:119
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:264
void GB_internal_error(const char *message)
Definition: arb_msg.cxx:435
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:1307
#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:771
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:1638
GB_ERROR GB_request_undo_type(GBDATA *gb_main, GB_UNDO_TYPE type)
Definition: adindex.cxx:718
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
char * GBS_strclose(GBS_strstruct *strstr)
Definition: arb_strbuf.cxx:69
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:803
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:97
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:644
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:107
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:874
GBDATA * gb_main
Definition: adname.cxx:33
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
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:1283
g_b_undo_header * father
Definition: gb_undo.h:55
void GB_close(GBDATA *gbd)
Definition: arbdb.cxx:625
void set_data(char *data)
Definition: gb_data.h:33
unsigned int flags
Definition: gb_header.h:20