Commit 52cb0c24 authored by Michael Widenius's avatar Michael Widenius

Added versioning of Maria index

Store max_trid in index file as state.create_trid. This is used to pack all transids in the index pages relative to max possible transid for file.
Enable versioning for transactional tables with index. Tables with an auto-increment key, rtree or fulltext keys are not versioned.
Changed info->lastkey to type MARIA_KEY. Removed info->lastkey_length as this is now part of info->lastkey
Renamed old info->lastkey to info->lastkey_buff
Use exact key lenghts for keys, not USE_WHOLE_KEY
For partial key searches, use SEARCH_PART_KEY
When searching to insert new key on page, use SEARCH_INSERT to mark that key has rowid

Changes done in a lot of files:
- Modified functions to use MARIA_KEY instead of key pointer and key length
- Use keyinfo->root_lock instead of share->key_root_lock[keynr]
- Simplify code by using local variable keyinfo instead if share->keyinfo[i]
- Added #fdef EXTERNAL_LOCKING around removed state elements
- HA_MAX_KEY_BUFF -> MARIA_MAX_KEY_BUFF (to reserve space for transid)
- Changed type of 'nextflag' to uint32 to ensure all SEARCH_xxx flags fits into it

.bzrignore:
  Added missing temporary directory
extra/Makefile.am:
  comp_err is now deleted on make distclean
include/maria.h:
  Added structure MARIA_KEY, which is used for intern key objects in Maria.
  Changed functions to take MARIA_KEY as an argument instead of pointer to packed key.
  Changed some functions that always return true or false to my_bool.
  Added virtual function make_key() to avoid if in _ma_make_key()
  Moved rw_lock_t for locking trees from share->key_root_lock to MARIA_KEYDEF. This makes usage of the locks simpler and faster
include/my_base.h:
  Added HA_RTREE_INDEX flag to mark rtree index. Used for easier checks in ma_check()
  Added SEARCH_INSERT to be used when inserting new keys
  Added SEARCH_PART_KEY for partial searches
  Added SEARCH_USER_KEY_HAS_TRANSID to be used when key we use for searching in btree has a TRANSID
  Added SEARCH_PAGE_KEY_HAS_TRANSID to be used when key we found in btree has a transid
include/my_handler.h:
  Make next_flag 32 bit to make sure we can handle all SEARCH_ bits
mysql-test/include/maria_empty_logs.inc:
  Read and restore current database; Don't assume we are using mysqltest.
  Don't log use databasename to log. Using this include should not cause any result changes.
mysql-test/r/maria-gis-rtree-dynamic.result:
  Updated results after adding some check table commands to help pinpoint errors
mysql-test/r/maria-mvcc.result:
  New tests
mysql-test/r/maria-purge.result:
  New result after adding removal of logs
mysql-test/r/maria-recovery-big.result:
  maria_empty_logs doesn't log 'use mysqltest' anymore
mysql-test/r/maria-recovery-bitmap.result:
  maria_empty_logs doesn't log 'use mysqltest' anymore
mysql-test/r/maria-recovery-rtree-ft.result:
  maria_empty_logs doesn't log 'use mysqltest' anymore
mysql-test/r/maria-recovery.result:
  maria_empty_logs doesn't log 'use mysqltest' anymore
mysql-test/r/maria.result:
  New tests
mysql-test/r/variables-big.result:
  Don't log id as it's not predictable
mysql-test/suite/rpl_ndb/r/rpl_truncate_7ndb_2.result:
  Updated results to new binlog results. (Test has not been run in a long time as it requires --big)
mysql-test/suite/rpl_ndb/t/rpl_truncate_7ndb_2-master.opt:
  Moved file to ndb replication test directory
mysql-test/suite/rpl_ndb/t/rpl_truncate_7ndb_2.test:
  Fixed wrong path to included tests
mysql-test/t/maria-gis-rtree-dynamic.test:
  Added some check table commands to help pinpoint errors
mysql-test/t/maria-mvcc.test:
  New tests
mysql-test/t/maria-purge.test:
  Remove logs to make test results predictable
mysql-test/t/maria.test:
  New tests for some possible problems
mysql-test/t/variables-big.test:
  Don't log id as it's not predictable
mysys/my_handler.c:
  Updated function comment to reflect old code
  Changed nextflag to be uint32 to ensure we can have flags > 16 bit
  Changed checking if we are in insert with NULL keys as next_flag can now include additional bits that have to be ignored.
  Added SEARCH_INSERT flag to be used when inserting new keys in btree. This flag tells us the that the keys includes row position and it's thus safe to remove SEARCH_FIND
  Added comparision of transid. This is only done if the keys actually have a transid, which is indicated by nextflag
mysys/my_lock.c:
  Fixed wrong test (Found by Guilhem)
scripts/Makefile.am:
  Ensure that test programs are deleted by make clean
sql/rpl_rli.cc:
  Moved assignment order to fix compiler warning
storage/heap/hp_write.c:
  Add SEARCH_INSERT to signal ha_key_cmp that we we should also compare rowid for keys
storage/maria/Makefile.am:
  Remove also maria log files when doing make distclean
storage/maria/ha_maria.cc:
  Use 'file->start_state' as default state for transactional tables without versioning
  At table unlock, set file->state to point to live state. (Needed for information schema to pick up right number of rows)
  In ha_maria::implicit_commit() move all locked (ie open) tables to new transaction. This is needed to ensure ha_maria->info doesn't point to a deleted history event.
  Disable concurrent inserts for insert ... select and table changes with subqueries if statement based replication as this would cause wrong results on slave
storage/maria/ma_blockrec.c:
  Updated comment
storage/maria/ma_check.c:
  Compact key pages (removes transid) when doing --zerofill
  Check that 'page_flag' on key pages contains KEYPAGE_FLAG_HAS_TRANSID if there is a single key on the page with a transid
  Modified functions to use MARIA_KEY instead of key pointer and key length
  Use new interface to _ma_rec_pos(), _ma_dpointer(), _ma_ft_del(), ma_update_state_lsn()
  Removed not needed argument from get_record_for_key()
  Fixed that we check doesn't give errors for RTREE; We now treath these like SPATIAL
  Remove some SPATIAL specific code where the virtual functions can handle this in a general manner
  Use info->lastkey_buff instead of info->lastkey
  _ma_dpos() -> _ma_row_pos_from_key()
  _ma_make_key() -> keyinfo->make_key()
  _ma_print_key() -> _ma_print_keydata()
  _ma_move_key() -> ma_copy_copy()
  Add SEARCH_INSERT to signal ha_key_cmp that we we should also compare rowid for keys
  Ensure that data on page doesn't overwrite page checksum position
  Use DBUG_DUMP_KEY instead of DBUG_DUMP
  Use exact key lengths instead of USE_WHOLE_KEY to ha_key_cmp()
  Fixed check if rowid points outside of BLOCK_RECORD data file
  Use info->lastkey_buff instead of key on stack in some safe places
  Added #fdef EXTERNAL_LOCKING around removed state elements
storage/maria/ma_close.c:
  Use keyinfo->root_lock instead of share->key_root_lock[keynr]
storage/maria/ma_create.c:
  Removed assert that is already checked in maria_init()
  Force transactinal tables to be of type BLOCK_RECORD
  Fixed wrong usage of HA_PACK_RECORD (should be HA_OPTION_PACK_RECORD)
  Mark keys that uses HA_KEY_ALG_RTREE with HA_RTREE_INDEX for easier handling of these in ma_check
  Store max_trid in index file as state.create_trid. This is used to pack all transids in the index pages relative to max possible transid for file.
storage/maria/ma_dbug.c:
  Changed _ma_print_key() to use MARIA_KEY
storage/maria/ma_delete.c:
  Modified functions to use MARIA_KEY instead of key pointer and key length
  info->lastkey2-> info->lastkey_buff2
  Added SEARCH_INSERT to signal ha_key_cmp that we we should also compare rowid for keys
  Use new interface for get_key(), _ma_get_last_key() and others
  _ma_dpos() -> ma_row_pos_from_key()
  Simplify setting of prev_key in del()
  Ensure that KEYPAGE_FLAG_HAS_TRANSID is set in page_flag if key page has transid
  Treath key pages that may have a transid as if keys would be of variable length
storage/maria/ma_delete_all.c:
  Reset history state if maria_delete_all_rows() are called
  Update parameters to _ma_update_state_lsns() call
storage/maria/ma_extra.c:
  Store and restore info->lastkey
storage/maria/ma_ft_boolean_search.c:
  Modified functions to use MARIA_KEY instead of key pointer and key length
storage/maria/ma_ft_nlq_search.c:
  Modified functions to use MARIA_KEY instead of key pointer and key length
  Use lastkey_buff2 instead of info->lastkey+info->s->base.max_key_length (same thing)
storage/maria/ma_ft_update.c:
  Modified functions to use MARIA_KEY instead of key pointer and key length
storage/maria/ma_ftdefs.h:
  Modified functions to use MARIA_KEY instead of key pointer and key length
storage/maria/ma_fulltext.h:
  Modified functions to use MARIA_KEY instead of key pointer and key length
storage/maria/ma_init.c:
  Check if blocksize is legal
  (Moved test here from ma_open())
storage/maria/ma_key.c:
  Added functions for storing/reading of transid 
  Modified functions to use MARIA_KEY instead of key pointer and key length
  Moved _ma_sp_make_key() out of _ma_make_key() as we now use keyinfo->make_key to create keys
  Add transid to keys if table is versioned
  Added _ma_copy_key()
