summaryrefslogtreecommitdiff
path: root/mysys/thr_lock.c
diff options
context:
space:
mode:
authorunknown <monty@mysql.com/narttu.mysql.fi>2008-04-10 05:26:36 +0300
committerunknown <monty@mysql.com/narttu.mysql.fi>2008-04-10 05:26:36 +0300
commit126c1228f5385411fbff586cbc1a48a6c61abfe9 (patch)
tree579e61c34e894da7546ea45a35823ca18b7170aa /mysys/thr_lock.c
parent722a8ebe5b78f82f9cda9872317ff0f8f1dcd63e (diff)
downloadmariadb-git-126c1228f5385411fbff586cbc1a48a6c61abfe9.tar.gz
Added versioning of row data
Will in future changeset (soon) av versioning of status variables (number of rows) and index Changed some LEX_STRING to LEX_CUSTRING to avoid casts and warnings Removed some not needed variables (as noticed by Guilhem) include/maria.h: Added prototypes for maria_chk_init_for_check(), maria_versioning() and maria_ignore_trids() include/my_base.h: Add new error HA_ERR_ROW_NOT_VISIBLE include/myisamchk.h: Added variables for checking visibility of rows during maria_chk include/thr_lock.h: Changed argument type from int to my_bool for get_status Added variable allow_multiple_concurrent_insert, to signal if table supports multiple concurrent inserts mysql-test/r/maria-page-checksum.result: Added missing drop table mysql-test/t/maria-page-checksum.test: Added missing drop table mysys/my_handler.c: Added new error messages mysys/thr_lock.c: Added support for multiple concurrent inserts, if table handler supports it sql/sql_yacc.yy: Added LOCK TABLE table_name WRITE CONCURRENT This was added (temporarly?) to be able to check versioning with Maria storage/csv/ha_tina.cc: Updated parameter for get_status storage/maria/ha_maria.cc: Added calls to maria_chk_init_status() Fixed call to ma_control_file_open() storage/maria/ma_blockrec.c: Changed some LEX_STRING to LEX_CUSTRING to avoid casts and warnings Changed back some 'header' parameters to const char* Removed some casts Added support for versioning: - If info->row_flag & ROW_FLAG_TRANSID is set, store transaction id together with the row - When reading rows, check if rows are visible. Give error if not - When scanning table, ignore not visible rows - Added function parameters to some functions, to be able to call _ma_compact_block_page() with different parameters depending of if the page is a HEAD or TAIL page - _ma_compact_block_page() deletes transaction id's that are visible by all running transactions - Added functions for thr_lock() to enable multiple concurrent inserts - Added helper function 'mysql_versioning()' to enable/disable versioning - Added helper function maria_ignore_trids(), used by maria_chk and maria_pack to see all rows. storage/maria/ma_blockrec.h: Updated parameters for some functions. Added new functions to read/store state with thr_lock storage/maria/ma_check.c: Enable handling of transaction id's in rows Give a readable error if a table contains a transation id that makes rows not visible storage/maria/ma_control_file.c: Added option to not give warning if control file doesn't exists. storage/maria/ma_control_file.h: Updated parameter lists for ma_control_file_open() storage/maria/ma_delete.c: Removed not used variable (suggestion by Guilhem) storage/maria/ma_locking.c: Changed type of argument from int -> my_bool storage/maria/ma_open.c: Removed not used variables 'key_write_undo_lsn' and 'key_delete_undo_lsn' Added new thr_lock interface functions for BLOCK_RECORD to enable multiple concurrent insert storage/maria/ma_test1.c: Added option --versioning (-C) to check versioning storage/maria/ma_test2.c: Added option -C to check versioning storage/maria/ma_test_recovery: Forward argumetns to ma_test_recovery.pl storage/maria/ma_write.c: Removed not used variable key_write_undo_lsn storage/maria/maria_chk.c: Always read control file (if exist) at start Initialize checking of tables by calling maria_chk_init_for_check() In verbose mode and in case of error, print max found transaction id storage/maria/maria_def.h: Added Trid to MARIA_ROW to be able to check transaction id for found row Moved 'base_length' from MARIA_ROW to MARIA_HA to be able to handle different base length (with and without TRANSID) without if's Added default row_flag to MARIA_HA for the same reason Changed LEX_STRING -> LEX_CUSTRING to avoid casts in ma_blockrec.c Removed not needed variables key_write_undo_lsn and key_delete_undo_lsn Added prototypes for new functions and fixed those that had changed storage/maria/maria_pack.c: Ensure we can read all rows from the file, independent of the used transaction id storage/maria/maria_read_log.c: Updated arguments to ma_control_file_open() storage/maria/trnman.c: If we have only one transaction, fixed that min_read_from contains current transaction Fixed that trnman_can_read_from() returns that row is readable if it was written by current transaction storage/maria/unittest/ma_control_file-t.c: Updated arguments to ma_control_file_open() storage/maria/unittest/ma_test_all-t: Added test of versioning Removed printing of one extra space storage/maria/unittest/ma_test_loghandler-t.c: Updated arguments to ma_control_file_open() storage/maria/unittest/ma_test_loghandler_first_lsn-t.c: Updated arguments to ma_control_file_open() storage/maria/unittest/ma_test_loghandler_max_lsn-t.c: Updated arguments to ma_control_file_open() storage/maria/unittest/ma_test_loghandler_multigroup-t.c: Updated arguments to ma_control_file_open() storage/maria/unittest/ma_test_loghandler_multithread-t.c: Updated arguments to ma_control_file_open() storage/maria/unittest/ma_test_loghandler_noflush-t.c: Updated arguments to ma_control_file_open() storage/maria/unittest/ma_test_loghandler_nologs-t.c: Updated arguments to ma_control_file_open() storage/maria/unittest/ma_test_loghandler_pagecache-t.c: Updated arguments to ma_control_file_open() storage/maria/unittest/ma_test_loghandler_purge-t.c: Updated arguments to ma_control_file_open() storage/maria/unittest/ma_test_recovery.expected: Updated file with result from new tests storage/maria/unittest/ma_test_recovery.pl: Added options --abort-on-error and --verbose In case of --verbose, print all excuted shell commands Added test of versioning storage/myisam/mi_locking.c: Updated type of parameter storage/myisam/myisamdef.h: Updated type of parameter mysql-test/r/maria-mvcc.result: New BitKeeper file ``mysql-test/r/maria-mvcc.result'' mysql-test/t/maria-mvcc.test: New BitKeeper file ``mysql-test/t/maria-mvcc.test''
Diffstat (limited to 'mysys/thr_lock.c')
-rw-r--r--mysys/thr_lock.c102
1 files changed, 70 insertions, 32 deletions
diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c
index 6decd6a6a27..484fd1dd559 100644
--- a/mysys/thr_lock.c
+++ b/mysys/thr_lock.c
@@ -69,9 +69,11 @@ get_status:
for concurrent reads.
The lock algorithm allows one to have one TL_WRITE_ALLOW_READ,
-TL_WRITE_CONCURRENT_INSERT or one TL_WRITE_DELAYED lock at the same time as
-multiple read locks.
+TL_WRITE_CONCURRENT_INSERT or one TL_WRITE_DELAYED lock at the same
+time as multiple read locks.
+In addition, if lock->allow_multiple_concurrent_insert is set then there can
+be any number of TL_WRITE_CONCURRENT_INSERT locks aktive at the same time.
*/
#if !defined(MAIN) && !defined(DBUG_OFF) && !defined(EXTRA_DEBUG)
@@ -152,7 +154,8 @@ static int check_lock(struct st_lock_list *list, const char* lock_type,
}
if (same_owner &&
!thr_lock_owner_equal(data->owner, first_owner) &&
- last_lock_type != TL_WRITE_ALLOW_WRITE)
+ last_lock_type != TL_WRITE_ALLOW_WRITE &&
+ last_lock_type != TL_WRITE_CONCURRENT_INSERT)
{
fprintf(stderr,
"Warning: Found locks from different threads in %s: %s\n",
@@ -205,7 +208,7 @@ static void check_locks(THR_LOCK *lock, const char *where,
THR_LOCK_DATA *data;
for (data=lock->read.data ; data ; data=data->next)
{
- if ((int) data->type == (int) TL_READ_NO_INSERT)
+ if (data->type == TL_READ_NO_INSERT)
count++;
/* Protect against infinite loop. */
DBUG_ASSERT(count <= lock->read_no_write_count);
@@ -254,7 +257,22 @@ static void check_locks(THR_LOCK *lock, const char *where,
}
}
else
- { /* Have write lock */
+ {
+ /* We have at least one write lock */
+ if (lock->write.data->type == TL_WRITE_CONCURRENT_INSERT)
+ {
+ THR_LOCK_DATA *data;
+ for (data=lock->write.data->next ; data ; data=data->next)
+ {
+ if (data->type != TL_WRITE_CONCURRENT_INSERT)
+ {
+ fprintf(stderr,
+ "Warning at '%s': Found TL_WRITE_CONCURRENT_INSERT lock mixed with other write locks\n",
+ where);
+ break;
+ }
+ }
+ }
if (lock->write_wait.data)
{
if (!allow_no_locks &&
@@ -514,7 +532,8 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner,
/* Request for READ lock */
if (lock->write.data)
{
- /* We can allow a read lock even if there is already a write lock
+ /*
+ We can allow a read lock even if there is already a write lock
on the table in one the following cases:
- This thread alread have a write lock on the table
- The write lock is TL_WRITE_ALLOW_READ or TL_WRITE_DELAYED
@@ -558,11 +577,11 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner,
(*lock->read.last)=data; /* Add to running FIFO */
data->prev=lock->read.last;
lock->read.last= &data->next;
- if (lock->get_status)
- (*lock->get_status)(data->status_param, 0);
if (lock_type == TL_READ_NO_INSERT)
lock->read_no_write_count++;
check_locks(lock,"read lock with no write locks",0);
+ if (lock->get_status)
+ (*lock->get_status)(data->status_param, 0);
statistic_increment(locks_immediate,&THR_LOCK_lock);
goto end;
}
@@ -626,16 +645,18 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner,
The following test will not work if the old lock was a
TL_WRITE_ALLOW_WRITE, TL_WRITE_ALLOW_READ or TL_WRITE_DELAYED in
the same thread, but this will never happen within MySQL.
+
+ The idea is to allow us to get a lock at once if we already have
+ a write lock or if there is no pending write locks and if all
+ write locks are of the same type and are either
+ TL_WRITE_ALLOW_WRITE or TL_WRITE_CONCURRENT_INSERT
*/
if (thr_lock_owner_equal(data->owner, lock->write.data->owner) ||
- (lock_type == TL_WRITE_ALLOW_WRITE &&
- !lock->write_wait.data &&
- lock->write.data->type == TL_WRITE_ALLOW_WRITE))
+ (!lock->write_wait.data && lock_type == lock->write.data->type &&
+ (lock_type == TL_WRITE_ALLOW_WRITE ||
+ (lock_type == TL_WRITE_CONCURRENT_INSERT &&
+ lock->allow_multiple_concurrent_insert))))
{
- /*
- We have already got a write lock or all locks are
- TL_WRITE_ALLOW_WRITE
- */
DBUG_PRINT("info", ("write_wait.data: 0x%lx old_type: %d",
(ulong) lock->write_wait.data,
lock->write.data->type));
@@ -644,8 +665,9 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner,
data->prev=lock->write.last;
lock->write.last= &data->next;
check_locks(lock,"second write lock",0);
- if (data->lock->get_status)
- (*data->lock->get_status)(data->status_param, 0);
+ if (lock->get_status)
+ (*lock->get_status)(data->status_param,
+ lock_type == TL_WRITE_CONCURRENT_INSERT);
statistic_increment(locks_immediate,&THR_LOCK_lock);
goto end;
}
@@ -678,8 +700,8 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner,
(*lock->write.last)=data; /* Add as current write lock */
data->prev=lock->write.last;
lock->write.last= &data->next;
- if (data->lock->get_status)
- (*data->lock->get_status)(data->status_param, concurrent_insert);
+ if (lock->get_status)
+ (*lock->get_status)(data->status_param, concurrent_insert);
check_locks(lock,"only write lock",0);
statistic_increment(locks_immediate,&THR_LOCK_lock);
goto end;
@@ -809,7 +831,6 @@ static void wake_up_waiters(THR_LOCK *lock)
{
THR_LOCK_DATA *data;
enum thr_lock_type lock_type;
-
DBUG_ENTER("wake_up_waiters");
if (!lock->write.data) /* If no active write locks */
@@ -1372,8 +1393,8 @@ my_bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data)
{
if (!lock->read.data) /* No read locks */
{ /* We have the lock */
- if (data->lock->get_status)
- (*data->lock->get_status)(data->status_param, 0);
+ if (lock->get_status)
+ (*lock->get_status)(data->status_param, 0);
pthread_mutex_unlock(&lock->mutex);
DBUG_RETURN(0);
}
@@ -1511,7 +1532,7 @@ struct st_test {
enum thr_lock_type lock_type;
};
-THR_LOCK locks[5]; /* 4 locks */
+THR_LOCK locks[6]; /* Number of locks +1 */
struct st_test test_0[] = {{0,TL_READ}}; /* One lock */
struct st_test test_1[] = {{0,TL_READ},{0,TL_WRITE}}; /* Read and write lock of lock 0 */
@@ -1531,9 +1552,20 @@ struct st_test test_14[] = {{0,TL_WRITE_CONCURRENT_INSERT},{1,TL_READ}};
struct st_test test_15[] = {{0,TL_WRITE_ALLOW_WRITE},{1,TL_READ}};
struct st_test test_16[] = {{0,TL_WRITE_ALLOW_WRITE},{1,TL_WRITE_ALLOW_WRITE}};
-struct st_test *tests[] = {test_0,test_1,test_2,test_3,test_4,test_5,test_6,
- test_7,test_8,test_9,test_10,test_11,test_12,
- test_13,test_14,test_15,test_16};
+struct st_test test_17[] = {{5,TL_WRITE_CONCURRENT_INSERT}};
+struct st_test test_18[] = {{5,TL_WRITE_CONCURRENT_INSERT}};
+struct st_test test_19[] = {{5,TL_READ}};
+struct st_test test_20[] = {{5,TL_READ_NO_INSERT}};
+struct st_test test_21[] = {{5,TL_WRITE}};
+
+
+struct st_test *tests[]=
+{
+ test_0, test_1, test_2, test_3, test_4, test_5, test_6, test_7, test_8,
+ test_9, test_10, test_11, test_12, test_13, test_14, test_15, test_16,
+ test_17, test_18, test_19, test_20, test_21
+};
+
int lock_counts[]= {sizeof(test_0)/sizeof(struct st_test),
sizeof(test_1)/sizeof(struct st_test),
sizeof(test_2)/sizeof(struct st_test),
@@ -1550,7 +1582,12 @@ int lock_counts[]= {sizeof(test_0)/sizeof(struct st_test),
sizeof(test_13)/sizeof(struct st_test),
sizeof(test_14)/sizeof(struct st_test),
sizeof(test_15)/sizeof(struct st_test),
- sizeof(test_16)/sizeof(struct st_test)
+ sizeof(test_16)/sizeof(struct st_test),
+ sizeof(test_17)/sizeof(struct st_test),
+ sizeof(test_18)/sizeof(struct st_test),
+ sizeof(test_19)/sizeof(struct st_test),
+ sizeof(test_20)/sizeof(struct st_test),
+ sizeof(test_21)/sizeof(struct st_test)
};
@@ -1594,7 +1631,6 @@ static void *test_thread(void *arg)
printf("Thread %s (%d) started\n",my_thread_name(),param); fflush(stdout);
-
thr_lock_info_init(&lock_info);
thr_lock_owner_init(&owner, &lock_info);
for (i=0; i < lock_counts[param] ; i++)
@@ -1640,7 +1676,8 @@ int main(int argc __attribute__((unused)),char **argv __attribute__((unused)))
{
pthread_t tid;
pthread_attr_t thr_attr;
- int i,*param,error;
+ int *param,error;
+ uint i;
MY_INIT(argv[0]);
if (argc > 1 && argv[1][0] == '-' && argv[1][1] == '#')
DBUG_PUSH(argv[1]+2);
@@ -1660,13 +1697,14 @@ int main(int argc __attribute__((unused)),char **argv __attribute__((unused)))
exit(1);
}
- for (i=0 ; i < (int) array_elements(locks) ; i++)
+ for (i=0 ; i < array_elements(locks) ; i++)
{
thr_lock_init(locks+i);
locks[i].check_status= test_check_status;
locks[i].update_status=test_update_status;
locks[i].copy_status= test_copy_status;
locks[i].get_status= test_get_status;
+ locks[i].allow_multiple_concurrent_insert= 1;
}
if ((error=pthread_attr_init(&thr_attr)))
{
@@ -1692,7 +1730,7 @@ int main(int argc __attribute__((unused)),char **argv __attribute__((unused)))
#ifdef HAVE_THR_SETCONCURRENCY
VOID(thr_setconcurrency(2));
#endif
- for (i=0 ; i < (int) array_elements(lock_counts) ; i++)
+ for (i=0 ; i < array_elements(lock_counts) ; i++)
{
param=(int*) malloc(sizeof(int));
*param=i;
@@ -1724,7 +1762,7 @@ int main(int argc __attribute__((unused)),char **argv __attribute__((unused)))
}
if ((error=pthread_mutex_unlock(&LOCK_thread_count)))
fprintf(stderr,"Got error: %d from pthread_mutex_unlock\n",error);
- for (i=0 ; i < (int) array_elements(locks) ; i++)
+ for (i=0 ; i < array_elements(locks) ; i++)
thr_lock_delete(locks+i);
#ifdef EXTRA_DEBUG
if (found_errors)