File: ltrx.h

package info (click to toggle)
virtuoso-opensource 6.1.6+dfsg2-4
  • links: PTS, VCS
  • area: main
  • in suites: bullseye, buster, sid, stretch
  • size: 260,992 kB
  • ctags: 125,220
  • sloc: ansic: 652,748; sql: 458,419; xml: 282,834; java: 61,031; sh: 40,031; cpp: 36,890; cs: 25,240; php: 12,692; yacc: 9,523; lex: 7,018; makefile: 6,157; jsp: 4,484; awk: 1,643; perl: 1,013; ruby: 1,003; python: 326
file content (827 lines) | stat: -rw-r--r-- 24,831 bytes parent folder | download | duplicates (2)
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
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
/*
 *  ltrx.h
 *
 *  $Id$
 *
 *  Locking transaction structures
 *
 *  This file is part of the OpenLink Software Virtuoso Open-Source (VOS)
 *  project.
 *
 *  Copyright (C) 1998-2012 OpenLink Software
 *
 *  This project is free software; you can redistribute it and/or modify it
 *  under the terms of the GNU General Public License as published by the
 *  Free Software Foundation; only version 2 of the License, dated June 1991.
 *
 *  This program is distributed in the hope that it will be useful, but
 *  WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 *  General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 *
 */

#ifndef _LTRX_H
#define _LTRX_H

#define LT_FREEZE 0
#define LT_PENDING		1
#define LT_COMMITTED		2
#define LT_BLOWN_OFF		3 /* Marked to be rolled back */
#define LT_CLOSING		4 /* locks being released, finalizing commit / rollback, inside lt_transact */
#define LT_DELTA_ROLLED_BACK	5 /* Only the trx object to be released */

#ifdef VIRTTP
#define LT_PREPARE_PENDING 	6
#define LT_PREPARED LT_COMMITTED
#define LT_FINAL_COMMIT_PENDING	7 /* when the commit came in, but there's a thread inside */
#endif

#define LT_CL_PREPARED 8 /* in cluster, first phase of commit started or finished.  Cancellable any time, during and after  */
#define LT_1PC_PENDING 9 /* waiting for cluster 1pc reply */
#define LT_2PC_PENDING 10 /* waiting for cluster 2pc replies */
#define LTE_OK		0
#define LTE_TIMEOUT	1
#define LTE_DEADLOCK	2
#define LTE_NO_DISK	3
#define LTE_LOG_FAILED	4
#define LTE_UNIQ	5
#define LTE_SQL_ERROR	6 /* Misc SQL STATE in log_replay_trx.  lt_error set
			     to this when misc. SQL error requires txn to be
			     rolled back.*/
#define LTE_2PC_ERROR	7
#define LTE_REMOTE_DISCONNECT 8 /* when the remote has disconnected it's connection */
#define LTE_CHECKPOINT 9 /* a checkpoint */
#define LTE_LOG_IMAGE 10
#define LTE_OUT_OF_MEM 11 /* out of memory */
#define LTE_REJECT    12  /* reject modifications */
#define LTE_CLUSTER 13 /* disconnect of peer */
#define LTE_CANCEL 14 /* async rollback from other thread */
#define LTE_CLUSTER_SYNC 15 /* unsynced async updates at time of transact */
#define LTE_PREPARED_NOT_COMMITTED 16 /* if a commit msg was dropped, then another action on same trx no, give this error */
#define LTE_UNSPECIFIED 17 /* use when not OK but no lte */

#define SET_DK_MEM_RESERVE_STATE(trx) \
     { \
       if (trx) \
	 { \
	   (trx)->lt_error = LTE_OUT_OF_MEM; \
	   (trx)->lt_status = LT_BLOWN_OFF; \
	 } \
     }

#define DK_MEM_RESERVE \
   DK_ALLOC_ON_RESERVE

#define CHECK_DK_MEM_RESERVE(trx) \
   if (DK_ALLOC_ON_RESERVE) \
     SET_DK_MEM_RESERVE_STATE (trx)


#ifndef SQL_ROLLBACK
# define SQL_COMMIT		0
# define SQL_ROLLBACK		1
#endif


#define REPL_NO_LOG	((caddr_t *) 1L)
#define REPL_LOG	((caddr_t *) 2L)

#define TM_LOCK		0
#define TM_SNAPSHOT	1



