tabcache_xt.h 11.1 KB
Newer Older
Paul McCullagh's avatar
Paul McCullagh committed
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
/* Copyright (c) 2007 PrimeBase Technologies GmbH
 *
 * PrimeBase XT
 *
 * This program 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; either version 2 of the License, or
 * (at your option) any later version.
 *
 * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 * 2007-10-31	Paul McCullagh
 *
 * H&G2JCtL
 *
 * The new table cache. Caches all non-index data. This includes the data
 * files and the row pointer files.
 */
#ifndef __tabcache_h__
#define __tabcache_h__

struct XTTable;
struct XTOpenTable;
struct XTTabCache;
Paul McCullagh's avatar
Paul McCullagh committed
32
struct XTDatabase;
Paul McCullagh's avatar
Paul McCullagh committed
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

#include "thread_xt.h"
#include "filesys_xt.h"
#include "lock_xt.h"

#ifdef DEBUG
//#define XT_USE_CACHE_DEBUG_SIZES
//#define XT_NOT_INLINE
#endif

#ifdef XT_USE_CACHE_DEBUG_SIZES

#define XT_TC_PAGE_SIZE				(4*1024)
#define XT_TC_SEGMENT_SHIFTS		1

#else

#define XT_TC_PAGE_SIZE				(32*1024)
#define XT_TC_SEGMENT_SHIFTS		3

#endif

#define XT_TIME_DIFF(start, now) (\
	((xtWord4) (now) < (xtWord4) (start)) ? \
	((xtWord4) 0XFFFFFFFF - ((xtWord4) (start) - (xtWord4) (now))) : \
	((xtWord4) (now) - (xtWord4) (start)))

#define XT_TC_SEGMENT_COUNT			((off_t) 1 << XT_TC_SEGMENT_SHIFTS)
#define XT_TC_SEGMENT_MASK			(XT_TC_SEGMENT_COUNT - 1)

typedef struct XTTabCachePage {
	xtWord1					tcp_dirty;						/* TRUE if the page is dirty. */
	xtWord1					tcp_seg;						/* Segement number of the page. */
	u_int					tcp_lock_count;					/* Number of read locks on this page. */
	u_int					tcp_hash_idx;					/* The hash index of the page. */
	u_int					tcp_page_idx;					/* The page address. */
	u_int					tcp_file_id;					/* The file id of the page. */
	xtDatabaseID			tcp_db_id;						/* The ID of the database. */
	xtTableID				tcp_tab_id;						/* The ID of the table of this cache page. */
	xtWord4					tcp_data_size;					/* Size of the data on this page. */
	xtOpSeqNo				tcp_op_seq;						/* The operation sequence number (dirty pages have a operations sequence) */
	xtWord4					tcp_ru_time;					/* If this is in the top 1/4 don't change position in MRU list. */
	struct XTTabCachePage	*tcp_next;						/* Pointer to next page on hash list, or next free page on free list. */
	struct XTTabCachePage	*tcp_mr_used;					/* More recently used pages. */
	struct XTTabCachePage	*tcp_lr_used;					/* Less recently used pages. */
	xtWord1					tcp_data[XT_TC_PAGE_SIZE];		/* This is actually tci_page_size! */
} XTTabCachePageRec, *XTTabCachePagePtr;

/*
 * Each table has a "table operation sequence". This sequence is incremented by
 * each operation on the table. Each operation in the log is tagged by a
 * sequence number.
 *
 * The writter threads re-order operations in the log, and write the operations
 * to the database in sequence.
 *
 * It is safe to free a cache page when the sequence number of the cache page,
 * is less than or equal to the written sequence number.
 */
typedef struct XTTableSeq {
	xtOpSeqNo				ts_next_seq;					/* The next sequence number for operations on the table. */
	xt_mutex_type			ts_ns_lock;						/* Lock for the next sequence number. */

	xtBool ts_log_no_op(XTThreadPtr thread, xtTableID tab_id, xtOpSeqNo op_seq);

	/* Return the next operation sequence number. */
#ifdef XT_NOT_INLINE
	xtOpSeqNo ts_set_op_seq(XTTabCachePagePtr page);

	xtOpSeqNo ts_get_op_seq();
#else
	xtOpSeqNo ts_set_op_seq(XTTabCachePagePtr page)
	{
		xtOpSeqNo seq;

		xt_lock_mutex_ns(&ts_ns_lock);
		page->tcp_op_seq = seq = ts_next_seq++;
		xt_unlock_mutex_ns(&ts_ns_lock);
		return seq;
	}

	xtOpSeqNo ts_get_op_seq()
	{
		xtOpSeqNo seq;

		xt_lock_mutex_ns(&ts_ns_lock);
		seq = ts_next_seq++;
		xt_unlock_mutex_ns(&ts_ns_lock);
		return seq;
	}
#endif

	void xt_op_seq_init(XTThreadPtr self) {
		xt_init_mutex_with_autoname(self, &ts_ns_lock);
	}

129
	void xt_op_seq_set(XTThreadPtr XT_UNUSED(self), xtOpSeqNo n) {
Paul McCullagh's avatar
Paul McCullagh committed
130 131 132
		ts_next_seq = n;
	}

133
	void xt_op_seq_exit(XTThreadPtr XT_UNUSED(self)) {
Paul McCullagh's avatar
Paul McCullagh committed
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
		xt_free_mutex(&ts_ns_lock);
	}

#ifdef XT_NOT_INLINE
	static xtBool xt_op_is_before(register xtOpSeqNo now, register xtOpSeqNo then);
#else
	static inline xtBool xt_op_is_before(register xtOpSeqNo now, register xtOpSeqNo then)
	{
		if (now >= then) {
			if ((now - then) > (xtOpSeqNo) 0xFFFFFFFF/2)
				return TRUE;
			return FALSE;
		}
		if ((then - now) > (xtOpSeqNo) 0xFFFFFFFF/2)
			return FALSE;
		return TRUE;
	}
#endif
} XTTableSeqRec, *XTTableSeqPtr;

