| 1 | // =============================================================== // |
|---|
| 2 | // // |
|---|
| 3 | // File : gb_data.h // |
|---|
| 4 | // Purpose : GBDATA/GBCONTAINER // |
|---|
| 5 | // // |
|---|
| 6 | // Institute of Microbiology (Technical University Munich) // |
|---|
| 7 | // http://www.arb-home.de/ // |
|---|
| 8 | // // |
|---|
| 9 | // =============================================================== // |
|---|
| 10 | |
|---|
| 11 | #ifndef GB_DATA_H |
|---|
| 12 | #define GB_DATA_H |
|---|
| 13 | |
|---|
| 14 | #ifndef GB_LOCAL_H |
|---|
| 15 | #include "gb_local.h" |
|---|
| 16 | #endif |
|---|
| 17 | #ifndef GB_MEMORY_H |
|---|
| 18 | #include "gb_memory.h" |
|---|
| 19 | #endif |
|---|
| 20 | |
|---|
| 21 | struct gb_callback_list; |
|---|
| 22 | |
|---|
| 23 | // -------------------------------------------------------------------------------- |
|---|
| 24 | |
|---|
| 25 | #define SIZOFINTERN 10 |
|---|
| 26 | |
|---|
| 27 | struct gb_extern_data { |
|---|
| 28 | GB_REL_STRING rel_data; |
|---|
| 29 | long memsize; |
|---|
| 30 | long size; |
|---|
| 31 | |
|---|
| 32 | char *get_data() { return GB_RESOLVE(char*, this, rel_data); } |
|---|
| 33 | void set_data(char *data) { GB_SETREL(this, rel_data, data); } |
|---|
| 34 | }; |
|---|
| 35 | |
|---|
| 36 | struct GB_INTern_strings { |
|---|
| 37 | char data[SIZOFINTERN]; |
|---|
| 38 | unsigned char memsize; |
|---|
| 39 | unsigned char size; |
|---|
| 40 | }; |
|---|
| 41 | |
|---|
| 42 | struct GB_INTern { |
|---|
| 43 | char data[SIZOFINTERN]; |
|---|
| 44 | }; |
|---|
| 45 | |
|---|
| 46 | union gb_data_base_type_union { |
|---|
| 47 | int32_t i; |
|---|
| 48 | GBDATA *ptr; |
|---|
| 49 | GB_INTern_strings istr; |
|---|
| 50 | GB_INTern in; |
|---|
| 51 | gb_extern_data ex; |
|---|
| 52 | }; |
|---|
| 53 | |
|---|
| 54 | // -------------------------------------------------------------------------------- |
|---|
| 55 | |
|---|
| 56 | struct gb_db_extended { |
|---|
| 57 | long creation_date; |
|---|
| 58 | long update_date; |
|---|
| 59 | gb_callback_list *callback; |
|---|
| 60 | gb_transaction_save *old; |
|---|
| 61 | }; |
|---|
| 62 | |
|---|
| 63 | // -------------------------------------------------------------------------------- |
|---|
| 64 | |
|---|
| 65 | struct gb_flag_types { // public flags |
|---|
| 66 | unsigned int type : 4; |
|---|
| 67 | unsigned int security_delete : 3; |
|---|
| 68 | unsigned int security_write : 3; |
|---|
| 69 | unsigned int security_read : 3; |
|---|
| 70 | unsigned int compressed_data : 1; |
|---|
| 71 | unsigned int unused : 1; // last bit saved! |
|---|
| 72 | unsigned int user_flags : 8; |
|---|
| 73 | unsigned int temporary : 1; // ==1 -> don't save entry |
|---|
| 74 | unsigned int saved_flags : 8; |
|---|
| 75 | }; |
|---|
| 76 | |
|---|
| 77 | struct gb_flag_types2 { // private flags (DB server and each client have their own copy!), abortable |
|---|
| 78 | // uncritical section, undoable |
|---|
| 79 | unsigned int last_updated : 8; |
|---|
| 80 | unsigned int user_bits : 7; // user flags (see GB_USERFLAG_...) |
|---|
| 81 | // critic section, do not update any below |
|---|
| 82 | unsigned int folded_container : 1; |
|---|
| 83 | unsigned int update_in_server : 1; // already informed |
|---|
| 84 | unsigned int extern_data : 1; // data ref. by pntr |
|---|
| 85 | unsigned int header_changed : 1; // used by container |
|---|
| 86 | unsigned int gbm_index : 8; // memory section |
|---|
| 87 | unsigned int should_be_indexed : 1; // this should be indexed |
|---|
| 88 | unsigned int is_indexed : 1; // this db. field is indexed |
|---|
| 89 | }; |
|---|
| 90 | |
|---|
| 91 | struct gb_flag_types3 { // user and project flags (public); not abortable !!! |
|---|
| 92 | unsigned int project : 8; |
|---|
| 93 | unsigned int unused : 24; |
|---|
| 94 | }; |
|---|
| 95 | |
|---|
| 96 | // -------------------------------------------------------------------------------- |
|---|
| 97 | |
|---|
| 98 | struct gb_data_list { |
|---|
| 99 | GB_REL_HLS rel_header; |
|---|
| 100 | int headermemsize; // array size (allocated entries) |
|---|
| 101 | int size; // number of valid (non-deleted) items - not valid in transaction mode |
|---|
| 102 | int nheader; // index of next new entry |
|---|
| 103 | }; |
|---|
| 104 | |
|---|
| 105 | CONSTEXPR_INLINE gb_header_list *GB_DATA_LIST_HEADER(gb_data_list& dl) { |
|---|
| 106 | return GB_RESOLVE(gb_header_list *, (&(dl)), rel_header); |
|---|
| 107 | } |
|---|
| 108 | inline void SET_GB_DATA_LIST_HEADER(gb_data_list& dl, gb_header_list *head) { |
|---|
| 109 | GB_SETREL(&dl, rel_header, head); |
|---|
| 110 | } |
|---|
| 111 | |
|---|
| 112 | // -------------------------------------------------------------------------------- |
|---|
| 113 | |
|---|
| 114 | #if defined(DEBUG) |
|---|
| 115 | #define ASSERT_STRICT_GBDATA_TYPES // just for refactoring/debugging (slow) |
|---|
| 116 | #endif |
|---|
| 117 | |
|---|
| 118 | #if defined(ASSERT_STRICT_GBDATA_TYPES) |
|---|
| 119 | #define gb_strict_assert(cond) gb_assert(cond) |
|---|
| 120 | #else |
|---|
| 121 | #define gb_strict_assert(cond) |
|---|
| 122 | #endif |
|---|
| 123 | |
|---|
| 124 | struct GBENTRY; |
|---|
| 125 | struct GBCONTAINER; |
|---|
| 126 | |
|---|
| 127 | #define GB_GBM_INDEX(gbd) ((gbd)->flags2.gbm_index) |
|---|
| 128 | |
|---|
| 129 | struct GBDATA { |
|---|
| 130 | long server_id; |
|---|
| 131 | GB_REL_CONTAINER rel_father; |
|---|
| 132 | gb_db_extended *ext; |
|---|
| 133 | long index; |
|---|
| 134 | gb_flag_types flags; |
|---|
| 135 | gb_flag_types2 flags2; |
|---|
| 136 | |
|---|
| 137 | // ---------------------------------------- |
|---|
| 138 | |
|---|
| 139 | GB_TYPES type() const { |
|---|
| 140 | gb_assert(knownNonNull(this)); |
|---|
| 141 | return GB_TYPES(flags.type); |
|---|
| 142 | } |
|---|
| 143 | |
|---|
| 144 | bool is_a_string() const { return type() == GB_STRING; } |
|---|
| 145 | bool is_indexable() const { return is_a_string(); } |
|---|
| 146 | |
|---|
| 147 | bool is_container() const { return type() == GB_DB; } |
|---|
| 148 | bool is_entry() const { return !is_container(); } |
|---|
| 149 | |
|---|
| 150 | GBENTRY *as_entry() const { |
|---|
| 151 | gb_assert(knownNonNull(this)); // use GBDATA::as_entry() instead |
|---|
| 152 | gb_strict_assert(is_entry()); |
|---|
| 153 | return (GBENTRY*)this; |
|---|
| 154 | } |
|---|
| 155 | GBCONTAINER *as_container() const { |
|---|
| 156 | gb_assert(knownNonNull(this)); // use GBDATA::as_container() instead |
|---|
| 157 | gb_strict_assert(is_container()); |
|---|
| 158 | return (GBCONTAINER*)this; |
|---|
| 159 | } |
|---|
| 160 | |
|---|
| 161 | static GBCONTAINER *as_container(GBDATA *gbd) { return gbd ? gbd->as_container() : NULp; } |
|---|
| 162 | static GBENTRY *as_entry (GBDATA *gbd) { return gbd ? gbd->as_entry() : NULp; } |
|---|
| 163 | |
|---|
| 164 | // meant to be used in client interface (i.e. on any GBDATA* passed from outside) |
|---|
| 165 | GBENTRY *expect_entry() const { |
|---|
| 166 | if (!is_entry()) GBK_terminate("expected a DB entry, got a container"); |
|---|
| 167 | return as_entry(); |
|---|
| 168 | } |
|---|
| 169 | GBCONTAINER *expect_container() const { |
|---|
| 170 | if (!is_container()) GBK_terminate("expected a DB container, got an entry"); |
|---|
| 171 | return as_container(); |
|---|
| 172 | } |
|---|
| 173 | |
|---|
| 174 | inline GBCONTAINER *get_father(); |
|---|
| 175 | |
|---|
| 176 | void create_extended() { |
|---|
| 177 | if (!ext) { |
|---|
| 178 | ext = (gb_db_extended *)gbm_get_mem(sizeof(gb_db_extended), GB_GBM_INDEX(this)); |
|---|
| 179 | } |
|---|
| 180 | } |
|---|
| 181 | void destroy_extended() { |
|---|
| 182 | if (ext) { |
|---|
| 183 | gbm_free_mem(ext, sizeof(gb_db_extended), GB_GBM_INDEX(this)); |
|---|
| 184 | ext = NULp; |
|---|
| 185 | } |
|---|
| 186 | } |
|---|
| 187 | |
|---|
| 188 | void touch_creation(long cdate) { ext->creation_date = cdate; } |
|---|
| 189 | void touch_update(long udate) { ext->update_date = udate; } |
|---|
| 190 | void touch_creation_and_update(long date) { ext->creation_date = ext->update_date = date; } |
|---|
| 191 | |
|---|
| 192 | long creation_date() const { return ext ? ext->creation_date : 0; } |
|---|
| 193 | long update_date() const { return ext ? ext->update_date : 0; } |
|---|
| 194 | |
|---|
| 195 | gb_callback_list *get_callbacks() const { return ext ? ext->callback : NULp; } |
|---|
| 196 | gb_transaction_save *get_oldData() const { return ext ? ext->old : NULp; } |
|---|
| 197 | }; |
|---|
| 198 | |
|---|
| 199 | class GBENTRY : public GBDATA { |
|---|
| 200 | // calls that make no sense: |
|---|
| 201 | bool is_entry() const; |
|---|
| 202 | GBENTRY *as_entry() const; |
|---|
| 203 | public: |
|---|
| 204 | gb_data_base_type_union info; |
|---|
| 205 | |
|---|
| 206 | int cache_index; |
|---|
| 207 | |
|---|
| 208 | void mark_as_intern() { flags2.extern_data = 0; } |
|---|
| 209 | void mark_as_extern() { flags2.extern_data = 1; } |
|---|
| 210 | |
|---|
| 211 | bool stored_external() const { return flags2.extern_data; } |
|---|
| 212 | bool stored_internal() const { return !stored_external(); } |
|---|
| 213 | |
|---|
| 214 | size_t size() const { return stored_external() ? info.ex.size : info.istr.size; } |
|---|
| 215 | size_t memsize() const { return stored_external() ? info.ex.memsize : info.istr.memsize; } |
|---|
| 216 | |
|---|
| 217 | inline size_t uncompressed_size() const; |
|---|
| 218 | |
|---|
| 219 | char *data() { return stored_external() ? info.ex.get_data() : &(info.istr.data[0]); } |
|---|
| 220 | |
|---|
| 221 | inline char *alloc_data(long Size, long Memsize); |
|---|
| 222 | inline void insert_data(const char *Data, long Size, long Memsize); |
|---|
| 223 | void free_data() { |
|---|
| 224 | index_check_out(); |
|---|
| 225 | if (stored_external()) { |
|---|
| 226 | char *exdata = info.ex.get_data(); |
|---|
| 227 | if (exdata) { |
|---|
| 228 | gbm_free_mem(exdata, (size_t)(info.ex.memsize), GB_GBM_INDEX(this)); |
|---|
| 229 | info.ex.set_data(NULp); |
|---|
| 230 | } |
|---|
| 231 | } |
|---|
| 232 | } |
|---|
| 233 | |
|---|
| 234 | void index_check_in(); |
|---|
| 235 | void index_re_check_in() { if (flags2.should_be_indexed) index_check_in(); } |
|---|
| 236 | |
|---|
| 237 | void index_check_out(); |
|---|
| 238 | }; |
|---|
| 239 | |
|---|
| 240 | class GBCONTAINER : public GBDATA { |
|---|
| 241 | // calls that make no sense: |
|---|
| 242 | bool is_container() const; |
|---|
| 243 | GBCONTAINER *as_container() const; |
|---|
| 244 | public: |
|---|
| 245 | gb_flag_types3 flags3; |
|---|
| 246 | gb_data_list d; |
|---|
| 247 | |
|---|
| 248 | long index_of_touched_one_son; /* index of modified son |
|---|
| 249 | * in case of a single mod. son |
|---|
| 250 | * -1 more than one (or one with ind = 0) |
|---|
| 251 | * 0 no son |
|---|
| 252 | * >0 index */ |
|---|
| 253 | long header_update_date; |
|---|
| 254 | |
|---|
| 255 | GB_MAIN_IDX main_idx; |
|---|
| 256 | GB_REL_IFS rel_ifs; |
|---|
| 257 | |
|---|
| 258 | void set_touched_idx(int idx) { |
|---|
| 259 | if (!index_of_touched_one_son || index_of_touched_one_son == idx+1) { |
|---|
| 260 | index_of_touched_one_son = idx+1; |
|---|
| 261 | } |
|---|
| 262 | else { |
|---|
| 263 | index_of_touched_one_son = -1; |
|---|
| 264 | } |
|---|
| 265 | } |
|---|
| 266 | }; |
|---|
| 267 | |
|---|
| 268 | // ---------------------- |
|---|
| 269 | // parent access |
|---|
| 270 | |
|---|
| 271 | CONSTEXPR_INLINE GBCONTAINER* GB_FATHER(GBDATA *gbd) { return GB_RESOLVE(GBCONTAINER*, gbd, rel_father); } |
|---|
| 272 | CONSTEXPR_INLINE GBCONTAINER* GB_GRANDPA(GBDATA *gbd) { return GB_FATHER(GB_FATHER(gbd)); } |
|---|
| 273 | |
|---|
| 274 | CONSTEXPR_INLINE_Cxx14 void SET_GB_FATHER(GBDATA *gbd, GBCONTAINER *father) { GB_SETREL(gbd, rel_father, father); } |
|---|
| 275 | |
|---|
| 276 | GBCONTAINER *GBDATA::get_father() { |
|---|
| 277 | // like GB_FATHER, but returns NULp for root_container |
|---|
| 278 | GBCONTAINER *father = GB_FATHER(this); |
|---|
| 279 | if (father && !GB_FATHER(father)) return NULp; |
|---|
| 280 | return father; |
|---|
| 281 | } |
|---|
| 282 | |
|---|
| 283 | |
|---|
| 284 | // ----------------------- |
|---|
| 285 | // GB_MAIN access |
|---|
| 286 | |
|---|
| 287 | extern GB_MAIN_TYPE *gb_main_array[]; |
|---|
| 288 | |
|---|
| 289 | inline GB_MAIN_TYPE *GBCONTAINER_MAIN(GBCONTAINER *gbc) { return gb_main_array[gbc->main_idx]; } |
|---|
| 290 | |
|---|
| 291 | inline GB_MAIN_TYPE *GB_MAIN(GBDATA *gbd) { return GBCONTAINER_MAIN(GB_FATHER(gbd)); } |
|---|
| 292 | inline GB_MAIN_TYPE *GB_MAIN(GBCONTAINER *gbc) { return GBCONTAINER_MAIN(gbc); } |
|---|
| 293 | |
|---|
| 294 | inline GB_MAIN_TYPE *GB_MAIN_NO_FATHER(GBDATA *gbd) { |
|---|
| 295 | return gbd->is_container() ? GBCONTAINER_MAIN(gbd->as_container()) : GB_MAIN(gbd->as_entry()); |
|---|
| 296 | } |
|---|
| 297 | |
|---|
| 298 | // ----------------------- |
|---|
| 299 | // security flags |
|---|
| 300 | |
|---|
| 301 | #define GB_GET_SECURITY_READ(gb) ((gb)->flags.security_read) |
|---|
| 302 | #define GB_GET_SECURITY_WRITE(gb) ((gb)->flags.security_write) |
|---|
| 303 | #define GB_GET_SECURITY_DELETE(gb) ((gb)->flags.security_delete) |
|---|
| 304 | |
|---|
| 305 | #define GB_PUT_SECURITY_READ(gb, i) ((gb)->flags.security_read = (i)) |
|---|
| 306 | #define GB_PUT_SECURITY_WRITE(gb, i) ((gb)->flags.security_write = (i)) |
|---|
| 307 | #define GB_PUT_SECURITY_DELETE(gb, i) ((gb)->flags.security_delete = (i)) |
|---|
| 308 | |
|---|
| 309 | // --------------------------------------------------------- |
|---|
| 310 | // strictly-aliased forwarders for some functions: |
|---|
| 311 | |
|---|
| 312 | inline __ATTR__USERESULT GB_ERROR gb_commit_transaction_local_rek(GBCONTAINER*& gbc, long mode, int *pson_created) { |
|---|
| 313 | return gb_commit_transaction_local_rek(StrictlyAliased_BasePtrRef<GBCONTAINER,GBDATA>(gbc).forward(), mode, pson_created); |
|---|
| 314 | } |
|---|
| 315 | |
|---|
| 316 | inline void gb_abort_transaction_local_rek(GBCONTAINER*& gbc) { |
|---|
| 317 | gb_abort_transaction_local_rek(StrictlyAliased_BasePtrRef<GBCONTAINER,GBDATA>(gbc).forward()); |
|---|
| 318 | } |
|---|
| 319 | |
|---|
| 320 | // -------------------------------------------------------------------------------- |
|---|
| 321 | |
|---|
| 322 | #ifndef GB_STORAGE_H |
|---|
| 323 | #include "gb_storage.h" |
|---|
| 324 | #endif |
|---|
| 325 | |
|---|
| 326 | #else |
|---|
| 327 | #error gb_data.h included twice |
|---|
| 328 | #endif // GB_DATA_H |
|---|
| 329 | |
|---|
| 330 | |
|---|
| 331 | |
|---|