typedef struct rb_entry_s
  {
    db_buf_t	rbe_string;
    struct rb_entry_s * rbe_next;
    key_id_t	rbe_key_id;
    short	rbe_row;
    short	rbe_row_len;
    char	rbe_op;
    char	rbe_used;
  } rb_entry_t;

#define RB_INSERT ((char) -1)
#define RB_UPDATE ((char) 0)
struct lock_trx_s;
#ifdef VIRTTP
struct tp_dtrx_s;
#endif
typedef void (*trx_hook_t) (struct lock_trx_s *);

/* #define CHECK_LT_THREADS */

#ifdef CHECK_LT_THREADS
#define LT_ENTER_SAVE(lt) \
do { \
  (lt)->lt_enter_file = __FILE__; \
  (lt)->lt_enter_line = __LINE__; \
} while (0)
#define LT_CLOSE_ACK_THREADS(lt) \
    do { \
      if (!(lt)->lt_last_increase_file[0]) \
        { \
	  (lt)->lt_last_increase_file[0] = __FILE__; \
	  (lt)->lt_last_increase_line[0] = __LINE__; \
	} \
      else if (!(lt)->lt_last_increase_file[1]) \
	{ \
	  (lt)->lt_last_increase_file[1] = __FILE__; \
	  (lt)->lt_last_increase_line[1] = __LINE__; \
	} \
      else \
	{ \
	  (lt)->lt_last_increase_file[1] = (lt)->lt_last_increase_file[0]; \
	  (lt)->lt_last_increase_line[1] = (lt)->lt_last_increase_line[0]; \
	  (lt)->lt_last_increase_file[1] = __FILE__; \
	  (lt)->lt_last_increase_line[1] = __LINE__; \
	} \
    } while (0)
#define LT_THREADS_REPORT(lt, action) \
  log_debug_dummy ("%s:%d : lt_threads %s to %d for lt %p on thread %p",	\
	__FILE__, __LINE__, action, \
	lt->lt_threads, \
		 lt, THREAD_CURRENT_THREAD)
#define lt_log_debug(x)
#else
#define LT_ENTER_SAVE(lt)
#define LT_CLOSE_ACK_THREADS(lt)
#define LT_THREADS_REPORT(lt, action)
#define lt_log_debug(x)
#endif

typedef struct lt_cl_branch_s {
  char 		clbr_change;
  cl_host_t *	clbr_host;
} lt_cl_branch_t;

#define CLBR_READ 0
#define CLBR_WRITE 1
#define CLBR_DONE 2 /* a read branch that already got a commit needs no rb if commit fails */

