/* Copyright (C) 2006 MySQL AB Copyright (c) 2011, 2020, MariaDB Corporation Ab 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; version 2 of the License. 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 Street, Fifth Floor, Boston, MA 02110-1335 USA */ /* Page cache variable structures */ #ifndef _ma_pagecache_h #define _ma_pagecache_h C_MODE_START #include "ma_loghandler_lsn.h" #include #include /* Type of the page */ enum pagecache_page_type { /* Used only for control page type changing during debugging. This define should only be using when using DBUG. */ PAGECACHE_EMPTY_PAGE, /* the page does not contain LSN */ PAGECACHE_PLAIN_PAGE, /* the page contain LSN (maria tablespace page) */ PAGECACHE_LSN_PAGE, /* Page type used when scanning file and we don't care about the type */ PAGECACHE_READ_UNKNOWN_PAGE }; /* This enum describe lock status changing. every type of page cache will interpret WRITE/READ lock as it need. */ enum pagecache_page_lock { PAGECACHE_LOCK_LEFT_UNLOCKED, /* free -> free */ PAGECACHE_LOCK_LEFT_READLOCKED, /* read -> read */ PAGECACHE_LOCK_LEFT_WRITELOCKED, /* write -> write */ PAGECACHE_LOCK_READ, /* free -> read */ PAGECACHE_LOCK_WRITE, /* free -> write */ PAGECACHE_LOCK_READ_UNLOCK, /* read -> free */ PAGECACHE_LOCK_WRITE_UNLOCK, /* write -> free */ PAGECACHE_LOCK_WRITE_TO_READ /* write -> read */ }; /* This enum describe pin status changing */ enum pagecache_page_pin { PAGECACHE_PIN_LEFT_PINNED, /* pinned -> pinned */ PAGECACHE_PIN_LEFT_UNPINNED, /* unpinned -> unpinned */ PAGECACHE_PIN, /* unpinned -> pinned */ PAGECACHE_UNPIN /* pinned -> unpinned */ }; /* How to write the page */ enum pagecache_write_mode { /* do not write immediately, i.e. it will be dirty page */ PAGECACHE_WRITE_DELAY, /* page already is in the file. (key cache insert analogue) */ PAGECACHE_WRITE_DONE }; /* page number for maria */ typedef ulonglong pgcache_page_no_t; /* args for read/write hooks */ typedef struct st_pagecache_io_hook_args { uchar * page; pgcache_page_no_t pageno; uchar * data; uchar *crypt_buf; /* when using encryption */ } PAGECACHE_IO_HOOK_ARGS; struct st_pagecache; /* Structure to store things from get_object */ typedef struct st_S3_BLOCK { uchar *str, *alloc_ptr; size_t length; } S3_BLOCK; /* file descriptor for Maria */ typedef struct st_pagecache_file { /* Number of pages in the header which are not read with big blocks */ size_t head_blocks; /* size of a big block for S3 or 0 */ size_t big_block_size; /* File number */ File file; /** Cannot be NULL */ my_bool (*pre_read_hook)(PAGECACHE_IO_HOOK_ARGS *args); my_bool (*post_read_hook)(int error, PAGECACHE_IO_HOOK_ARGS *args); /** Cannot be NULL */ my_bool (*pre_write_hook)(PAGECACHE_IO_HOOK_ARGS *args); void (*post_write_hook)(int error, PAGECACHE_IO_HOOK_ARGS *args); my_bool (*flush_log_callback)(PAGECACHE_IO_HOOK_ARGS *args); /** Cannot be NULL */ uchar *callback_data; } PAGECACHE_FILE; /* declare structures that is used by st_pagecache */ struct st_pagecache_block_link; typedef struct st_pagecache_block_link PAGECACHE_BLOCK_LINK; struct st_pagecache_page; typedef struct st_pagecache_page PAGECACHE_PAGE; struct st_pagecache_hash_link; typedef struct st_pagecache_hash_link PAGECACHE_HASH_LINK; #include /* Default size of hash for changed files */ #define MIN_PAGECACHE_CHANGED_BLOCKS_HASH_SIZE 512 #define PAGECACHE_PRIORITY_LOW 0 #define PAGECACHE_PRIORITY_DEFAULT 3 #define PAGECACHE_PRIORITY_HIGH 6 /* The page cache structure It also contains read-only statistics parameters. */ typedef struct st_pagecache { size_t mem_size; /* specified size of the cache memory */ size_t min_warm_blocks; /* min number of warm blocks; */ size_t age_threshold; /* age threshold for hot blocks */ ulonglong time; /* total number of block link operations */ size_t hash_entries; /* max number of entries in the hash table */ size_t changed_blocks_hash_size;/* Number of hash buckets for file blocks */ ssize_t hash_links; /* max number of hash links */ ssize_t hash_links_used; /* number of hash links taken from free links pool */ ssize_t disk_blocks; /* max number of blocks in the cache */ size_t blocks_used; /* maximum number of concurrently used blocks */ size_t blocks_unused; /* number of currently unused blocks */ size_t blocks_changed; /* number of currently dirty blocks */ size_t warm_blocks; /* number of blocks in warm sub-chain */ size_t cnt_for_resize_op; /* counter to block resize operation */ size_t blocks_available; /* number of blocks available in the LRU chain */ ssize_t blocks; /* max number of blocks in the cache */ uint32 block_size; /* size of the page buffer of a cache block */ PAGECACHE_HASH_LINK **hash_root;/* arr. of entries into hash table buckets */ PAGECACHE_HASH_LINK *hash_link_root;/* memory for hash table links */ PAGECACHE_HASH_LINK *free_hash_list;/* list of free hash links */ PAGECACHE_BLOCK_LINK *free_block_list;/* list of free blocks */ PAGECACHE_BLOCK_LINK *block_root;/* memory for block links */ uchar *block_mem; /* memory for block buffers */ PAGECACHE_BLOCK_LINK *used_last;/* ptr to the last block of the LRU chain */ PAGECACHE_BLOCK_LINK *used_ins;/* ptr to the insertion block in LRU chain */ mysql_mutex_t cache_lock; /* to lock access to the cache structure */ WQUEUE resize_queue; /* threads waiting during resize operation */ WQUEUE waiting_for_hash_link;/* waiting for a free hash link */ WQUEUE waiting_for_block; /* requests waiting for a free block */ /* hash for dirty file bl.*/ PAGECACHE_BLOCK_LINK **changed_blocks; /* hash for other file bl.*/ PAGECACHE_BLOCK_LINK **file_blocks; /** Function for reading file in big hunks from S3 Data will be filled with pointer and length to data read start_page will be contain first page read. */ my_bool (*big_block_read)(struct st_pagecache *pagecache, PAGECACHE_IO_HOOK_ARGS *args, struct st_pagecache_file *file, S3_BLOCK *data); void (*big_block_free)(S3_BLOCK *data); /* The following variables are and variables used to hold parameters for initializing the key cache. */ ulonglong param_buff_size; /* size the memory allocated for the cache */ size_t param_block_size; /* size of the blocks in the key cache */ size_t param_division_limit; /* min. percentage of warm blocks */ size_t param_age_threshold; /* determines when hot block is downgraded */ /* Statistics variables. These are reset in reset_pagecache_counters(). */ size_t global_blocks_changed; /* number of currently dirty blocks */ ulonglong global_cache_w_requests;/* number of write requests (write hits) */ ulonglong global_cache_write; /* number of writes from cache to files */ ulonglong global_cache_r_requests;/* number of read requests (read hits) */ ulonglong global_cache_read; /* number of reads from files to cache */ uint shift; /* block size = 2 ^ shift */ myf readwrite_flags; /* Flags to pread/pwrite() */ myf org_readwrite_flags; /* Flags to pread/pwrite() at init */ my_bool inited; my_bool resize_in_flush; /* true during flush of resize operation */ my_bool can_be_used; /* usage of cache for read/write is allowed */ my_bool in_init; /* Set to 1 in MySQL during init/resize */ my_bool extra_debug; /* set to 1 if one wants extra logging */ HASH files_in_flush; /**< files in flush_pagecache_blocks_int() */ } PAGECACHE; /** @brief Return values for PAGECACHE_FLUSH_FILTER */ enum pagecache_flush_filter_result { FLUSH_FILTER_SKIP_TRY_NEXT= 0,/**< skip page and move on to next one */ FLUSH_FILTER_OK, /**< flush page and move on to next one */ FLUSH_FILTER_SKIP_ALL /**< skip page and all next ones */ }; /** @brief a filter function type for flush_pagecache_blocks_with_filter() */ typedef enum pagecache_flush_filter_result (*PAGECACHE_FLUSH_FILTER)(enum pagecache_page_type type, pgcache_page_no_t page, LSN rec_lsn, void *arg); /* The default key cache */ extern PAGECACHE dflt_pagecache_var, *dflt_pagecache; extern size_t init_pagecache(PAGECACHE *pagecache, size_t use_mem, uint division_limit, uint age_threshold, uint block_size, uint changed_blocks_hash_size, myf my_read_flags)__attribute__((visibility("default"))) ; extern size_t resize_pagecache(PAGECACHE *pagecache, size_t use_mem, uint division_limit, uint age_threshold, uint changed_blocks_hash_size); extern void change_pagecache_param(PAGECACHE *pagecache, uint division_limit, uint age_threshold); extern uchar *pagecache_read(PAGECACHE *pagecache, PAGECACHE_FILE *file, pgcache_page_no_t pageno, uint level, uchar *buff, enum pagecache_page_type type, enum pagecache_page_lock lock, PAGECACHE_BLOCK_LINK **link); #define pagecache_write(P,F,N,L,B,T,O,I,M,K,R) \ pagecache_write_part(P,F,N,L,B,T,O,I,M,K,R,0,(P)->block_size) #define pagecache_inject(P,F,N,L,B,T,O,I,K,R) \ pagecache_write_part(P,F,N,L,B,T,O,I,PAGECACHE_WRITE_DONE, \ K,R,0,(P)->block_size) extern my_bool pagecache_write_part(PAGECACHE *pagecache, PAGECACHE_FILE *file, pgcache_page_no_t pageno, uint level, uchar *buff, enum pagecache_page_type type, enum pagecache_page_lock lock, enum pagecache_page_pin pin, enum pagecache_write_mode write_mode, PAGECACHE_BLOCK_LINK **link, LSN first_REDO_LSN_for_page, uint offset, uint size); extern void pagecache_unlock(PAGECACHE *pagecache, PAGECACHE_FILE *file, pgcache_page_no_t pageno, enum pagecache_page_lock lock, enum pagecache_page_pin pin, LSN first_REDO_LSN_for_page, LSN lsn, my_bool was_changed); extern void pagecache_unlock_by_link(PAGECACHE *pagecache, PAGECACHE_BLOCK_LINK *block, enum pagecache_page_lock lock, enum pagecache_page_pin pin, LSN first_REDO_LSN_for_page, LSN lsn, my_bool was_changed, my_bool any); extern void pagecache_unpin(PAGECACHE *pagecache, PAGECACHE_FILE *file, pgcache_page_no_t pageno, LSN lsn); extern void pagecache_unpin_by_link(PAGECACHE *pagecache, PAGECACHE_BLOCK_LINK *link, LSN lsn); extern void pagecache_set_write_on_delete_by_link(PAGECACHE_BLOCK_LINK *block); /* Results of flush operation (bit field in fact) */ /* The flush is done. */ #define PCFLUSH_OK 0 /* There was errors during the flush process. */ #define PCFLUSH_ERROR 1 /* Pinned blocks was met and skipped. */ #define PCFLUSH_PINNED 2 /* PCFLUSH_ERROR and PCFLUSH_PINNED. */ #define PCFLUSH_PINNED_AND_ERROR (PCFLUSH_ERROR|PCFLUSH_PINNED) // initialize file with empty hooks void pagecache_file_set_null_hooks(PAGECACHE_FILE*); #define flush_pagecache_blocks(A,B,C) \ flush_pagecache_blocks_with_filter(A,B,C,NULL,NULL) extern int flush_pagecache_blocks_with_filter(PAGECACHE *keycache, PAGECACHE_FILE *file, enum flush_type type, PAGECACHE_FLUSH_FILTER filter, void *filter_arg)__attribute__((visibility("default"))) ; extern my_bool pagecache_delete(PAGECACHE *pagecache, PAGECACHE_FILE *file, pgcache_page_no_t pageno, enum pagecache_page_lock lock, my_bool flush); extern my_bool pagecache_delete_by_link(PAGECACHE *pagecache, PAGECACHE_BLOCK_LINK *link, enum pagecache_page_lock lock, my_bool flush); extern my_bool pagecache_delete_pages(PAGECACHE *pagecache, PAGECACHE_FILE *file, pgcache_page_no_t pageno, uint page_count, enum pagecache_page_lock lock, my_bool flush); extern void end_pagecache(PAGECACHE *keycache, my_bool cleanup)__attribute__((visibility("default"))) ; extern my_bool pagecache_collect_changed_blocks_with_lsn(PAGECACHE *pagecache, LEX_STRING *str, LSN *min_lsn); extern int reset_pagecache_counters(const char *name, PAGECACHE *pagecache); extern uchar *pagecache_block_link_to_buffer(PAGECACHE_BLOCK_LINK *block); extern uint pagecache_pagelevel(PAGECACHE_BLOCK_LINK *block); extern void pagecache_add_level_by_link(PAGECACHE_BLOCK_LINK *block, uint level); /* Functions to handle multiple key caches */ extern my_bool multi_pagecache_init(void); extern void multi_pagecache_free(void); extern PAGECACHE *multi_pagecache_search(uchar *key, uint length, PAGECACHE *def); extern my_bool multi_pagecache_set(const uchar *key, uint length, PAGECACHE *pagecache); extern void multi_pagecache_change(PAGECACHE *old_data, PAGECACHE *new_data); #ifndef DBUG_OFF void pagecache_file_no_dirty_page(PAGECACHE *pagecache, PAGECACHE_FILE *file); #else #define pagecache_file_no_dirty_page(A,B) {} #endif C_MODE_END #endif /* _keycache_h */