1
/* Copyright (c) 2007 PrimeBase Technologies GmbH
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
* 2007-10-31 Paul McCullagh
23
* The new table cache. Caches all non-index data. This includes the data
24
* files and the row pointer files.
26
#ifndef __tabcache_h__
27
#define __tabcache_h__
34
#include "thread_xt.h"
35
#include "filesys_xt.h"
39
//#define XT_USE_CACHE_DEBUG_SIZES
40
//#define XT_NOT_INLINE
41
//#define CHECK_DOUBLE_READ
44
#ifdef XT_USE_CACHE_DEBUG_SIZES
46
#define XT_TC_PAGE_SIZE (4*1024)
47
#define XT_TC_SEGMENT_SHIFTS 1
51
#define XT_TC_PAGE_SIZE (32*1024)
52
#define XT_TC_SEGMENT_SHIFTS 3
56
#define XT_TIME_DIFF(start, now) (\
57
((xtWord4) (now) < (xtWord4) (start)) ? \
58
((xtWord4) 0XFFFFFFFF - ((xtWord4) (start) - (xtWord4) (now))) : \
59
((xtWord4) (now) - (xtWord4) (start)))
61
#define XT_TC_SEGMENT_COUNT ((off_t) 1 << XT_TC_SEGMENT_SHIFTS)
62
#define XT_TC_SEGMENT_MASK (XT_TC_SEGMENT_COUNT - 1)
64
typedef struct XTTabCachePage {
65
xtWord1 tcp_dirty; /* TRUE if the page is dirty. */
66
xtWord1 tcp_seg; /* Segement number of the page. */
67
#ifdef XT_CLUSTER_FREE_RECORDS
68
xtWord2 tcp_free_rec; /* 0xFFFF if there is no free record in this page. */
70
u_int tcp_lock_count; /* Number of read locks on this page. */
71
u_int tcp_hash_idx; /* The hash index of the page. */
72
u_int tcp_page_idx; /* The page address. */
73
u_int tcp_file_id; /* The file id of the page. */
74
xtDatabaseID tcp_db_id; /* The ID of the database. */
75
xtTableID tcp_tab_id; /* The ID of the table of this cache page. */
76
xtWord4 tcp_data_size; /* Size of the data on this page. */
77
xtOpSeqNo tcp_op_seq; /* The operation sequence number (dirty pages have a operations sequence) */
78
xtWord4 tcp_ru_time; /* If this is in the top 1/4 don't change position in MRU list. */
79
struct XTTabCachePage *tcp_next; /* Pointer to next page on hash list, or next free page on free list. */
80
struct XTTabCachePage *tcp_mr_used; /* More recently used pages. */
81
struct XTTabCachePage *tcp_lr_used; /* Less recently used pages. */
82
xtWord1 tcp_data[XT_TC_PAGE_SIZE]; /* This is actually tci_page_size! */
83
} XTTabCachePageRec, *XTTabCachePagePtr;
86
* Each table has a "table operation sequence". This sequence is incremented by
87
* each operation on the table. Each operation in the log is tagged by a
90
* The writter threads re-order operations in the log, and write the operations
91
* to the database in sequence.
93
* It is safe to free a cache page when the sequence number of the cache page,
94
* is less than or equal to the written sequence number.
96
typedef struct XTTableSeq {
97
xtOpSeqNo ts_next_seq; /* The next sequence number for operations on the table. */
98
xt_mutex_type ts_ns_lock; /* Lock for the next sequence number. */
100
xtBool ts_log_no_op(XTThreadPtr thread, xtTableID tab_id, xtOpSeqNo op_seq);
102
/* Return the next operation sequence number. */
104
xtOpSeqNo ts_set_op_seq(XTTabCachePagePtr page);
106
xtOpSeqNo ts_get_op_seq();
108
xtOpSeqNo ts_set_op_seq(XTTabCachePagePtr page)
112
xt_lock_mutex_ns(&ts_ns_lock);
113
page->tcp_op_seq = seq = ts_next_seq++;
114
xt_unlock_mutex_ns(&ts_ns_lock);
118
xtOpSeqNo ts_get_op_seq()
122
xt_lock_mutex_ns(&ts_ns_lock);
124
xt_unlock_mutex_ns(&ts_ns_lock);
129
void xt_op_seq_init(XTThreadPtr self) {
130
xt_init_mutex_with_autoname(self, &ts_ns_lock);
133
void xt_op_seq_set(XTThreadPtr XT_UNUSED(self), xtOpSeqNo n) {
137
void xt_op_seq_exit(XTThreadPtr XT_UNUSED(self)) {
138
xt_free_mutex(&ts_ns_lock);
142
static xtBool xt_op_is_before(register xtOpSeqNo now, register xtOpSeqNo then);
144
static inline xtBool xt_op_is_before(register xtOpSeqNo now, register xtOpSeqNo then)
147
if ((now - then) > (xtOpSeqNo) 0xFFFFFFFF/2)
151
if ((then - now) > (xtOpSeqNo) 0xFFFFFFFF/2)
156
} XTTableSeqRec, *XTTableSeqPtr;
159
#define TAB_CAC_USE_PTHREAD_RW
161
//#define TAB_CAC_USE_PTHREAD_RW
162
#define TAB_CAC_USE_XSMUTEX
163
//#define IDX_USE_SPINXSLOCK
166
#if defined(TAB_CAC_USE_PTHREAD_RW)
167
#define TAB_CAC_LOCK_TYPE xt_rwlock_type
168
#define TAB_CAC_INIT_LOCK(s, i) xt_init_rwlock_with_autoname(s, i)
169
#define TAB_CAC_FREE_LOCK(s, i) xt_free_rwlock(i)
170
#define TAB_CAC_READ_LOCK(i, o) xt_slock_rwlock_ns(i)
171
#define TAB_CAC_WRITE_LOCK(i, o) xt_xlock_rwlock_ns(i)
172
#define TAB_CAC_UNLOCK(i, o) xt_unlock_rwlock_ns(i)
173
#elif defined(TAB_CAC_USE_XSMUTEX)
174
#define TAB_CAC_LOCK_TYPE XTMutexXSLockRec
175
#define TAB_CAC_INIT_LOCK(s, i) xt_xsmutex_init_with_autoname(s, i)
176
#define TAB_CAC_FREE_LOCK(s, i) xt_xsmutex_free(s, i)
177
#define TAB_CAC_READ_LOCK(i, o) xt_xsmutex_slock(i, o)
178
#define TAB_CAC_WRITE_LOCK(i, o) xt_xsmutex_xlock(i, o)
179
#define TAB_CAC_UNLOCK(i, o) xt_xsmutex_unlock(i, o)
180
#elif defined(TAB_CAC_USE_SPINXSLOCK)
181
#define TAB_CAC_LOCK_TYPE XTSpinXSLockRec
182
#define TAB_CAC_INIT_LOCK(s, i) xt_spinxslock_init_with_autoname(s, i)
183
#define TAB_CAC_FREE_LOCK(s, i) xt_spinxslock_free(s, i)
184
#define TAB_CAC_READ_LOCK(i, o) xt_spinxslock_slock(i, o)
185
#define TAB_CAC_WRITE_LOCK(i, o) xt_spinxslock_xlock(i, FALSE, o)
186
#define TAB_CAC_UNLOCK(i, o) xt_spinxslock_unlock(i, o)
188
#error Please define the lock type
191
/* A disk cache segment. The cache is divided into a number of segments
192
* to improve concurrency.
194
typedef struct XTTabCacheSeg {
195
TAB_CAC_LOCK_TYPE tcs_lock; /* The cache segment read/write lock. */
196
XTTabCachePagePtr *tcs_hash_table;
197
size_t tcs_cache_in_use;
198
#ifdef CHECK_DOUBLE_READ
199
u_int tcs_total_reads;
200
u_int tcs_read_not_req;
202
} XTTabCacheSegRec, *XTTabCacheSegPtr;
205
* The free'er thread has a list of tables to be purged from the cache.
206
* If a table is in the list then it is not allowed to fetch a cache page from
208
* The free'er thread goes through all the cache, and removes
209
* all cache pages for any table in the purge list.
210
* When a table has been purged it signals any threads waiting for the
211
* purge to complete (this is usually due to a drop table).
213
typedef struct XTTabCachePurge {
214
int tcp_state; /* The state of the purge. */
215
XTTableSeqPtr tcp_tab_seq; /* Identifies the table to be purged from cache. */
216
} XTTabCachePurgeRec, *XTTabCachePurgePtr;
218
typedef struct XTTabCacheMem {
219
xt_mutex_type tcm_lock; /* The public cache lock. */
220
xt_cond_type tcm_cond; /* The public cache wait condition. */
221
XTTabCacheSegRec tcm_segment[XT_TC_SEGMENT_COUNT];
222
XTTabCachePagePtr tcm_lru_page;
223
XTTabCachePagePtr tcm_mru_page;
225
size_t tcm_approx_page_count;
226
size_t tcm_hash_size;
227
u_int tcm_writer_thread_count;
228
size_t tcm_cache_size;
229
size_t tcm_cache_high; /* The high water level of cache allocation. */
230
size_t tcm_low_level; /* This is the level to which the freeer will free, once it starts working. */
231
size_t tcm_high_level; /* This is the level at which the freeer will start to work (to avoid waiting)! */
232
size_t tcm_mid_level; /* At this level the freeer will not sleep if there are threads waiting. */
234
/* The free'er thread: */
235
struct XTThread *tcm_freeer_thread; /* The freeer thread . */
236
xt_mutex_type tcm_freeer_lock; /* The public cache lock. */
237
xt_cond_type tcm_freeer_cond; /* The public cache wait condition. */
238
u_int tcm_purge_list_len; /* The length of the purge list. */
239
XTTabCachePurgePtr tcm_purge_list; /* Non-NULL if a table is to be purged. */
240
u_int tcm_threads_waiting; /* Count of the number of threads waiting for the freeer. */
241
xtBool tcm_freeer_busy;
242
u_int tcm_free_try_count;
243
} XTTabCacheMemRec, *XTTabCacheMemPtr;
246
* This structure contains the information about a particular table
247
* for the cache. Each table has its own page size, row size
251
typedef struct XTTabCache {
252
struct XTTable *tci_table;
253
xtBool tci_rec_file; /* TRUE if this is a record file (handle data), as appossed to a row file. */
254
size_t tci_header_size;
255
size_t tci_page_size;
257
size_t tci_rows_per_page;
260
void xt_tc_setup(struct XTTable *tab, xtBool rec_file, size_t head_size, size_t row_size);
261
xtBool xt_tc_write(XT_ROW_REC_FILE_PTR file, xtRefID ref_id, size_t offset, size_t size, xtWord1 *data, xtOpSeqNo *op_seq, xtBool read, XTThreadPtr thread);
262
xtBool xt_tc_write_cond(XTThreadPtr self, XT_ROW_REC_FILE_PTR file, xtRefID ref_id, xtWord1 new_type, xtOpSeqNo *op_seq, xtXactID xn_id, xtRowID row_id, u_int stat_id, u_int rec_type);
263
xtBool xt_tc_read(XT_ROW_REC_FILE_PTR file, xtRefID ref_id, size_t size, xtWord1 *data, XTThreadPtr thread);
264
xtBool xt_tc_read_4(XT_ROW_REC_FILE_PTR file, xtRefID ref_id, xtWord4 *data, XTThreadPtr thread);
265
xtBool xt_tc_read_page(XT_ROW_REC_FILE_PTR file, xtRefID ref_id, xtWord1 *data, XTThreadPtr thread);
266
xtBool xt_tc_get_page(XT_ROW_REC_FILE_PTR file, xtRefID ref_id, xtBool load, XTTabCachePagePtr *page, size_t *offset, XTThreadPtr thread);
267
void xt_tc_release_page(XT_ROW_REC_FILE_PTR file, XTTabCachePagePtr page, XTThreadPtr thread);
268
xtBool tc_fetch(XT_ROW_REC_FILE_PTR file, xtRefID ref_id, XTTabCacheSegPtr *ret_seg, XTTabCachePagePtr *ret_page, size_t *offset, xtBool read, XTThreadPtr thread);
270
xtBool xt_tc_lock_page(XT_ROW_REC_FILE_PTR file, XTTabCachePagePtr *page, xtRefID ref_id, size_t *offset, XTThreadPtr thread);
271
void xt_tc_unlock_page(XT_ROW_REC_FILE_PTR file, XTTabCachePagePtr page, xtOpSeqNo *op_seq, XTThreadPtr thread);
274
xtBool tc_read_direct(XT_ROW_REC_FILE_PTR file, xtRefID ref_id, size_t size, xtWord1 *data, XTThreadPtr thread);
275
xtBool tc_fetch_direct(XT_ROW_REC_FILE_PTR file, xtRefID ref_id, XTTabCacheSegPtr *ret_seg, XTTabCachePagePtr *ret_page, size_t *offset, XTThreadPtr thread);
276
} XTTabCacheRec, *XTTabCachePtr;
278
extern XTTabCacheMemRec xt_tab_cache;
280
void xt_tc_init(XTThreadPtr self, size_t cache_size);
281
void xt_tc_exit(XTThreadPtr self);
282
void xt_tc_set_cache_size(size_t cache_size);
283
xtInt8 xt_tc_get_usage();
284
xtInt8 xt_tc_get_size();
285
xtInt8 xt_tc_get_high();
286
void xt_load_pages(XTThreadPtr self, struct XTOpenTable *ot);
288
void xt_check_table_cache(struct XTTable *tab);
291
void xt_quit_freeer(XTThreadPtr self);
292
void xt_stop_freeer(XTThreadPtr self);
293
void xt_start_freeer(XTThreadPtr self);
294
void xt_wr_wake_freeer(XTThreadPtr self, struct XTDatabase *db);