typedef struct lock_trx_s
  {
    char			lt_status;
    char			lt_mode;  /* lock / snapshot  */
    char			lt_is_excl;
    char			lt_error;
    char		lt_cl_enlisted;
    char		lt_is_cl_server; /* serving a cluster req, whether enlisted or not */
    int			lt_threads;
    int			lt_cl_ref_count; /* no of cluster continuable itc's or qf's wit ref to this.  Don't free until all gone.  Under wi_txn_mtx. No resetting on lt_clear, also no writing outside of txn_mtx, also not in lt_clear */
    int64		lt_trx_no;
    struct client_connection_s *	lt_client;
    dk_mutex_t		lt_locks_mtx;
    dk_mutex_t		lt_rb_mtx;
    dk_mutex_t *	lt_log_mtx;
    dk_hash_t *		lt_rb_hash;
    dk_hash_t *		lt_dirty_blobs;	/* Hashtable of blobs modified by transaction, some are deld at commit, others at rollback */

    dk_session_t *	lt_log;
    dk_set_t		lt_remotes;
    thread_t *		lt_thr;
    dk_hash_t 		lt_lock;
#define lt_has_locks(lt) ((lt)->lt_lock.ht_count)
    /* all below members are considered data area and cleared with memset in lt_cleare, saving individual ones as needed */
#define LT_DATA_AREA_FIRST lt_waits_for
    dk_set_t		lt_waits_for;
    dk_set_t		lt_waiting_for_this;
#ifdef CHECK_LT_THREADS
    const char *	lt_enter_file;
    int	        	lt_enter_line;
    const char *	lt_last_increase_file[2];
    int			lt_last_increase_line[2];
#endif
    int		lt_age;
    int			lt_lw_threads;
    int			lt_close_ack_threads;
    int			lt_vdb_threads;
    uint32		lt_timeout;
    uint32		lt_started;
    uint32		lt_last_enter_time;
    uint32		lt_wait_since;
    caddr_t *		lt_replicate;
    int                 lt_repl_is_raw;
    int			lt_log_fd;
    caddr_t		lt_log_name;
    dk_set_t		lt_blob_log; /* pdl of blob start addresses to log. Zero if overwritten in the same trx */
    char		lt_timestamp[DT_LENGTH];
    dk_session_t *	lt_backup;  /* if running an online backup,
				     * the session to the backup device */
    int64		lt_backup_length;

    db_buf_t		lt_rb_page;
    short		lt_rbp_fill;
    dk_set_t		lt_rb_pages;


    dk_set_t		lt_wait_end; /* threads waiting for commit / rollback to finalize */

    void *		lt_cd;
    trx_hook_t		lt_commit_hook;
    trx_hook_t		lt_rollback_hook;
    dk_set_t		lt_repl_logs;
    caddr_t		lt_replica_of;
    /* in repl feed replay this is the remote server name that originated the action */
    struct dbe_schema_s *	lt_pending_schema;

    /* External TP's transaction info */
#ifdef VIRTTP
    struct {
      int		_2pc_type;
      int		_2pc_params;
      struct tp_dtrx_s* _2pc_info;
      OFF_T		_2pc_logged;
      box_t		_2pc_log;
      caddr_t		_2pc_prepared;
      dk_set_t		_2pc_remotes;
      int		_2pc_invalid; /* is set if one of branches in unreachable  */
      box_t             _2pc_xid;
      char              _2pc_wait_commit;
    } lt_2pc;
#endif

    dk_hash_t *	lt_upd_hi;  /* for each update node active in txn, the set of affected hi's */
    dk_set_t		lt_hi_delta;
    int64		lt_w_id;
    dk_set_t 		lt_cl_branches; /* cl_host_t for cluster hosts in same commit */
    struct cl_host_s *	lt_branch_of;
    OFF_T		lt_commit_flag_offset; /* use for updating log record state in 2pc */
    char		lt_known_in_cl; /* if ever participated in wait or had remote branch, must notify monitor of transact, else not */
    char		lt_log_2pc;
    char		lt_transact_notify_sent; /* if non-monitor commits a branch on the monitor, no separate notify wanted */
    struct cl_req_group_s *	lt_clrg;
    caddr_t		lt_error_detail; /* if non-zero fill it with details about the error at hand */
#ifdef MSDTC_DEBUG
    bitf_t 		lt_in_mts:1;
#endif
    char 		lt_name[20];
    struct name_id_cache_s *	lt_rdf_prefix;
    struct name_id_cache_s *	lt_rdf_iri;
  } lock_trx_t;

#define LT_LAST_RESERVED_NO 99 /* the first 100 trx_no are reserved for temp use, no real transaction uses them */
#define LT_ID_FREE ((int64)-1) /* lt_w_id and lt_trx_no when lt is free in trx_rc */

#define LTN_HOST(ltn) ((uint32)((ltn) >> 32))
#define LTN_NO(ltn) ((uint32)((ltn) & 0xffffffff))

#define LOCK_MAX_WAITS 1024 /* no more than this many queued on a single lock */

typedef struct lock_wait_s {
  lock_trx_t *	lw_trx;
  int		lw_mode;
} lock_wait_t;


/* use the below macro to portably set the lt_error_detail member of the LT */
#define LT_ERROR_DETAIL_SET(lt, det) \
  do \
    { \
      if ((lt)->lt_error_detail) \
	dk_free_box ((lt)->lt_error_detail); \
      (lt)->lt_error_detail = det; \
    } \
  while (0)

/* use the below macro to portably get the lt_error_detail member of the LT */
#define LT_ERROR_DETAIL(lt) \
    (lt)->lt_error_detail

#define LT_HAS_DELTA(lt) ((lt)->lt_rb_hash->ht_count)


#define TRX_NO(lt) lt->lt_trx_no
#define LT_W_NO(lt) QFID_HOST (lt->lt_w_id), (uint32)lt->lt_w_id

#define ITC_IS_LTRX(itc) \
  (itc->itc_ltrx)


