1/*
2 * PROGRAM: JRD Access Method
3 * MODULE: tra.h
4 * DESCRIPTION: Transaction block definitions
5 *
6 * The contents of this file are subject to the Interbase Public
7 * License Version 1.0 (the "License"); you may not use this file
8 * except in compliance with the License. You may obtain a copy
9 * of the License at http://www.Inprise.com/IPL.html
10 *
11 * Software distributed under the License is distributed on an
12 * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
13 * or implied. See the License for the specific language governing
14 * rights and limitations under the License.
15 *
16 * The Original Code was created by Inprise Corporation
17 * and its predecessors. Portions created by Inprise Corporation are
18 * Copyright (C) Inprise Corporation.
19 *
20 * All Rights Reserved.
21 * Contributor(s): ______________________________________.
22 * 2001.6.25 Claudio Valderrama: add dfw_delete_generator and dfw_delete_udf
23 * to the dfw_t enumeration.
24 * 2002.10.29 Nickolay Samofatov: Added support for savepoints
25 */
26
27#ifndef JRD_TRA_H
28#define JRD_TRA_H
29
30/*
31 * TMN: Fix this header! It should include any header it needs
32 * to define the types this header uses.
33 */
34
35#include "../include/fb_blk.h"
36#include "../common/classes/tree.h"
37#include "../common/classes/GenericMap.h"
38#include "../jrd/exe.h"
39#include "../jrd/rpb_chain.h"
40#include "../jrd/blb.h" // For bid structure
41#include "../jrd/sbm.h" // For bid structure
42#include "../jrd/sort.h"
43
44#include "../jrd/DatabaseSnapshot.h"
45#include "../jrd/TempSpace.h"
46#include "../jrd/obj.h"
47#include "../jrd/EngineInterface.h"
48
49namespace EDS {
50class Transaction;
51}
52
53namespace Jrd {
54
55class blb;
56class Lock;
57class jrd_rel;
58template <typename T> class vec;
59class Savepoint;
60class Record;
61class VerbAction;
62class ArrayField;
63class Attachment;
64class DeferredWork;
65class DeferredJob;
66class dsql_opn;
67class UserManagement;
68class thread_db;
69
70
71//Moved to fb_types.h
72//typedef ULONG TraNumber;
73
74// Moved to constants.h
75//const TraNumber MAX_TRA_NUMBER = ~TraNumber(0);
76
77// Blobs active in transaction identified by bli_temp_id. Please keep this
78// structure small as there can be huge amount of them floating in memory.
79struct BlobIndex
80{
81 ULONG bli_temp_id;
82 bool bli_materialized;
83 jrd_req* bli_request;
84 union
85 {
86 bid bli_blob_id; // ID of materialized blob
87 blb* bli_blob_object; // Blob object
88 };
89 static const ULONG& generate(const void* /*sender*/, const BlobIndex& item)
90 {
91 return item.bli_temp_id;
92 }
93 // Empty default constructor to make it behave like POD structure
94 BlobIndex() {}
95 BlobIndex(ULONG temp_id, blb* blob_object) :
96 bli_temp_id(temp_id), bli_materialized(false), bli_request(NULL),
97 bli_blob_object(blob_object)
98 { }
99};
100
101typedef Firebird::BePlusTree<BlobIndex, ULONG, MemoryPool, BlobIndex> BlobIndexTree;
102
103// Transaction block
104
105struct CallerName
106{
107 CallerName(int aType, const Firebird::MetaName& aName)
108 : type(aType),
109 name(aName)
110 {
111 }
112
113 CallerName()
114 : type(obj_type_MAX)
115 {
116 }
117
118 CallerName(const CallerName& o)
119 : type(o.type),
120 name(o.name)
121 {
122 }
123
124 void operator =(const CallerName& o)
125 {
126 if (&o != this)
127 {
128 type = o.type;
129 name = o.name;
130 }
131 }
132
133 int type;
134 Firebird::MetaName name;
135};
136
137const int DEFAULT_LOCK_TIMEOUT = -1; // infinite
138const char* const TRA_BLOB_SPACE = "fb_blob_";
139const char* const TRA_UNDO_SPACE = "fb_undo_";
140
141class jrd_tra : public pool_alloc<type_tra>
142{
143 typedef Firebird::GenericMap<Firebird::Pair<Firebird::NonPooled<USHORT, SINT64> > > GenIdCache;
144
145public:
146 enum wait_t {
147 tra_no_wait,
148 tra_probe,
149 tra_wait
150 };
151
152 jrd_tra(MemoryPool* p, Firebird::MemoryStats* parent_stats,
153 Attachment* attachment, jrd_tra* outer)
154 : tra_attachment(attachment),
155 tra_pool(p),
156 tra_memory_stats(parent_stats),
157 tra_blobs_tree(p),
158 tra_blobs(outer ? outer->tra_blobs : &tra_blobs_tree),
159 tra_arrays(NULL),
160 tra_deferred_job(NULL),
161 tra_resources(*p),
162 tra_context_vars(*p),
163 tra_lock_timeout(DEFAULT_LOCK_TIMEOUT),
164 tra_timestamp(Firebird::TimeStamp::getCurrentTimeStamp()),
165 tra_stats(*p),
166 tra_open_cursors(*p),
167 tra_outer(outer),
168 tra_transactions(*p),
169 tra_sorts(*p),
170 tra_public_interface(NULL),
171 tra_gen_ids(NULL),
172 tra_interface(NULL),
173 tra_blob_space(NULL),
174 tra_undo_space(NULL),
175 tra_undo_record(NULL),
176 tra_user_management(NULL),
177 tra_autonomous_pool(NULL),
178 tra_autonomous_cnt(0)
179 {
180 }
181
182 ~jrd_tra();
183
184 static jrd_tra* create(MemoryPool* pool, Attachment* attachment, jrd_tra* outer)
185 {
186 jrd_tra* const transaction =
187 FB_NEW(*pool) jrd_tra(pool, &attachment->att_memory_stats, attachment, outer);
188
189 if (!outer)
190 {
191 pool->setStatsGroup(transaction->tra_memory_stats);
192 }
193
194 return transaction;
195 }
196
197 static void destroy(Attachment* const attachment, jrd_tra* const transaction)
198 {
199 if (transaction)
200 {
201 if (!attachment)
202 delete transaction;
203 else if (transaction->tra_outer)
204 {
205 jrd_tra* outer = transaction->tra_outer;
206 MemoryPool* const pool = transaction->tra_pool;
207 delete transaction;
208 outer->releaseAutonomousPool(pool);
209 }
210 else
211 {
212 MemoryPool* const pool = transaction->tra_pool;
213 Firebird::MemoryStats temp_stats;
214 pool->setStatsGroup(temp_stats);
215 delete transaction;
216 attachment->deletePool(pool);
217 }
218 }
219 }
220
221 Attachment* getAttachment()
222 {
223 return tra_attachment;
224 }
225
226 dsql_dbb* getDsqlAttachment()
227 {
228 return tra_attachment->att_dsql_instance;
229 }
230
231 JTransaction* getInterface();
232 void setInterface(JTransaction* jt);
233
234 FB_API_HANDLE tra_public_handle; // Public handle
235 Attachment* tra_attachment; // database attachment
236 TraNumber tra_number; // transaction number
237 TraNumber tra_top; // highest transaction in snapshot
238 TraNumber tra_oldest; // oldest interesting transaction
239 TraNumber tra_oldest_active; // record versions older than this can be
240 // gargage-collected by this tx
241 TraNumber tra_att_oldest_active; // oldest active transaction in the same attachment
242 jrd_tra* tra_next; // next transaction in attachment
243 MemoryPool* const tra_pool; // pool for transaction
244 Firebird::MemoryStats tra_memory_stats;
245 BlobIndexTree tra_blobs_tree; // list of active blobs
246 BlobIndexTree* tra_blobs; // pointer to actual list of active blobs
247 ArrayField* tra_arrays; // Linked list of active arrays
248 Lock* tra_lock; // lock for transaction
249 vec<Lock*>* tra_relation_locks; // locks for relations
250 UInt32Bitmap* tra_commit_sub_trans; // commited sub-transactions
251 Savepoint* tra_save_point; // list of savepoints
252 Savepoint* tra_save_free; // free savepoints
253 SLONG tra_save_point_number; // next save point number to use
254 ULONG tra_flags;
255 DeferredJob* tra_deferred_job; // work deferred to commit time
256 ResourceList tra_resources; // resource existence list
257 Firebird::StringMap tra_context_vars; // Context variables for the transaction
258 traRpbList* tra_rpblist; // active record_param's of given transaction
259 UCHAR tra_use_count; // use count for safe AST delivery
260 UCHAR tra_callback_count; // callback count for 'execute statement'
261 SSHORT tra_lock_timeout; // in seconds, -1 means infinite, 0 means NOWAIT
262 ULONG tra_next_blob_id; // ID of the previous blob or array created in this transaction
263 const Firebird::TimeStamp tra_timestamp; // transaction start time
264 jrd_req* tra_requests; // Doubly linked list of requests active in this transaction
265 DatabaseSnapshot* tra_db_snapshot; // Database state snapshot (for monitoring purposes)
266 RuntimeStatistics tra_stats;
267 Firebird::Array<dsql_req*> tra_open_cursors;
268 bool tra_in_use; // transaction in use (can't be committed or rolled back)
269 jrd_tra* const tra_outer; // outer transaction of an autonomous transaction
270 CallerName tra_caller_name; // caller object name
271 Firebird::Array<UCHAR> tra_transactions;
272 SortOwner tra_sorts;
273
274 EDS::Transaction *tra_ext_common;
275 //Transaction *tra_ext_two_phase;
276 Firebird::ITransaction* tra_public_interface;
277 GenIdCache* tra_gen_ids;
278
279private:
280 JTransaction* tra_interface;
281 TempSpace* tra_blob_space; // temp blob storage
282 TempSpace* tra_undo_space; // undo log storage
283
284 Record* tra_undo_record; // temporary record used for the undo purposes
285 UserManagement* tra_user_management;
286 MemoryPool* tra_autonomous_pool;
287 USHORT tra_autonomous_cnt;
288 static const USHORT TRA_AUTONOMOUS_PER_POOL = 64;
289
290public:
291 MemoryPool* getAutonomousPool();
292 void releaseAutonomousPool(MemoryPool* toRelease);
293 jrd_tra* getOuter();
294
295 SSHORT getLockWait() const
296 {
297 return -tra_lock_timeout;
298 }
299
300 TempSpace* getBlobSpace()
301 {
302 if (tra_outer)
303 return tra_outer->getBlobSpace();
304
305 if (!tra_blob_space)
306 {
307 fb_assert(!tra_outer);
308 tra_blob_space = FB_NEW(*tra_pool) TempSpace(*tra_pool, TRA_BLOB_SPACE);
309 }
310
311 return tra_blob_space;
312 }
313
314 TempSpace* getUndoSpace()
315 {
316 if (!tra_undo_space)
317 {
318 tra_undo_space = FB_NEW(*tra_pool) TempSpace(*tra_pool, TRA_UNDO_SPACE);
319 }
320
321 return tra_undo_space;
322 }
323
324 Record* getUndoRecord(ULONG length)
325 {
326 if (!tra_undo_record || tra_undo_record->rec_length < length)
327 {
328 delete tra_undo_record;
329 tra_undo_record = FB_NEW_RPT(*tra_pool, length) Record(*tra_pool);
330 }
331
332 memset(tra_undo_record, 0, sizeof(Record) + length);
333
334 return tra_undo_record;
335 }
336
337 UserManagement* getUserManagement();
338
339 GenIdCache* getGenIdCache()
340 {
341 if (!tra_gen_ids)
342 {
343 tra_gen_ids = FB_NEW(*tra_pool) GenIdCache(*tra_pool);
344 }
345
346 return tra_gen_ids;
347 }
348};
349
350// System transaction is always transaction 0.
351const TraNumber TRA_system_transaction = 0;
352
353// Flag definitions for tra_flags.
354
355const ULONG TRA_system = 0x1L; // system transaction
356const ULONG TRA_prepared = 0x2L; // transaction is in limbo
357const ULONG TRA_reconnected = 0x4L; // reconnect in progress
358const ULONG TRA_degree3 = 0x8L; // serializeable transaction
359const ULONG TRA_write = 0x10L; // transaction has written
360const ULONG TRA_readonly = 0x20L; // transaction is readonly
361const ULONG TRA_prepare2 = 0x40L; // transaction has updated RDB$TRANSACTIONS
362const ULONG TRA_ignore_limbo = 0x80L; // ignore transactions in limbo
363const ULONG TRA_invalidated = 0x100L; // transaction invalidated by failed write
364const ULONG TRA_deferred_meta = 0x200L; // deferred meta work posted
365const ULONG TRA_read_committed = 0x400L; // can see latest committed records
366const ULONG TRA_autocommit = 0x800L; // autocommits all updates
367const ULONG TRA_perform_autocommit = 0x1000L; // indicates autocommit is necessary
368const ULONG TRA_rec_version = 0x2000L; // don't wait for uncommitted versions
369const ULONG TRA_restart_requests = 0x4000L; // restart all requests in attachment
370const ULONG TRA_no_auto_undo = 0x8000L; // don't start a savepoint in TRA_start
371const ULONG TRA_precommitted = 0x10000L; // transaction committed at startup
372const ULONG TRA_own_interface = 0x20000L; // tra_interface was created for internal needs
373
374// flags derived from TPB, see also transaction_options() at tra.cpp
375const ULONG TRA_OPTIONS_MASK = (TRA_degree3 | TRA_readonly | TRA_ignore_limbo | TRA_read_committed |
376 TRA_autocommit | TRA_rec_version | TRA_no_auto_undo | TRA_restart_requests);
377
378const int TRA_MASK = 3;
379//const int TRA_BITS_PER_TRANS = 2;
380//const int TRA_TRANS_PER_BYTE = 4;
381const int TRA_SHIFT = 2;
382
383#define TRANS_SHIFT(number) (((number) & TRA_MASK) << 1)
384#define TRANS_OFFSET(number) ((number) >> TRA_SHIFT)
385
386// Transaction cleanup. If a database is never quiescent, look
387// for "dead" active transactions every so often at transaction
388// startup
389
390const int TRA_ACTIVE_CLEANUP = 100;
391
392// Transaction states. The first four are states found
393// in the transaction inventory page; the last two are
394// returned internally
395
396const int tra_active = 0; // Transaction is active
397const int tra_limbo = 1;
398const int tra_dead = 2;
399const int tra_committed = 3;
400const int tra_us = 4; // Transaction is us
401const int tra_precommitted = 5; // Transaction is precommitted
402
403// The highest transaction number possible. This is 0x7fffffff if SLONG is 32 bits.
404//#define MAX_TRA_NUMBER (~(1L << (BITS_PER_LONG - 1)))
405
406// Savepoint block
407
408class Savepoint : public pool_alloc<type_sav>
409{
410public:
411 ~Savepoint()
412 {
413 deleteActions(sav_verb_actions);
414 deleteActions(sav_verb_free);
415 }
416
417 VerbAction* sav_verb_actions; // verb action list
418 VerbAction* sav_verb_free; // free verb actions
419 USHORT sav_verb_count; // Active verb count
420 SLONG sav_number; // save point number
421 Savepoint* sav_next;
422 USHORT sav_flags;
423 TEXT sav_name[MAX_SQL_IDENTIFIER_SIZE]; // Savepoint name
424
425private:
426 void deleteActions(VerbAction* list);
427};
428
429// Savepoint block flags.
430
431const int SAV_trans_level = 1; // savepoint was started by TRA_start
432const int SAV_force_dfw = 2; // DFW is present even if savepoint is empty
433const int SAV_user = 4; // named user savepoint as opposed to system ones
434
435// Maximum size in bytes of transaction-level savepoint data.
436// When transaction-level savepoint gets past this size we drop it and use GC
437// mechanisms to clean out changes done in transaction
438const IPTR SAV_LARGE = 1024 * 32;
439
440// Deferred work blocks are used by the meta data handler to keep track
441// of work deferred to commit time. This are usually used to perform
442// meta data updates
443
444enum dfw_t {
445 dfw_null,
446 dfw_create_relation,
447 dfw_delete_relation,
448 dfw_update_format,
449 dfw_create_index,
450 dfw_delete_index,
451 dfw_compute_security,
452 dfw_add_file,
453 dfw_add_shadow,
454 dfw_delete_shadow,
455 dfw_modify_file,
456 dfw_erase_file,
457 dfw_create_field,
458 dfw_delete_field,
459 dfw_modify_field,
460 dfw_delete_global,
461 dfw_delete_rfr,
462 dfw_post_event,
463 dfw_create_trigger,
464 dfw_delete_trigger,
465 dfw_modify_trigger,
466 //dfw_load_triggers,
467 dfw_grant,
468 dfw_revoke,
469 dfw_scan_relation,
470 dfw_create_expression_index,
471 dfw_delete_expression_index,
472 dfw_create_procedure,
473 dfw_modify_procedure,
474 dfw_delete_procedure,
475 dfw_delete_prm,
476 dfw_create_collation,
477 dfw_delete_collation,
478 dfw_delete_exception,
479 //dfw_unlink_file,
480 dfw_delete_generator,
481 dfw_create_function,
482 dfw_modify_function,
483 dfw_delete_function,
484 dfw_add_difference,
485 dfw_delete_difference,
486 dfw_begin_backup,
487 dfw_end_backup,
488 dfw_user_management,
489 dfw_drop_package_header,
490 dfw_drop_package_body,
491 dfw_check_not_null,
492 dfw_store_view_context_type,
493 dfw_set_generator,
494
495 // deferred works argument types
496 dfw_arg_index_name, // index name for dfw_delete_expression_index, mandatory
497 dfw_arg_partner_rel_id, // partner relation id for dfw_delete_index if index is FK, optional
498 dfw_arg_proc_name, // procedure name for dfw_delete_prm, mandatory
499 dfw_arg_force_computed, // we need to drop dependencies from a field that WAS computed
500 dfw_arg_check_blr, // check if BLR is still compilable
501 dfw_arg_rel_name, // relation name of a trigger
502 dfw_arg_trg_type, // trigger type
503 dfw_arg_new_name, // new name
504 dfw_arg_field_not_null, // set domain to not nullable
505 dfw_db_crypt, // change database encryption status
506 dfw_set_linger // set database linger
507};
508
509// Verb actions
510
511class UndoItem
512{
513public:
514 static const SINT64& generate(const void* /*sender*/, const UndoItem& item)
515 {
516 return item.number;
517 }
518
519 UndoItem() {}
520
521 UndoItem(RecordNumber recordNumber, UCHAR recordFlags)
522 : number(recordNumber.getValue()),
523 flags(recordFlags),
524 length(0), offset(0), format(NULL)
525 {}
526
527 UndoItem(jrd_tra* transaction, RecordNumber recordNumber, const Record* record, UCHAR recordFlags)
528 : number(recordNumber.getValue()),
529 flags(recordFlags),
530 length(record->rec_length),
531 offset(0),
532 format(record->rec_format)
533 {
534 if (length)
535 {
536 offset = transaction->getUndoSpace()->allocateSpace(length);
537 transaction->getUndoSpace()->write(offset, record->rec_data, length);
538 }
539 }
540
541 Record* setupRecord(jrd_tra* transaction, UCHAR newFlags = 0)
542 {
543 flags |= newFlags;
544
545 Record* const record = transaction->getUndoRecord(length);
546 record->rec_number.setValue(number);
547 record->rec_flags = flags;
548 record->rec_length = length;
549 record->rec_format = format;
550
551 if (length)
552 transaction->getUndoSpace()->read(offset, record->rec_data, length);
553
554 return record;
555 }
556
557 void release(jrd_tra* transaction)
558 {
559 if (length)
560 {
561 transaction->getUndoSpace()->releaseSpace(offset, length);
562 length = 0;
563 format = NULL;
564 }
565 }
566
567 const UCHAR getFlags() const
568 {
569 return flags;
570 }
571
572 ULONG getLength() const
573 {
574 return length;
575 }
576
577private:
578 SINT64 number;
579 UCHAR flags;
580 ULONG length;
581 offset_t offset;
582 const Format* format;
583};
584
585typedef Firebird::BePlusTree<UndoItem, SINT64, MemoryPool, UndoItem> UndoItemTree;
586
587class VerbAction : public pool_alloc<type_vct>
588{
589public:
590 ~VerbAction()
591 {
592 delete vct_records;
593 delete vct_undo;
594 }
595
596 VerbAction* vct_next; // Next action within verb
597 jrd_rel* vct_relation; // Relation involved
598 RecordBitmap* vct_records; // Record involved
599 UndoItemTree* vct_undo; // Data for undo records
600};
601
602
603inline void Savepoint::deleteActions(VerbAction* list)
604{
605 while (list)
606 {
607 VerbAction* next = list->vct_next;
608 delete list;
609 list = next;
610 }
611};
612
613} //namespace Jrd
614
615#endif // JRD_TRA_H
616