154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
#ifdef XT_NO_ATOMICS
#define TAB_CAC_USE_PTHREAD_RW
#else
//#define TAB_CAC_USE_RWMUTEX
//#define TAB_CAC_USE_PTHREAD_RW
//#define IDX_USE_SPINXSLOCK
#define TAB_CAC_USE_XSMUTEX
#endif

#ifdef TAB_CAC_USE_XSMUTEX
#define TAB_CAC_LOCK_TYPE				XTXSMutexRec
#define TAB_CAC_INIT_LOCK(s, i)			xt_xsmutex_init_with_autoname(s, i)
#define TAB_CAC_FREE_LOCK(s, i)			xt_xsmutex_free(s, i)	
#define TAB_CAC_READ_LOCK(i, o)			xt_xsmutex_slock(i, o)
#define TAB_CAC_WRITE_LOCK(i, o)		xt_xsmutex_xlock(i, o)
#define TAB_CAC_UNLOCK(i, o)			xt_xsmutex_unlock(i, o)
#elif defined(TAB_CAC_USE_PTHREAD_RW)
#define TAB_CAC_LOCK_TYPE				xt_rwlock_type
172
#define TAB_CAC_INIT_LOCK(s, i)			xt_init_rwlock_with_autoname(s, i)
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
#define TAB_CAC_FREE_LOCK(s, i)			xt_free_rwlock(i)	
#define TAB_CAC_READ_LOCK(i, o)			xt_slock_rwlock_ns(i)
#define TAB_CAC_WRITE_LOCK(i, o)		xt_xlock_rwlock_ns(i)
#define TAB_CAC_UNLOCK(i, o)			xt_unlock_rwlock_ns(i)
#elif defined(TAB_CAC_USE_RWMUTEX)
#define TAB_CAC_LOCK_TYPE				XTRWMutexRec
#define TAB_CAC_INIT_LOCK(s, i)			xt_rwmutex_init_with_autoname(s, i)
#define TAB_CAC_FREE_LOCK(s, i)			xt_rwmutex_free(s, i)	
#define TAB_CAC_READ_LOCK(i, o)			xt_rwmutex_slock(i, o)
#define TAB_CAC_WRITE_LOCK(i, o)		xt_rwmutex_xlock(i, o)
#define TAB_CAC_UNLOCK(i, o)			xt_rwmutex_unlock(i, o)
#elif defined(TAB_CAC_USE_SPINXSLOCK)
#define TAB_CAC_LOCK_TYPE				XTSpinXSLockRec
#define TAB_CAC_INIT_LOCK(s, i)			xt_spinxslock_init_with_autoname(s, i)
#define TAB_CAC_FREE_LOCK(s, i)			xt_spinxslock_free(s, i)	
#define TAB_CAC_READ_LOCK(i, o)			xt_spinxslock_slock(i, o)
#define TAB_CAC_WRITE_LOCK(i, o)		xt_spinxslock_xlock(i, o)
#define TAB_CAC_UNLOCK(i, o)			xt_spinxslock_unlock(i, o)
#endif

Paul McCullagh's avatar
Paul McCullagh committed
193 194 195 196
/* A disk cache segment. The cache is divided into a number of segments
 * to improve concurrency.
 */
typedef struct XTTabCacheSeg {
197
	TAB_CAC_LOCK_TYPE		tcs_lock;						/* The cache segment read/write lock. */
Paul McCullagh's avatar
Paul McCullagh committed
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
	XTTabCachePagePtr		*tcs_hash_table;
	size_t					tcs_cache_in_use;
} XTTabCacheSegRec, *XTTabCacheSegPtr;

/*
 * The free'er thread has a list of tables to be purged from the cache.
 * If a table is in the list then it is not allowed to fetch a cache page from
 * that table.
 * The free'er thread goes through all the cache, and removes
 * all cache pages for any table in the purge list.
 * When a table has been purged it signals any threads waiting for the
 * purge to complete (this is usually due to a drop table).
 */