#if defined (PAGE_TRACE) | defined (MTX_DEBUG)
#define ITC_FIND_PL(itc, buf) \
  if (ITC_IS_LTRX (itc)) \
    { \
      ITC_IN_KNOWN_MAP (itc, itc->itc_page);						\
      itc->itc_pl = (page_lock_t*) gethash (DP_ADDR2VOID (itc->itc_page), &IT_DP_MAP (itc->itc_tree, itc->itc_page)->itm_locks); \
      if ((buf)->bd_pl != itc->itc_pl) GPF_T1 ("bd_pl and itc_pl not in sync"); \
    }
#else
#define ITC_FIND_PL(itc, buf) \
  if (ITC_IS_LTRX (itc)) \
    itc->itc_pl = (buf)->bd_pl;
#endif


#define IT_DP_PL(it, dp) \
  ((page_lock_t *) gethash (DP_ADDR2VOID (dp), &IT_DP_MAP (it, dp)->itm_locks))

#define LT_NAME(lt) \
  (snprintf (lt->lt_name, sizeof (lt->lt_name), "%d:%u", QFID_HOST (lt->lt_w_id), (uint32)(0xffffffff & (lt)->lt_w_id) ), lt->lt_name)

#define LT_IS_TIMED_OUT(lt) \
  (lt->lt_started && approx_msec_real_time () - lt->lt_started > lt->lt_timeout)

#define LOCK \
    lock_trx_t *	pl_owner; \
    it_cursor_t *	pl_waiting; \
    char		pl_type; \
    char		pl_is_owner_list


typedef struct gen_lock_s
  {
    LOCK;
  } gen_lock_t;

#define N_RLOCK_SETS 4


typedef struct row_lock_s
  {
    LOCK;
    short		rl_pos;
    struct row_lock_s *	rl_next;

  } row_lock_t;


typedef struct page_lock_s
  {
    LOCK;
    short		pl_n_row_locks;
    short		pl_finish_ref_count;
    dp_addr_t		pl_page;
    index_tree_t *	pl_it;
    row_lock_t *	pl_rows[N_RLOCK_SETS];
  } page_lock_t;



/* lock type */
#define PL_FREE		0
#define PL_EXCLUSIVE	1
#define PL_SHARED	2
#define RL_FOLLOW	8
#define PL_PAGE_LOCK	16
#define PL_FINALIZE	32



#define PL_TYPE(pl) (pl->pl_type & 0x3)
#define RL_IS_FOLLOW(pl) (pl->pl_type & RL_FOLLOW)
#define PL_IS_PAGE(pl) (pl->pl_type & PL_PAGE_LOCK)
#define PL_IS_FINALIZE(pl) (pl->pl_type & PL_FINALIZE)
#define PL_IS_ESCALABLE(pl) (!(pl->pl_type & PL_NO_ESCALATION))

#define PL_SET_FLAG(pl, f) pl->pl_type |= f
#define PL_SET_TYPE(pl, f) pl->pl_type = (pl->pl_type & 0xfc) | f

/* put into pl_page after it is removed from the itm_locks.  Intermediate state, for a page lock, wait refs can be left hanging after the lock has no more owners and is thus free.
 * Relates to pl_finish_ref_count.  This is used to delay free of a pl until all the wait refs from already closing lt's are handled. */
#define PL_FINISHING ((dp_addr_t)-2)

#define ITC_PREFER_PAGE_LOCK(itc) \
  ((itc)->itc_n_lock_escalations > 2 || lock_escalation_pct < 0)




#define PL_RLS(pl, pos)  pl->pl_rows[(pos) & 0x3]


#define ITC_MAYBE_LOCK(itc, pos) \
  (it->itc_pl \
   && (PL_RLS (it->itc_pl, pos) || PL_IS_PAGE (it->itc_pl)))


#define PL_RL_ADD(pl, rl, to) \
{ \
  if (PL_RLS (pl, to) == rl) GPF_T1 ("circular rl_next"); \
  rl->rl_next = PL_RLS (pl, to); PL_RLS(pl, to) = rl; }


#define DO_RLOCK(rl, pl) \
{ \
  int r_i; \
  for (r_i = 0; r_i < N_RLOCK_SETS; r_i++) \
    { \
      row_lock_t * rl, * _rl_next; \
      for (rl = pl->pl_rows[r_i]; rl; rl = _rl_next) \
	{ \
	  _rl_next = rl->rl_next;

#define END_DO_RLOCK \
	} \
    } \
}


