source: tags/ms_r16q3/ARBDB/ad_core.cxx

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