typedef struct XTTabCachePurge {
	int						tcp_state;						/* The state of the purge. */
	XTTableSeqPtr			tcp_tab_seq;					/* Identifies the table to be purged from cache. */
} XTTabCachePurgeRec, *XTTabCachePurgePtr;

typedef struct XTTabCacheMem {
	xt_mutex_type			tcm_lock;						/* The public cache lock. */
	xt_cond_type			tcm_cond;						/* The public cache wait condition. */
	XTTabCacheSegRec		tcm_segment[XT_TC_SEGMENT_COUNT];
	XTTabCachePagePtr		tcm_lru_page;
	XTTabCachePagePtr		tcm_mru_page;
	xtWord4					tcm_ru_now;
	size_t					tcm_approx_page_count;
	size_t					tcm_hash_size;
	u_int					tcm_writer_thread_count;
	size_t					tcm_cache_size;
	size_t					tcm_cache_high;					/* The high water level of cache allocation. */
	size_t					tcm_low_level;					/* This is the level to which the freeer will free, once it starts working. */
	size_t					tcm_high_level;					/* This is the level at which the freeer will start to work (to avoid waiting)! */
Paul McCullagh's avatar
Paul McCullagh committed
230
	size_t					tcm_mid_level;					/* At this level the freeer will not sleep if there are threads waiting. */
Paul McCullagh's avatar
Paul McCullagh committed
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

	/* The free'er thread: */
	struct XTThread			*tcm_freeer_thread;				/* The freeer thread . */
	xt_mutex_type			tcm_freeer_lock;				/* The public cache lock. */
	xt_cond_type			tcm_freeer_cond;				/* The public cache wait condition. */
	u_int					tcm_purge_list_len;				/* The length of the purge list. */
	XTTabCachePurgePtr		tcm_purge_list;					/* Non-NULL if a table is to be purged. */
	u_int					tcm_threads_waiting;			/* Count of the number of threads waiting for the freeer. */
	xtBool					tcm_freeer_busy;
	u_int					tcm_free_try_count;
} XTTabCacheMemRec, *XTTabCacheMemPtr;

/*
 * This structure contains the information about a particular table
 * for the cache. Each table has its own page size, row size
 * and rows per page.
 * Tables also have 
 */
typedef struct XTTabCache {
	struct XTTable			*tci_table;
	size_t					tci_header_size;
	size_t					tci_page_size;
	size_t					tci_rec_size;
	size_t					tci_rows_per_page;

public:
	void					xt_tc_setup(struct XTTable *tab, size_t head_size, size_t row_size);
	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);
	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);
	xtBool					xt_tc_read(XT_ROW_REC_FILE_PTR file, xtRefID ref_id, size_t size, xtWord1 *data, XTThreadPtr thread);
	xtBool					xt_tc_read_4(XT_ROW_REC_FILE_PTR file, xtRefID ref_id, xtWord4 *data, XTThreadPtr thread);
	xtBool					xt_tc_read_page(XT_ROW_REC_FILE_PTR file, xtRefID ref_id, xtWord1 *data, XTThreadPtr thread);
263
	xtBool					xt_tc_get_page(XT_ROW_REC_FILE_PTR file, xtRefID ref_id, xtBool load, XTTabCachePagePtr *page, size_t *offset, XTThreadPtr thread);
Paul McCullagh's avatar
Paul McCullagh committed
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
	void					xt_tc_release_page(XT_ROW_REC_FILE_PTR file, XTTabCachePagePtr page, XTThreadPtr thread);
	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);

private:
	xtBool					tc_read_direct(XT_ROW_REC_FILE_PTR file, xtRefID ref_id, size_t size, xtWord1 *data, XTThreadPtr thread);
	xtBool					tc_fetch_direct(XT_ROW_REC_FILE_PTR file, xtRefID ref_id, XTTabCacheSegPtr *ret_seg, XTTabCachePagePtr *ret_page, size_t *offset, XTThreadPtr thread);
} XTTabCacheRec, *XTTabCachePtr;

extern XTTabCacheMemRec xt_tab_cache;

void	xt_tc_init(XTThreadPtr self, size_t cache_size);
void	xt_tc_exit(XTThreadPtr self);
void	xt_tc_set_cache_size(size_t cache_size);
xtInt8	xt_tc_get_usage();
xtInt8	xt_tc_get_size();
xtInt8	xt_tc_get_high();
void	xt_load_pages(XTThreadPtr self, struct XTOpenTable *ot);
#ifdef DEBUG
void	xt_check_table_cache(struct XTTable *tab);
#endif

void	xt_quit_freeer(XTThreadPtr self);
void	xt_stop_freeer(XTThreadPtr self);
void	xt_start_freeer(XTThreadPtr self);
Paul McCullagh's avatar
Paul McCullagh committed
288
void	xt_wr_wake_freeer(XTThreadPtr self, struct XTDatabase *db);
Paul McCullagh's avatar
Paul McCullagh committed
289 290

#endif