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 | |
---|