#define PL_ANY_RLS(pl) \
  (pl->pl_rows[0] || pl->pl_rows[1] || pl->pl_rows[2] || pl->pl_rows[3])


#define PL_CAN_ESCALATE(itc, pl, buf) \
  ((pl->pl_n_row_locks * 100) / (buf->bd_content_map->pm_count + 1) > lock_escalation_pct \
    && !PL_IS_PAGE (pl) \
    && !pl->pl_is_owner_list \
    && pl->pl_owner == itc->itc_ltrx \
    && pl->pl_n_row_locks)



#define LT_CLEAR_ERROR_AFTER_RB(lt, max_thr) \
  { \
  ASSERT_IN_TXN; \
  if (lt->lt_threads <= max_thr && lt->lt_status == LT_DELTA_ROLLED_BACK) \
    lt_restart (lt, TRX_CONT);							\
}


int lock_wait (gen_lock_t * pl, it_cursor_t * it, buffer_desc_t * buf, int acquire);
int lock_add_owner (gen_lock_t * pl, it_cursor_t * it, int was_waiting);

/* return values for lock_wait */
#define WAIT_RESET	0
#define NO_WAIT		1
#define WAIT_OVER	2

void pl_release (page_lock_t * pl, lock_trx_t * lt, buffer_desc_t * buf);
void pl_page_deleted (page_lock_t * pl, buffer_desc_t * buf);
page_lock_t * pl_allocate (void);
void pl_free (page_lock_t * pl);
row_lock_t * rl_allocate (void);
void rl_free (row_lock_t * rl);
row_lock_t * pl_row_lock_at (page_lock_t * pl, int pos);

extern resource_t * lock_rc;
extern resource_t * row_lock_rc;
extern resource_t * trx_rc;

void lt_done (lock_trx_t * lt);
lock_trx_t * lt_allocate (void);
void lt_free (lock_trx_t * lt);
void lt_clear (lock_trx_t * lt);
void lt_kill_other_trx (lock_trx_t * lt, it_cursor_t * itc, buffer_desc_t * buf, int May_freeze);
#define LT_KILL_FREEZE 0  /* will freeze the txn until cpt done if txn has no delta */
#define LT_KILL_ROLLBACK 1  /* Rollback always */

void lt_killall (lock_trx_t * lt, int lte);
int lock_enter (gen_lock_t * pl, it_cursor_t * it, buffer_desc_t * buf);
EXE_EXPORT (lock_trx_t *, lt_start, (void));
lock_trx_t * lt_start_outside_map (void);
int lt_commit (lock_trx_t * lt, int free_trx);
int lt_commit_cl_local_only (lock_trx_t * lt);
void lt_rollback (lock_trx_t * lt, int free_trx);
void lt_rollback_1 (lock_trx_t * lt, int free_trx);
void lt_transact (lock_trx_t * lt, int op);
void lt_hi_transact (lock_trx_t * lt, int op);
void lt_resume_waiting_end (lock_trx_t * lt);
void log_cl_final(lock_trx_t* lt, int is_commit);
void lt_commit_schema_merge (lock_trx_t * lt);

extern dk_mutex_t * log_write_mtx;
void lt_wait_until_dead (lock_trx_t * lt);
void lt_ack_close (lock_trx_t * lt);
void lt_ack_freeze_inner (lock_trx_t * lt);
void lt_restart (lock_trx_t * lt, int leave_flag);
int itc_rollback_row (it_cursor_t * itc, buffer_desc_t ** buf_ret, int pos, row_lock_t * was_rl,
		  page_lock_t * pl, dk_set_t * rd_list);
void  rbe_page_row (rb_entry_t * rbe, row_delta_t * rd);


/* free_trx for lt_commit / lt_rollbak */
#define TRX_FREE 1
#define TRX_CONT 0
#define TRX_CONT_LT_LEAVE 2

void lt_clear_waits (lock_trx_t * lt);

void itc_bust_this_trx (it_cursor_t * it, buffer_desc_t ** buf, int may_return);
#define ITC_BUST_THROW 0
#define ITC_BUST_CONTINUABLE 1

void pl_rlock_table (page_lock_t * pl, row_lock_t ** locks, int *fill_ret);
void pg_move_lock (it_cursor_t * itc, row_lock_t ** locks, int n_locks, int from, int to,
	      page_lock_t * pl_to, int is_to_extend);