storage/maria/ma_key_recover.c:
  Add logging of page_flag (holds information if there are keys with transid on page)
  Changed DBUG_PRINT("info" -> DBUG_PRINT("redo" as the redo logging can be quite extensive
  Added lots of DBUG_PRINT()
  Added support for index page operations: KEY_OP_SET_PAGEFLAG and KEY_OP_COMPACT_PAGE
storage/maria/ma_key_recover.h:
  Modified functions to use MARIA_KEY instead of key pointer and key length
storage/maria/ma_locking.c:
  Added new arguments to _ma_update_state_lsns_sub()
storage/maria/ma_loghandler.c:
  Fixed all logging of LSN to look similar in DBUG log
  Changed if (left != 0) to if (left) as the later is used also later in the code
storage/maria/ma_loghandler.h:
  Added new index page operations
storage/maria/ma_open.c:
  Removed allocated "state_dummy" and instead use share->state.common for transactional tables that are not versioned
  This is needed to not get double increments of state.records (one in ma_write.c and on when log is written)
  Changed info->lastkey to MARIA_KEY type
  Removed resetting of MARIA_HA variables that have 0 as default value (as info is zerofilled)
  Enable versioning for transactional tables with index. Tables with an auto-increment key, rtree or fulltext keys are not versioned.
  Check on open that state.create_trid is correct
  Extend share->base.max_key_length in case of transactional table so that it can hold transid
  Removed 4.0 compatible fulltext key mode as this is not relevant for Maria
  Removed old and wrong #ifdef ENABLE_WHEN_WE_HAVE_TRANS_ROW_ID code block
  Initialize all new virtual function pointers
  Removed storing of state->unique, state->process and store state->create_trid instead
storage/maria/ma_page.c:
  Added comment to describe key page structure
  Added functions to compact key page and log the compact operation
storage/maria/ma_range.c:
  Modified functions to use MARIA_KEY instead of key pointer and key length
  Use SEARCH_PART_KEY indicator instead of USE_WHOLE_KEY to detect if we are doing a part key search
  Added handling of pages with transid
storage/maria/ma_recovery.c:
  Don't assert if table we opened are not transactional. This may be a table which has been changed from transactional to not transactinal
  Added new arguments to _ma_update_state_lsns()
storage/maria/ma_rename.c:
  Added new arguments to _ma_update_state_lsns()
storage/maria/ma_rkey.c:
  Modified functions to use MARIA_KEY instead of key pointer and key length
  Don't use USE_WHOLE_KEY, use real length of key
  Use share->row_is_visible() to test if row is visible
  Moved search_flag == HA_READ_KEY_EXACT out of 'read-next-row' loop as this only need to be tested once
  Removed test if last_used_keyseg != 0 as this is always true
storage/maria/ma_rnext.c:
  Modified functions to use MARIA_KEY instead of key pointer and key length
  Simplify code by using local variable keyinfo instead if share->keyinfo[i]
  Use share->row_is_visible() to test if row is visible
storage/maria/ma_rnext_same.c:
  Modified functions to use MARIA_KEY instead of key pointer and key length
  lastkey2 -> lastkey_buff2
storage/maria/ma_rprev.c:
  Modified functions to use MARIA_KEY instead of key pointer and key length
  Simplify code by using local variable keyinfo instead if share->keyinfo[i]
  Use share->row_is_visible() to test if row is visible
storage/maria/ma_rsame.c:
  Updated comment
  Simplify code by using local variable keyinfo instead if share->keyinfo[i]
  Modified functions to use MARIA_KEY instead of key pointer and key length
storage/maria/ma_rsamepos.c:
  Modified functions to use MARIA_KEY instead of key pointer and key length
storage/maria/ma_rt_index.c:
  Modified functions to use MARIA_KEY instead of key pointer and key length
  Use better variable names
  Removed not needed casts
  _ma_dpos() -> _ma_row_pos_from_key()
  Use info->last_rtree_keypos to save position to key instead of info->int_keypos
  Simplify err: condition
  Changed return type for maria_rtree_insert() to my_bool as we are only intressed in ok/fail from this function
storage/maria/ma_rt_index.h:
  Modified functions to use MARIA_KEY instead of key pointer and key length
storage/maria/ma_rt_key.c:
  Modified functions to use MARIA_KEY instead of key pointer and key length
  Simplify maria_rtree_add_key by combining idenitcal code and removing added_len
storage/maria/ma_rt_key.h:
  Modified functions to use MARIA_KEY instead of key pointer and key length
storage/maria/ma_rt_mbr.c:
  Changed type of 'nextflag' to uint32
  Added 'to' argument to RT_PAGE_MBR_XXX functions to more clearly see which variables changes value
storage/maria/ma_rt_mbr.h:
  Changed type of 'nextflag' to uint32
storage/maria/ma_rt_split.c:
  Modified functions to use MARIA_KEY instead of key pointer and key length
  key_length -> key_data_length to catch possible errors
storage/maria/ma_rt_test.c:
  Fixed wrong comment
  Reset recinfo to avoid valgrind varnings
  Fixed wrong argument to create_record() that caused test to fail
storage/maria/ma_search.c:
  Modified functions to use MARIA_KEY instead of key pointer and key length
  Added support of keys with optional trid
  Test for SEARCH_PART_KEY instead of USE_WHOLE_KEY to detect part key reads
  _ma_dpos() -> _ma_row_pos_from_key()
  If there may be keys with transid on the page, have _ma_bin_search() call _ma_seq_search()
  Add _ma_skip_xxx() functions to quickly step over keys (faster than calling get_key() in most cases as we don't have to copy key data)
  Combine similar code at end of _ma_get_binary_pack_key()
  Removed not used function _ma_move_key()
  In _ma_search_next() don't call _ma_search() if we aren't on a nod page.
  Update info->cur_row.trid with trid for found key
  
  
  
  Removed some not needed casts
  Added _ma_trid_from_key()
  Use MARIA_SHARE instead of MARIA_HA as arguments to _ma_rec_pos(), _ma_dpointer() and _ma_xxx_keypos_to_recpos() to make functions faster and smaller
storage/maria/ma_sort.c:
  Modified functions to use MARIA_KEY instead of key pointer and key length
storage/maria/ma_sp_defs.h:
  _ma_sp_make_key() now fills in and returns (MARIA_KEY *) value
storage/maria/ma_sp_key.c:
  _ma_sp_make_key() now fills in and returns (MARIA_KEY *) value
  Don't test sizeof(double), test against 8 as we are using float8store()
  Use mi_float8store() instead of doing swap of value (same thing but faster)
storage/maria/ma_state.c:
  maria_versioning() now only calls _ma_block_get_status() if table supports versioning
  Added _ma_row_visible_xxx() functions for different occasions
  When emptying history, set info->state to point to the first history event.
storage/maria/ma_state.h:
  Added _ma_row_visible_xxx() prototypes
storage/maria/ma_static.c:
  Indentation changes
storage/maria/ma_statrec.c:
  Fixed arguments to _ma_dpointer() and _ma_rec_pos()
storage/maria/ma_test1.c:
  Call init_thr_lock() if we have versioning
storage/maria/ma_test2.c:
  Call init_thr_lock() if we have versioning
storage/maria/ma_unique.c:
  Modified functions to use MARIA_KEY
storage/maria/ma_update.c:
  Modified functions to use MARIA_KEY instead of key pointer and key length
storage/maria/ma_write.c:
  Modified functions to use MARIA_KEY instead of key pointer and key length
  Simplify code by using local variable keyinfo instead if share->keyinfo[i]
  In _ma_enlarge_root(), mark in page_flag if new key has transid
  _ma_dpos() -> _ma_row_pos_from_key()
  Changed return type of _ma_ck_write_tree() to my_bool as we are only testing if result is true or not
  Moved 'reversed' to outside block as area was used later
storage/maria/maria_chk.c:
  Added error if trying to sort with HA_BINARY_PACK_KEY
  Use new interface to get_key() and _ma_dpointer()
  _ma_dpos() -> _ma_row_pos_from_key()
storage/maria/maria_def.h:
  Modified functions to use MARIA_KEY instead of key pointer and key length
  Added 'common' to MARIA_SHARE->state for storing state for transactional tables without versioning
  Added create_trid to MARIA_SHARE
  Removed not used state variables 'process' and 'unique'
  Added defines for handling TRID's in index pages
  Changed to use MARIA_SHARE instead of MARIA_HA for some functions
  Added 'have_versioning' flag if table supports versioning
  Moved key_root_lock from MARIA_SHARE to MARIA_KEYDEF
  Changed last_key to be of type MARIA_KEY. Removed lastkey_length
  lastkey -> lastkey_buff, lastkey2 -> lastkey_buff2
  Added _ma_get_used_and_nod_with_flag() for faster access to page data when page_flag is read
  Added DBUG_DUMP_KEY for easier DBUG_DUMP of a key
  Changed 'nextflag' and assocaited variables to uint32
storage/maria/maria_ftdump.c:
  lastkey -> lastkey_buff
storage/maria/trnman.c:
  Fixed wrong initialization of min_read_from and max_commit_trid
  Added trnman_get_min_safe_trid()
storage/maria/unittest/ma_test_all-t:
  Added --start-from
storage/myisam/mi_check.c:
  Added SEARCH_INSERT, as ha_key_cmp() needs it when doing key comparision for inserting key on page in rowid order
storage/myisam/mi_delete.c:
  Added SEARCH_INSERT, as ha_key_cmp() needs it when doing key comparision for inserting key on page in rowid order
storage/myisam/mi_range.c:
  Updated comment
storage/myisam/mi_write.c:
  Added SEARCH_INSERT, as ha_key_cmp() needs it when doing key comparision for inserting key on page in rowid order
storage/myisam/rt_index.c:
  Fixed wrong parameter to rtree_get_req() which could cause crash
parent ab75389a
......@@ -1448,6 +1448,7 @@ storage/maria/maria_log
storage/maria/maria_log.*
storage/maria/maria_pack
storage/maria/maria_read_log
storage/maria/tmp
storage/maria/tmp/*
storage/maria/unittest/ma_pagecache_consist_1k-t-big
storage/maria/unittest/ma_pagecache_consist_1kHC-t-big
......
......@@ -22,7 +22,8 @@ BUILT_SOURCES= $(top_builddir)/include/mysqld_error.h \
$(top_builddir)/include/sql_state.h \
$(top_builddir)/include/mysqld_ername.h
pkginclude_HEADERS= $(BUILT_SOURCES)
DISTCLEANFILES = $(BUILT_SOURCES)
EXTRA_PROGRAMS = comp_err
DISTCLEANFILES = $(BUILT_SOURCES) $(EXTRA_PROGRAMS)
SUBDIRS = @yassl_dir@
DIST_SUBDIRS = yassl
......@@ -45,7 +46,6 @@ $(top_builddir)/include/sql_state.h: $(top_builddir)/include/mysqld_error.h
bin_PROGRAMS = replace perror resolveip my_print_defaults \
resolve_stack_dump mysql_waitpid innochecksum
noinst_PROGRAMS = charset2html
EXTRA_PROGRAMS = comp_err
EXTRA_DIST = CMakeLists.txt
perror.o: perror.c
......
......@@ -160,10 +160,24 @@ struct st_maria_share;
struct st_maria_handler; /* For referense */
typedef struct st_maria_handler MARIA_HA;
struct st_maria_s_param;
struct st_maria_keydef;
typedef struct st_maria_key /* Internal info about a key */
{
uchar *data; /* Data for key */
struct st_maria_keydef *keyinfo; /* Definition for key */
uint data_length; /* Length of key data */
uint ref_length; /* record ref + transid */
uint32 flag; /* 0 or SEARCH_PART_KEY */
} MARIA_KEY;
typedef struct st_maria_keydef /* Key definition with open & info */
{
struct st_maria_share *share; /* Pointer to base (set in open) */
#ifdef THREAD
rw_lock_t root_lock; /* locking of tree */
#endif
uint16 keysegs; /* Number of key-segment */
uint16 flag; /* NOSAME, PACK_USED */
......@@ -180,20 +194,23 @@ typedef struct st_maria_keydef /* Key definition with open & info */
HA_KEYSEG *seg, *end;
struct st_mysql_ftparser *parser; /* Fulltext [pre]parser */
int (*bin_search)(MARIA_HA *info,
struct st_maria_keydef *keyinfo, uchar *page,
const uchar *key, uint key_len, uint comp_flag,
uchar **ret_pos,
uchar *buff, my_bool *was_last_key);
uint(*get_key)(struct st_maria_keydef *keyinfo, uint nod_flag,
uchar **page, uchar *key);
int (*pack_key)(struct st_maria_keydef *keyinfo, uint nod_flag,
int (*bin_search)(const MARIA_KEY *key, uchar *page,
uint32 comp_flag, uchar **ret_pos, uchar *buff,
my_bool *was_last_key);
uint (*get_key)(MARIA_KEY *key, uint page_flag, uint nod_flag,
uchar **page);
uchar *(*skip_key)(MARIA_KEY *key, uint page_flag, uint nod_flag,
uchar *page);
int (*pack_key)(const MARIA_KEY *key, uint nod_flag,
uchar *next_key, uchar *org_key, uchar *prev_key,
const uchar *key, struct st_maria_s_param *s_temp);
struct st_maria_s_param *s_temp);
void (*store_key)(struct st_maria_keydef *keyinfo, uchar *key_pos,
struct st_maria_s_param *s_temp);
int (*ck_insert)(MARIA_HA *inf, uint k_nr, uchar *k, uint klen);
int (*ck_delete)(MARIA_HA *inf, uint k_nr, uchar *k, uint klen);
my_bool (*ck_insert)(MARIA_HA *inf, MARIA_KEY *key);
int (*ck_delete)(MARIA_HA *inf, MARIA_KEY *klen);
MARIA_KEY *(*make_key)(MARIA_HA *info, MARIA_KEY *int_key, uint keynr,
uchar *key, const uchar *record,
MARIA_RECORD_POS filepos, ulonglong trid);
} MARIA_KEYDEF;
......
......@@ -252,11 +252,13 @@ enum ha_base_keytype {
#define HA_SPATIAL 1024 /* For spatial search */
#define HA_NULL_ARE_EQUAL 2048 /* NULL in key are cmp as equal */
#define HA_GENERATED_KEY 8192 /* Automaticly generated key */
#define HA_RTREE_INDEX 16384 /* For RTREE search */
/* The combination of the above can be used for key type comparison. */
#define HA_KEYFLAG_MASK (HA_NOSAME | HA_PACK_KEY | HA_AUTO_KEY | \
HA_BINARY_PACK_KEY | HA_FULLTEXT | HA_UNIQUE_CHECK | \
HA_SPATIAL | HA_NULL_ARE_EQUAL | HA_GENERATED_KEY)
HA_SPATIAL | HA_NULL_ARE_EQUAL | HA_GENERATED_KEY | \
HA_RTREE_INDEX)
#define HA_KEY_HAS_PART_KEY_SEG 65536 /* Key contains partial segments */
......@@ -479,6 +481,14 @@ typedef ulong key_part_map;
#define MBR_DATA 16384
#define SEARCH_NULL_ARE_EQUAL 32768 /* NULL in keys are equal */
#define SEARCH_NULL_ARE_NOT_EQUAL 65536 /* NULL in keys are not equal */
/* Use this when inserting a key in position order */
#define SEARCH_INSERT SEARCH_NULL_ARE_NOT_EQUAL*2
/* Only part of the key is specified while reading */
#define SEARCH_PART_KEY SEARCH_INSERT*2
/* Used when user key (key 2) contains transaction id's */
#define SEARCH_USER_KEY_HAS_TRANSID SEARCH_PART_KEY*2
/* Used when page key (key 1) contains transaction id's */
#define SEARCH_PAGE_KEY_HAS_TRANSID SEARCH_USER_KEY_HAS_TRANSID*2
/* bits in opt_flag */
#define QUICK_USED 1
......
......@@ -110,8 +110,8 @@ typedef struct st_HA_KEYSEG /* Key-portion */
extern int ha_compare_text(CHARSET_INFO *, const uchar *, uint,
const uchar *, uint , my_bool, my_bool);
extern int ha_key_cmp(register HA_KEYSEG *keyseg, register const uchar *a,
register const uchar *b, uint key_length, uint nextflag,
uint *diff_pos);
register const uchar *b, uint key_length,
uint32 nextflag, uint *diff_pos);
extern HA_KEYSEG *ha_find_null(HA_KEYSEG *keyseg, const uchar *a);
extern void my_handler_error_register(void);
......
......@@ -6,6 +6,8 @@
connection admin;
let $current_database= `select database()`;
-- echo * shut down mysqld, removed logs, restarted it
append_file $MYSQLTEST_VARDIR/tmp/master0.expect;
wait-maria_empty_logs.inc
......@@ -69,6 +71,7 @@ EOF
--source include/wait_until_connected_again.inc
connection default;
# the effect of "use" is lost after a restart so we are back into db "test",
# because connection 'default' was created with db "test".
use mysqltest;
# Restore current database as the effect of "use" was lost after restart
--disable_query_log
eval use $current_database;
--enable_query_log
......@@ -993,6 +993,9 @@ SET @@RAND_SEED1=178507359, @@RAND_SEED2=332493072;
DELETE FROM t1 ORDER BY RAND() LIMIT 10;
SET @@RAND_SEED1=1034033013, @@RAND_SEED2=558966507;
DELETE FROM t1 ORDER BY RAND() LIMIT 10;
CHECK TABLE t1 extended;
Table Op Msg_type Msg_text
test.t1 check status OK
UPDATE t1 set spatial_point=GeomFromText('POINT(230 9)') where c1 like 'y%';
UPDATE t1 set spatial_point=GeomFromText('POINT(95 35)') where c1 like 'j%';
UPDATE t1 set spatial_point=GeomFromText('POINT(93 99)') where c1 like 'a%';
......@@ -1163,6 +1166,9 @@ UPDATE t1 set spatial_point=GeomFromText('POINT(120 137)') where c1 like 'w%';
UPDATE t1 set spatial_point=GeomFromText('POINT(207 147)') where c1 like 'c%';
UPDATE t1 set spatial_point=GeomFromText('POINT(31 125)') where c1 like 'e%';
UPDATE t1 set spatial_point=GeomFromText('POINT(27 36)') where c1 like 'r%';
check table t1 extended;
Table Op Msg_type Msg_text
test.t1 check status OK
INSERT INTO t1 (c2, c1, c3, spatial_point) VALUES
('b', 'c', 'e', GeomFromText('POINT(41 137)')),
('p', 'y', 'k', GeomFromText('POINT(50 22)')),
......@@ -1264,6 +1270,9 @@ INSERT INTO t1 (c2, c1, c3, spatial_point) VALUES
('m', 'i', 'd', GeomFromText('POINT(117 226)')),
('z', 'y', 'y', GeomFromText('POINT(62 81)')),
('g', 'v', 'm', GeomFromText('POINT(66 158)'));
check table t1 extended;
Table Op Msg_type Msg_text
test.t1 check status OK
SET @@RAND_SEED1=481064922, @@RAND_SEED2=438133497;
DELETE FROM t1 ORDER BY RAND() LIMIT 10;
SET @@RAND_SEED1=280535103, @@RAND_SEED2=444518646;
......
......@@ -138,3 +138,22 @@ select count(*) from t1;
count(*)
7
drop table t1;
CREATE TABLE t1 (fid INT NOT NULL AUTO_INCREMENT PRIMARY KEY, g GEOMETRY NOT NULL, SPATIAL KEY(g) ) transactional=1 row_format=page engine=maria;
lock tables t1 write concurrent, t1 as t2 write concurrent;
insert into t1 (fid,g) values (NULL,GeomFromText('LineString(0 0,1 1)'));
select fid from t1 as t2;
fid
1
select count(*) from t1 as t2;
count(*)
1
insert into t1 (fid,g) values (NULL,GeomFromText('LineString(0 0,1 1)'));
select fid from t1 as t2;
fid
1
2
select count(*) from t1 as t2;
count(*)
2
unlock tables;
drop table t1;
* shut down mysqld, removed logs, restarted it
set global storage_engine=maria;
set session storage_engine=maria;
set global maria_log_file_size=4294967295;
......
......@@ -4,7 +4,6 @@ create database mysqltest;
use mysqltest;
* TEST of recovery with blobs
* shut down mysqld, removed logs, restarted it
use mysqltest;
set @@max_allowed_packet=32000000;
create table t1 (a int, b longtext) engine=maria table_checksum=1;
* copied t1 for feeding_recovery
......
......@@ -2,7 +2,6 @@ drop database if exists mysqltest;
create database mysqltest;
use mysqltest;
* shut down mysqld, removed logs, restarted it
use mysqltest;
create table t1 (a varchar(10000)) engine=maria;
* TEST of over-allocated bitmap not flushed by checkpoint
insert into t1 values ("bbbbbbb");
......
......@@ -3,7 +3,6 @@ drop database if exists mysqltest;
create database mysqltest;
use mysqltest;
* shut down mysqld, removed logs, restarted it
use mysqltest;
CREATE TABLE t1 (
line LINESTRING NOT NULL,
kind ENUM('po', 'pp', 'rr', 'dr', 'rd', 'ts', 'cl') NOT NULL DEFAULT 'po',
......
......@@ -3,7 +3,6 @@ drop database if exists mysqltest;
create database mysqltest;
use mysqltest;
* shut down mysqld, removed logs, restarted it
use mysqltest;
create table t1 (a varchar(1000)) engine=maria;
* TEST of REDO: see if recovery can reconstruct if we give it an old table
* copied t1 for feeding_recovery
......@@ -121,7 +120,6 @@ a
drop table t1;
* TEST of two REDOs for same page in one REDO group
* shut down mysqld, removed logs, restarted it
use mysqltest;
CREATE TABLE t1 (
i int,
b blob default NULL,
......@@ -154,7 +152,6 @@ LENGTH(b)
drop table t1;
* TEST of INSERT vs state.auto_increment
* shut down mysqld, removed logs, restarted it
use mysqltest;
CREATE TABLE t1 (
i int auto_increment primary key,
c varchar(6),
......@@ -242,7 +239,6 @@ insert into t1 values(null, "f");
drop table t1;
* TEST of removing logs manually
* shut down mysqld, removed logs, restarted it
use mysqltest;
* TEST of UNDO_ROW_DELETE preserving rowid
create table t1(a int) engine=maria;
insert into t1 values(1),(2);
......
......@@ -2346,6 +2346,25 @@ t1 CREATE TABLE `t1` (
`c` char(1) DEFAULT NULL
) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 TRANSACTIONAL=1
drop table t1;
create table t1 (a int, key(a)) transactional=0;
insert into t1 values (0),(1),(2),(3),(4);
insert into t1 select NULL from t1;
check table t1;
Table Op Msg_type Msg_text
test.t1 check status OK
drop table t1;
create temporary table t1 (a int, key(a)) transactional=1;
create temporary table t2 (a int, key(a)) transactional=1;
insert into t1 values (0),(1),(2),(3),(4);
insert into t2 select * from t1;
insert into t1 select NULL from t2;
select count(*) from t1;
count(*)
10
select count(*) from t1 where a >= 4;
count(*)
1
drop table t1;
create table t1 (i int auto_increment not null primary key) transactional=0;
check table t1 extended;
Table Op Msg_type Msg_text
......
set session transaction_prealloc_size=1024*1024*1024*1;
show processlist;
Id User Host db Command Time State Info
1 root localhost test Query 0 NULL show processlist
# root localhost test Query 0 NULL show processlist
set session transaction_prealloc_size=1024*1024*1024*2;
show processlist;
Id User Host db Command Time State Info
1 root localhost test Query 0 NULL show processlist
# root localhost test Query 0 NULL show processlist
set session transaction_prealloc_size=1024*1024*1024*3;
show processlist;
Id User Host db Command Time State Info
1 root localhost test Query 0 NULL show processlist
# root localhost test Query 0 NULL show processlist
set session transaction_prealloc_size=1024*1024*1024*4;
show processlist;
Id User Host db Command Time State Info
1 root localhost test Query 0 NULL show processlist
# root localhost test Query 0 NULL show processlist
set session transaction_prealloc_size=1024*1024*1024*5;
show processlist;
Id User Host db Command Time State Info
1 root localhost test Query 0 NULL show processlist
# root localhost test Query 0 NULL show processlist
......@@ -32,13 +32,13 @@ Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 4 Format_desc 1 106 Server ver: SERVER_VERSION, Binlog ver: 4
master-bin.000001 106 Query 1 223 use `test`; CREATE TABLE t1 (a INT PRIMARY KEY, b LONG) ENGINE=NDB
master-bin.000001 223 Query 1 287 BEGIN
master-bin.000001 287 Table_map 1 40 table_id: # (test.t1)
master-bin.000001 327 Table_map 1 98 table_id: # (mysql.ndb_apply_status)
master-bin.000001 385 Write_rows 1 157 table_id: #
master-bin.000001 444 Write_rows 1 204 table_id: # flags: STMT_END_F
master-bin.000001 491 Query 1 556 COMMIT
master-bin.000001 556 Query 1 636 use `test`; TRUNCATE TABLE t1
master-bin.000001 636 Query 1 712 use `test`; DROP TABLE t1
master-bin.000001 287 Table_map 1 330 table_id: # (test.t1)
master-bin.000001 330 Table_map 1 392 table_id: # (mysql.ndb_apply_status)
master-bin.000001 392 Write_rows 1 451 table_id: #
master-bin.000001 451 Write_rows 1 498 table_id: # flags: STMT_END_F
master-bin.000001 498 Query 1 563 COMMIT
master-bin.000001 563 Query 1 643 use `test`; TRUNCATE TABLE t1
master-bin.000001 643 Query 1 719 use `test`; DROP TABLE t1
**** On Master ****
CREATE TABLE t1 (a INT PRIMARY KEY, b LONG) ENGINE=NDB;
INSERT INTO t1 VALUES (1,1), (2,2);
......@@ -68,24 +68,24 @@ Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 4 Format_desc 1 106 Server ver: SERVER_VERSION, Binlog ver: 4
master-bin.000001 106 Query 1 223 use `test`; CREATE TABLE t1 (a INT PRIMARY KEY, b LONG) ENGINE=NDB
master-bin.000001 223 Query 1 287 BEGIN
master-bin.000001 287 Table_map 1 40 table_id: # (test.t1)
master-bin.000001 327 Table_map 1 98 table_id: # (mysql.ndb_apply_status)
master-bin.000001 385 Write_rows 1 157 table_id: #
master-bin.000001 444 Write_rows 1 204 table_id: # flags: STMT_END_F
master-bin.000001 491 Query 1 556 COMMIT
master-bin.000001 556 Query 1 636 use `test`; TRUNCATE TABLE t1
master-bin.000001 636 Query 1 712 use `test`; DROP TABLE t1
master-bin.000001 712 Query 1 829 use `test`; CREATE TABLE t1 (a INT PRIMARY KEY, b LONG) ENGINE=NDB
master-bin.000001 829 Query 1 893 BEGIN
master-bin.000001 893 Table_map 1 40 table_id: # (test.t1)
master-bin.000001 933 Table_map 1 98 table_id: # (mysql.ndb_apply_status)
master-bin.000001 991 Write_rows 1 157 table_id: #
master-bin.000001 1050 Write_rows 1 204 table_id: # flags: STMT_END_F
master-bin.000001 1097 Query 1 1162 COMMIT
master-bin.000001 1162 Query 1 1226 BEGIN
master-bin.000001 1226 Table_map 1 40 table_id: # (test.t1)
master-bin.000001 1266 Table_map 1 98 table_id: # (mysql.ndb_apply_status)
master-bin.000001 1324 Write_rows 1 157 table_id: #
master-bin.000001 1383 Delete_rows 1 196 table_id: # flags: STMT_END_F
master-bin.000001 1422 Query 1 1487 COMMIT
master-bin.000001 1487 Query 1 1563 use `test`; DROP TABLE t1
master-bin.000001 287 Table_map 1 330 table_id: # (test.t1)
master-bin.000001 330 Table_map 1 392 table_id: # (mysql.ndb_apply_status)
master-bin.000001 392 Write_rows 1 451 table_id: #
master-bin.000001 451 Write_rows 1 498 table_id: # flags: STMT_END_F
master-bin.000001 498 Query 1 563 COMMIT
master-bin.000001 563 Query 1 643 use `test`; TRUNCATE TABLE t1
master-bin.000001 643 Query 1 719 use `test`; DROP TABLE t1
master-bin.000001 719 Query 1 836 use `test`; CREATE TABLE t1 (a INT PRIMARY KEY, b LONG) ENGINE=NDB
master-bin.000001 836 Query 1 900 BEGIN
master-bin.000001 900 Table_map 1 943 table_id: # (test.t1)
master-bin.000001 943 Table_map 1 1005 table_id: # (mysql.ndb_apply_status)
master-bin.000001 1005 Write_rows 1 1064 table_id: #
master-bin.000001 1064 Write_rows 1 1111 table_id: # flags: STMT_END_F
master-bin.000001 1111 Query 1 1176 COMMIT
master-bin.000001 1176 Query 1 1240 BEGIN
master-bin.000001 1240 Table_map 1 1283 table_id: # (test.t1)
master-bin.000001 1283 Table_map 1 1345 table_id: # (mysql.ndb_apply_status)
master-bin.000001 1345 Write_rows 1 1404 table_id: #
master-bin.000001 1404 Delete_rows 1 1443 table_id: # flags: STMT_END_F
master-bin.000001 1443 Query 1 1508 COMMIT
master-bin.000001 1508 Query 1 1584 use `test`; DROP TABLE t1
......@@ -3,4 +3,4 @@
# so slow...
--source include/big_test.inc
--source t/rpl_truncate_7ndb.test
--source suite/rpl_ndb/t/rpl_truncate_7ndb.test
......@@ -369,6 +369,7 @@ SET @@RAND_SEED1=178507359, @@RAND_SEED2=332493072;
DELETE FROM t1 ORDER BY RAND() LIMIT 10;
SET @@RAND_SEED1=1034033013, @@RAND_SEED2=558966507;
DELETE FROM t1 ORDER BY RAND() LIMIT 10;
CHECK TABLE t1 extended;
UPDATE t1 set spatial_point=GeomFromText('POINT(230 9)') where c1 like 'y%';
UPDATE t1 set spatial_point=GeomFromText('POINT(95 35)') where c1 like 'j%';
UPDATE t1 set spatial_point=GeomFromText('POINT(93 99)') where c1 like 'a%';
......@@ -539,6 +540,7 @@ UPDATE t1 set spatial_point=GeomFromText('POINT(120 137)') where c1 like 'w%';
UPDATE t1 set spatial_point=GeomFromText('POINT(207 147)') where c1 like 'c%';
UPDATE t1 set spatial_point=GeomFromText('POINT(31 125)') where c1 like 'e%';
UPDATE t1 set spatial_point=GeomFromText('POINT(27 36)') where c1 like 'r%';
check table t1 extended;
INSERT INTO t1 (c2, c1, c3, spatial_point) VALUES
('b', 'c', 'e', GeomFromText('POINT(41 137)')),
('p', 'y', 'k', GeomFromText('POINT(50 22)')),
......@@ -640,6 +642,7 @@ INSERT INTO t1 (c2, c1, c3, spatial_point) VALUES
('m', 'i', 'd', GeomFromText('POINT(117 226)')),
('z', 'y', 'y', GeomFromText('POINT(62 81)')),
('g', 'v', 'm', GeomFromText('POINT(66 158)'));
check table t1 extended;
SET @@RAND_SEED1=481064922, @@RAND_SEED2=438133497;
DELETE FROM t1 ORDER BY RAND() LIMIT 10;
SET @@RAND_SEED1=280535103, @@RAND_SEED2=444518646;
......
......@@ -85,3 +85,20 @@ select count(*) from t1;
connection default;
drop table t1;
#
# Test count(*) for not versioned tables
#
CREATE TABLE t1 (fid INT NOT NULL AUTO_INCREMENT PRIMARY KEY, g GEOMETRY NOT NULL, SPATIAL KEY(g) ) transactional=1 row_format=page engine=maria;
lock tables t1 write concurrent, t1 as t2 write concurrent;
insert into t1 (fid,g) values (NULL,GeomFromText('LineString(0 0,1 1)'));
select fid from t1 as t2;
select count(*) from t1 as t2;
insert into t1 (fid,g) values (NULL,GeomFromText('LineString(0 0,1 1)'));
select fid from t1 as t2;
select count(*) from t1 as t2;
unlock tables;
drop table t1;
-- source include/have_maria.inc
-- source include/big_test.inc
#
# Empty logs to get log file numbers repeatable
#
--enable_reconnect
connect (admin, localhost, root,,);
--enable_reconnect
--source include/maria_empty_logs.inc
let $default=`select @@global.storage_engine`;
set global storage_engine=maria;
set session storage_engine=maria;
......@@ -54,8 +63,6 @@ SHOW ENGINE maria logs;
insert into t2 select * from t1;
insert into t1 select * from t2;
eval set global maria_checkpoint_interval=$def_checkinterval;
--replace_regex /Size +[0-9]+ ; .+master-data/master-data/
SHOW ENGINE maria logs;
......
......@@ -1518,6 +1518,30 @@ alter table t1 engine=maria;
show create table t1;
drop table t1;
#
# Some tests that have failed with transactional=0
#
# Testing buik insert
create table t1 (a int, key(a)) transactional=0;
insert into t1 values (0),(1),(2),(3),(4);
insert into t1 select NULL from t1;
check table t1;
drop table t1;
#
# Some tests with temporary tables
#
create temporary table t1 (a int, key(a)) transactional=1;
create temporary table t2 (a int, key(a)) transactional=1;
insert into t1 values (0),(1),(2),(3),(4);
insert into t2 select * from t1;
insert into t1 select NULL from t2;
select count(*) from t1;
select count(*) from t1 where a >= 4;
drop table t1;
#
# Test problems with small rows and row_type=page
# Bug 35048 "maria table corruption reported when transactional=0"
......
......@@ -9,12 +9,18 @@
#
set session transaction_prealloc_size=1024*1024*1024*1;
--replace_column 1 #
show processlist;
set session transaction_prealloc_size=1024*1024*1024*2;
--replace_column 1 #
show processlist;
--replace_column 1 #
set session transaction_prealloc_size=1024*1024*1024*3;
--replace_column 1 #
show processlist;
set session transaction_prealloc_size=1024*1024*1024*4;
--replace_column 1 #
show processlist;
set session transaction_prealloc_size=1024*1024*1024*5;
--replace_column 1 #
show processlist;
......@@ -84,13 +84,15 @@ static int compare_bin(const uchar *a, uint a_length,
ha_key_cmp()
keyseg Array of key segments of key to compare
a First key to compare, in format from _mi_pack_key()
This is normally key specified by user
b Second key to compare. This is always from a row
key_length Length of key to compare. This can be shorter than
a to just compare sub keys
This is always from the row
b Second key to compare. This is from the row or the user
key_length Length of key to compare, based on key b. This can be shorter
than b to just compare sub keys
next_flag How keys should be compared
If bit SEARCH_FIND is not set the keys includes the row
position and this should also be compared
If SEARCH_PAGE_KEY_HAS_TRANSID is set then 'a' has transid
If SEARCH_USER_KEY_HAS_TRANSID is set then 'b' has transid
diff_pos OUT Number of first keypart where values differ, counting
from one.
diff_pos[1] OUT (b + diff_pos[1]) points to first value in tuple b
......@@ -120,7 +122,7 @@ static int compare_bin(const uchar *a, uint a_length,
#define FCMP(A,B) ((int) (A) - (int) (B))
int ha_key_cmp(register HA_KEYSEG *keyseg, register const uchar *a,
register const uchar *b, uint key_length, uint nextflag,
register const uchar *b, uint key_length, uint32 nextflag,
uint *diff_pos)
{
int flag;
......@@ -152,8 +154,13 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register const uchar *a,
b++;
if (!*a++) /* If key was NULL */
{
if (nextflag == (SEARCH_FIND | SEARCH_UPDATE))
nextflag=SEARCH_SAME; /* Allow duplicate keys */
if ((nextflag & (SEARCH_FIND | SEARCH_UPDATE | SEARCH_INSERT |
SEARCH_NULL_ARE_EQUAL)) ==
(SEARCH_FIND | SEARCH_UPDATE | SEARCH_INSERT))
{
/* Allow duplicate keys */
nextflag= (nextflag & ~(SEARCH_FIND | SEARCH_UPDATE)) | SEARCH_SAME;
}
else if (nextflag & SEARCH_NULL_ARE_NOT_EQUAL)
{
/*
......@@ -456,18 +463,90 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register const uchar *a,
end:
if (!(nextflag & SEARCH_FIND))
{
/*
Compare rowid and possible transid
This happens in the following case:
- INSERT, UPDATE, DELETE when we have not unique keys or
are using versioning
- SEARCH_NEXT, SEARCH_PREVIOUS when we need to restart search
The logic for comparing transid are as follows:
Keys with have a transid have lowest bit in the rowidt. This means that
if we are comparing a key with a transid with another key that doesn't
have a tranid, we must reset the lowest bit for both keys.
When we have transid, the keys are compared in transid order.
A key without a transid is regared to be smaller than a key with
a transid.
*/
uint i;
uchar key_mask, tmp_a, tmp_b;
if (nextflag & (SEARCH_NO_FIND | SEARCH_LAST)) /* Find record after key */
return (nextflag & (SEARCH_BIGGER | SEARCH_LAST)) ? -1 : 1;
flag=0;
for (i=keyseg->length ; i-- > 0 ; )
key_mask= (uchar) 255;
if (!(nextflag & (SEARCH_USER_KEY_HAS_TRANSID |
SEARCH_PAGE_KEY_HAS_TRANSID)))
{
/*
Neither key has a trid. Only compare row id's and don't
try to store rows in trid order
*/
key_length= keyseg->length;
nextflag&= ~SEARCH_INSERT;
}
else
{
/*
Set key_mask so that we reset the last bit in the rowid before
we compare it. This is needed as the lowest bit in the rowid is
used to mark if the key has a transid or not.
*/
key_mask= (uchar) 254;
if (!test_all_bits(nextflag, (SEARCH_USER_KEY_HAS_TRANSID |
SEARCH_PAGE_KEY_HAS_TRANSID)))
{
/*
No transaction id for user key or for key on page
Ignore transid as at least one of the keys are visible for all
*/
key_length= keyseg->length;
}
else
{
/*
Both keys have trids. No need of special handling of incomplete
trids below.
*/
nextflag&= ~SEARCH_INSERT;
}
}
DBUG_ASSERT(key_length > 0);
for (i= key_length-1 ; (int) i-- > 0 ; )
{
if (*a++ != *b++)
{
flag= FCMP(a[-1],b[-1]);
break;
goto found;
}
}
tmp_a= *a & key_mask;
tmp_b= *b & key_mask;
flag= FCMP(tmp_a, tmp_b);
if (flag == 0 && (nextflag & SEARCH_INSERT))
{
/*
Ensure that on insert we get rows stored in trid order.
If one of the parts doesn't have a trid, this should be regarded
as smaller than the other
*/
return (nextflag & SEARCH_USER_KEY_HAS_TRANSID) ? -1 : 1;
}
found:
if (nextflag & SEARCH_SAME)
return (flag); /* read same */
if (nextflag & SEARCH_BIGGER)
......
......@@ -87,7 +87,7 @@ int my_lock(File fd, int locktype, my_off_t start, my_off_t length,
nxLockFlags = NX_RANGE_LOCK_EXCL;
}
if (MyFlags & MY_DONT_WAIT)
if (MyFlags & MY_NO_WAIT)
{
/* Don't block on the lock. */
nxLockFlags |= NX_RANGE_LOCK_TRYLOCK;
......
......@@ -90,7 +90,8 @@ CLEANFILES = @server_scripts@ \
mysql_find_rows \
mysqlhotcopy \
mysqldumpslow \
mysqld_multi
mysqld_multi \
$(EXTRA_PROGRAMS)
pkgplugindir = $(pkglibdir)/plugin
......
......@@ -33,10 +33,10 @@ Relay_log_info::Relay_log_info()
:Slave_reporting_capability("SQL"),
no_storage(FALSE), replicate_same_server_id(::replicate_same_server_id),
info_fd(-1), cur_log_fd(-1), save_temporary_tables(0),
cur_log_old_open_count(0), group_relay_log_pos(0), event_relay_log_pos(0),
#if HAVE_purify
is_fake(FALSE),
#endif
cur_log_old_open_count(0), group_relay_log_pos(0), event_relay_log_pos(0),
group_master_log_pos(0), log_space_total(0), ignore_log_space_limit(0),
last_master_timestamp(0), slave_skip_counter(0),
abort_pos_wait(0), slave_run_id(0), sql_thd(0),
......
......@@ -109,7 +109,7 @@ int hp_rb_write_key(HP_INFO *info, HP_KEYDEF *keyinfo, const uchar *record,
custom_arg.key_length= hp_rb_make_key(keyinfo, info->recbuf, record, recpos);
if (keyinfo->flag & HA_NOSAME)
{
custom_arg.search_flag= SEARCH_FIND | SEARCH_UPDATE;
custom_arg.search_flag= SEARCH_FIND | SEARCH_UPDATE | SEARCH_INSERT;
keyinfo->rb_tree.flag= TREE_NO_DUPS;
}
else
......
......@@ -136,7 +136,7 @@ libmaria_a_SOURCES = ma_init.c ma_open.c ma_extra.c ma_info.c ma_rkey.c \
ma_checkpoint.c ma_recovery.c ma_commit.c \
ma_pagecrc.c ma_recovery_util.c \
ha_maria.cc
CLEANFILES = test?.MA? FT?.MA? isam.log ma_test_all ma_rt_test.MA? sp_test.MA?
CLEANFILES = test?.MA? FT?.MA? isam.log ma_test_all ma_rt_test.MA? sp_test.MA? maria_log_control maria_log.0000*
SUFFIXES = .sh
......
......@@ -2271,10 +2271,17 @@ int ha_maria::external_lock(THD *thd, int lock_type)
else
{
/*
Copy the current state. This may have been wrong if the same file
was used several times in the last statement. This should only
happen for temporary tables.
We come here in the following cases:
- The table is a temporary table
- It's a table which is crash safe but not yet versioned, for
example a table with fulltext or rtree keys
Set the current state to point to save_state so that the
block_format code don't count the same record twice.
Copy also the current state. This may have been wrong if the
same file was used several times in the last statement
*/
file->state= file->state_start;
*file->state= file->s->state.state;
}
......@@ -2305,7 +2312,13 @@ int ha_maria::external_lock(THD *thd, int lock_type)
if (_ma_reenable_logging_for_table(file, TRUE))
DBUG_RETURN(1);
/** @todo zero file->trn also in commit and rollback */
file->trn= 0;
file->trn= 0; // Safety
/*
Ensure that file->state points to the current number of rows. This
is needed if someone calls maria_info() without first doing an
external lock of the table
*/
file->state= &file->s->state.state;
if (trn && trnman_has_locked_tables(trn))
{
if (!trnman_decrement_locked_tables(trn))
......@@ -2341,6 +2354,8 @@ int ha_maria::start_stmt(THD *thd, thr_lock_type lock_type)
DBUG_ASSERT(trn); // this may be called only after external_lock()
DBUG_ASSERT(trnman_has_locked_tables(trn));
DBUG_ASSERT(lock_type != TL_UNLOCK);
DBUG_ASSERT(file->trn == trn);
/*
If there was an implicit commit under this LOCK TABLES by a previous
statement (like a DDL), at least if that previous statement was about a
......@@ -2378,6 +2393,7 @@ int ha_maria::implicit_commit(THD *thd)
#endif
TRN *trn;
int error= 0;
TABLE *table;
DBUG_ENTER("ha_maria::implicit_commit");
if ((trn= THD_TRN) != NULL)
{
......@@ -2398,6 +2414,30 @@ int ha_maria::implicit_commit(THD *thd)
THD_TRN= trn;
if (unlikely(trn == NULL))
error= HA_ERR_OUT_OF_MEM;
/*
Move all locked tables to the new transaction
We must do it here as otherwise file->thd and file->state may be
stale pointers. We can't do this in start_stmt() as we don't know
when we should call _ma_setup_live_state() and in some cases, like
in check table, we use the table without calling start_stmt().
*/
for (table=thd->open_tables; table ; table=table->next)
{
if (table->db_stat && table->file->ht == maria_hton)
{
MARIA_HA *handler= ((ha_maria*) table->file)->file;
if (handler->s->base.born_transactional)
{
handler->trn= trn;
if (handler->s->lock.get_status)
{
if (_ma_setup_live_state(handler))
error= HA_ERR_OUT_OF_MEM;
}
}
}
}
}
DBUG_RETURN(error);
}
......@@ -2407,8 +2447,25 @@ THR_LOCK_DATA **ha_maria::store_lock(THD *thd,
THR_LOCK_DATA **to,
enum thr_lock_type lock_type)
{
/* Test if we can fix test below */
DBUG_ASSERT(lock_type != TL_UNLOCK &&
(lock_type == TL_IGNORE || file->lock.type == TL_UNLOCK));
if (lock_type != TL_IGNORE && file->lock.type == TL_UNLOCK)
{
/*
We have to disable concurrent inserts for INSERT ... SELECT or
INSERT/UPDATE/DELETE with sub queries if we are using statement based
logging. We take the safe route here and disable this for all commands
that only does reading that are not SELECT.
*/
if (lock_type <= TL_READ_HIGH_PRIORITY &&
!thd->current_stmt_binlog_row_based &&
(thd->lex->sql_command != SQLCOM_SELECT &&
thd->lex->sql_command != SQLCOM_LOCK_TABLES) &&
mysql_bin_log.is_open())
lock_type= TL_READ_NO_INSERT;
file->lock.type= lock_type;
}
*to++= &file->lock;
return to;
}
......
......@@ -860,12 +860,12 @@ static my_bool extend_area_on_page(MARIA_HA *info,
}
/*
@brief Copy not changed fields from 'from' to 'to'
/**
@brief Copy not changed fields from 'from' to 'to'
@notes
Assumption is that most fields are not changed!
(Which is why we don't test if all bits are set for some bytes in bitmap)
@notes
Assumption is that most fields are not changed!
(Which is why we don't test if all bits are set for some bytes in bitmap)
*/
void copy_not_changed_fields(MARIA_HA *info, MY_BITMAP *changed_fields,
......@@ -1362,7 +1362,6 @@ static void calc_record_size(MARIA_HA *info, const uchar *record,
min_read_from If <> 0, remove all trid's that are less than this
*/
void _ma_compact_block_page(uchar *buff, uint block_size, uint rownr,
my_bool extend_block, TrID min_read_from,
uint min_row_length)
......
This diff is collapsed.
......@@ -115,7 +115,7 @@ int maria_close(register MARIA_HA *info)
keys = share->state.header.keys;
VOID(rwlock_destroy(&share->mmap_lock));
for(i=0; i<keys; i++) {
VOID(rwlock_destroy(&share->key_root_lock[i]));
VOID(rwlock_destroy(&share->keyinfo[i].root_lock));
}
}
#endif
......
......@@ -75,7 +75,7 @@ int maria_create(const char *name, enum data_file_type datafile_type,
DBUG_PRINT("enter", ("keys: %u columns: %u uniques: %u flags: %u",
keys, columns, uniques, flags));
DBUG_ASSERT(maria_block_size && maria_block_size % MARIA_MIN_KEY_BLOCK_LENGTH == 0);
DBUG_ASSERT(maria_inited);
LINT_INIT(dfile);
LINT_INIT(file);
......@@ -95,6 +95,7 @@ int maria_create(const char *name, enum data_file_type datafile_type,
if (flags & HA_DONT_TOUCH_DATA)
{
/* We come here from recreate table */
org_datafile_type= ci->org_data_file_type;
if (!(ci->old_options & HA_OPTION_TEMP_COMPRESS_RECORD))
options= (ci->old_options &
......@@ -111,6 +112,12 @@ int maria_create(const char *name, enum data_file_type datafile_type,
HA_OPTION_PAGE_CHECKSUM));
}
}
else
{
/* Transactional tables must be of type BLOCK_RECORD */
if (ci->transactional)
datafile_type= BLOCK_RECORD;
}
if (ci->reloc_rows > ci->max_rows)
ci->reloc_rows=ci->max_rows; /* Check if wrong parameter */
......@@ -128,7 +135,6 @@ int maria_create(const char *name, enum data_file_type datafile_type,
/* Start by checking fields and field-types used */
varchar_length=long_varchar_count=packed= not_block_record_extra_length=
pack_reclength= max_field_lengths= 0;
reclength= min_pack_length= ci->null_bytes;
......@@ -296,7 +302,7 @@ int maria_create(const char *name, enum data_file_type datafile_type,
pack_bytes= (packed + 7) / 8;
if (pack_reclength != INT_MAX32)
pack_reclength+= reclength+pack_bytes +
test(test_all_bits(options, HA_OPTION_CHECKSUM | HA_PACK_RECORD));
test(test_all_bits(options, HA_OPTION_CHECKSUM | HA_OPTION_PACK_RECORD));
min_pack_length+= pack_bytes;
/* Calculate min possible row length for rows-in-block */
extra_header_size= MAX_FIXED_HEADER_SIZE;
......@@ -393,6 +399,9 @@ int maria_create(const char *name, enum data_file_type datafile_type,
length= real_length_diff= 0;
min_key_length= key_length= pointer;
if (keydef->key_alg == HA_KEY_ALG_RTREE)
keydef->flag|= HA_RTREE_INDEX; /* For easier tests */
if (keydef->flag & HA_SPATIAL)
{
#ifdef HAVE_SPATIAL
......@@ -1055,7 +1064,8 @@ int maria_create(const char *name, enum data_file_type datafile_type,
DROP+CREATE happened (applying REDOs to the wrong table).
*/
share.kfile.file= file;
if (_ma_update_state_lsns_sub(&share, lsn, FALSE, TRUE))
if (_ma_update_state_lsns_sub(&share, lsn, trnman_get_min_safe_trid(),
FALSE, TRUE))
goto err;
my_free(log_data, MYF(0));
}
......@@ -1277,6 +1287,8 @@ int _ma_initialize_data_file(MARIA_SHARE *share, File dfile)
It acquires intern_lock to protect the LSNs and state write.
@param share table's share
@param lsn LSN to write to log files
@param create_trid Trid to be used as state.create_trid
@param do_sync if the write should be forced to disk
@param update_create_rename_lsn if this LSN should be updated or not
......@@ -1285,12 +1297,12 @@ int _ma_initialize_data_file(MARIA_SHARE *share, File dfile)
@retval 1 error (disk problem)
*/
int _ma_update_state_lsns(MARIA_SHARE *share, LSN lsn, my_bool do_sync,
my_bool update_create_rename_lsn)
int _ma_update_state_lsns(MARIA_SHARE *share, LSN lsn, TrID create_trid,
my_bool do_sync, my_bool update_create_rename_lsn)
{
int res;
pthread_mutex_lock(&share->intern_lock);
res= _ma_update_state_lsns_sub(share, lsn, do_sync,
res= _ma_update_state_lsns_sub(share, lsn, create_trid, do_sync,
update_create_rename_lsn);
pthread_mutex_unlock(&share->intern_lock);
return res;
......@@ -1305,6 +1317,8 @@ int _ma_update_state_lsns(MARIA_SHARE *share, LSN lsn, my_bool do_sync,
needed (when creating a table or opening it for the first time).
@param share table's share
@param lsn LSN to write to log files
@param create_trid Trid to be used as state.create_trid
@param do_sync if the write should be forced to disk
@param update_create_rename_lsn if this LSN should be updated or not
......@@ -1320,15 +1334,19 @@ int _ma_update_state_lsns(MARIA_SHARE *share, LSN lsn, my_bool do_sync,
*/
#pragma optimize("",off)
#endif
int _ma_update_state_lsns_sub(MARIA_SHARE *share, LSN lsn, my_bool do_sync,
int _ma_update_state_lsns_sub(MARIA_SHARE *share, LSN lsn, TrID create_trid,
my_bool do_sync,
my_bool update_create_rename_lsn)
{
uchar buf[LSN_STORE_SIZE * 3], *ptr;
uchar trid_buff[8];
File file= share->kfile.file;
DBUG_ASSERT(file >= 0);
for (ptr= buf; ptr < (buf + sizeof(buf)); ptr+= LSN_STORE_SIZE)
lsn_store(ptr, lsn);
share->state.skip_redo_lsn= share->state.is_of_horizon= lsn;
share->state.create_trid= create_trid;
mi_int8store(trid_buff, create_trid);
if (update_create_rename_lsn)
{
share->state.create_rename_lsn= lsn;
......@@ -1348,13 +1366,14 @@ int _ma_update_state_lsns_sub(MARIA_SHARE *share, LSN lsn, my_bool do_sync,
}
else
lsn_store(buf, share->state.create_rename_lsn);
return my_pwrite(file, buf, sizeof(buf),
sizeof(share->state.header) +
MARIA_FILE_CREATE_RENAME_LSN_OFFSET, MYF(MY_NABP)) ||
(do_sync && my_sync(file, MYF(0)));
return (my_pwrite(file, buf, sizeof(buf),
sizeof(share->state.header) +
MARIA_FILE_CREATE_RENAME_LSN_OFFSET, MYF(MY_NABP)) ||
my_pwrite(file, trid_buff, sizeof(trid_buff),
sizeof(share->state.header) +
MARIA_FILE_CREATE_TRID_OFFSET, MYF(MY_NABP)) ||
(do_sync && my_sync(file, MYF(0))));
}
#if (_MSC_VER == 1310)
#pragma optimize("",on)
#endif /*VS2003 compiler bug workaround*/
......@@ -17,10 +17,16 @@
#include "maria_def.h"
/* Print a key in user understandable format */
void _ma_print_key(FILE *stream, MARIA_KEY *key)
{
_ma_print_keydata(stream, key->keyinfo->seg, key->data, key->data_length);
}
/* Print a key in a user understandable format */
void _ma_print_key(FILE *stream, register HA_KEYSEG *keyseg,
const uchar *key, uint length)
void _ma_print_keydata(FILE *stream, register HA_KEYSEG *keyseg,
const uchar *key, uint length)
{
int flag;
short int s_1;
......
This diff is collapsed.
......@@ -81,6 +81,8 @@ int maria_delete_all_rows(MARIA_HA *info)
/* Other branch called function below when writing log record, in hook */
_ma_reset_status(info);
}
/* Remove old history as the table is now empty for everyone */
_ma_reset_state(info);
/*
If we are using delayed keys or if the user has done changes to the tables
......@@ -115,7 +117,7 @@ int maria_delete_all_rows(MARIA_HA *info)
files.
*/
my_bool error= _ma_state_info_write(share, 1|4) ||
_ma_update_state_lsns(share, lsn, FALSE, FALSE) ||
_ma_update_state_lsns(share, lsn, trnman_get_min_trid(), FALSE, FALSE) ||
_ma_sync_table_files(info);
info->trn->rec_lsn= LSN_IMPOSSIBLE;
if (error)
......@@ -159,6 +161,7 @@ void _ma_reset_status(MARIA_HA *info)
MARIA_SHARE *share= info->s;
MARIA_STATE_INFO *state= &share->state;
uint i;
DBUG_ENTER("_ma_reset_status");
state->split= 0;
state->state.records= state->state.del= 0;
......@@ -177,4 +180,5 @@ void _ma_reset_status(MARIA_HA *info)
/* Clear all keys */
for (i=0 ; i < share->base.keys ; i++)
state->key_root[i]= HA_OFFSET_ERROR;
DBUG_VOID_RETURN;
}
......@@ -189,12 +189,14 @@ int maria_extra(MARIA_HA *info, enum ha_extra_function function,
case HA_EXTRA_KEYREAD: /* Read only keys to record */
case HA_EXTRA_REMEMBER_POS:
info->opt_flag|= REMEMBER_OLD_POS;
bmove((uchar*) info->lastkey+share->base.max_key_length*2,
(uchar*) info->lastkey,info->lastkey_length);
bmove((uchar*) info->last_key.data + share->base.max_key_length*2,
(uchar*) info->last_key.data,
info->last_key.data_length + info->last_key.ref_length);
info->save_update= info->update;
info->save_lastinx= info->lastinx;
info->save_lastpos= info->cur_row.lastpos;
info->save_lastkey_length= info->lastkey_length;
info->save_lastkey_data_length= info->last_key.data_length;
info->save_lastkey_ref_length= info->last_key.ref_length;
if (function == HA_EXTRA_REMEMBER_POS)
break;
/* fall through */
......@@ -206,13 +208,15 @@ int maria_extra(MARIA_HA *info, enum ha_extra_function function,
case HA_EXTRA_RESTORE_POS:
if (info->opt_flag & REMEMBER_OLD_POS)
{
bmove((uchar*) info->lastkey,
(uchar*) info->lastkey+share->base.max_key_length*2,
info->save_lastkey_length);
bmove((uchar*) info->last_key.data,
(uchar*) info->last_key.data + share->base.max_key_length*2,
info->save_lastkey_data_length + info->save_lastkey_ref_length);
info->update= info->save_update | HA_STATE_WRITTEN;
info->lastinx= info->save_lastinx;
info->cur_row.lastpos= info->save_lastpos;
info->lastkey_length= info->save_lastkey_length;
info->last_key.data_length= info->save_lastkey_data_length;
info->last_key.ref_length= info->save_lastkey_ref_length;
info->last_key.flag= 0;
}
info->read_record= share->read_record;
info->opt_flag&= ~(KEY_READ_USED | REMEMBER_OLD_POS);
......
......@@ -196,7 +196,7 @@ static int ftb_query_add_word(MYSQL_FTPARSER_PARAM *param,
case FT_TOKEN_WORD:
ftbw= (FTB_WORD *)alloc_root(&ftb_param->ftb->mem_root,
sizeof(FTB_WORD) +
(info->trunc ? HA_MAX_KEY_BUFF :
(info->trunc ? MARIA_MAX_KEY_BUFF :
word_len * ftb_param->ftb->charset->mbmaxlen +
HA_FT_WLEN +
ftb_param->ftb->info->s->rec_reflength));
......@@ -335,7 +335,9 @@ static int _ftb_no_dupes_cmp(void* not_used __attribute__((unused)),
return CMP_NUM((*((my_off_t*)a)), (*((my_off_t*)b)));
}
/* returns 1 if the search was finished (must-word wasn't found) */
static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search)
{
int r;
......@@ -344,6 +346,7 @@ static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search)
MARIA_HA *info=ftb->info;
uint off, extra=HA_FT_WLEN+info->s->base.rec_reflength;
uchar *lastkey_buf= ftbw->word+ftbw->off;
MARIA_KEY key;
LINT_INIT(off);
if (ftbw->flags & FTB_FLAG_TRUNC)
......@@ -353,9 +356,13 @@ static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search)
{
ftbw->key_root=info->s->state.key_root[ftb->keynr];
ftbw->keyinfo=info->s->keyinfo+ftb->keynr;
key.keyinfo= ftbw->keyinfo;
key.data= ftbw->word;
key.data_length= ftbw->len;
key.ref_length= 0;
key.flag= 0;
r= _ma_search(info, ftbw->keyinfo, ftbw->word, ftbw->len,
SEARCH_FIND | SEARCH_BIGGER, ftbw->key_root);
r= _ma_search(info, &key, SEARCH_FIND | SEARCH_BIGGER, ftbw->key_root);
}
else
{
......@@ -369,11 +376,17 @@ static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search)
if (ftbw->docid[0] < max_docid)
{
sflag|= SEARCH_SAME;
_ma_dpointer(info, (uchar*) (ftbw->word + ftbw->len + HA_FT_WLEN),
_ma_dpointer(info->s, (uchar*) (ftbw->word + ftbw->len + HA_FT_WLEN),
max_docid);
}
r= _ma_search(info, ftbw->keyinfo, lastkey_buf,
USE_WHOLE_KEY, sflag, ftbw->key_root);
key.keyinfo= ftbw->keyinfo;
key.data= lastkey_buf;
key.data_length= USE_WHOLE_KEY;
key.ref_length= 0;
key.flag= 0;
r= _ma_search(info, &key, sflag, ftbw->key_root);
}
can_go_down=(!ftbw->off && (init_search || (ftbw->flags & FTB_FLAG_TRUNC)));
......@@ -383,21 +396,20 @@ static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search)
if (can_go_down)
{
/* going down ? */
off=info->lastkey_length-extra;
subkeys=ft_sintXkorr(info->lastkey+off);
off= info->last_key.data_length + info->last_key.ref_length - extra;
subkeys=ft_sintXkorr(info->last_key.data + off);
}
if (subkeys<0 || info->cur_row.lastpos < info->state->data_file_length)
break;
r= _ma_search_next(info, ftbw->keyinfo, info->lastkey,
info->lastkey_length,
SEARCH_BIGGER, ftbw->key_root);
r= _ma_search_next(info, &info->last_key, SEARCH_BIGGER, ftbw->key_root);
}
if (!r && !ftbw->off)
{
r= ha_compare_text(ftb->charset,
info->lastkey+1,
info->lastkey_length-extra-1,
info->last_key.data+1,
info->last_key.data_length + info->last_key.ref_length-
extra-1,
(uchar*) ftbw->word+1,
ftbw->len-1,
(my_bool) (ftbw->flags & FTB_FLAG_TRUNC), 0);
......@@ -422,7 +434,7 @@ static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search)
}
/* going up to the first-level tree to continue search there */
_ma_dpointer(info, (lastkey_buf+HA_FT_WLEN), ftbw->key_root);
_ma_dpointer(info->s, (lastkey_buf+HA_FT_WLEN), ftbw->key_root);
ftbw->key_root=info->s->state.key_root[ftb->keynr];
ftbw->keyinfo=info->s->keyinfo+ftb->keynr;
ftbw->off=0;
......@@ -430,9 +442,10 @@ static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search)
}
/* matching key found */
memcpy(lastkey_buf, info->lastkey, info->lastkey_length);
memcpy(lastkey_buf, info->last_key.data,
info->last_key.data_length + info->last_key.ref_length);
if (lastkey_buf == ftbw->word)
ftbw->len=info->lastkey_length-extra;
ftbw->len= info->last_key.data_length + info->last_key.ref_length - extra;
/* going down ? */
if (subkeys<0)
......@@ -446,7 +459,8 @@ static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search)
ftbw->keyinfo=& info->s->ft2_keyinfo;
r= _ma_search_first(info, ftbw->keyinfo, ftbw->key_root);
DBUG_ASSERT(r==0); /* found something */
memcpy(lastkey_buf+off, info->lastkey, info->lastkey_length);
memcpy(lastkey_buf+off, info->last_key.data,
info->last_key.data_length + info->last_key.ref_length);
}
ftbw->docid[0]= info->cur_row.lastpos;
if (ftbw->flags & FTB_FLAG_YES && !(ftbw->flags & FTB_FLAG_TRUNC))
......
......@@ -64,7 +64,7 @@ static int FT_SUPERDOC_cmp(void* cmp_arg __attribute__((unused)),
static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio)
{
int subkeys, r;
uint keylen, doc_cnt;
uint doc_cnt;
FT_SUPERDOC sdoc, *sptr;
TREE_ELEMENT *selem;
double gweight=1;
......@@ -73,27 +73,28 @@ static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio)
MARIA_KEYDEF *keyinfo=info->s->keyinfo+aio->keynr;
my_off_t key_root=info->s->state.key_root[aio->keynr];
uint extra=HA_FT_WLEN+info->s->base.rec_reflength;
MARIA_KEY key;
#if HA_FT_WTYPE == HA_KEYTYPE_FLOAT
float tmp_weight;
#else
#error
#endif
DBUG_ENTER("walk_and_match");
word->weight=LWS_FOR_QUERY;
keylen= _ma_ft_make_key(info, aio->keynr, keybuff, word, 0);
keylen-=HA_FT_WLEN;
_ma_ft_make_key(info, &key, aio->keynr, keybuff, word, 0);
key.data_length-= HA_FT_WLEN;
doc_cnt=0;
/* Skip rows inserted by current inserted */
for (r= _ma_search(info, keyinfo, keybuff, keylen, SEARCH_FIND, key_root) ;
for (r= _ma_search(info, &key, SEARCH_FIND, key_root) ;
!r &&
(subkeys=ft_sintXkorr(info->lastkey+info->lastkey_length-extra)) > 0 &&
(subkeys=ft_sintXkorr(info->last_key.data +
info->last_key.data_length +
info->last_key.ref_length - extra)) > 0 &&
info->cur_row.lastpos >= info->state->data_file_length ;
r= _ma_search_next(info, keyinfo, info->lastkey,
info->lastkey_length, SEARCH_BIGGER, key_root))
r= _ma_search_next(info, &info->last_key, SEARCH_BIGGER, key_root))
;
info->update|= HA_STATE_AKTIV; /* for _ma_test_if_changed() */
......@@ -102,10 +103,12 @@ static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio)
while (!r && gweight)
{
if (keylen &&
if (key.data_length &&
ha_compare_text(aio->charset,
(uchar*) info->lastkey+1, info->lastkey_length-extra-1,
(uchar*) keybuff+1, keylen-1, 0, 0))
info->last_key.data+1,
info->last_key.data_length +
info->last_key.ref_length - extra - 1,
key.data+1, key.data_length-1, 0, 0))
break;
if (subkeys<0)
......@@ -116,10 +119,10 @@ static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio)
TODO here: unsafe optimization, should this word
be skipped (based on subkeys) ?
*/
keybuff+=keylen;
keyinfo=& info->s->ft2_keyinfo;
keybuff+= key.data_length;
keyinfo= &info->s->ft2_keyinfo;
key_root= info->cur_row.lastpos;
keylen=0;
key.data_length= 0;
r= _ma_search_first(info, keyinfo, key_root);
goto do_skip;
}
......@@ -155,16 +158,15 @@ static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio)
gweight=0;
if (_ma_test_if_changed(info) == 0)
r= _ma_search_next(info, keyinfo, info->lastkey, info->lastkey_length,
SEARCH_BIGGER, key_root);
r= _ma_search_next(info, &info->last_key, SEARCH_BIGGER, key_root);
else
r= _ma_search(info, keyinfo, info->lastkey, info->lastkey_length,
SEARCH_BIGGER, key_root);
r= _ma_search(info, &info->last_key, SEARCH_BIGGER, key_root);
do_skip:
while ((subkeys=ft_sintXkorr(info->lastkey+info->lastkey_length-extra)) > 0 &&
while ((subkeys=ft_sintXkorr(info->last_key.data +
info->last_key.data_length +
info->last_key.ref_length - extra)) > 0 &&
!r && info->cur_row.lastpos >= info->state->data_file_length)
r= _ma_search_next(info, keyinfo, info->lastkey, info->lastkey_length,
SEARCH_BIGGER, key_root);
r= _ma_search_next(info, &info->last_key, SEARCH_BIGGER, key_root);
}
word->weight=gweight;
......@@ -224,7 +226,7 @@ FT_INFO *maria_ft_init_nlq_search(MARIA_HA *info, uint keynr, uchar *query,
aio.info=info;
aio.keynr=keynr;
aio.charset=info->s->keyinfo[keynr].seg->charset;
aio.keybuff= (uchar*) info->lastkey+info->s->base.max_key_length;
aio.keybuff= info->lastkey_buff2;
parser= info->s->keyinfo[keynr].parser;
if (! (ftparser_param= maria_ftparser_call_initializer(info, keynr, 0)))
goto err;
......
......@@ -135,13 +135,13 @@ FT_WORD * _ma_ft_parserecord(MARIA_HA *info, uint keynr, const uchar *record,
static int _ma_ft_store(MARIA_HA *info, uint keynr, uchar *keybuf,
FT_WORD *wlist, my_off_t filepos)
{
uint key_length;
DBUG_ENTER("_ma_ft_store");
for (; wlist->pos; wlist++)
{
key_length= _ma_ft_make_key(info,keynr,keybuf,wlist,filepos);
if (_ma_ck_write(info, keynr, keybuf, key_length))
MARIA_KEY key;
_ma_ft_make_key(info, &key, keynr, keybuf, wlist, filepos);
if (_ma_ck_write(info, &key))
DBUG_RETURN(1);
}
DBUG_RETURN(0);
......@@ -150,13 +150,14 @@ static int _ma_ft_store(MARIA_HA *info, uint keynr, uchar *keybuf,
static int _ma_ft_erase(MARIA_HA *info, uint keynr, uchar *keybuf,
FT_WORD *wlist, my_off_t filepos)
{
uint key_length, err=0;
uint err=0;
DBUG_ENTER("_ma_ft_erase");
for (; wlist->pos; wlist++)
{
key_length= _ma_ft_make_key(info,keynr,keybuf,wlist,filepos);
if (_ma_ck_delete(info, keynr, keybuf, key_length))
MARIA_KEY key;
_ma_ft_make_key(info, &key, keynr, keybuf, wlist, filepos);
if (_ma_ck_delete(info, &key))
err=1;
}
DBUG_RETURN(err);
......@@ -199,7 +200,6 @@ int _ma_ft_update(MARIA_HA *info, uint keynr, uchar *keybuf,
int error= -1;
FT_WORD *oldlist,*newlist, *old_word, *new_word;
CHARSET_INFO *cs=info->s->keyinfo[keynr].seg->charset;
uint key_length;
int cmp, cmp2;
DBUG_ENTER("_ma_ft_update");
......@@ -218,14 +218,16 @@ int _ma_ft_update(MARIA_HA *info, uint keynr, uchar *keybuf,
if (cmp < 0 || cmp2)
{
key_length= _ma_ft_make_key(info,keynr,keybuf,old_word,pos);
if ((error= _ma_ck_delete(info,keynr, keybuf,key_length)))
MARIA_KEY key;
_ma_ft_make_key(info, &key, keynr, keybuf, old_word, pos);
if ((error= _ma_ck_delete(info, &key)))
goto err;
}
if (cmp > 0 || cmp2)
{
key_length= _ma_ft_make_key(info, keynr, keybuf, new_word,pos);
if ((error= _ma_ck_write(info, keynr, keybuf,key_length)))
MARIA_KEY key;
_ma_ft_make_key(info, &key, keynr, keybuf, new_word,pos);
if ((error= _ma_ck_write(info, &key)))
goto err;
}
if (cmp<=0) old_word++;
......@@ -278,8 +280,9 @@ int _ma_ft_del(MARIA_HA *info, uint keynr, uchar *keybuf, const uchar *record,
}
uint _ma_ft_make_key(MARIA_HA *info, uint keynr, uchar *keybuf, FT_WORD *wptr,
my_off_t filepos)
MARIA_KEY *_ma_ft_make_key(MARIA_HA *info, MARIA_KEY *key, uint keynr,
uchar *keybuf,
FT_WORD *wptr, my_off_t filepos)
{
uchar buf[HA_FT_MAXBYTELEN+16];
DBUG_ENTER("_ma_ft_make_key");
......@@ -295,7 +298,8 @@ uint _ma_ft_make_key(MARIA_HA *info, uint keynr, uchar *keybuf, FT_WORD *wptr,
int2store(buf+HA_FT_WLEN,wptr->len);
memcpy(buf+HA_FT_WLEN+2,wptr->pos,wptr->len);
DBUG_RETURN(_ma_make_key(info, keynr, keybuf, buf, filepos));
/* Can't be spatial so it's ok to call _ma_make_key directly here */
DBUG_RETURN(_ma_make_key(info, key, keynr, keybuf, buf, filepos, 0));
}
......@@ -303,7 +307,7 @@ uint _ma_ft_make_key(MARIA_HA *info, uint keynr, uchar *keybuf, FT_WORD *wptr,
convert key value to ft2
*/
uint _ma_ft_convert_to_ft2(MARIA_HA *info, uint keynr, uchar *key)
uint _ma_ft_convert_to_ft2(MARIA_HA *info, MARIA_KEY *key)
{
MARIA_SHARE *share= info->s;
my_off_t root;
......@@ -312,6 +316,7 @@ uint _ma_ft_convert_to_ft2(MARIA_HA *info, uint keynr, uchar *key)
uchar *key_ptr= (uchar*) dynamic_array_ptr(da, 0), *end;
uint length, key_length;
MARIA_PINNED_PAGE tmp_page_link, *page_link= &tmp_page_link;
MARIA_KEY tmp_key;
DBUG_ENTER("_ma_ft_convert_to_ft2");
/* we'll generate one pageful at once, and insert the rest one-by-one */
......@@ -320,8 +325,8 @@ uint _ma_ft_convert_to_ft2(MARIA_HA *info, uint keynr, uchar *key)
set_if_smaller(length, da->elements);
length=length * keyinfo->keylength;
get_key_full_length_rdonly(key_length, key);
while (_ma_ck_delete(info, keynr, key, key_length) == 0)
get_key_full_length_rdonly(key_length, key->data);
while (_ma_ck_delete(info, key) == 0)
{
/*
nothing to do here.
......@@ -331,7 +336,7 @@ uint _ma_ft_convert_to_ft2(MARIA_HA *info, uint keynr, uchar *key)
/* creating pageful of keys */
bzero(info->buff, share->keypage_header);
_ma_store_keynr(share, info->buff, keynr);
_ma_store_keynr(share, info->buff, keyinfo->key_nr);
_ma_store_page_used(share, info->buff, length + share->keypage_header);
memcpy(info->buff + share->keypage_header, key_ptr, length);
info->keyread_buff_used= info->page_changed=1; /* info->buff is used */
......@@ -346,17 +351,23 @@ uint _ma_ft_convert_to_ft2(MARIA_HA *info, uint keynr, uchar *key)
/* inserting the rest of key values */
end= (uchar*) dynamic_array_ptr(da, da->elements);
tmp_key.keyinfo= keyinfo;
tmp_key.data_length= keyinfo->keylength;
tmp_key.ref_length= 0;
tmp_key.flag= 0;
for (key_ptr+=length; key_ptr < end; key_ptr+=keyinfo->keylength)
if(_ma_ck_real_write_btree(info, keyinfo, key_ptr, 0, &root, SEARCH_SAME))
{
tmp_key.data= key_ptr;
if (_ma_ck_real_write_btree(info, key, &root, SEARCH_SAME))
DBUG_RETURN(-1);
}
/* now, writing the word key entry */
ft_intXstore(key+key_length, - (int) da->elements);
_ma_dpointer(info, key+key_length+HA_FT_WLEN, root);
DBUG_RETURN(_ma_ck_real_write_btree(info,
share->keyinfo+keynr,
key, 0,
&share->state.key_root[keynr],
SEARCH_SAME));
ft_intXstore(key->data + key_length, - (int) da->elements);
_ma_dpointer(share, key->data + key_length + HA_FT_WLEN, root);
DBUG_RETURN(_ma_ck_real_write_btree(info, key,
&share->state.key_root[key->keyinfo->
key_nr],
SEARCH_SAME));
}
......@@ -103,12 +103,13 @@ typedef struct st_maria_ft_word {
int is_stopword(char *word, uint len);
uint _ma_ft_make_key(MARIA_HA *, uint , uchar *, FT_WORD *, my_off_t);
MARIA_KEY *_ma_ft_make_key(MARIA_HA *, MARIA_KEY *, uint , uchar *, FT_WORD *,
my_off_t);
uchar maria_ft_get_word(CHARSET_INFO *, uchar **, uchar *, FT_WORD *,
MYSQL_FTPARSER_BOOLEAN_INFO *);
MYSQL_FTPARSER_BOOLEAN_INFO *);
uchar maria_ft_simple_get_word(CHARSET_INFO *, uchar **, const uchar *,
FT_WORD *, my_bool);
FT_WORD *, my_bool);
typedef struct _st_maria_ft_seg_iterator {
uint num, len;
......
......@@ -24,4 +24,4 @@ int _ma_ft_cmp(MARIA_HA *, uint, const uchar *, const uchar *);
int _ma_ft_add(MARIA_HA *, uint, uchar *, const uchar *, my_off_t);
int _ma_ft_del(MARIA_HA *, uint, uchar *, const uchar *, my_off_t);
uint _ma_ft_convert_to_ft2(MARIA_HA *, uint, uchar *);
uint _ma_ft_convert_to_ft2(MARIA_HA *, MARIA_KEY *);
......@@ -56,6 +56,8 @@ void history_state_free(MARIA_STATE_HISTORY_CLOSED *closed_history)
int maria_init(void)
{
DBUG_ASSERT(maria_block_size &&
maria_block_size % MARIA_MIN_KEY_BLOCK_LENGTH == 0);
if (!maria_inited)
{
maria_inited= TRUE;
......
......@@ -18,12 +18,16 @@
#include "maria_def.h"
#include "m_ctype.h"
#include "ma_sp_defs.h"
#include "ma_blockrec.h" /* For ROW_FLAG_TRANSID */
#include <trnman.h>
#ifdef HAVE_IEEEFP_H
#include <ieeefp.h>
#endif
#define CHECK_KEYS /* Enable safety checks */
static int _ma_put_key_in_record(MARIA_HA *info,uint keynr,uchar *record);
#define FIX_LENGTH(cs, pos, length, char_length) \
do { \
if (length > char_length) \
......@@ -31,46 +35,146 @@
set_if_smaller(char_length,length); \
} while(0)
static int _ma_put_key_in_record(MARIA_HA *info,uint keynr,uchar *record);
/**
Store trid in a packed format as part of a key
@fn transid_store_packed
@param info Maria handler
@param to End of key to which we should store a packed transid
@param trid Trid to be stored
@notes
Keys that have a transid has the lowest bit set for the last byte of the key
This function sets this bit for the key.
Trid is max 6 bytes long
First Trid it's converted to a smaller number by using
trid= trid - create_trid.
Then trid is then shifted up one bit so that we can use the
lowest bit as a marker if it's followed by another trid.
Trid is then stored as follows:
if trid < 256-12
one byte
else
one byte prefix (256-length_of_trid_in_bytes) followed by data
in high-byte-first order
Prefix bytes 244 to 249 are reserved for negative transid, that can be used
when we pack transid relative to each other on a key block.
We have to store transid in high-byte-first order to be able to do a
fast byte-per-byte comparision of them without packing them up.
*/
uint transid_store_packed(MARIA_HA *info, uchar *to, ulonglong trid)
{
uchar *start;
uint length;
uchar buff[8];
DBUG_ASSERT(trid < (LL(1) << (MAX_PACK_TRANSID_SIZE*8)));
DBUG_ASSERT(trid >= info->s->state.create_trid);
trid= (trid - info->s->state.create_trid) << 1;
/* Mark that key contains transid */
to[-1]|= 1;
if (trid < MIN_TRANSID_PACK_PREFIX)
{
to[0]= (uchar) trid;
return 1;
}
start= to;
/* store things in low-byte-first-order in buff */
to= buff;
do
{
*to++= (uchar) trid;
trid= trid>>8;
} while (trid);
length= (uint) (to - buff);
start[0]= (uchar) (256 - length); /* Store length prefix */
start++;
/* Copy things in high-byte-first order to output buffer */
do
{
*start++= *--to;
} while (to != buff);
return length+1;
}
/**
Read packed transid
@fn transid_get_packed
@param info Maria handler
@param from Transid is stored here
See transid_store_packed() for how transid is packed
*/
ulonglong transid_get_packed(MARIA_SHARE *share, const uchar *from)
{
ulonglong value;
uint length;
if (from[0] < MIN_TRANSID_PACK_PREFIX)
value= (ulonglong) from[0];
else
{
value= 0;
for (length= (uint) (256 - from[0]), value= (ulonglong) from[1], from+=2;
--length ;
from++)
value= (value << 8) + ((ulonglong) *from);
}
return (value >> 1) + share->state.create_trid;
}
/*
Make a intern key from a record
Make a normal (not spatial or fulltext) intern key from a record
SYNOPSIS
_ma_make_key()
info MyiSAM handler
int_key Store created key here
keynr key number
key Store created key here
key Buffer used to store key data
record Record
filepos Position to record in the data file
NOTES
This is used to generate keys from the record on insert, update and delete
RETURN
Length of key
key
*/
uint _ma_make_key(register MARIA_HA *info, uint keynr, uchar *key,
const uchar *record, MARIA_RECORD_POS filepos)
MARIA_KEY *_ma_make_key(MARIA_HA *info, MARIA_KEY *int_key, uint keynr,
uchar *key, const uchar *record,
MARIA_RECORD_POS filepos, ulonglong trid)
{
const uchar *pos;
uchar *start;
reg1 HA_KEYSEG *keyseg;
my_bool is_ft= info->s->keyinfo[keynr].flag & HA_FULLTEXT;
my_bool is_ft;
DBUG_ENTER("_ma_make_key");
if (info->s->keyinfo[keynr].flag & HA_SPATIAL)
{
/*
TODO: nulls processing
*/
#ifdef HAVE_SPATIAL
DBUG_RETURN(_ma_sp_make_key(info,keynr, key,record,filepos));
#else
DBUG_ASSERT(0); /* maria_open should check that this never happens*/
#endif
}
int_key->data= key;
int_key->flag= 0; /* Always return full key */
int_key->keyinfo= info->s->keyinfo + keynr;
start=key;
for (keyseg=info->s->keyinfo[keynr].seg ; keyseg->type ;keyseg++)
is_ft= int_key->keyinfo->flag & HA_FULLTEXT;
for (keyseg= int_key->keyinfo->seg ; keyseg->type ;keyseg++)
{
enum ha_base_keytype type=(enum ha_base_keytype) keyseg->type;
uint length=keyseg->length;
......@@ -188,13 +292,22 @@ uint _ma_make_key(register MARIA_HA *info, uint keynr, uchar *key,
cs->cset->fill(cs, (char*) key+char_length, length-char_length, ' ');
key+= length;
}
_ma_dpointer(info,key,filepos);
_ma_dpointer(info->s, key, filepos);
int_key->data_length= (key - int_key->data);
int_key->ref_length= info->s->rec_reflength;
int_key->flag= 0;
if (_ma_have_versioning(info) && trid)
{
int_key->ref_length+= transid_store_packed(info,
key + int_key->ref_length,
(TrID) trid);
int_key->flag|= SEARCH_USER_KEY_HAS_TRANSID;
}
DBUG_PRINT("exit",("keynr: %d",keynr));
DBUG_DUMP("key",start,(uint) (key-start)+keyseg->length);
DBUG_EXECUTE("key",
_ma_print_key(DBUG_FILE,info->s->keyinfo[keynr].seg,start,
(uint) (key-start)););
DBUG_RETURN((uint) (key-start)); /* Return keylength */
DBUG_DUMP_KEY("key", int_key);
DBUG_EXECUTE("key", _ma_print_key(DBUG_FILE, int_key););
DBUG_RETURN(int_key);
} /* _ma_make_key */
......@@ -204,35 +317,40 @@ uint _ma_make_key(register MARIA_HA *info, uint keynr, uchar *key,
SYNOPSIS
_ma_pack_key()
info MARIA handler
uint keynr key number
key Store packed key here
old Not packed key
int_key Store key here
keynr key number
key Buffer for key data
old Original not packed key
keypart_map bitmap of used keyparts
last_used_keyseg out parameter. May be NULL
RETURN
length of packed key
int_key
last_use_keyseg Store pointer to the keyseg after the last used one
*/
uint _ma_pack_key(register MARIA_HA *info, uint keynr, uchar *key,
const uchar *old, key_part_map keypart_map,
HA_KEYSEG **last_used_keyseg)
MARIA_KEY *_ma_pack_key(register MARIA_HA *info, MARIA_KEY *int_key,
uint keynr, uchar *key,
const uchar *old, key_part_map keypart_map,
HA_KEYSEG **last_used_keyseg)
{
uchar *start_key=key;
HA_KEYSEG *keyseg;
my_bool is_ft= info->s->keyinfo[keynr].flag & HA_FULLTEXT;
my_bool is_ft;
DBUG_ENTER("_ma_pack_key");
int_key->data= key;
int_key->keyinfo= info->s->keyinfo + keynr;
/* "one part" rtree key is 2*SPDIMS part key in Maria */
if (info->s->keyinfo[keynr].key_alg == HA_KEY_ALG_RTREE)
if (int_key->keyinfo->key_alg == HA_KEY_ALG_RTREE)
keypart_map= (((key_part_map)1) << (2*SPDIMS)) - 1;
/* only key prefixes are supported */
DBUG_ASSERT(((keypart_map+1) & keypart_map) == 0);
for (keyseg=info->s->keyinfo[keynr].seg ; keyseg->type && keypart_map;
is_ft= int_key->keyinfo->flag & HA_FULLTEXT;
for (keyseg=int_key->keyinfo->seg ; keyseg->type && keypart_map;
old+= keyseg->length, keyseg++)
{
enum ha_base_keytype type= (enum ha_base_keytype) keyseg->type;
......@@ -303,11 +421,29 @@ uint _ma_pack_key(register MARIA_HA *info, uint keynr, uchar *key,
if (last_used_keyseg)
*last_used_keyseg= keyseg;
DBUG_PRINT("exit", ("length: %u", (uint) (key-start_key)));
DBUG_RETURN((uint) (key-start_key));
/* set flag to SEARCH_PART_KEY if we are not using all key parts */
int_key->flag= keyseg->type ? SEARCH_PART_KEY : 0;
int_key->ref_length= 0;
int_key->data_length= (key - int_key->data);
DBUG_PRINT("exit", ("length: %u", int_key->data_length));
DBUG_RETURN(int_key);
} /* _ma_pack_key */
/**
Copy a key
*/
void _ma_copy_key(MARIA_KEY *to, const MARIA_KEY *from)
{
memcpy(to->data, from->data, from->data_length + from->ref_length);
to->keyinfo= from->keyinfo;
to->data_length= from->data_length;
to->ref_length= from->ref_length;
to->flag= from->flag;
}
/*
Store found key in record
......@@ -337,9 +473,9 @@ static int _ma_put_key_in_record(register MARIA_HA *info, uint keynr,
uchar *blob_ptr;
DBUG_ENTER("_ma_put_key_in_record");
blob_ptr= info->lastkey2; /* Place to put blob parts */
key=info->lastkey; /* KEy that was read */
key_end=key+info->lastkey_length;
blob_ptr= info->lastkey_buff2; /* Place to put blob parts */
key= info->last_key.data; /* Key that was read */
key_end= key + info->last_key.data_length;
for (keyseg=info->s->keyinfo[keynr].seg ; keyseg->type ;keyseg++)
{
if (keyseg->null_bit)
......
This diff is collapsed.
......@@ -46,12 +46,10 @@ my_bool _ma_write_clr(MARIA_HA *info, LSN undo_lsn,
enum translog_record_type undo_type,
my_bool store_checksum, ha_checksum checksum,
LSN *res_lsn, void *extra_msg);
int _ma_write_undo_key_insert(MARIA_HA *info, const MARIA_KEYDEF *keyinfo,
const uchar *key, uint key_length,
int _ma_write_undo_key_insert(MARIA_HA *info, const MARIA_KEY *key,
my_off_t *root, my_off_t new_root,
LSN *res_lsn);
int _ma_write_undo_key_delete(MARIA_HA *info, uint keynr,
const uchar *key, uint key_length,
int _ma_write_undo_key_delete(MARIA_HA *info, const MARIA_KEY *key,
my_off_t new_root, LSN *res_lsn);
my_bool write_hook_for_clr_end(enum translog_record_type type,
TRN *trn, MARIA_HA *tbl_info, LSN *lsn,
......
......@@ -427,6 +427,7 @@ int _ma_mark_file_changed(MARIA_HA *info)
if (_ma_set_uuid(info, 0) ||
(share->state.create_rename_lsn == LSN_REPAIRED_BY_MARIA_CHK &&
_ma_update_state_lsns_sub(share, translog_get_horizon(),
trnman_get_min_trid(),
TRUE, TRUE)))
DBUG_RETURN(1);
share->state.changed|= STATE_NOT_MOVABLE;
......
......@@ -1649,7 +1649,7 @@ static void translog_new_page_header(TRANSLOG_ADDRESS *horizon,
}
cursor->ptr= ptr;
DBUG_PRINT("info", ("NewP buffer #%u: 0x%lx chaser: %d Size: %lu (%lu) "
"Horizon: (%lu,0x%lu)",
"Horizon: (%lu,0x%lx)",
(uint) cursor->buffer->buffer_no, (ulong) cursor->buffer,
cursor->chaser, (ulong) cursor->buffer->size,
(ulong) (cursor->ptr - cursor->buffer->buffer),
......@@ -3162,8 +3162,8 @@ static my_bool translog_truncate_log(TRANSLOG_ADDRESS addr)
uchar page_buff[TRANSLOG_PAGE_SIZE];
DBUG_ENTER("translog_truncate_log");
/* TODO: write warning to the client */
DBUG_PRINT("warning", ("removing all records from (%lx,0x%lx) "
"till (%lx,0x%lx)",
DBUG_PRINT("warning", ("removing all records from (%lu,0x%lx) "
"till (%lu,0x%lx)",
LSN_IN_PARTS(addr),
LSN_IN_PARTS(log_descriptor.horizon)));
DBUG_ASSERT(cmp_translog_addr(addr, log_descriptor.horizon) < 0);
......@@ -4945,7 +4945,7 @@ static uchar *translog_put_LSN_diff(LSN base_lsn, LSN lsn, uchar *dst)
{
uint64 diff;
DBUG_ENTER("translog_put_LSN_diff");
DBUG_PRINT("enter", ("Base: (0x%lu,0x%lx) val: (0x%lu,0x%lx) dst: 0x%lx",
DBUG_PRINT("enter", ("Base: (%lu,0x%lx) val: (%lu,0x%lx) dst: 0x%lx",
LSN_IN_PARTS(base_lsn), LSN_IN_PARTS(lsn),
(ulong) dst));
DBUG_ASSERT(base_lsn > lsn);
......@@ -5030,7 +5030,7 @@ static uchar *translog_get_LSN_from_diff(LSN base_lsn, uchar *src, uchar *dst)
uint32 file_no, rec_offset;
uint8 code;
DBUG_ENTER("translog_get_LSN_from_diff");
DBUG_PRINT("enter", ("Base: (0x%lx,0x%lx) src: 0x%lx dst 0x%lx",
DBUG_PRINT("enter", ("Base: (%lu,0x%lx) src: 0x%lx dst 0x%lx",
LSN_IN_PARTS(base_lsn), (ulong) src, (ulong) dst));
first_byte= *((uint8*) src);
code= first_byte >> 6; /* Length is in 2 most significant bits */
......@@ -6297,7 +6297,7 @@ my_bool translog_scanner_init(LSN lsn,
{
TRANSLOG_VALIDATOR_DATA data;
DBUG_ENTER("translog_scanner_init");
DBUG_PRINT("enter", ("Scanner: 0x%lx LSN: (0x%lu,0x%lx)",
DBUG_PRINT("enter", ("Scanner: 0x%lx LSN: (%lu,0x%lx)",
(ulong) scanner, LSN_IN_PARTS(lsn)));
DBUG_ASSERT(translog_status == TRANSLOG_OK ||
translog_status == TRANSLOG_READONLY);
......@@ -6312,8 +6312,7 @@ my_bool translog_scanner_init(LSN lsn,
scanner->direct_link= NULL;
scanner->horizon= translog_get_horizon();
DBUG_PRINT("info", ("horizon: (0x%lu,0x%lx)",
LSN_IN_PARTS(scanner->horizon)));
DBUG_PRINT("info", ("horizon: (%lu,0x%lx)", LSN_IN_PARTS(scanner->horizon)));
/* lsn < horizon */
DBUG_ASSERT(lsn <= scanner->horizon);
......@@ -6783,7 +6782,7 @@ int translog_read_record_header(LSN lsn, TRANSLOG_HEADER_BUFFER *buff)
TRANSLOG_ADDRESS addr;
TRANSLOG_VALIDATOR_DATA data;
DBUG_ENTER("translog_read_record_header");
DBUG_PRINT("enter", ("LSN: (0x%lu,0x%lx)", LSN_IN_PARTS(lsn)));
DBUG_PRINT("enter", ("LSN: (%lu,0x%lx)", LSN_IN_PARTS(lsn)));
DBUG_ASSERT(LSN_OFFSET(lsn) % TRANSLOG_PAGE_SIZE != 0);
DBUG_ASSERT(translog_status == TRANSLOG_OK ||
translog_status == TRANSLOG_READONLY);
......@@ -7221,7 +7220,7 @@ static void translog_force_current_buffer_to_finish()
LSN_FILE_NO(log_descriptor.bc.buffer->offset));
translog_check_cursor(&log_descriptor.bc);
DBUG_ASSERT(left < TRANSLOG_PAGE_SIZE);
if (left != 0)
if (left)
{
/*
TODO: if 'left' is so small that can't hold any other record
......
......@@ -161,7 +161,9 @@ enum en_key_op
KEY_OP_ADD_SUFFIX, /* Insert data at end of page */
KEY_OP_DEL_SUFFIX, /* Delete data at end of page */
KEY_OP_CHECK, /* For debugging; CRC of used part of page */
KEY_OP_MULTI_COPY /* List of memcpy()s with fixed-len sources in page */
KEY_OP_MULTI_COPY, /* List of memcpy()s with fixed-len sources in page */
KEY_OP_SET_PAGEFLAG, /* Set pageflag from next byte */
KEY_OP_COMPACT_PAGE /* Compact key page */
};
/* Size of log file; One log file is restricted to 4G */
......
This diff is collapsed.
......@@ -13,7 +13,32 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Read and write key blocks */
/*
Read and write key blocks
The basic structure of a key block is as follows:
LSN 7 (LSN_STORE_SIZE); Log number for last change;
Only for transactional pages
PACK_TRANSID 6 (TRANSID_SIZE); Relative transid to pack page transid's
Only for transactional pages
KEYNR 1 (KEYPAGE_KEYID_SIZE) Which index this page belongs to
FLAG 1 (KEYPAGE_FLAG_SIZE) Flags for page
PAGE_SIZE 2 (KEYPAGE_USED_SIZE) How much of the page is used.
high-byte-first
The flag is a combination of the following values:
KEYPAGE_FLAG_ISNOD Page is a node
KEYPAGE_FLAG_HAS_TRANSID There may be a transid on the page.
After this we store key data, either packed or not packed, directly
after each other. If the page is a node flag, there is a pointer to
the next key page at page start and after each key.
At end of page the last KEYPAGE_CHECKSUM_SIZE bytes are reserved for a
page checksum.
*/
#include "maria_def.h"
#include "trnman.h"
......@@ -163,7 +188,7 @@ int _ma_write_keypage(register MARIA_HA *info,
}
/*
/**
@brief Put page in free list
@fn _ma_dispose()
......@@ -366,3 +391,150 @@ my_off_t _ma_new(register MARIA_HA *info, int level,
DBUG_PRINT("exit",("Pos: %ld",(long) pos));
DBUG_RETURN(pos);
} /* _ma_new */
/**
Log compactation of a index page
*/
static my_bool _ma_log_compact_keypage(MARIA_HA *info, my_off_t page,
TrID min_read_from)
{
LSN lsn;
uchar log_data[FILEID_STORE_SIZE + PAGE_STORE_SIZE + 1 + TRANSID_SIZE];
LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 1];
MARIA_SHARE *share= info->s;
DBUG_ENTER("_ma_log_compact_keypage");
DBUG_PRINT("enter", ("page: %lu", (ulong) page));
/* Store address of new root page */
page/= share->block_size;
page_store(log_data + FILEID_STORE_SIZE, page);
log_data[FILEID_STORE_SIZE + PAGE_STORE_SIZE]= KEY_OP_COMPACT_PAGE;
transid_store(log_data + FILEID_STORE_SIZE + PAGE_STORE_SIZE +1,
min_read_from);
log_array[TRANSLOG_INTERNAL_PARTS + 0].str= log_data;
log_array[TRANSLOG_INTERNAL_PARTS + 0].length= sizeof(log_data);
if (translog_write_record(&lsn, LOGREC_REDO_INDEX,
info->trn, info,
(translog_size_t) sizeof(log_data),
TRANSLOG_INTERNAL_PARTS + 1, log_array,
log_data, NULL))
DBUG_RETURN(1);
DBUG_RETURN(0);
}
/**
Remove all transaction id's less than given one from a key page
@fn _ma_compact_keypage()
@param keyinfo Key handler
@param page_pos Page position on disk
@param page Buffer for page
@param min_read_from Remove all trids from page less than this
@retval 0 Ok
retval 1 Error; my_errno contains the error
*/
my_bool _ma_compact_keypage(MARIA_HA *info, MARIA_KEYDEF *keyinfo,
my_off_t page_pos, uchar *page, TrID min_read_from)
{
MARIA_SHARE *share= keyinfo->share;
MARIA_KEY key;
uchar *start_of_page, *endpos, *start_of_empty_space;
uint page_flag, nod_flag, saved_space;
my_bool page_has_transid;
DBUG_ENTER("_ma_compact_keypage");
page_flag= _ma_get_keypage_flag(share, page);
if (!(page_flag & KEYPAGE_FLAG_HAS_TRANSID))
DBUG_RETURN(0); /* No transaction id on page */
nod_flag= _ma_test_if_nod(share, page);
endpos= page + _ma_get_page_used(share, page);
key.data= info->lastkey_buff;
key.keyinfo= keyinfo;
start_of_page= page;
page_has_transid= 0;
page+= share->keypage_header + nod_flag;
key.data[0]= 0; /* safety */
start_of_empty_space= 0;
saved_space= 0;
do
{
if (!(page= (*keyinfo->skip_key)(&key, 0, 0, page)))
{
DBUG_PRINT("error",("Couldn't find last key: page: 0x%lx",
(long) page));
maria_print_error(share, HA_ERR_CRASHED);
my_errno=HA_ERR_CRASHED;
DBUG_RETURN(1);
}
if (key_has_transid(page-1))
{
uint transid_length;
transid_length= transid_packed_length(page);
if (min_read_from == ~(TrID) 0 ||
min_read_from < transid_get_packed(share, page))
{
page[-1]&= 254; /* Remove transid marker */
transid_length= transid_packed_length(page);
if (start_of_empty_space)
{
/* Move block before the transid up in page */
uint copy_length= (uint) (page - start_of_empty_space) - saved_space;
memmove(start_of_empty_space, start_of_empty_space + saved_space,
copy_length);
start_of_empty_space+= copy_length;
}
else
start_of_empty_space= page;
saved_space+= transid_length;
}
else
page_has_transid= 1; /* At least one id left */
page+= transid_length;
}
page+= nod_flag;
} while (page < endpos);
DBUG_ASSERT(page == endpos);
if (start_of_empty_space)
{
/*
Move last block down
This is always true if any transid was removed
*/
uint copy_length= (uint) (endpos - start_of_empty_space) - saved_space;
uint page_length;
if (copy_length)
memmove(start_of_empty_space, start_of_empty_space + saved_space,
copy_length);
page_length= (uint) (start_of_empty_space + copy_length - start_of_page);
_ma_store_page_used(share, start_of_page, page_length);
}
if (!page_has_transid)
{
page_flag&= ~KEYPAGE_FLAG_HAS_TRANSID;
_ma_store_keypage_flag(share, start_of_page, page_flag);
/* Clear packed transid (in case of zerofill) */
bzero(start_of_page + LSN_STORE_SIZE, TRANSID_SIZE);
}
if (share->now_transactional)
{
if (_ma_log_compact_keypage(info, page_pos, min_read_from))
DBUG_RETURN(1);
}
DBUG_RETURN(0);
}
......@@ -23,8 +23,7 @@
static ha_rows _ma_record_pos(MARIA_HA *,const uchar *, key_part_map,
enum ha_rkey_function);
static double _ma_search_pos(MARIA_HA *, MARIA_KEYDEF *, uchar *,
uint, uint, my_off_t);
static double _ma_search_pos(MARIA_HA *, MARIA_KEY *, uint32, my_off_t);
static uint _ma_keynr(MARIA_HA *, MARIA_KEYDEF *, uchar *, uchar *, uint *);
......@@ -49,6 +48,8 @@ ha_rows maria_records_in_range(MARIA_HA *info, int inx, key_range *min_key,
{
ha_rows start_pos,end_pos,res;
MARIA_SHARE *share= info->s;
MARIA_KEY key;
MARIA_KEYDEF *keyinfo;
DBUG_ENTER("maria_records_in_range");
if ((inx = _ma_check_index(info,inx)) < 0)
......@@ -57,15 +58,15 @@ ha_rows maria_records_in_range(MARIA_HA *info, int inx, key_range *min_key,
if (fast_ma_readinfo(info))
DBUG_RETURN(HA_POS_ERROR);
info->update&= (HA_STATE_CHANGED+HA_STATE_ROW_CHANGED);
keyinfo= share->keyinfo + inx;
if (share->lock_key_trees)
rw_rdlock(&share->key_root_lock[inx]);
rw_rdlock(&keyinfo->root_lock);
switch(share->keyinfo[inx].key_alg){
switch (keyinfo->key_alg) {
#ifdef HAVE_RTREE_KEYS
case HA_KEY_ALG_RTREE:
{
uchar *key_buff;
uint start_key_len;
/*
The problem is that the optimizer doesn't support
......@@ -82,12 +83,11 @@ ha_rows maria_records_in_range(MARIA_HA *info, int inx, key_range *min_key,
res= HA_POS_ERROR;
break;
}
key_buff= info->lastkey+share->base.max_key_length;
start_key_len= _ma_pack_key(info,inx, key_buff,
min_key->key, min_key->keypart_map,
(HA_KEYSEG**) 0);
res= maria_rtree_estimate(info, inx, key_buff, start_key_len,
maria_read_vec[min_key->flag]);
key_buff= info->last_key.data + share->base.max_key_length;
_ma_pack_key(info, &key, inx, key_buff,
min_key->key, min_key->keypart_map,
(HA_KEYSEG**) 0);
res= maria_rtree_estimate(info, &key, maria_read_vec[min_key->flag]);
res= res ? res : 1; /* Don't return 0 */
break;
}
......@@ -109,7 +109,7 @@ ha_rows maria_records_in_range(MARIA_HA *info, int inx, key_range *min_key,
}
if (share->lock_key_trees)
rw_unlock(&share->key_root_lock[inx]);
rw_unlock(&keyinfo->root_lock);
fast_ma_writeinfo(info);
/**
......@@ -126,26 +126,24 @@ ha_rows maria_records_in_range(MARIA_HA *info, int inx, key_range *min_key,
/* Find relative position (in records) for key in index-tree */
static ha_rows _ma_record_pos(MARIA_HA *info, const uchar *key,
static ha_rows _ma_record_pos(MARIA_HA *info, const uchar *key_data,
key_part_map keypart_map,
enum ha_rkey_function search_flag)
{
uint inx=(uint) info->lastinx, nextflag, key_len;
MARIA_KEYDEF *keyinfo=info->s->keyinfo+inx;
uint inx= (uint) info->lastinx;
uint32 nextflag;
uchar *key_buff;
double pos;
MARIA_KEY key;
DBUG_ENTER("_ma_record_pos");
DBUG_PRINT("enter",("search_flag: %d",search_flag));
DBUG_ASSERT(keypart_map);
key_buff=info->lastkey+info->s->base.max_key_length;
key_len= _ma_pack_key(info, inx, key_buff, key, keypart_map,
key_buff= info->lastkey_buff+info->s->base.max_key_length;
_ma_pack_key(info, &key, inx, key_buff, key_data, keypart_map,
(HA_KEYSEG**) 0);
DBUG_EXECUTE("key", _ma_print_key(DBUG_FILE, keyinfo->seg,
key_buff, key_len););
DBUG_EXECUTE("key", _ma_print_key(DBUG_FILE, &key););
nextflag=maria_read_vec[search_flag];
if (!(nextflag & (SEARCH_FIND | SEARCH_NO_FIND | SEARCH_LAST)))
key_len=USE_WHOLE_KEY;
/*
my_handler.c:ha_compare_text() has a flag 'skip_end_space'.
......@@ -181,9 +179,9 @@ static ha_rows _ma_record_pos(MARIA_HA *info, const uchar *key,
above mentioned condition only. So it can safely be used together
with other flags.
*/
pos= _ma_search_pos(info,keyinfo, key_buff, key_len,
nextflag | SEARCH_SAVE_BUFF | SEARCH_UPDATE,
info->s->state.key_root[inx]);
pos= _ma_search_pos(info, &key,
nextflag | SEARCH_SAVE_BUFF | SEARCH_UPDATE,
info->s->state.key_root[inx]);
if (pos >= 0.0)
{
DBUG_PRINT("exit",("pos: %ld",(ulong) (pos*info->state->records)));
......@@ -193,19 +191,25 @@ static ha_rows _ma_record_pos(MARIA_HA *info, const uchar *key,
}
/* This is a modified version of _ma_search */
/* Returns offset for key in indextable (decimal 0.0 <= x <= 1.0) */
/**
Find offset for key on index page
@notes
Modified version of _ma_search()
@return
@retval 0.0 <= x <= 1.0
*/
static double _ma_search_pos(register MARIA_HA *info,
register MARIA_KEYDEF *keyinfo,
uchar *key, uint key_len, uint nextflag,
register my_off_t pos)
static double _ma_search_pos(MARIA_HA *info, MARIA_KEY *key,
uint32 nextflag, my_off_t pos)
{
int flag;
uint nod_flag,keynr,max_keynr;
my_bool after_key;
uchar *keypos, *buff;
double offset;
MARIA_KEYDEF *keyinfo= key->keyinfo;
DBUG_ENTER("_ma_search_pos");
LINT_INIT(max_keynr);
......@@ -216,8 +220,8 @@ static double _ma_search_pos(register MARIA_HA *info,
PAGECACHE_LOCK_LEFT_UNLOCKED, DFLT_INIT_HITS,
info->buff, 1, 0)))
goto err;
flag=(*keyinfo->bin_search)(info, keyinfo, buff, key, key_len, nextflag,
&keypos,info->lastkey, &after_key);
flag= (*keyinfo->bin_search)(key, buff, nextflag, &keypos,
info->lastkey_buff, &after_key);
nod_flag=_ma_test_if_nod(info->s, buff);
keynr= _ma_keynr(info,keyinfo,buff,keypos,&max_keynr);
......@@ -232,8 +236,8 @@ static double _ma_search_pos(register MARIA_HA *info,
*/
if (flag > 0 && ! nod_flag)
offset= 1.0;
else if ((offset= _ma_search_pos(info,keyinfo,key,key_len,nextflag,
_ma_kpos(nod_flag,keypos))) < 0)
else if ((offset= _ma_search_pos(info, key, nextflag,
_ma_kpos(nod_flag,keypos))) < 0)
DBUG_RETURN(offset);
}
else
......@@ -245,14 +249,15 @@ static double _ma_search_pos(register MARIA_HA *info,
offset=1.0; /* Matches keynr+1 */
if ((nextflag & SEARCH_FIND) && nod_flag &&
((keyinfo->flag & (HA_NOSAME | HA_NULL_PART)) != HA_NOSAME ||
key_len != USE_WHOLE_KEY))
(nextflag & (SEARCH_PREFIX | SEARCH_NO_FIND | SEARCH_LAST |
SEARCH_PART_KEY))))
{
/*
There may be identical keys in the tree. Try to match on of those.
Matches keynr + [0-1]
*/
if ((offset= _ma_search_pos(info,keyinfo,key,key_len,SEARCH_FIND,
_ma_kpos(nod_flag,keypos))) < 0)
if ((offset= _ma_search_pos(info, key, SEARCH_FIND,
_ma_kpos(nod_flag,keypos))) < 0)
DBUG_RETURN(offset); /* Read error */
}
}
......@@ -270,14 +275,18 @@ static double _ma_search_pos(register MARIA_HA *info,
static uint _ma_keynr(MARIA_HA *info, register MARIA_KEYDEF *keyinfo,
uchar *page, uchar *keypos, uint *ret_max_key)
{
uint nod_flag, used_length, keynr, max_key;
uchar t_buff[HA_MAX_KEY_BUFF],*end;
uint page_flag, nod_flag, used_length, keynr, max_key;
uchar t_buff[MARIA_MAX_KEY_BUFF],*end;
MARIA_KEY key;
_ma_get_used_and_nod(info->s, page, used_length, nod_flag);
page_flag= _ma_get_keypage_flag(info->s, page);
_ma_get_used_and_nod_with_flag(info->s, page_flag, page, used_length,
nod_flag);
end= page+ used_length;
page+= info->s->keypage_header + nod_flag;
if (!(keyinfo->flag & (HA_VAR_LENGTH_KEY | HA_BINARY_PACK_KEY)))
if (!(keyinfo->flag & (HA_VAR_LENGTH_KEY | HA_BINARY_PACK_KEY)) &&
! (page_flag & KEYPAGE_FLAG_HAS_TRANSID))
{
*ret_max_key= (uint) (end-page)/(keyinfo->keylength+nod_flag);
return (uint) (keypos-page)/(keyinfo->keylength+nod_flag);
......@@ -285,13 +294,19 @@ static uint _ma_keynr(MARIA_HA *info, register MARIA_KEYDEF *keyinfo,
max_key=keynr=0;
t_buff[0]=0; /* Safety */
key.data= t_buff;
key.keyinfo= keyinfo;
while (page < end)
{
if (!(*keyinfo->get_key)(keyinfo,nod_flag,&page,t_buff))
if (!(page= (*keyinfo->skip_key)(&key, page_flag, nod_flag, page)))
{
DBUG_ASSERT(0);
return 0; /* Error */
}
max_key++;
if (page == keypos)
keynr=max_key;
keynr= max_key;
}
*ret_max_key=max_key;
return(keynr);
......
......@@ -951,7 +951,8 @@ prototype_redo_exec_hook(REDO_RENAME_TABLE)
eprint(tracef, "Failed to open renamed table");
goto end;
}
if (_ma_update_state_lsns(info->s, rec->lsn, TRUE, TRUE))
if (_ma_update_state_lsns(info->s, rec->lsn, info->s->state.create_trid,
TRUE, TRUE))
goto end;
if (maria_close(info))
goto end;
......@@ -1027,8 +1028,8 @@ prototype_redo_exec_hook(REDO_REPAIR_TABLE)
else if (maria_repair(&param, info, name, quick_repair))
goto end;
if (_ma_update_state_lsns(info->s, rec->lsn, TRUE,
!(param.testflag & T_NO_CREATE_RENAME_LSN)))
if (_ma_update_state_lsns(info->s, rec->lsn, trnman_get_min_safe_trid(),
TRUE, !(param.testflag & T_NO_CREATE_RENAME_LSN)))
goto end;
error= 0;
......@@ -1202,11 +1203,13 @@ static int new_table(uint16 sid, const char *name, LSN lsn_of_file_id)
if (close_one_table(share->open_file_name, lsn_of_file_id))
goto end;
}
DBUG_ASSERT(share->now_transactional == share->base.born_transactional);
if (!share->base.born_transactional)
{
tprint(tracef, ", is not transactional\n");
ALERT_USER();
/*
This can happen if one converts a transactional table to a
not transactional table
*/
tprint(tracef, ", is not transactional. Ignoring open request");
error= -1;
goto end;
}
......@@ -1789,7 +1792,7 @@ prototype_redo_exec_hook(UNDO_KEY_INSERT)
if (keyseg->flag & HA_SWAP_KEY)
{
/* We put key from log record to "data record" packing format... */
uchar reversed[HA_MAX_KEY_BUFF];
uchar reversed[MARIA_MAX_KEY_BUFF];
uchar *key_ptr= to;
uchar *key_end= key_ptr + keyseg->length;
to= reversed + keyseg->length;
......
......@@ -95,7 +95,8 @@ int maria_rename(const char *old_name, const char *new_name)
store LSN into file, needed for Recovery to not be confused if a
RENAME happened (applying REDOs to the wrong table).
*/
if (_ma_update_state_lsns(share, lsn, TRUE, TRUE))
if (_ma_update_state_lsns(share, lsn, share->state.create_trid, TRUE,
TRUE))
{
maria_close(info);
DBUG_RETURN(1);
......
......@@ -18,17 +18,22 @@
#include "maria_def.h"
#include "ma_rt_index.h"
/* Read a record using key */
/* Ordinary search_flag is 0 ; Give error if no record with key */
/**
Read a record using key
int maria_rkey(MARIA_HA *info, uchar *buf, int inx, const uchar *key,
@note
Ordinary search_flag is 0 ; Give error if no record with key
*/
int maria_rkey(MARIA_HA *info, uchar *buf, int inx, const uchar *key_data,
key_part_map keypart_map, enum ha_rkey_function search_flag)
{
uchar *key_buff;
MARIA_SHARE *share= info->s;
MARIA_KEYDEF *keyinfo;
HA_KEYSEG *last_used_keyseg;
uint pack_key_length, use_key_length, nextflag;
uint32 nextflag;
MARIA_KEY key;
DBUG_ENTER("maria_rkey");
DBUG_PRINT("enter", ("base: 0x%lx buf: 0x%lx inx: %d search_flag: %d",
(long) info, (long) buf, inx, search_flag));
......@@ -40,6 +45,8 @@ int maria_rkey(MARIA_HA *info, uchar *buf, int inx, const uchar *key,
info->last_key_func= search_flag;
keyinfo= share->keyinfo + inx;
key_buff= info->lastkey_buff+info->s->base.max_key_length;
if (info->once_flags & USE_PACKED_KEYS)
{
info->once_flags&= ~USE_PACKED_KEYS; /* Reset flag */
......@@ -47,40 +54,39 @@ int maria_rkey(MARIA_HA *info, uchar *buf, int inx, const uchar *key,
key is already packed!; This happens when we are using a MERGE TABLE
In this key 'key_part_map' is the length of the key !
*/
key_buff= info->lastkey+info->s->base.max_key_length;
pack_key_length= keypart_map;
bmove(key_buff, key, pack_key_length);
last_used_keyseg= info->s->keyinfo[inx].seg + info->last_used_keyseg;
bmove(key_buff, key_data, keypart_map);
key.data= key_buff;
key.keyinfo= keyinfo;
key.data_length= keypart_map;
key.ref_length= 0;
key.flag= 0;
last_used_keyseg= keyinfo->seg + info->last_used_keyseg;
}
else
{
DBUG_ASSERT(keypart_map);
/* Save the packed key for later use in the second buffer of lastkey. */
key_buff=info->lastkey+info->s->base.max_key_length;
pack_key_length= _ma_pack_key(info,(uint) inx, key_buff, key,
keypart_map, &last_used_keyseg);
_ma_pack_key(info, &key, inx, key_buff, key_data,
keypart_map, &last_used_keyseg);
/* Save packed_key_length for use by the MERGE engine. */
info->pack_key_length= pack_key_length;
info->pack_key_length= key.data_length;
info->last_used_keyseg= (uint16) (last_used_keyseg -
info->s->keyinfo[inx].seg);
DBUG_EXECUTE("key", _ma_print_key(DBUG_FILE, keyinfo->seg,
key_buff, pack_key_length););
keyinfo->seg);
DBUG_EXECUTE("key", _ma_print_key(DBUG_FILE, &key););
}
if (fast_ma_readinfo(info))
goto err;
if (share->lock_key_trees)
rw_rdlock(&share->key_root_lock[inx]);
rw_rdlock(&keyinfo->root_lock);
nextflag=maria_read_vec[search_flag];
use_key_length=pack_key_length;
if (!(nextflag & (SEARCH_FIND | SEARCH_NO_FIND | SEARCH_LAST)))
use_key_length=USE_WHOLE_KEY;
nextflag= maria_read_vec[search_flag] | key.flag;
switch (info->s->keyinfo[inx].key_alg) {
switch (keyinfo->key_alg) {
#ifdef HAVE_RTREE_KEYS
case HA_KEY_ALG_RTREE:
if (maria_rtree_find_first(info,inx,key_buff,use_key_length,nextflag) < 0)
if (maria_rtree_find_first(info, &key, nextflag) < 0)
{
maria_print_error(info->s, HA_ERR_CRASHED);
my_errno= HA_ERR_CRASHED;
......@@ -90,74 +96,66 @@ int maria_rkey(MARIA_HA *info, uchar *buf, int inx, const uchar *key,
#endif
case HA_KEY_ALG_BTREE:
default:
if (!_ma_search(info, keyinfo, key_buff, use_key_length,
maria_read_vec[search_flag],
info->s->state.key_root[inx]) &&
share->non_transactional_concurrent_insert)
{
if (!_ma_search(info, &key, nextflag, info->s->state.key_root[inx]))
{
MARIA_KEY lastkey;
lastkey.keyinfo= keyinfo;
lastkey.data= info->lastkey_buff;
/*
Found a key, but it might not be usable. We cannot use rows that
are inserted by other threads after we got our table lock
("concurrent inserts"). The record may not even be present yet.
Keys are inserted into the index(es) before the record is
inserted into the data file. When we got our table lock, we
saved the current data_file_length. Concurrent inserts always go
to the end of the file. So we can test if the found key
references a new record.
inserted into the data file.
*/
if (info->cur_row.lastpos >= info->state->data_file_length)
if ((*share->row_is_visible)(info))
break;
/* The key references a concurrently inserted record. */
if (search_flag == HA_READ_KEY_EXACT &&
last_used_keyseg == keyinfo->seg + keyinfo->keysegs)
{
/* Simply ignore the key if it matches exactly. (Bug #29838) */
my_errno= HA_ERR_KEY_NOT_FOUND;
info->cur_row.lastpos= HA_OFFSET_ERROR;
break;
}
do
{
/* The key references a concurrently inserted record. */
if (search_flag == HA_READ_KEY_EXACT &&
last_used_keyseg == keyinfo->seg + keyinfo->keysegs)
uint not_used[2];
/*
Skip rows that are inserted by other threads since we got
a lock. Note that this can only happen if we are not
searching after a full length exact key, because the keys
are sorted according to position.
*/
lastkey.data_length= info->last_key.data_length;
lastkey.ref_length= info->last_key.ref_length;
lastkey.flag= info->last_key.flag;
if (_ma_search_next(info, &lastkey, maria_readnext_vec[search_flag],
info->s->state.key_root[inx]))
break; /* purecov: inspected */
/*
Check that the found key does still match the search.
_ma_search_next() delivers the next key regardless of its
value.
*/
if (!(nextflag & (SEARCH_BIGGER | SEARCH_SMALLER)) &&
ha_key_cmp(keyinfo->seg, info->last_key.data, key.data,
key.data_length, SEARCH_FIND, not_used))
{
/* Simply ignore the key if it matches exactly. (Bug #29838) */
/* purecov: begin inspected */
my_errno= HA_ERR_KEY_NOT_FOUND;
info->cur_row.lastpos= HA_OFFSET_ERROR;
break;
/* purecov: end */
}
else
{
/*
If searching for a partial key (or using >, >=, < or <=) and
the data is outside of the data file, we need to continue
searching for the first key inside the data file.
*/
do
{
uint not_used[2];
/*
Skip rows that are inserted by other threads since we got
a lock. Note that this can only happen if we are not
searching after a full length exact key, because the keys
are sorted according to position.
*/
if (_ma_search_next(info, keyinfo, info->lastkey,
info->lastkey_length,
maria_readnext_vec[search_flag],
info->s->state.key_root[inx]))
break; /* purecov: inspected */
/*
Check that the found key does still match the search.
_ma_search_next() delivers the next key regardless of its
value.
*/
if (search_flag == HA_READ_KEY_EXACT &&
ha_key_cmp(keyinfo->seg, key_buff, info->lastkey,
use_key_length, SEARCH_FIND, not_used))
{
/* purecov: begin inspected */
my_errno= HA_ERR_KEY_NOT_FOUND;
info->cur_row.lastpos= HA_OFFSET_ERROR;
break;
/* purecov: end */
}
} while (info->cur_row.lastpos >= info->state->data_file_length);
}
}
} while (!(*share->row_is_visible)(info));
}
}
if (share->lock_key_trees)
rw_unlock(&share->key_root_lock[inx]);
rw_unlock(&keyinfo->root_lock);
if (info->cur_row.lastpos == HA_OFFSET_ERROR)
{
......@@ -166,11 +164,11 @@ int maria_rkey(MARIA_HA *info, uchar *buf, int inx, const uchar *key,
}
/* Calculate length of the found key; Used by maria_rnext_same */
if ((keyinfo->flag & HA_VAR_LENGTH_KEY) && last_used_keyseg)
info->last_rkey_length= _ma_keylength_part(keyinfo, info->lastkey,
if ((keyinfo->flag & HA_VAR_LENGTH_KEY))
info->last_rkey_length= _ma_keylength_part(keyinfo, info->lastkey_buff,
last_used_keyseg);
else
info->last_rkey_length= pack_key_length;
info->last_rkey_length= key.data_length;
/* Check if we don't want to have record back, only error message */
if (!buf)
......@@ -188,10 +186,13 @@ int maria_rkey(MARIA_HA *info, uchar *buf, int inx, const uchar *key,
err:
/* Store last used key as a base for read next */
memcpy(info->lastkey,key_buff,pack_key_length);
info->last_rkey_length= pack_key_length;
bzero((char*) info->lastkey+pack_key_length,info->s->base.rec_reflength);
info->lastkey_length=pack_key_length+info->s->base.rec_reflength;
memcpy(info->last_key.data, key_buff, key.data_length);
info->last_key.data_length= key.data_length;
info->last_key.ref_length= info->s->base.rec_reflength;
info->last_key.flag= 0;
/* Create key with rowid 0 */
bzero((char*) info->last_key.data + info->last_key.data_length,
info->s->base.rec_reflength);
if (search_flag == HA_READ_AFTER_KEY)
info->update|=HA_STATE_NEXT_FOUND; /* Previous gives last row */
......
......@@ -28,6 +28,8 @@ int maria_rnext(MARIA_HA *info, uchar *buf, int inx)
{
int error,changed;
uint flag;
MARIA_SHARE *share= info->s;
MARIA_KEYDEF *keyinfo;
DBUG_ENTER("maria_rnext");
if ((inx = _ma_check_index(info,inx)) < 0)
......@@ -39,27 +41,30 @@ int maria_rnext(MARIA_HA *info, uchar *buf, int inx)
if (fast_ma_readinfo(info))
DBUG_RETURN(my_errno);
if (info->s->lock_key_trees)
rw_rdlock(&info->s->key_root_lock[inx]);
keyinfo= share->keyinfo + inx;
if (share->lock_key_trees)
rw_rdlock(&keyinfo->root_lock);
changed= _ma_test_if_changed(info);
if (!flag)
{
switch(info->s->keyinfo[inx].key_alg){
switch (keyinfo->key_alg){
#ifdef HAVE_RTREE_KEYS
case HA_KEY_ALG_RTREE:
error=maria_rtree_get_first(info,inx,info->lastkey_length);
error=maria_rtree_get_first(info, inx,
info->last_key.data_length +
info->last_key.ref_length);
break;
#endif
case HA_KEY_ALG_BTREE:
default:
error= _ma_search_first(info,info->s->keyinfo+inx,
info->s->state.key_root[inx]);
error= _ma_search_first(info, keyinfo, share->state.key_root[inx]);
break;
}
}
else
{
switch (info->s->keyinfo[inx].key_alg) {
switch (keyinfo->key_alg) {
#ifdef HAVE_RTREE_KEYS
case HA_KEY_ALG_RTREE:
/*
......@@ -67,38 +72,36 @@ int maria_rnext(MARIA_HA *info, uchar *buf, int inx)
may be changed since last call, so we do need
to skip rows inserted by other threads like in btree
*/
error= maria_rtree_get_next(info,inx,info->lastkey_length);
error= maria_rtree_get_next(info, inx, info->last_key.data_length +
info->last_key.ref_length);
break;
#endif
case HA_KEY_ALG_BTREE:
default:
if (!changed)
error= _ma_search_next(info,info->s->keyinfo+inx,info->lastkey,
info->lastkey_length,flag,
info->s->state.key_root[inx]);
error= _ma_search_next(info, &info->last_key,
flag | info->last_key.flag,
share->state.key_root[inx]);
else
error= _ma_search(info,info->s->keyinfo+inx,info->lastkey,
USE_WHOLE_KEY,flag, info->s->state.key_root[inx]);
error= _ma_search(info, &info->last_key, flag | info->last_key.flag,
share->state.key_root[inx]);
}
}
if (info->s->non_transactional_concurrent_insert)
if (!error)
{
if (!error)
while (!(*share->row_is_visible)(info))
{
while (info->cur_row.lastpos >= info->state->data_file_length)
{
/* Skip rows inserted by other threads since we got a lock */
if ((error= _ma_search_next(info,info->s->keyinfo+inx,
info->lastkey,
info->lastkey_length,
SEARCH_BIGGER,
info->s->state.key_root[inx])))
break;
}
/* Skip rows inserted by other threads since we got a lock */
if ((error= _ma_search_next(info, &info->last_key,
SEARCH_BIGGER,
share->state.key_root[inx])))
break;
}
rw_unlock(&info->s->key_root_lock[inx]);
}
if (share->lock_key_trees)
rw_unlock(&keyinfo->root_lock);
/* Don't clear if database-changed */
info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
info->update|= HA_STATE_NEXT_FOUND;
......
......@@ -35,12 +35,12 @@ int maria_rnext_same(MARIA_HA *info, uchar *buf)
if ((int) (inx= info->lastinx) < 0 ||
info->cur_row.lastpos == HA_OFFSET_ERROR)
DBUG_RETURN(my_errno=HA_ERR_WRONG_INDEX);
keyinfo= info->s->keyinfo+inx;
if (fast_ma_readinfo(info))
DBUG_RETURN(my_errno);
keyinfo= info->s->keyinfo+inx;
if (info->s->lock_key_trees)
rw_rdlock(&info->s->key_root_lock[inx]);
rw_rdlock(&keyinfo->root_lock);
switch (keyinfo->key_alg) {
#ifdef HAVE_RTREE_KEYS
......@@ -60,17 +60,19 @@ int maria_rnext_same(MARIA_HA *info, uchar *buf)
if (!(info->update & HA_STATE_RNEXT_SAME))
{
/* First rnext_same; Store old key */
memcpy(info->lastkey2,info->lastkey,info->last_rkey_length);
memcpy(info->lastkey_buff2, info->last_key.data,
info->last_rkey_length);
}
for (;;)
{
if ((error= _ma_search_next(info,keyinfo,info->lastkey,
info->lastkey_length,SEARCH_BIGGER,
if ((error= _ma_search_next(info, &info->last_key,
SEARCH_BIGGER,
info->s->state.key_root[inx])))
break;
if (ha_key_cmp(keyinfo->seg, (uchar*) info->lastkey,
(uchar*) info->lastkey2,
info->last_rkey_length, SEARCH_FIND, not_used))
if (ha_key_cmp(keyinfo->seg, (uchar*) info->last_key.data,
(uchar*) info->lastkey_buff2,
info->last_rkey_length, SEARCH_FIND,
not_used))
{
error=1;
my_errno=HA_ERR_END_OF_FILE;
......@@ -78,13 +80,12 @@ int maria_rnext_same(MARIA_HA *info, uchar *buf)
break;
}
/* Skip rows that are inserted by other threads since we got a lock */
if (!info->s->non_transactional_concurrent_insert ||
info->cur_row.lastpos < info->state->data_file_length)
if ((info->s->row_is_visible)(info))
break;
}
}
if (info->s->lock_key_trees)
rw_unlock(&info->s->key_root_lock[inx]);
rw_unlock(&keyinfo->root_lock);
/* Don't clear if database-changed */
info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
info->update|= HA_STATE_NEXT_FOUND | HA_STATE_RNEXT_SAME;
......
......@@ -27,6 +27,7 @@ int maria_rprev(MARIA_HA *info, uchar *buf, int inx)
int error,changed;
register uint flag;
MARIA_SHARE *share= info->s;
MARIA_KEYDEF *keyinfo;
DBUG_ENTER("maria_rprev");
if ((inx = _ma_check_index(info,inx)) < 0)
......@@ -38,37 +39,33 @@ int maria_rprev(MARIA_HA *info, uchar *buf, int inx)
if (fast_ma_readinfo(info))
DBUG_RETURN(my_errno);
keyinfo= share->keyinfo + inx;
changed= _ma_test_if_changed(info);
if (share->lock_key_trees)
rw_rdlock(&share->key_root_lock[inx]);
rw_rdlock(&keyinfo->root_lock);
if (!flag)
error= _ma_search_last(info, share->keyinfo+inx,
share->state.key_root[inx]);
error= _ma_search_last(info, keyinfo, share->state.key_root[inx]);
else if (!changed)
error= _ma_search_next(info,share->keyinfo+inx,info->lastkey,
info->lastkey_length,flag,
share->state.key_root[inx]);
error= _ma_search_next(info, &info->last_key,
flag | info->last_key.flag,
share->state.key_root[inx]);
else
error= _ma_search(info,share->keyinfo+inx,info->lastkey,
USE_WHOLE_KEY, flag, share->state.key_root[inx]);
error= _ma_search(info, &info->last_key, flag | info->last_key.flag,
share->state.key_root[inx]);
if (share->non_transactional_concurrent_insert)
if (!error)
{
if (!error)
while (!(*share->row_is_visible)(info))
{
while (info->cur_row.lastpos >= info->state->data_file_length)
{
/* Skip rows that are inserted by other threads since we got a lock */
if ((error= _ma_search_next(info,share->keyinfo+inx,info->lastkey,
info->lastkey_length,
SEARCH_SMALLER,
share->state.key_root[inx])))
break;
}
/* Skip rows that are inserted by other threads since we got a lock */
if ((error= _ma_search_next(info, &info->last_key,
SEARCH_SMALLER,
share->state.key_root[inx])))
break;
}
}
if (share->lock_key_trees)
rw_unlock(&share->key_root_lock[inx]);
rw_unlock(&keyinfo->root_lock);
info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
info->update|= HA_STATE_PREV_FOUND;
if (error)
......
......@@ -15,16 +15,20 @@
#include "maria_def.h"
/*
/**
Find current row with read on position or read on key
NOTES
If inx >= 0 find record using key
@notes
If inx >= 0 find record using key
RETURN
0 Ok
HA_ERR_KEY_NOT_FOUND Row is deleted
HA_ERR_END_OF_FILE End of file
@warning
This function is not row version safe.
This is not crtical as this function is not used by MySQL
@return
@retval 0 Ok
@retval HA_ERR_KEY_NOT_FOUND Row is deleted
@retval HA_ERR_END_OF_FILE End of file
*/
......@@ -51,16 +55,18 @@ int maria_rsame(MARIA_HA *info, uchar *record, int inx)
if (inx >= 0)
{
info->lastinx=inx;
info->lastkey_length= _ma_make_key(info,(uint) inx,info->lastkey,record,
info->cur_row.lastpos);
MARIA_KEYDEF *keyinfo= info->s->keyinfo + inx;
info->lastinx= inx;
(*keyinfo->make_key)(info, &info->last_key, (uint) inx,
info->lastkey_buff, record,
info->cur_row.lastpos,
info->cur_row.trid);
if (info->s->lock_key_trees)
rw_rdlock(&info->s->key_root_lock[inx]);
VOID(_ma_search(info,info->s->keyinfo+inx,info->lastkey, USE_WHOLE_KEY,
SEARCH_SAME,
rw_rdlock(&keyinfo->root_lock);
VOID(_ma_search(info, &info->last_key, SEARCH_SAME,
info->s->state.key_root[inx]));
if (info->s->lock_key_trees)
rw_unlock(&info->s->key_root_lock[inx]);
rw_unlock(&keyinfo->root_lock);
}
if (!(*info->read_record)(info, record, info->cur_row.lastpos))
......
......@@ -19,13 +19,16 @@
#include "maria_def.h"
/*
** If inx >= 0 update index pointer
** Returns one of the following values:
** 0 = Ok.
** HA_ERR_KEY_NOT_FOUND = Row is deleted
** HA_ERR_END_OF_FILE = End of file
*/
/*
Read row based on postion
@param inx If inx >= 0 postion the given index on found row
@return
@retval 0 Ok
@retval HA_ERR_KEY_NOT_FOUND Row is deleted
@retval HA_ERR_END_OF_FILE End of file
*/
int maria_rsame_with_pos(MARIA_HA *info, uchar *record, int inx,
MARIA_RECORD_POS filepos)
......@@ -50,8 +53,10 @@ int maria_rsame_with_pos(MARIA_HA *info, uchar *record, int inx,
info->lastinx= inx;
if (inx >= 0)
{
info->lastkey_length= _ma_make_key(info,(uint) inx,info->lastkey,record,
info->cur_row.lastpos);
(*info->s->keyinfo[inx].make_key)(info, &info->last_key, (uint) inx,
info->lastkey_buff,
record, info->cur_row.lastpos,
info->cur_row.trid);
info->update|=HA_STATE_KEY_CHANGED; /* Don't use indexposition */
}
DBUG_RETURN(0);
......
This diff is collapsed.
......@@ -26,31 +26,21 @@
#define rt_PAGE_MIN_SIZE(block_length) ((uint)(block_length - KEYPAGE_CHECKSUM_SIZE) / 3)
int maria_rtree_insert(MARIA_HA *info, uint keynr, uchar *key,
uint key_length);
int maria_rtree_delete(MARIA_HA *info, uint keynr, uchar *key,
uint key_length);
int maria_rtree_insert_level(MARIA_HA *info, uint keynr,
const uchar *key,
uint key_length, int ins_level,
my_off_t *root);
int maria_rtree_real_delete(MARIA_HA *info, uint keynr,
const uchar *key, uint key_length,
my_off_t *root);
int maria_rtree_find_first(MARIA_HA *info, uint keynr, uchar *key,
uint key_length, uint search_flag);
int maria_rtree_find_next(MARIA_HA *info, uint keynr, uint search_flag);
my_bool maria_rtree_insert(MARIA_HA *info, MARIA_KEY *key);
int maria_rtree_delete(MARIA_HA *info, MARIA_KEY *key);
int maria_rtree_insert_level(MARIA_HA *info, MARIA_KEY *key,
int ins_level, my_off_t *root);
int maria_rtree_real_delete(MARIA_HA *info, MARIA_KEY *key, my_off_t *root);
int maria_rtree_find_first(MARIA_HA *info, MARIA_KEY *key, uint search_flag);
int maria_rtree_find_next(MARIA_HA *info, uint keynr, uint32 search_flag);
int maria_rtree_get_first(MARIA_HA *info, uint keynr, uint key_length);
int maria_rtree_get_next(MARIA_HA *info, uint keynr, uint key_length);
ha_rows maria_rtree_estimate(MARIA_HA *info, uint keynr, uchar *key,
uint key_length, uint flag);
ha_rows maria_rtree_estimate(MARIA_HA *info, MARIA_KEY *key, uint32 flag);
int maria_rtree_split_page(MARIA_HA *info, const MARIA_KEYDEF *keyinfo,
int maria_rtree_split_page(MARIA_HA *info, const MARIA_KEY *key,
my_off_t page_offs, uchar *page,
const uchar *key, uint key_length,
my_off_t *new_page_offs);
/**
When you obtain a MARIA_PINNED_PAGE* link (by calling
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -20,7 +20,7 @@
#ifdef HAVE_RTREE_KEYS
int maria_rtree_key_cmp(HA_KEYSEG *keyseg, const uchar *a, const uchar *b,
uint key_length, uint nextflag);
uint key_length, uint32 nextflag);
int maria_rtree_combine_rect(const HA_KEYSEG *keyseg,
const uchar *, const uchar *, uchar*,
uint key_length);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment