- Notifications
You must be signed in to change notification settings - Fork 234
/
Copy pathRelation.h
508 lines (406 loc) · 13.5 KB
/
Relation.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
/*
* The contents of this file are subject to the Interbase Public
* License Version 1.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy
* of the License at http://www.Inprise.com/IPL.html
*
* Software distributed under the License is distributed on an
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
* or implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code was created by Inprise Corporation
* and its predecessors. Portions created by Inprise Corporation are
* Copyright (C) Inprise Corporation.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*
*
*/
#ifndef JRD_RELATION_H
#defineJRD_RELATION_H
#include"../jrd/jrd.h"
#include"../jrd/btr.h"
#include"../jrd/lck.h"
#include"../jrd/pag.h"
#include"../jrd/val.h"
#include"../jrd/Attachment.h"
namespaceJrd
{
classBoolExprNode;
classRseNode;
classStmtNode;
// view context block to cache view aliases
classViewContext
{
public:
explicitViewContext(MemoryPool& p, const TEXT* context_name,
const TEXT* relation_name, USHORT context,
ViewContextType type)
: vcx_context_name(p, context_name, fb_strlen(context_name)),
vcx_relation_name(relation_name),
vcx_context(context),
vcx_type(type)
{
}
static USHORT generate(const ViewContext* vc)
{
return vc->vcx_context;
}
const Firebird::string vcx_context_name;
const MetaName vcx_relation_name;
const USHORT vcx_context;
const ViewContextType vcx_type;
};
typedef Firebird::SortedArray<ViewContext*, Firebird::EmptyStorage<ViewContext*>,
USHORT, ViewContext> ViewContexts;
classRelationPages
{
public:
typedef FB_UINT64 InstanceId;
// Vlad asked for this compile-time check to make sure we can contain a txn/att number here
static_assert(sizeof(InstanceId) >= sizeof(TraNumber), "InstanceId must fit TraNumber");
static_assert(sizeof(InstanceId) >= sizeof(AttNumber), "InstanceId must fit AttNumber");
vcl* rel_pages; // vector of pointer page numbers
InstanceId rel_instance_id; // 0 or att_attachment_id or tra_number
ULONG rel_index_root; // index root page number
ULONG rel_data_pages; // count of relation data pages
ULONG rel_slot_space; // lowest pointer page with slot space
ULONG rel_pri_data_space; // lowest pointer page with primary data page space
ULONG rel_sec_data_space; // lowest pointer page with secondary data page space
ULONG rel_last_free_pri_dp; // last primary data page found with space
ULONG rel_last_free_blb_dp; // last blob data page found with space
USHORT rel_pg_space_id;
RelationPages(Firebird::MemoryPool& pool)
: rel_pages(NULL), rel_instance_id(0),
rel_index_root(0), rel_data_pages(0), rel_slot_space(0),
rel_pri_data_space(0), rel_sec_data_space(0),
rel_last_free_pri_dp(0), rel_last_free_blb_dp(0),
rel_pg_space_id(DB_PAGE_SPACE), rel_next_free(NULL),
useCount(0),
dpMap(pool),
dpMapMark(0)
{}
inline SLONG addRef()
{
return useCount++;
}
voidfree(RelationPages*& nextFree);
staticinline InstanceId generate(const RelationPages* item)
{
return item->rel_instance_id;
}
ULONG getDPNumber(ULONG dpSequence)
{
FB_SIZE_T pos;
if (dpMap.find(dpSequence, pos))
{
if (dpMap[pos].mark != dpMapMark)
dpMap[pos].mark = ++dpMapMark;
return dpMap[pos].physNum;
}
return0;
}
voidsetDPNumber(ULONG dpSequence, ULONG dpNumber)
{
FB_SIZE_T pos;
if (dpMap.find(dpSequence, pos))
{
if (dpNumber)
{
dpMap[pos].physNum = dpNumber;
dpMap[pos].mark = ++dpMapMark;
}
else
dpMap.remove(pos);
}
elseif (dpNumber)
{
dpMap.insert(pos, {dpSequence, dpNumber, ++dpMapMark});
if (dpMap.getCount() == MAX_DPMAP_ITEMS)
freeOldestMapItems();
}
}
voidfreeOldestMapItems()
{
ULONG minMark = MAX_ULONG;
FB_SIZE_T i;
for (i = 0; i < dpMap.getCount(); i++)
{
if (minMark > dpMap[i].mark)
minMark = dpMap[i].mark;
}
minMark = (minMark + dpMapMark) / 2;
i = 0;
while (i < dpMap.getCount())
{
if (dpMap[i].mark > minMark)
dpMap[i++].mark -= minMark;
else
dpMap.remove(i);
}
dpMapMark -= minMark;
}
private:
RelationPages* rel_next_free;
SLONG useCount;
staticconst ULONG MAX_DPMAP_ITEMS = 64;
structDPItem
{
ULONG seqNum;
ULONG physNum;
ULONG mark;
static ULONG generate(const DPItem& item)
{
return item.seqNum;
}
};
Firebird::SortedArray<DPItem, Firebird::InlineStorage<DPItem, MAX_DPMAP_ITEMS>, ULONG, DPItem> dpMap;
ULONG dpMapMark;
friendclassjrd_rel;
};
// Primary dependencies from all foreign references to relation's
// primary/unique keys
structprim
{
vec<int>* prim_reference_ids;
vec<int>* prim_relations;
vec<int>* prim_indexes;
};
// Foreign references to other relations' primary/unique keys
structfrgn
{
vec<int>* frgn_reference_ids;
vec<int>* frgn_relations;
vec<int>* frgn_indexes;
};
// Relation block; one is created for each relation referenced
// in the database, though it is not really filled out until
// the relation is scanned
classjrd_rel : publicpool_alloc<type_rel>
{
typedef Firebird::HalfStaticArray<Record*, 4> GCRecordList;
public:
MemoryPool* rel_pool;
USHORT rel_id;
USHORT rel_current_fmt; // Current format number
ULONG rel_flags;
Format* rel_current_format; // Current record format
MetaName rel_name; // ascii relation name
MetaName rel_owner_name; // ascii owner
MetaName rel_security_name; // security class name for relation
vec<Format*>* rel_formats; // Known record formats
vec<jrd_fld*>* rel_fields; // vector of field blocks
RseNode* rel_view_rse; // view record select expression
ViewContexts rel_view_contexts; // sorted array of view contexts
ExternalFile* rel_file; // external file name
GCRecordList rel_gc_records; // records for garbage collection
USHORT rel_use_count; // requests compiled with relation
USHORT rel_sweep_count; // sweep and/or garbage collector threads active
SSHORT rel_scan_count; // concurrent sequential scan count
Lock* rel_existence_lock; // existence lock, if any
Lock* rel_partners_lock; // partners lock
Lock* rel_rescan_lock; // lock forcing relation to be scanned
Lock* rel_gc_lock; // garbage collection lock
IndexLock* rel_index_locks; // index existence locks
IndexBlock* rel_index_blocks; // index blocks for caching index info
TrigVector* rel_pre_erase; // Pre-operation erase trigger
TrigVector* rel_post_erase; // Post-operation erase trigger
TrigVector* rel_pre_modify; // Pre-operation modify trigger
TrigVector* rel_post_modify; // Post-operation modify trigger
TrigVector* rel_pre_store; // Pre-operation store trigger
TrigVector* rel_post_store; // Post-operation store trigger
prim rel_primary_dpnds; // foreign dependencies on this relation's primary key
frgn rel_foreign_refs; // foreign references to other relations' primary keys
Nullable<bool> rel_ss_definer;
TriState rel_repl_state; // replication state
Firebird::Mutex rel_drop_mutex;
boolisSystem() const;
boolisTemporary() const;
boolisVirtual() const;
boolisView() const;
boolisReplicating(thread_db* tdbb);
// global temporary relations attributes
RelationPages* getPages(thread_db* tdbb, TraNumber tran = MAX_TRA_NUMBER, bool allocPages = true);
RelationPages* getBasePages()
{
return &rel_pages_base;
}
booldelPages(thread_db* tdbb, TraNumber tran = MAX_TRA_NUMBER, RelationPages* aPages = NULL);
voidretainPages(thread_db* tdbb, TraNumber oldNumber, TraNumber newNumber);
voidgetRelLockKey(thread_db* tdbb, UCHAR* key);
USHORT getRelLockKeyLength() const;
voidcleanUp();
classRelPagesSnapshot : publicFirebird::Array<RelationPages*>
{
public:
typedef Firebird::Array<RelationPages*> inherited;
RelPagesSnapshot(thread_db* tdbb, jrd_rel* relation)
{
spt_tdbb = tdbb;
spt_relation = relation;
}
~RelPagesSnapshot() { clear(); }
voidclear();
private:
thread_db* spt_tdbb;
jrd_rel* spt_relation;
friendclassjrd_rel;
};
voidfillPagesSnapshot(RelPagesSnapshot&, constbool AttachmentOnly = false);
private:
typedef Firebird::SortedArray<
RelationPages*,
Firebird::EmptyStorage<RelationPages*>,
RelationPages::InstanceId,
RelationPages>
RelationPagesInstances;
RelationPagesInstances* rel_pages_inst;
RelationPages rel_pages_base;
RelationPages* rel_pages_free;
RelationPages* getPagesInternal(thread_db* tdbb, TraNumber tran, bool allocPages);
public:
explicitjrd_rel(MemoryPool& p);
boolhasTriggers() const;
voidreleaseTriggers(thread_db* tdbb, bool destroy);
voidreplaceTriggers(thread_db* tdbb, TrigVector** triggers);
static Lock* createLock(thread_db* tdbb, MemoryPool* pool, jrd_rel* relation, lck_t, bool);
staticintblocking_ast_gcLock(void*);
voiddowngradeGCLock(thread_db* tdbb);
boolacquireGCLock(thread_db* tdbb, int wait);
// This guard is used by regular code to prevent online validation while
// dead- or back- versions is removed from disk.
classGCShared
{
public:
GCShared(thread_db* tdbb, jrd_rel* relation);
~GCShared();
boolgcEnabled() const
{
return m_gcEnabled;
}
private:
thread_db* m_tdbb;
jrd_rel* m_relation;
bool m_gcEnabled;
};
// This guard is used by online validation to prevent any modifications of
// table data while it is checked.
classGCExclusive
{
public:
GCExclusive(thread_db* tdbb, jrd_rel* relation);
~GCExclusive();
boolacquire(int wait);
voidrelease();
private:
thread_db* m_tdbb;
jrd_rel* m_relation;
Lock* m_lock;
};
};
// rel_flags
const ULONG REL_scanned = 0x0001; // Field expressions scanned (or being scanned)
const ULONG REL_system = 0x0002;
const ULONG REL_deleted = 0x0004; // Relation known gonzo
const ULONG REL_get_dependencies = 0x0008; // New relation needs dependencies during scan
const ULONG REL_check_existence = 0x0010; // Existence lock released pending drop of relation
const ULONG REL_blocking = 0x0020; // Blocking someone from dropping relation
const ULONG REL_sys_triggers = 0x0040; // The relation has system triggers to compile
const ULONG REL_sql_relation = 0x0080; // Relation defined as sql table
const ULONG REL_check_partners = 0x0100; // Rescan primary dependencies and foreign references
const ULONG REL_being_scanned = 0x0200; // relation scan in progress
const ULONG REL_sys_trigs_being_loaded = 0x0400; // System triggers being loaded
const ULONG REL_deleting = 0x0800; // relation delete in progress
const ULONG REL_temp_tran = 0x1000; // relation is a GTT delete rows
const ULONG REL_temp_conn = 0x2000; // relation is a GTT preserve rows
const ULONG REL_virtual = 0x4000; // relation is virtual
const ULONG REL_jrd_view = 0x8000; // relation is VIEW
const ULONG REL_gc_blocking = 0x10000; // request to downgrade\release gc lock
const ULONG REL_gc_disabled = 0x20000; // gc is disabled temporarily
const ULONG REL_gc_lockneed = 0x40000; // gc lock should be acquired
/// class jrd_rel
inlinejrd_rel::jrd_rel(MemoryPool& p)
: rel_pool(&p), rel_flags(REL_gc_lockneed),
rel_name(p), rel_owner_name(p), rel_security_name(p),
rel_view_contexts(p), rel_gc_records(p), rel_ss_definer(false),
rel_pages_base(p)
{
}
inlinebooljrd_rel::isSystem() const
{
return rel_flags & REL_system;
}
inlinebooljrd_rel::isTemporary() const
{
return (rel_flags & (REL_temp_tran | REL_temp_conn));
}
inlinebooljrd_rel::isVirtual() const
{
return (rel_flags & REL_virtual);
}
inlinebooljrd_rel::isView() const
{
return (rel_flags & REL_jrd_view);
}
inline RelationPages* jrd_rel::getPages(thread_db* tdbb, TraNumber tran, bool allocPages)
{
if (!isTemporary())
return &rel_pages_base;
returngetPagesInternal(tdbb, tran, allocPages);
}
/// class jrd_rel::GCShared
inlinejrd_rel::GCShared::GCShared(thread_db* tdbb, jrd_rel* relation)
: m_tdbb(tdbb),
m_relation(relation),
m_gcEnabled(false)
{
if (m_relation->rel_flags & (REL_gc_blocking | REL_gc_disabled))
return;
if (m_relation->rel_flags & REL_gc_lockneed)
m_relation->acquireGCLock(tdbb, LCK_NO_WAIT);
if (!(m_relation->rel_flags & (REL_gc_blocking | REL_gc_disabled | REL_gc_lockneed)))
{
++m_relation->rel_sweep_count;
m_gcEnabled = true;
}
if ((m_relation->rel_flags & REL_gc_blocking) && !m_relation->rel_sweep_count)
m_relation->downgradeGCLock(m_tdbb);
}
inlinejrd_rel::GCShared::~GCShared()
{
if (m_gcEnabled)
--m_relation->rel_sweep_count;
if ((m_relation->rel_flags & REL_gc_blocking) && !m_relation->rel_sweep_count)
m_relation->downgradeGCLock(m_tdbb);
}
// Field block, one for each field in a scanned relation
const USHORT FLD_parse_computed = 0x0001; // computed expression is being parsed
classjrd_fld : publicpool_alloc<type_fld>
{
public:
BoolExprNode* fld_validation; // validation clause, if any
BoolExprNode* fld_not_null; // if field cannot be NULL
ValueExprNode* fld_missing_value; // missing value, if any
ValueExprNode* fld_computation; // computation for virtual field
ValueExprNode* fld_source; // source for view fields
ValueExprNode* fld_default_value; // default value, if any
ArrayField* fld_array; // array description, if array
MetaName fld_name; // Field name
MetaName fld_security_name; // security class name for field
MetaName fld_generator_name; // identity generator name
MetaNamePair fld_source_rel_field; // Relation/field source name
Nullable<IdentityType> fld_identity_type;
USHORT fld_flags;
public:
explicitjrd_fld(MemoryPool& p)
: fld_name(p),
fld_security_name(p),
fld_generator_name(p),
fld_source_rel_field(p)
{
}
};
}
#endif // JRD_RELATION_H