void itc_split_lock (it_cursor_t * itc, buffer_desc_t * left, buffer_desc_t * extend);
void itc_split_lock_waits (it_cursor_t * itc, buffer_desc_t * left, buffer_desc_t * extend);
row_lock_t * upd_refit_rlock (it_cursor_t * itc, int pos);
void lt_clear_pl_wait_ref (lock_trx_t * waiting, gen_lock_t * pl);
int itc_check_ins_deleted (it_cursor_t * itc, buffer_desc_t * buf, row_delta_t * rd);
void itc_insert_rl (it_cursor_t * itc, buffer_desc_t * buf, int pos, row_lock_t * rl, int do_not_escalate);
#define RL_NO_ESCALATE 1
#define RL_ESCALATE_OK 0


int itc_insert_lock (it_cursor_t * itc, buffer_desc_t * buf, int *res_ret);
int itc_landed_lock_check (it_cursor_t * itc, buffer_desc_t ** buf_ret);
void lt_add_pl (lock_trx_t * lt, page_lock_t * pl, int is_new_pl);
int pl_lt_is_owner (page_lock_t * pl, lock_trx_t * lt);
int itc_set_lock_on_row (it_cursor_t * itc, buffer_desc_t ** buf_ret);
int itc_serializable_land (it_cursor_t * itc, buffer_desc_t ** buf_ret);
int itc_read_committed_check (it_cursor_t * itc, buffer_desc_t * buf);
void pl_set_finalize (page_lock_t * pl, buffer_desc_t * buf);
void lt_blob_transact (it_cursor_t * itc, int op);

rb_entry_t * lt_rb_entry (lock_trx_t * lt, buffer_desc_t * buf, db_buf_t row, uint32 *code_ret, rb_entry_t ** prev_ret, int leave_mtx);

void lt_rb_insert (lock_trx_t * lt, buffer_desc_t * buf, db_buf_t key);
void lt_no_rb_insert (lock_trx_t * lt, db_buf_t row);
void lt_rb_update (lock_trx_t * lt, buffer_desc_t * buf, db_buf_t  row);
int pg_key_len (db_buf_t key1);
void lt_free_rb (lock_trx_t * lt, int is_rb);

void lt_close_snapshot (lock_trx_t * lt);
int lt_set_checkpoint (lock_trx_t * lt);



#define ITC_AGE_TRX(it, n) \
  if (it->itc_ltrx) \
    it->itc_ltrx->lt_age += n;

#define TRX_REMAP_SIZE		31
#define COMMIT_REMAP_SIZE	123


/*! Type of a callback to be executed by the_grim_lock_reaper() */
typedef void (* srv_background_task_t)(void *appdata);

int srv_add_background_task (srv_background_task_t task, void *appdata);
void the_grim_lock_reaper (void);

int lt_set_snapshot (lock_trx_t * lt);

#define LT_CHECK_RW(lt) \
  if (lt && lt->lt_mode == TM_SNAPSHOT) \
    { \
      sqlr_new_error ("42000", "SR107", "Read only transaction for modify operation."); \
    }


void lt_timestamp (lock_trx_t * lt, char * tv_ret);
caddr_t lt_timestamp_box (lock_trx_t * lt);
void itc_assert_lock (it_cursor_t * itc);




void lt_rb_new_entry (lock_trx_t * lt, uint32 rb_code, rb_entry_t * prev,
		 buffer_desc_t * buf, db_buf_t row, char op);
int32 rd_pos_key (row_delta_t * rd);

#define TRX_POISON(lt) \
{ \
  lt->lt_status = LT_BLOWN_OFF; \
  lt->lt_error = LTE_SQL_ERROR; \
}


#define it_title(it) \
  (!it ? " NULL IT " : ((it->it_key  && it->it_key->key_name) ? it->it_key->key_name : " unnamed key "))


#ifdef PAGE_TRACE

#define it_title(it) \
  (!it ? " NULL IT " : ((it->it_key  && it->it_key->key_name) ? it->it_key->key_name : " unnamed key "))

extern int page_trace_on;

#ifndef DBG_PT_PRINTF
# define DBG_PT_PRINTF(a) if (page_trace_on) { printf a; fflush (stdout); }
#endif

#define DBG_PT_READ(buf, lt) \
{ \
  DBG_PT_PRINTF (("READ L=%d P=%d FL=%d B=%p TX=%d SP=%s\n", \
      buf->bd_page, buf->bd_physical_page, SHORT_REF (buf->bd_buffer + DP_FLAGS), buf,lt ?  lt->lt_trx_no : -1, \
      it_title (buf->bd_tree))); \
  buf->bd_trx_no = lt? lt->lt_trx_no : -1; \
}

#define DBG_PT_WRITE(buf, overr) \
  DBG_PT_PRINTF (("WRITE L=%d P=%d B=%p TX=%d SP=%s PHYS=%d\n", \
      buf->bd_page, buf->bd_physical_page, buf, buf->bd_trx_no, \
      it_title (buf->bd_tree), overr))



#define DBG_PT_PRE_IMAGE(buf) \
  DBG_PT_PRINTF (("PREIMAGE L=%d P=%d B=%p\n", \
      buf->bd_page, buf->bd_physical_page, buf))

#define DBG_PT_COMMIT(lt) \
  DBG_PT_PRINTF (("COMMIT TX=%d\n", lt->lt_trx_no))

#define DBG_PT_COMMIT_END(lt) \
  /*DBG_PT_PRINTF (("COMMIT DONE TX=%d\n", lt->lt_trx_no)) */

#define DBG_PT_ROLLBACK(lt) \
  DBG_PT_PRINTF (("ROLLBACK START T=%d\n", lt->lt_trx_no))

#define DBG_PT_ROLLBACK_END(lt) \
  DBG_PT_PRINTF (("ROLLBACK DONE T=%d\n", lt->lt_trx_no))

#define DBG_PT_BUFFER_SCRAP(buf) \
  DBG_PT_PRINTF (("SCRAP L=%d P=%d B=%p TX=%d\n", \
      buf->bd_page, buf->bd_physical_page, buf, buf->bd_trx_no))

#define DBG_PT_NEW_PAGE(buf) \
{ \
  buf->bd_trx_no = buf->bd_space->isp_trx->trx_no; \
  DBG_PT_PRINTF (("NEW L=%d B=%p FL=%d TX=%d \n", \
	buf->bd_page, SHORT_REF (buf->bd_buffer + DP_FLAGS)buf, buf->bd_trx_no)) \
}

#define DBG_PT_NEW(lt, buf, new_dp) \
  DBG_PT_PRINTF (("L=%d P=%d NP=%d B=%x %TX=%d\n", \
      buf->bd_page, buf->bd_physical_page, new_dp, buf, buf->bd_trx_no))

#define DBG_PT_PRE_PAGE(dp) \
  DBG_PT_PRINTF (("PREV REMAP=%d ", dp))

#define DBG_PT_BUF_SCRAP(buf) \
  DBG_PT_PRINTF (("SCRAP L=%d P=%d B=%p TX=%d SP=%s\n", \
      buf->bd_page, buf->bd_physical_page, buf, buf->bd_trx_no, \
      it_title (buf->bd_tree)))

#endif



#ifndef DBG_PT_PRINTF
#define DBG_PT_PRINTF(a)
#endif

#ifndef DBG_PT_READ
#define DBG_PT_READ(buf, lt)
#endif

#ifndef DBG_PT_WRITE
#define DBG_PT_WRITE(buf, overr)
#endif

#ifndef DBG_PT_DELTA
#define DBG_PT_DELTA(buf, lt)
#endif

#ifndef DBG_PT_PRE_IMAGE
#define DBG_PT_PRE_IMAGE(buf)
#endif

#ifndef DBG_PT_COMMIT
#define DBG_PT_COMMIT(lt)
#endif

#ifndef DBG_PT_COMMIT_END
#define DBG_PT_COMMIT_END(lt)
#endif

#ifndef DBG_PT_ROLLBACK
#define DBG_PT_ROLLBACK(lt)
#endif

#ifndef DBG_PT_ROLLBACK_END
#define DBG_PT_ROLLBACK_END(lt)
#endif

#ifndef DBG_PT_BUFFER_SCRAP
#define DBG_PT_BUFFER_SCRAP(buf)
#endif

#ifndef DBG_PT_PRE_PAGE
#define DBG_PT_PRE_PAGE(dp)
#endif

#ifndef DBG_PT_DELTA_DIRTY
#define DBG_PT_DELTA_DIRTY(buf, old_dp)
#endif

#ifndef DBG_PT_BUF_SCRAP
#define DBG_PT_BUF_SCRAP(buf)
#endif

#ifndef DBG_PT_DELTA_CLEAN
#define DBG_PT_DELTA_CLEAN(buf, old_dp)
#endif


#define TC(f) f++


extern long  tc_try_land_write;
extern long  tc_try_land_reset;
extern  long tc_dp_changed_while_waiting_mtx;
extern long tc_dp_set_parent_being_read;
extern long tc_up_transit_parent_change;
extern long  tc_dive_split;
extern long  tc_dtrans_split;
extern long  tc_up_transit_wait;
extern long  tc_double_deletes;
extern long  tc_delete_parent_waits;
extern long  tc_wait_trx_self_kill;
extern long  tc_split_while_committing;
extern long  tc_rb_code_non_unique;
extern long  tc_set_by_pl_wait;
extern long  tc_split_2nd_read;
extern long  tc_read_wait;
extern long  tc_reentry_split;
extern long  tc_write_wait;
extern long tc_dive_would_deadlock;
extern long tc_cl_deadlocks;
extern long tc_cl_wait_queries;
extern long tc_cl_kill_1pc;
extern long tc_cl_kill_2pc;
extern long tc_get_buffer_while_stat;
extern long tc_autocompact_split;
extern long tc_bp_wait_flush;
extern long tc_page_fill_hash_overflow;
extern long tc_key_sample_reset;
extern long tc_pl_moved_in_reentry;
extern long tc_enter_transiting_bm_inx;
extern long tc_aio_seq_read;
extern long tc_aio_seq_write;
extern long tc_read_absent_while_finalize;
extern long tc_fix_outdated_leaf_ptr;
extern long tc_bm_split_left_separate_but_no_split;
extern long tc_unregister_enter;
extern long tc_root_write;
extern long tc_root_image_miss;
extern long tc_root_image_ref_deleted;
extern long tc_uncommit_cpt_page;
extern long tc_root_cache_miss;
extern long tc_aq_sleep;
extern long  tc_release_pl_on_deleted_dp;
extern long  tc_release_pl_on_absent_dp;
extern long  tc_cpt_lt_start_wait;
extern long  tc_cpt_rollback;
extern long  tc_wait_for_closing_lt;
extern long  tc_pl_non_owner_wait_ref_deld;
extern long  tc_pl_split;
extern long  tc_pl_split_multi_owner_page;
extern long  tc_pl_split_while_wait;
extern long  tc_insert_follow_wait;
extern long  tc_history_itc_delta_wait;
extern long  tc_page_wait_reset;
extern long  tc_posthumous_lock;
extern long  tc_finalize_while_being_read;
extern long  tc_rollback_cpt_page;
extern  long tc_kill_closing;
extern long  tc_dive_cache_hits;
extern long  tc_deadlock_win_get_lock;
extern long  tc_double_deadlock;
extern long  tc_update_wait_move;
extern long  tc_cpt_rollback_retry;
extern long  tc_repl_cycle;
extern long  tc_repl_connect_quick_reuse;

extern long  tc_no_thread_kill_idle;
extern long  tc_no_thread_kill_vdb;
extern long  tc_no_thread_kill_running;
extern long  tc_deld_row_rl_rb;

extern long  tc_blob_read;
extern long  tc_blob_write;
extern long  tc_blob_ra;
extern long  tc_blob_ra_size;
extern long  tc_get_buf_failed;
extern long  tc_read_wait_decoy;
extern long  tc_read_wait_while_ra_finding_buf;


extern int dive_cache_threshold; /* % consecutive for dive cache to be active */
extern int lock_escalation_pct;

extern resource_t * rb_page_rc;

#define STR_OR(s, n) ((s) ? (s) : (n))

#define dbg_pt_printf_2(a)
#if defined (PAGE_TRACE) || 0 /* off unless page trace */
#define rdbg_printf(a) printf a
#define rdbg_printf_2(a) printf a

#else
#define rdbg_printf(a)
#define rdbg_printf_2(a)

#endif

#define LT_IS_RUNNING(lt) \
	(lt->lt_threads > 0 \
	  && !lt->lt_vdb_threads \
	  && !lt->lt_lw_threads \
	  && !lt->lt_close_ack_threads)


#define LW_CALL(it)  rdbg_printf (("    LW call it %p %s:%d\n", it, __FILE__, __LINE__));

#endif /* _LTRX_H */