Commit 4f6e375b authored by Michael Widenius's avatar Michael Widenius

Fixes for Aria storage engine:

- Fixed bug lp:624099 ma_close.c:75: maria_close: Assertion `share->in_trans == 0' failed on UNLOCK TABLES
- Fixed bug that caused table to be marked as not closed (crashed) during recovery testing.
- Use maria_delete_table_files() instead of maria_delete_table() to delete tempoary tables (faster and safer)
- Added checks to ensure that bitmap and internal mutex are always taken in right order.
- For transactional tables, only mark the table as changed before page for table is to be written to disk (and thus the log is flushed).
  This speeds up things a bit and fixes a problem where open_count was incremented on disk but there was no log entry to fix it during recovery -> table was crashed.
- Fixed a bug in repair() where table was not automaticly repaired.
- Ensure that state->global_changed, share->changed and share->state.open_count are set and reset properly.
- Added option --ignore-control-file to maria_chk to be able to run maria_chk even if the control file is locked.


mysql-test/suite/maria/r/maria-recover.result:
  Test result changed as we now force checkpoint before copying table, which results in pagecache getting flushed and we have more rows to recover.
mysql-test/suite/maria/r/maria.result:
  Added new tests
mysql-test/suite/maria/t/maria-recover.test:
  Force checkpoint before copying table.
  This is needed as now the open-count is increased first when first page is flushed.
mysql-test/suite/maria/t/maria.test:
  Added tests to verify fix for lp:624099
storage/maria/ha_maria.cc:
  Use table->in_use instead of current_thd (trivial optimization)
  Use maria_delete_table_files() instead of maria_delete_table() to delete tempoary tables (faster and safer)
  More DBUG_ASSERT()
  Reset locked tables count after locked tables have been moved to new transaction. This fixed lp:624099
storage/maria/ma_bitmap.c:
  Temporarly unlock bitmap mutex when calling _ma_mark_file_changed() and pagecache_delete_pages() to ensure right mutex lock order.
  Call _ma_bitmap_unpin_all() when bitmap->non_flusable is set to 0. This fixed a case when bitmap was not proparly unpinned.
  More comments
  Added DBUG_ASSERT() for detecting wrong share->bitmap usage
storage/maria/ma_blockrec.c:
  More DBUG_ASSERT()
  Moved code around in _ma_apply_redo_insert_row_head_or_tail() to make things safer on error conditions.
storage/maria/ma_check.c:
  Changed parameter for _ma_set_uuid()
  Corrected test for detecting if we lost many rows. This fixed some cases where auto-recovery failed.
  share->changed need to be set if state.open_count is changed.
  Removed setting of share->changed= 0 as called function sets it.
storage/maria/ma_close.c:
  - Added code to properly decrement open_count and have it written by _ma_state_info_write() for transactional tables.
    (This is more correct and also saves us one extra write by _ma_decrement_open_count() at close.
  - Added DBUG_ASSERT() to detect if open_count is wrong at maria_close().
storage/maria/ma_delete.c:
  Updated argument to _ma_mark_file_changed()
storage/maria/ma_delete_all.c:
  Updated argument to _ma_mark_file_changed()
  For transactional tables, call _ma_mark_file_changed() after log entry has been written (to allow recover to fix open_count)
  Reset more needed variables in _ma_reset_status()
storage/maria/ma_delete_table.c:
  Moved deletion of Aria files to maria_delete_table_files().
  Remove RAID usage (old not working code)
storage/maria/ma_extra.c:
  Set share->changed=1 when state needs to be updated on disk.
  Don't reset share->changed after call to _ma_state_info_write() as this calls sets share->changed.
  Set share->state.open_count to 1 to force table to be auto repaired if drop fails.
  Set share->global_changed before call to _ma_flush_table_files() to ensure that we don't try to mark the table changed during flush.
  Added DBUG_ENTER
storage/maria/ma_locking.c:
  Split _ma_mark_file_changed() into two functions to delay marking transactional tables as changed on disk until first disk write.
  Added argument to _ma_decrement_open_count() to tell if we should call ma_lock_database() or not.
  Don't decrement open count for transactional tables during _ma_decrement_open_count(). This will be done during close.
  Changed parameter for _ma_set_uuid()
storage/maria/ma_open.c:
  Set share->open_count_not_zero_on_open if state.open_count is not zero.
  This is needed for DBUG_ASSERT() in maria_close() that is there to enforce that open_count is always 0 at close.
  This test doesn't however work for tables that had open_count != 0 already on disk (ie, crashed tables).
  Enforce right mutex order for share->intern_lock and share->bitmap.bitmap_lock
  Don't set share->changed to 0 if share->state.open_count != 0, as state needs to be be written at close
storage/maria/ma_pagecache.c:
  Moved a bit of code in find_block() to avoid one if.
  More DBUG_ASSERT()
  (I left a comment in the code for Sanja to look at;  The code probably works but we need to check if it's optimal)
storage/maria/ma_pagecrc.c:
  For transactional tables, just before first write to disk, but after log is flushed, mark the file changed.
  This fixes some cases where recovery() did not detect that table was marked as changed and could thus not recover the marker.
storage/maria/ma_recovery.c:
  Set share->changed when share->global_changed is set.
storage/maria/ma_update.c:
  Updated parameter for _ma_mark_file_changed()
storage/maria/ma_write.c:
  Updated parameter for _ma_mark_file_changed()
storage/maria/maria_chk.c:
  Added option --ignore-control-file to be able to run maria_chk even if the control file is locked.
storage/maria/maria_def.h:
  Updated function prototypes.
  Added open_count_not_zero_on_open to MARIA_SHARE.
storage/myisam/ha_myisam.cc:
  current_thd -> table->in_use
parent 65fb551e
...@@ -20,9 +20,11 @@ create table t1 (a varchar(1000), index(a)) engine=maria; ...@@ -20,9 +20,11 @@ create table t1 (a varchar(1000), index(a)) engine=maria;
insert into t1 values("ThursdayMorningsMarket"); insert into t1 values("ThursdayMorningsMarket");
flush table t1; flush table t1;
insert into t1 select concat(a,'b') from t1 limit 1; insert into t1 select concat(a,'b') from t1 limit 1;
set global maria_checkpoint_interval=1000;
select * from t_corrupted2; select * from t_corrupted2;
a a
ThursdayMorningsMarket ThursdayMorningsMarket
ThursdayMorningsMarketb
Warnings: Warnings:
Error 145 t_corrupted2' is marked as crashed and should be repaired Error 145 t_corrupted2' is marked as crashed and should be repaired
Error 1194 t_corrupted2' is marked as crashed and should be repaired Error 1194 t_corrupted2' is marked as crashed and should be repaired
...@@ -31,5 +33,7 @@ Error 1034 Wrong base information on indexpage at page: 1 ...@@ -31,5 +33,7 @@ Error 1034 Wrong base information on indexpage at page: 1
select * from t_corrupted2; select * from t_corrupted2;
a a
ThursdayMorningsMarket ThursdayMorningsMarket
ThursdayMorningsMarketb
drop database mysqltest; drop database mysqltest;
set global maria_recover=backup; set global maria_recover=backup;
set global maria_checkpoint_interval=30;
...@@ -2640,3 +2640,29 @@ repair table t1 extended; ...@@ -2640,3 +2640,29 @@ repair table t1 extended;
Table Op Msg_type Msg_text Table Op Msg_type Msg_text
test.t1 repair status OK test.t1 repair status OK
drop table t1; drop table t1;
create table t1 (a int, b int, key (a), key(b));
alter table t1 disable keys;
insert into t1 values(1,1),(2,1),(3,1),(4,1),(5,1),(6,1),(7,1),(8,1),(9,1),(10,1),(11,1),(12,1),(13,1);
alter table t1 enable keys;
select count(*) from t1;
count(*)
13
drop table t1;
create table t1 (a int not null, b int, primary key (a), key(b));
alter table t1 disable keys;
insert into t1 values(1,1),(2,1),(3,1),(4,1),(5,1),(6,1),(7,1),(8,1),(9,1),(10,1),(11,1),(12,1),(13,1);
alter table t1 enable keys;
select count(*) from t1;
count(*)
13
drop table t1;
create table t1 (a int not null, b int, primary key (a), key(b));
lock tables t1 write;
alter table t1 disable keys;
insert into t1 values(1,1),(2,1),(3,1),(4,1),(5,1),(6,1),(7,1),(8,1),(9,1),(10,1),(11,1),(12,1),(13,1);
alter table t1 enable keys;
unlock tables;
select count(*) from t1;
count(*)
13
drop table t1;
...@@ -10,6 +10,8 @@ call mtr.add_suppression("Recovering table: '\\..mysqltest.t_corrupted2'"); ...@@ -10,6 +10,8 @@ call mtr.add_suppression("Recovering table: '\\..mysqltest.t_corrupted2'");
call mtr.add_suppression("Table '\\..mysqltest.t_corrupted2' is marked as crashed and should be repaired"); call mtr.add_suppression("Table '\\..mysqltest.t_corrupted2' is marked as crashed and should be repaired");
call mtr.add_suppression("Table 't_corrupted2' is marked as crashed and should be repaired"); call mtr.add_suppression("Table 't_corrupted2' is marked as crashed and should be repaired");
let $def_checkinterval=`select @@global.maria_checkpoint_interval`;
--enable_query_log --enable_query_log
# Note: we're setting an environment variable (not prefixing it by $), # Note: we're setting an environment variable (not prefixing it by $),
...@@ -36,6 +38,10 @@ insert into t1 values("ThursdayMorningsMarket"); ...@@ -36,6 +38,10 @@ insert into t1 values("ThursdayMorningsMarket");
flush table t1; # put index page on disk flush table t1; # put index page on disk
insert into t1 select concat(a,'b') from t1 limit 1; insert into t1 select concat(a,'b') from t1 limit 1;
# force a checkpoint to get the open count > 0
set global maria_checkpoint_interval=1000;
# Wait for checkpoint to happen
--sleep 1
# now t1 has its open_count>0 and so will t2_corrupted. # now t1 has its open_count>0 and so will t2_corrupted.
# It is not named t2 because the corruption messages which will be put # It is not named t2 because the corruption messages which will be put
# in the error log need to be detected in mtr_process.pl, and we want # in the error log need to be detected in mtr_process.pl, and we want
...@@ -59,7 +65,6 @@ perl; ...@@ -59,7 +65,6 @@ perl;
syswrite (FILE, $whatever) or die; syswrite (FILE, $whatever) or die;
close FILE; close FILE;
EOF EOF
replace_regex /Table.*t_corrupted2/t_corrupted2/ ; replace_regex /Table.*t_corrupted2/t_corrupted2/ ;
--enable_prepare_warnings --enable_prepare_warnings
select * from t_corrupted2; # should show corruption and repair messages select * from t_corrupted2; # should show corruption and repair messages
...@@ -68,3 +73,4 @@ select * from t_corrupted2; # should show just rows ...@@ -68,3 +73,4 @@ select * from t_corrupted2; # should show just rows
drop database mysqltest; drop database mysqltest;
set global maria_recover=backup; set global maria_recover=backup;
eval set global maria_checkpoint_interval=$def_checkinterval;
...@@ -1928,6 +1928,33 @@ check table t1; ...@@ -1928,6 +1928,33 @@ check table t1;
repair table t1 extended; repair table t1 extended;
drop table t1; drop table t1;
#
# Test problem with disable/enable keys
#
create table t1 (a int, b int, key (a), key(b));
alter table t1 disable keys;
insert into t1 values(1,1),(2,1),(3,1),(4,1),(5,1),(6,1),(7,1),(8,1),(9,1),(10,1),(11,1),(12,1),(13,1);
alter table t1 enable keys;
select count(*) from t1;
drop table t1;
create table t1 (a int not null, b int, primary key (a), key(b));
alter table t1 disable keys;
insert into t1 values(1,1),(2,1),(3,1),(4,1),(5,1),(6,1),(7,1),(8,1),(9,1),(10,1),(11,1),(12,1),(13,1);
alter table t1 enable keys;
select count(*) from t1;
drop table t1;
create table t1 (a int not null, b int, primary key (a), key(b));
lock tables t1 write;
alter table t1 disable keys;
insert into t1 values(1,1),(2,1),(3,1),(4,1),(5,1),(6,1),(7,1),(8,1),(9,1),(10,1),(11,1),(12,1),(13,1);
alter table t1 enable keys;
unlock tables;
select count(*) from t1;
drop table t1;
# #
# End of test # End of test
# #
......
...@@ -1568,7 +1568,7 @@ int ha_maria::repair(THD *thd, HA_CHECK *param, bool do_optimize) ...@@ -1568,7 +1568,7 @@ int ha_maria::repair(THD *thd, HA_CHECK *param, bool do_optimize)
llstr(rows, llbuff), llstr(rows, llbuff),
llstr(file->state->records, llbuff2)); llstr(file->state->records, llbuff2));
/* Abort if warning was converted to error */ /* Abort if warning was converted to error */
if (current_thd->is_error()) if (table->in_use->is_error())
error= 1; error= 1;
} }
} }
...@@ -1803,7 +1803,7 @@ int ha_maria::enable_indexes(uint mode) ...@@ -1803,7 +1803,7 @@ int ha_maria::enable_indexes(uint mode)
} }
else if (mode == HA_KEY_SWITCH_NONUNIQ_SAVE) else if (mode == HA_KEY_SWITCH_NONUNIQ_SAVE)
{ {
THD *thd= current_thd; THD *thd= table->in_use;
HA_CHECK &param= *(HA_CHECK*) thd->alloc(sizeof(param)); HA_CHECK &param= *(HA_CHECK*) thd->alloc(sizeof(param));
if (!&param) if (!&param)
return HA_ADMIN_INTERNAL_ERROR; return HA_ADMIN_INTERNAL_ERROR;
...@@ -1905,7 +1905,7 @@ int ha_maria::indexes_are_disabled(void) ...@@ -1905,7 +1905,7 @@ int ha_maria::indexes_are_disabled(void)
void ha_maria::start_bulk_insert(ha_rows rows) void ha_maria::start_bulk_insert(ha_rows rows)
{ {
DBUG_ENTER("ha_maria::start_bulk_insert"); DBUG_ENTER("ha_maria::start_bulk_insert");
THD *thd= current_thd; THD *thd= table->in_use;
ulong size= min(thd->variables.read_buff_size, ulong size= min(thd->variables.read_buff_size,
(ulong) (table->s->avg_row_length * rows)); (ulong) (table->s->avg_row_length * rows));
MARIA_SHARE *share= file->s; MARIA_SHARE *share= file->s;
...@@ -2388,7 +2388,7 @@ int ha_maria::extra_opt(enum ha_extra_function operation, ulong cache_size) ...@@ -2388,7 +2388,7 @@ int ha_maria::extra_opt(enum ha_extra_function operation, ulong cache_size)
int ha_maria::delete_all_rows() int ha_maria::delete_all_rows()
{ {
THD *thd= current_thd; THD *thd= table->in_use;
(void) translog_log_debug_info(file->trn, LOGREC_DEBUG_INFO_QUERY, (void) translog_log_debug_info(file->trn, LOGREC_DEBUG_INFO_QUERY,
(uchar*) thd->query(), thd->query_length()); (uchar*) thd->query(), thd->query_length());
if (file->s->now_transactional && if (file->s->now_transactional &&
...@@ -2418,8 +2418,9 @@ int ha_maria::delete_table(const char *name) ...@@ -2418,8 +2418,9 @@ int ha_maria::delete_table(const char *name)
void ha_maria::drop_table(const char *name) void ha_maria::drop_table(const char *name)
{ {
DBUG_ASSERT(file->s->temporary);
(void) close(); (void) close();
(void) maria_delete_table(name); (void) maria_delete_table_files(name, 0);
} }
...@@ -2514,6 +2515,7 @@ int ha_maria::external_lock(THD *thd, int lock_type) ...@@ -2514,6 +2515,7 @@ int ha_maria::external_lock(THD *thd, int lock_type)
{ {
DBUG_PRINT("info", DBUG_PRINT("info",
("locked_tables: %u", trnman_has_locked_tables(trn))); ("locked_tables: %u", trnman_has_locked_tables(trn)));
DBUG_ASSERT(trnman_has_locked_tables(trn) > 0);
if (trnman_has_locked_tables(trn) && if (trnman_has_locked_tables(trn) &&
!trnman_decrement_locked_tables(trn)) !trnman_decrement_locked_tables(trn))
{ {
...@@ -2647,12 +2649,12 @@ int ha_maria::implicit_commit(THD *thd, bool new_trn) ...@@ -2647,12 +2649,12 @@ int ha_maria::implicit_commit(THD *thd, bool new_trn)
statement assuming they have a trn (see ha_maria::start_stmt()). statement assuming they have a trn (see ha_maria::start_stmt()).
*/ */
trn= trnman_new_trn(& thd->transaction.wt); trn= trnman_new_trn(& thd->transaction.wt);
/* This is just a commit, tables stay locked if they were: */
trnman_reset_locked_tables(trn, locked_tables);
THD_TRN= trn; THD_TRN= trn;
if (unlikely(trn == NULL)) if (unlikely(trn == NULL))
{
error= HA_ERR_OUT_OF_MEM; error= HA_ERR_OUT_OF_MEM;
goto end;
}
/* /*
Move all locked tables to the new transaction Move all locked tables to the new transaction
We must do it here as otherwise file->thd and file->state may be We must do it here as otherwise file->thd and file->state may be
...@@ -2677,6 +2679,8 @@ int ha_maria::implicit_commit(THD *thd, bool new_trn) ...@@ -2677,6 +2679,8 @@ int ha_maria::implicit_commit(THD *thd, bool new_trn)
} }
} }
} }
/* This is just a commit, tables stay locked if they were: */
trnman_reset_locked_tables(trn, locked_tables);
} }
end: end:
DBUG_RETURN(error); DBUG_RETURN(error);
...@@ -2813,7 +2817,7 @@ int ha_maria::create(const char *name, register TABLE *table_arg, ...@@ -2813,7 +2817,7 @@ int ha_maria::create(const char *name, register TABLE *table_arg,
ha_create_info->row_type != ROW_TYPE_PAGE && ha_create_info->row_type != ROW_TYPE_PAGE &&
ha_create_info->row_type != ROW_TYPE_NOT_USED && ha_create_info->row_type != ROW_TYPE_NOT_USED &&
ha_create_info->row_type != ROW_TYPE_DEFAULT) ha_create_info->row_type != ROW_TYPE_DEFAULT)
push_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_NOTE, push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_ILLEGAL_HA_CREATE_OPTION, ER_ILLEGAL_HA_CREATE_OPTION,
"Row format set to PAGE because of TRANSACTIONAL=1 option"); "Row format set to PAGE because of TRANSACTIONAL=1 option");
......
...@@ -144,6 +144,8 @@ static my_bool _ma_read_bitmap_page(MARIA_HA *info, ...@@ -144,6 +144,8 @@ static my_bool _ma_read_bitmap_page(MARIA_HA *info,
static my_bool _ma_bitmap_create_missing(MARIA_HA *info, static my_bool _ma_bitmap_create_missing(MARIA_HA *info,
MARIA_FILE_BITMAP *bitmap, MARIA_FILE_BITMAP *bitmap,
pgcache_page_no_t page); pgcache_page_no_t page);
static void _ma_bitmap_unpin_all(MARIA_SHARE *share);
/* Write bitmap page to key cache */ /* Write bitmap page to key cache */
...@@ -177,6 +179,15 @@ static inline my_bool write_changed_bitmap(MARIA_SHARE *share, ...@@ -177,6 +179,15 @@ static inline my_bool write_changed_bitmap(MARIA_SHARE *share,
} }
else else
{ {
/*
bitmap->non_flushable means that someone has changed the bitmap,
but it's not yet complete so it can't yet be written to disk.
In this case we write the changed bitmap to the disk cache,
but keep it pinned until the change is completed. The page will
be unpinned later by _ma_bitmap_unpin_all() as soon as non_flushable
is set back to 0.
*/
DBUG_PRINT("info", ("Writing pinned bitmap page"));
MARIA_PINNED_PAGE page_link; MARIA_PINNED_PAGE page_link;
int res= pagecache_write(share->pagecache, int res= pagecache_write(share->pagecache,
&bitmap->file, bitmap->page, 0, &bitmap->file, bitmap->page, 0,
...@@ -275,8 +286,15 @@ my_bool _ma_bitmap_init(MARIA_SHARE *share, File file) ...@@ -275,8 +286,15 @@ my_bool _ma_bitmap_init(MARIA_SHARE *share, File file)
my_bool _ma_bitmap_end(MARIA_SHARE *share) my_bool _ma_bitmap_end(MARIA_SHARE *share)
{ {
my_bool res= _ma_bitmap_flush(share); my_bool res;
safe_mutex_assert_owner(&share->close_lock); safe_mutex_assert_owner(&share->close_lock);
DBUG_ASSERT(share->bitmap.non_flushable == 0);
DBUG_ASSERT(share->bitmap.flush_all_requested == 0);
DBUG_ASSERT(share->bitmap.waiting_for_non_flushable == 0 &&
share->bitmap.waiting_for_flush_all_requested == 0);
DBUG_ASSERT(share->bitmap.pinned_pages.elements == 0);
res= _ma_bitmap_flush(share);
pthread_mutex_destroy(&share->bitmap.bitmap_lock); pthread_mutex_destroy(&share->bitmap.bitmap_lock);
pthread_cond_destroy(&share->bitmap.bitmap_cond); pthread_cond_destroy(&share->bitmap.bitmap_cond);
delete_dynamic(&share->bitmap.pinned_pages); delete_dynamic(&share->bitmap.pinned_pages);
...@@ -388,6 +406,30 @@ my_bool _ma_bitmap_flush_all(MARIA_SHARE *share) ...@@ -388,6 +406,30 @@ my_bool _ma_bitmap_flush_all(MARIA_SHARE *share)
#endif #endif
pthread_mutex_lock(&bitmap->bitmap_lock); pthread_mutex_lock(&bitmap->bitmap_lock);
if (!bitmap->changed && !bitmap->changed_not_flushed)
{
pthread_mutex_unlock(&bitmap->bitmap_lock);
DBUG_RETURN(0);
}
/*
Before flusing bitmap, ensure that we have incremented open count.
This is needed to ensure that we don't call
_ma_mark_file_changed() as part of flushing bitmap page as in this
case we would use mutex lock in wrong order.
It's extremely unlikely that the following test is true as normally
this is happening when table is flushed.
*/
if (unlikely(!share->global_changed))
{
/* purecov: begin inspected */
/* unlock bitmap mutex as it can't be hold during _ma_mark_file_changed */
pthread_mutex_unlock(&bitmap->bitmap_lock);
_ma_mark_file_changed(share);
pthread_mutex_lock(&bitmap->bitmap_lock);
/* purecov: end */
}
if (bitmap->changed || bitmap->changed_not_flushed) if (bitmap->changed || bitmap->changed_not_flushed)
{ {
bitmap->flush_all_requested++; bitmap->flush_all_requested++;
...@@ -514,6 +556,7 @@ void _ma_bitmap_unlock(MARIA_SHARE *share) ...@@ -514,6 +556,7 @@ void _ma_bitmap_unlock(MARIA_SHARE *share)
pthread_mutex_lock(&bitmap->bitmap_lock); pthread_mutex_lock(&bitmap->bitmap_lock);
bitmap->non_flushable= 0; bitmap->non_flushable= 0;
_ma_bitmap_unpin_all(share);
send_signal= bitmap->waiting_for_non_flushable; send_signal= bitmap->waiting_for_non_flushable;
if (!--bitmap->flush_all_requested) if (!--bitmap->flush_all_requested)
send_signal|= bitmap->waiting_for_flush_all_requested; send_signal|= bitmap->waiting_for_flush_all_requested;
...@@ -2544,9 +2587,9 @@ my_bool _ma_bitmap_free_full_pages(MARIA_HA *info, const uchar *extents, ...@@ -2544,9 +2587,9 @@ my_bool _ma_bitmap_free_full_pages(MARIA_HA *info, const uchar *extents,
uint count) uint count)
{ {
MARIA_FILE_BITMAP *bitmap= &info->s->bitmap; MARIA_FILE_BITMAP *bitmap= &info->s->bitmap;
my_bool res;
DBUG_ENTER("_ma_bitmap_free_full_pages"); DBUG_ENTER("_ma_bitmap_free_full_pages");
pthread_mutex_lock(&bitmap->bitmap_lock);
for (; count--; extents+= ROW_EXTENT_SIZE) for (; count--; extents+= ROW_EXTENT_SIZE)
{ {
pgcache_page_no_t page= uint5korr(extents); pgcache_page_no_t page= uint5korr(extents);
...@@ -2557,15 +2600,15 @@ my_bool _ma_bitmap_free_full_pages(MARIA_HA *info, const uchar *extents, ...@@ -2557,15 +2600,15 @@ my_bool _ma_bitmap_free_full_pages(MARIA_HA *info, const uchar *extents,
if (page == 0 && page_count == 0) if (page == 0 && page_count == 0)
continue; /* Not used extent */ continue; /* Not used extent */
if (pagecache_delete_pages(info->s->pagecache, &info->dfile, page, if (pagecache_delete_pages(info->s->pagecache, &info->dfile, page,
page_count, PAGECACHE_LOCK_WRITE, 1) || page_count, PAGECACHE_LOCK_WRITE, 1))
_ma_bitmap_reset_full_page_bits(info, bitmap, page, page_count)) DBUG_RETURN(1);
{ pthread_mutex_lock(&bitmap->bitmap_lock);
pthread_mutex_unlock(&bitmap->bitmap_lock); res= _ma_bitmap_reset_full_page_bits(info, bitmap, page, page_count);
pthread_mutex_unlock(&bitmap->bitmap_lock);
if (res)
DBUG_RETURN(1); DBUG_RETURN(1);
}
} }
} }
pthread_mutex_unlock(&bitmap->bitmap_lock);
DBUG_RETURN(0); DBUG_RETURN(0);
} }
......
...@@ -2017,6 +2017,7 @@ static my_bool write_tail(MARIA_HA *info, ...@@ -2017,6 +2017,7 @@ static my_bool write_tail(MARIA_HA *info,
PAGECACHE_WRITE_DELAY, &page_link.link, PAGECACHE_WRITE_DELAY, &page_link.link,
LSN_IMPOSSIBLE))) LSN_IMPOSSIBLE)))
{ {
DBUG_ASSERT(page_link.link);
page_link.unlock= PAGECACHE_LOCK_READ_UNLOCK; page_link.unlock= PAGECACHE_LOCK_READ_UNLOCK;
page_link.changed= 1; page_link.changed= 1;
push_dynamic(&info->pinned_pages, (void*) &page_link); push_dynamic(&info->pinned_pages, (void*) &page_link);
...@@ -3146,6 +3147,7 @@ static my_bool write_block_record(MARIA_HA *info, ...@@ -3146,6 +3147,7 @@ static my_bool write_block_record(MARIA_HA *info,
PAGECACHE_WRITE_DELAY, &page_link.link, PAGECACHE_WRITE_DELAY, &page_link.link,
LSN_IMPOSSIBLE)) LSN_IMPOSSIBLE))
goto disk_err; goto disk_err;
DBUG_ASSERT(page_link.link);
page_link.unlock= PAGECACHE_LOCK_READ_UNLOCK; page_link.unlock= PAGECACHE_LOCK_READ_UNLOCK;
page_link.changed= 1; page_link.changed= 1;
push_dynamic(&info->pinned_pages, (void*) &page_link); push_dynamic(&info->pinned_pages, (void*) &page_link);
...@@ -6337,6 +6339,12 @@ uint _ma_apply_redo_insert_row_head_or_tail(MARIA_HA *info, LSN lsn, ...@@ -6337,6 +6339,12 @@ uint _ma_apply_redo_insert_row_head_or_tail(MARIA_HA *info, LSN lsn,
empty_space-= (uint) data_length; empty_space-= (uint) data_length;
int2store(buff + EMPTY_SPACE_OFFSET, empty_space); int2store(buff + EMPTY_SPACE_OFFSET, empty_space);
/* Fix bitmap */
if (!enough_free_entries_on_page(share, buff))
empty_space= 0; /* Page is full */
if (_ma_bitmap_set(info, page, page_type == HEAD_PAGE, empty_space))
goto err;
/* /*
If page was not read before, write it but keep it pinned. If page was not read before, write it but keep it pinned.
We don't update its LSN When we have processed all REDOs for this page We don't update its LSN When we have processed all REDOs for this page
...@@ -6354,12 +6362,6 @@ uint _ma_apply_redo_insert_row_head_or_tail(MARIA_HA *info, LSN lsn, ...@@ -6354,12 +6362,6 @@ uint _ma_apply_redo_insert_row_head_or_tail(MARIA_HA *info, LSN lsn,
LSN_IMPOSSIBLE)) LSN_IMPOSSIBLE))
result= my_errno; result= my_errno;
/* Fix bitmap */
if (!enough_free_entries_on_page(share, buff))
empty_space= 0; /* Page is full */
if (_ma_bitmap_set(info, page, page_type == HEAD_PAGE, empty_space))
goto err;
page_link.unlock= PAGECACHE_LOCK_WRITE_UNLOCK; page_link.unlock= PAGECACHE_LOCK_WRITE_UNLOCK;
page_link.changed= 1; page_link.changed= 1;
push_dynamic(&info->pinned_pages, (void*) &page_link); push_dynamic(&info->pinned_pages, (void*) &page_link);
......
...@@ -3478,7 +3478,7 @@ int maria_zerofill(HA_CHECK *param, MARIA_HA *info, const char *name) ...@@ -3478,7 +3478,7 @@ int maria_zerofill(HA_CHECK *param, MARIA_HA *info, const char *name)
_ma_tmp_disable_logging_for_table(info, 0); _ma_tmp_disable_logging_for_table(info, 0);
if (!(error= (maria_zerofill_index(param, info, name) || if (!(error= (maria_zerofill_index(param, info, name) ||
maria_zerofill_data(param, info, name) || maria_zerofill_data(param, info, name) ||
_ma_set_uuid(info, 0)))) _ma_set_uuid(info->s, 0))))
{ {
/* /*
Mark that we have done zerofill of data and index. If we zeroed pages' Mark that we have done zerofill of data and index. If we zeroed pages'
...@@ -3857,11 +3857,13 @@ int maria_repair_by_sort(HA_CHECK *param, register MARIA_HA *info, ...@@ -3857,11 +3857,13 @@ int maria_repair_by_sort(HA_CHECK *param, register MARIA_HA *info,
if (param->testflag & T_SAFE_REPAIR) if (param->testflag & T_SAFE_REPAIR)
{ {
/* Don't repair if we loosed more than one row */ /* Don't repair if we loosed more than one row */
if (share->state.state.records+1 < start_records) if (sort_info.new_info->s->state.state.records+1 < start_records)
{ {
_ma_check_print_error(param, _ma_check_print_error(param,
"Rows lost; Aborting because safe repair was " "Rows lost (Found %lu of %lu); Aborting "
"requested"); "because safe repair was requested",
(ulong) share->state.state.records,
(ulong) start_records);
share->state.state.records=start_records; share->state.state.records=start_records;
goto err; goto err;
} }
...@@ -4420,8 +4422,13 @@ int maria_repair_parallel(HA_CHECK *param, register MARIA_HA *info, ...@@ -4420,8 +4422,13 @@ int maria_repair_parallel(HA_CHECK *param, register MARIA_HA *info,
if (param->testflag & T_SAFE_REPAIR) if (param->testflag & T_SAFE_REPAIR)
{ {
/* Don't repair if we loosed more than one row */ /* Don't repair if we loosed more than one row */
if (share->state.state.records+1 < start_records) if (sort_info.new_info->s->state.state.records+1 < start_records)
{ {
_ma_check_print_error(param,
"Rows lost (Found %lu of %lu); Aborting "
"because safe repair was requested",
(ulong) share->state.state.records,
(ulong) start_records);
share->state.state.records=start_records; share->state.state.records=start_records;
goto err; goto err;
} }
...@@ -6069,6 +6076,7 @@ int maria_update_state_info(HA_CHECK *param, MARIA_HA *info,uint update) ...@@ -6069,6 +6076,7 @@ int maria_update_state_info(HA_CHECK *param, MARIA_HA *info,uint update)
{ {
share->state.open_count=0; share->state.open_count=0;
share->global_changed=0; share->global_changed=0;
share->changed= 1;
} }
if (update & UPDATE_STAT) if (update & UPDATE_STAT)
{ {
...@@ -6096,7 +6104,6 @@ int maria_update_state_info(HA_CHECK *param, MARIA_HA *info,uint update) ...@@ -6096,7 +6104,6 @@ int maria_update_state_info(HA_CHECK *param, MARIA_HA *info,uint update)
MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET | MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET |
MA_STATE_INFO_WRITE_FULL_INFO)) MA_STATE_INFO_WRITE_FULL_INFO))
goto err; goto err;
share->changed=0;
} }
{ /* Force update of status */ { /* Force update of status */
int error; int error;
......
...@@ -39,9 +39,6 @@ int maria_close(register MARIA_HA *info) ...@@ -39,9 +39,6 @@ int maria_close(register MARIA_HA *info)
if (info->lock_type == F_EXTRA_LCK) if (info->lock_type == F_EXTRA_LCK)
info->lock_type=F_UNLCK; /* HA_EXTRA_NO_USER_CHANGE */ info->lock_type=F_UNLCK; /* HA_EXTRA_NO_USER_CHANGE */
if (share->reopen == 1 && share->kfile.file >= 0)
_ma_decrement_open_count(info);
if (info->lock_type != F_UNLCK) if (info->lock_type != F_UNLCK)
{ {
if (maria_lock_database(info,F_UNLCK)) if (maria_lock_database(info,F_UNLCK))
...@@ -76,6 +73,11 @@ int maria_close(register MARIA_HA *info) ...@@ -76,6 +73,11 @@ int maria_close(register MARIA_HA *info)
if (share->kfile.file >= 0) if (share->kfile.file >= 0)
{ {
my_bool save_global_changed= share->global_changed;
/* Avoid _ma_mark_file_changed() when flushing pages */
share->global_changed= 1;
if ((*share->once_end)(share)) if ((*share->once_end)(share))
error= my_errno; error= my_errno;
if (flush_pagecache_blocks(share->pagecache, &share->kfile, if (flush_pagecache_blocks(share->pagecache, &share->kfile,
...@@ -97,6 +99,16 @@ int maria_close(register MARIA_HA *info) ...@@ -97,6 +99,16 @@ int maria_close(register MARIA_HA *info)
if (((share->changed && share->base.born_transactional) || if (((share->changed && share->base.born_transactional) ||
maria_is_crashed(info))) maria_is_crashed(info)))
{ {
if (save_global_changed)
{
/*
Reset effect of _ma_mark_file_changed(). Better to do it
here than in _ma_decrement_open_count(), as
_ma_state_info_write() will write the open_count.
*/
save_global_changed= 0;
share->state.open_count--;
}
/* /*
State must be written to file as it was not done at table's State must be written to file as it was not done at table's
unlocking. unlocking.
...@@ -104,6 +116,19 @@ int maria_close(register MARIA_HA *info) ...@@ -104,6 +116,19 @@ int maria_close(register MARIA_HA *info)
if (_ma_state_info_write(share, MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET)) if (_ma_state_info_write(share, MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET))
error= my_errno; error= my_errno;
} }
DBUG_ASSERT(maria_is_crashed(info) || !share->base.born_transactional ||
share->state.open_count == 0 ||
share->open_count_not_zero_on_open);
/* Ensure that open_count is zero on close */
share->global_changed= save_global_changed;
_ma_decrement_open_count(info, 0);
/* Ensure that open_count really is zero */
DBUG_ASSERT(maria_is_crashed(info) || share->temporary ||
share->state.open_count == 0 ||
share->open_count_not_zero_on_open);
/* /*
File must be synced as it is going out of the maria_open_list and so File must be synced as it is going out of the maria_open_list and so
becoming unknown to future Checkpoints. becoming unknown to future Checkpoints.
......
...@@ -63,7 +63,7 @@ int maria_delete(MARIA_HA *info,const uchar *record) ...@@ -63,7 +63,7 @@ int maria_delete(MARIA_HA *info,const uchar *record)
if ((*share->compare_record)(info,record)) if ((*share->compare_record)(info,record))
goto err; /* Error on read-check */ goto err; /* Error on read-check */
if (_ma_mark_file_changed(info)) if (_ma_mark_file_changed(share))
goto err; goto err;
/* Ensure we don't change the autoincrement value */ /* Ensure we don't change the autoincrement value */
......
...@@ -52,8 +52,6 @@ int maria_delete_all_rows(MARIA_HA *info) ...@@ -52,8 +52,6 @@ int maria_delete_all_rows(MARIA_HA *info)
if (_ma_readinfo(info,F_WRLCK,1)) if (_ma_readinfo(info,F_WRLCK,1))
DBUG_RETURN(my_errno); DBUG_RETURN(my_errno);
log_record= share->now_transactional && !share->temporary; log_record= share->now_transactional && !share->temporary;
if (_ma_mark_file_changed(info))
goto err;
if (log_record) if (log_record)
{ {
...@@ -75,14 +73,19 @@ int maria_delete_all_rows(MARIA_HA *info) ...@@ -75,14 +73,19 @@ int maria_delete_all_rows(MARIA_HA *info)
If we fail in this function after this point, log and table will be If we fail in this function after this point, log and table will be
inconsistent. inconsistent.
*/ */
if (_ma_mark_file_changed(share))
goto err;
} }
else else
{ {
if (_ma_mark_file_changed(share))
goto err;
/* Other branch called function below when writing log record, in hook */ /* Other branch called function below when writing log record, in hook */
_ma_reset_status(info); _ma_reset_status(info);
} }
/* Remove old history as the table is now empty for everyone */ /* Remove old history as the table is now empty for everyone */
_ma_reset_state(info); _ma_reset_state(info);
share->state.changed= 0;
/* /*
If we are using delayed keys or if the user has done changes to the tables If we are using delayed keys or if the user has done changes to the tables
...@@ -180,6 +183,10 @@ void _ma_reset_status(MARIA_HA *info) ...@@ -180,6 +183,10 @@ void _ma_reset_status(MARIA_HA *info)
state->state.data_file_length= 0; state->state.data_file_length= 0;
state->state.empty= state->state.key_empty= 0; state->state.empty= state->state.key_empty= 0;
state->state.checksum= 0; state->state.checksum= 0;
share->state.open_count= 0;
share->global_changed= 0;
share->changed= 1; /* We must write state */
*info->state= state->state; *info->state= state->state;
......
...@@ -28,10 +28,6 @@ ...@@ -28,10 +28,6 @@
int maria_delete_table(const char *name) int maria_delete_table(const char *name)
{ {
char from[FN_REFLEN];
#ifdef USE_RAID
uint raid_type=0,raid_chunks=0;
#endif
MARIA_HA *info; MARIA_HA *info;
myf sync_dir; myf sync_dir;
DBUG_ENTER("maria_delete_table"); DBUG_ENTER("maria_delete_table");
...@@ -53,17 +49,10 @@ int maria_delete_table(const char *name) ...@@ -53,17 +49,10 @@ int maria_delete_table(const char *name)
*/ */
if (!(info= maria_open(name, O_RDONLY, HA_OPEN_FOR_REPAIR))) if (!(info= maria_open(name, O_RDONLY, HA_OPEN_FOR_REPAIR)))
{ {
#ifdef USE_RAID
raid_type= 0;
#endif
sync_dir= 0; sync_dir= 0;
} }
else else
{ {
#ifdef USE_RAID
raid_type= info->s->base.raid_type;
raid_chunks= info->s->base.raid_chunks;
#endif
sync_dir= (info->s->now_transactional && !info->s->temporary && sync_dir= (info->s->now_transactional && !info->s->temporary &&
!maria_in_recovery) ? !maria_in_recovery) ?
MY_SYNC_DIR : 0; MY_SYNC_DIR : 0;
...@@ -93,15 +82,19 @@ int maria_delete_table(const char *name) ...@@ -93,15 +82,19 @@ int maria_delete_table(const char *name)
DBUG_RETURN(1); DBUG_RETURN(1);
} }
DBUG_RETURN(maria_delete_table_files(name, sync_dir));
}
int maria_delete_table_files(const char *name, myf sync_dir)
{
char from[FN_REFLEN];
DBUG_ENTER("maria_delete_table_files");
fn_format(from,name,"",MARIA_NAME_IEXT,MY_UNPACK_FILENAME|MY_APPEND_EXT); fn_format(from,name,"",MARIA_NAME_IEXT,MY_UNPACK_FILENAME|MY_APPEND_EXT);
if (my_delete_with_symlink(from, MYF(MY_WME | sync_dir))) if (my_delete_with_symlink(from, MYF(MY_WME | sync_dir)))
DBUG_RETURN(my_errno); DBUG_RETURN(my_errno);
fn_format(from,name,"",MARIA_NAME_DEXT,MY_UNPACK_FILENAME|MY_APPEND_EXT); fn_format(from,name,"",MARIA_NAME_DEXT,MY_UNPACK_FILENAME|MY_APPEND_EXT);
#ifdef USE_RAID
if (raid_type)
DBUG_RETURN(my_raid_delete(from, raid_chunks, MYF(MY_WME | sync_dir)) ?
my_errno : 0);
#endif
DBUG_RETURN(my_delete_with_symlink(from, MYF(MY_WME | sync_dir)) ? DBUG_RETURN(my_delete_with_symlink(from, MYF(MY_WME | sync_dir)) ?
my_errno : 0); my_errno : 0);
} }
...@@ -254,8 +254,8 @@ int maria_extra(MARIA_HA *info, enum ha_extra_function function, ...@@ -254,8 +254,8 @@ int maria_extra(MARIA_HA *info, enum ha_extra_function function,
if (!share->changed) if (!share->changed)
{ {
share->state.changed|= STATE_CHANGED | STATE_NOT_ANALYZED;
share->changed= 1; /* Update on close */ share->changed= 1; /* Update on close */
share->state.changed|= STATE_CHANGED | STATE_NOT_ANALYZED;
if (!share->global_changed) if (!share->global_changed)
{ {
share->global_changed= 1; share->global_changed= 1;
...@@ -291,10 +291,9 @@ int maria_extra(MARIA_HA *info, enum ha_extra_function function, ...@@ -291,10 +291,9 @@ int maria_extra(MARIA_HA *info, enum ha_extra_function function,
if (!error && share->changed) if (!error && share->changed)
{ {
pthread_mutex_lock(&share->intern_lock); pthread_mutex_lock(&share->intern_lock);
if (!(error= _ma_state_info_write(share, error= _ma_state_info_write(share,
MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET| MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET|
MA_STATE_INFO_WRITE_FULL_INFO))) MA_STATE_INFO_WRITE_FULL_INFO);
share->changed= 0;
pthread_mutex_unlock(&share->intern_lock); pthread_mutex_unlock(&share->intern_lock);
} }
pthread_mutex_lock(&THR_LOCK_maria); pthread_mutex_lock(&THR_LOCK_maria);
...@@ -311,11 +310,14 @@ int maria_extra(MARIA_HA *info, enum ha_extra_function function, ...@@ -311,11 +310,14 @@ int maria_extra(MARIA_HA *info, enum ha_extra_function function,
share->deleting= TRUE; share->deleting= TRUE;
share->global_changed= FALSE; /* force writing changed flag */ share->global_changed= FALSE; /* force writing changed flag */
/* To force repair if reopened */ /* To force repair if reopened */
_ma_mark_file_changed(info); share->state.open_count= 1;
share->changed= 1;
_ma_mark_file_changed_now(share);
/* Fall trough */ /* Fall trough */
case HA_EXTRA_PREPARE_FOR_RENAME: case HA_EXTRA_PREPARE_FOR_RENAME:
{ {
my_bool do_flush= test(function != HA_EXTRA_PREPARE_FOR_DROP); my_bool do_flush= test(function != HA_EXTRA_PREPARE_FOR_DROP);
my_bool save_global_changed;
enum flush_type type; enum flush_type type;
pthread_mutex_lock(&THR_LOCK_maria); pthread_mutex_lock(&THR_LOCK_maria);
/* /*
...@@ -340,7 +342,7 @@ int maria_extra(MARIA_HA *info, enum ha_extra_function function, ...@@ -340,7 +342,7 @@ int maria_extra(MARIA_HA *info, enum ha_extra_function function,
*/ */
pthread_mutex_lock(&share->intern_lock); pthread_mutex_lock(&share->intern_lock);
if (share->kfile.file >= 0 && function != HA_EXTRA_PREPARE_FOR_DROP) if (share->kfile.file >= 0 && function != HA_EXTRA_PREPARE_FOR_DROP)
_ma_decrement_open_count(info); _ma_decrement_open_count(info, 0);
if (info->trn) if (info->trn)
{ {
_ma_remove_table_from_trnman(share, info->trn); _ma_remove_table_from_trnman(share, info->trn);
...@@ -349,12 +351,15 @@ int maria_extra(MARIA_HA *info, enum ha_extra_function function, ...@@ -349,12 +351,15 @@ int maria_extra(MARIA_HA *info, enum ha_extra_function function,
} }
type= do_flush ? FLUSH_RELEASE : FLUSH_IGNORE_CHANGED; type= do_flush ? FLUSH_RELEASE : FLUSH_IGNORE_CHANGED;
save_global_changed= share->global_changed;
share->global_changed= 1; /* Don't increment open count */
if (_ma_flush_table_files(info, MARIA_FLUSH_DATA | MARIA_FLUSH_INDEX, if (_ma_flush_table_files(info, MARIA_FLUSH_DATA | MARIA_FLUSH_INDEX,
type, type)) type, type))
{ {
error=my_errno; error=my_errno;
share->changed= 1; share->changed= 1;
} }
share->global_changed= save_global_changed;
if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED)) if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))
{ {
info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED); info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
...@@ -372,13 +377,13 @@ int maria_extra(MARIA_HA *info, enum ha_extra_function function, ...@@ -372,13 +377,13 @@ int maria_extra(MARIA_HA *info, enum ha_extra_function function,
MA_STATE_INFO_WRITE_FULL_INFO)) || MA_STATE_INFO_WRITE_FULL_INFO)) ||
my_sync(share->kfile.file, MYF(0))) my_sync(share->kfile.file, MYF(0)))
error= my_errno; error= my_errno;
else
share->changed= 0;
} }
else else
{ {
/* be sure that state is not tried for write as file may be closed */ /* be sure that state is not tried for write as file may be closed */
share->changed= 0; share->changed= 0;
share->global_changed= 0;
share->state.open_count= 0;
} }
} }
if (share->data_file_type == BLOCK_RECORD && if (share->data_file_type == BLOCK_RECORD &&
...@@ -410,8 +415,8 @@ int maria_extra(MARIA_HA *info, enum ha_extra_function function, ...@@ -410,8 +415,8 @@ int maria_extra(MARIA_HA *info, enum ha_extra_function function,
if (!share->temporary) if (!share->temporary)
error= _ma_flush_table_files(info, MARIA_FLUSH_DATA | MARIA_FLUSH_INDEX, error= _ma_flush_table_files(info, MARIA_FLUSH_DATA | MARIA_FLUSH_INDEX,
FLUSH_KEEP, FLUSH_KEEP); FLUSH_KEEP, FLUSH_KEEP);
#ifdef HAVE_PWRITE #ifdef HAVE_PREAD
_ma_decrement_open_count(info); _ma_decrement_open_count(info, 1);
#endif #endif
if (share->not_flushed) if (share->not_flushed)
{ {
...@@ -601,6 +606,8 @@ int _ma_flush_table_files(MARIA_HA *info, uint flush_data_or_index, ...@@ -601,6 +606,8 @@ int _ma_flush_table_files(MARIA_HA *info, uint flush_data_or_index,
{ {
int error= 0; int error= 0;
MARIA_SHARE *share= info->s; MARIA_SHARE *share= info->s;
DBUG_ENTER("_ma_flush_table_files");
/* flush data file first because it's more critical */ /* flush data file first because it's more critical */
if (flush_data_or_index & MARIA_FLUSH_DATA) if (flush_data_or_index & MARIA_FLUSH_DATA)
{ {
...@@ -632,8 +639,8 @@ int _ma_flush_table_files(MARIA_HA *info, uint flush_data_or_index, ...@@ -632,8 +639,8 @@ int _ma_flush_table_files(MARIA_HA *info, uint flush_data_or_index,
flush_type_for_index)) flush_type_for_index))
error= 1; error= 1;
if (!error) if (!error)
return 0; DBUG_RETURN(0);
_ma_set_fatal_error(info->s, HA_ERR_CRASHED); _ma_set_fatal_error(info->s, HA_ERR_CRASHED);
return 1; DBUG_RETURN(1);
} }
...@@ -386,12 +386,39 @@ int _ma_test_if_changed(register MARIA_HA *info) ...@@ -386,12 +386,39 @@ int _ma_test_if_changed(register MARIA_HA *info)
#define _MA_ALREADY_MARKED_FILE_CHANGED \ #define _MA_ALREADY_MARKED_FILE_CHANGED \
((share->state.changed & STATE_CHANGED) && share->global_changed) ((share->state.changed & STATE_CHANGED) && share->global_changed)
int _ma_mark_file_changed(MARIA_HA *info) int _ma_mark_file_changed(register MARIA_SHARE *share)
{
if (!share->base.born_transactional)
{
if (!_MA_ALREADY_MARKED_FILE_CHANGED)
return _ma_mark_file_changed_now(share);
}
else
{
/*
For transactional tables, the table is marked changed when the first page
is written. Here we just mark the state to be updated so that caller
can do 'anaylze table' and find that is has changed before any pages
are written.
*/
if (! test_all_bits(share->state.changed,
(STATE_CHANGED | STATE_NOT_ANALYZED |
STATE_NOT_OPTIMIZED_KEYS)))
{
pthread_mutex_lock(&share->intern_lock);
share->state.changed|=(STATE_CHANGED | STATE_NOT_ANALYZED |
STATE_NOT_OPTIMIZED_KEYS);
pthread_mutex_unlock(&share->intern_lock);
}
}
return 0;
}
int _ma_mark_file_changed_now(register MARIA_SHARE *share)
{ {
uchar buff[3]; uchar buff[3];
register MARIA_SHARE *share= info->s;
int error= 1; int error= 1;
DBUG_ENTER("_ma_mark_file_changed"); DBUG_ENTER("_ma_mark_file_changed_now");
if (_MA_ALREADY_MARKED_FILE_CHANGED) if (_MA_ALREADY_MARKED_FILE_CHANGED)
DBUG_RETURN(0); DBUG_RETURN(0);
...@@ -402,7 +429,7 @@ int _ma_mark_file_changed(MARIA_HA *info) ...@@ -402,7 +429,7 @@ int _ma_mark_file_changed(MARIA_HA *info)
STATE_NOT_OPTIMIZED_KEYS); STATE_NOT_OPTIMIZED_KEYS);
if (!share->global_changed) if (!share->global_changed)
{ {
share->global_changed=1; share->changed= share->global_changed= 1;
share->state.open_count++; share->state.open_count++;
} }
/* /*
...@@ -430,7 +457,7 @@ int _ma_mark_file_changed(MARIA_HA *info) ...@@ -430,7 +457,7 @@ int _ma_mark_file_changed(MARIA_HA *info)
!(share->state.changed & STATE_NOT_MOVABLE)) !(share->state.changed & STATE_NOT_MOVABLE))
{ {
/* Lock table to current installation */ /* Lock table to current installation */
if (_ma_set_uuid(info, 0) || if (_ma_set_uuid(share, 0) ||
(share->state.create_rename_lsn == LSN_NEEDS_NEW_STATE_LSNS && (share->state.create_rename_lsn == LSN_NEEDS_NEW_STATE_LSNS &&
_ma_update_state_lsns_sub(share, LSN_IMPOSSIBLE, _ma_update_state_lsns_sub(share, LSN_IMPOSSIBLE,
trnman_get_min_trid(), trnman_get_min_trid(),
...@@ -472,22 +499,31 @@ my_bool _ma_check_if_zero(uchar *pos, size_t length) ...@@ -472,22 +499,31 @@ my_bool _ma_check_if_zero(uchar *pos, size_t length)
call. In these context the following code should be safe! call. In these context the following code should be safe!
*/ */
int _ma_decrement_open_count(MARIA_HA *info) int _ma_decrement_open_count(MARIA_HA *info, my_bool lock_tables)
{ {
uchar buff[2]; uchar buff[2];
register MARIA_SHARE *share= info->s; register MARIA_SHARE *share= info->s;
int lock_error=0,write_error=0; int lock_error=0,write_error=0;
DBUG_ENTER("_ma_decrement_open_count");
if (share->global_changed) if (share->global_changed)
{ {
uint old_lock=info->lock_type; uint old_lock=info->lock_type;
share->global_changed=0; share->global_changed=0;
lock_error= my_disable_locking ? 0 : maria_lock_database(info, F_WRLCK); lock_error= (my_disable_locking || ! lock_tables ? 0 :
maria_lock_database(info, F_WRLCK));
/* Its not fatal even if we couldn't get the lock ! */ /* Its not fatal even if we couldn't get the lock ! */
if (share->state.open_count > 0) if (share->state.open_count > 0)
{ {
share->state.open_count--; share->state.open_count--;
share->changed= 1; /* We have to update state */ share->changed= 1; /* We have to update state */
if (!share->temporary) /*
For temporary tables that will just be deleted, we don't have
to decrement state. For transactional tables the state will be
updated in maria_close().
*/
if (!share->temporary && !share->now_transactional)
{ {
mi_int2store(buff,share->state.open_count); mi_int2store(buff,share->state.open_count);
write_error= (int) my_pwrite(share->kfile.file, buff, sizeof(buff), write_error= (int) my_pwrite(share->kfile.file, buff, sizeof(buff),
...@@ -496,10 +532,10 @@ int _ma_decrement_open_count(MARIA_HA *info) ...@@ -496,10 +532,10 @@ int _ma_decrement_open_count(MARIA_HA *info)
MYF(MY_NABP)); MYF(MY_NABP));
} }
} }
if (!lock_error && !my_disable_locking) if (!lock_error && !my_disable_locking && lock_tables)
lock_error=maria_lock_database(info,old_lock); lock_error=maria_lock_database(info,old_lock);
} }
return test(lock_error || write_error); DBUG_RETURN(test(lock_error || write_error));
} }
...@@ -552,12 +588,12 @@ void _ma_set_fatal_error(MARIA_SHARE *share, int error) ...@@ -552,12 +588,12 @@ void _ma_set_fatal_error(MARIA_SHARE *share, int error)
@brief Set uuid of for a Maria file @brief Set uuid of for a Maria file
@fn _ma_set_uuid() @fn _ma_set_uuid()
@param info Maria handler @param share Maria share
@param reset_uuid Instead of setting file to maria_uuid, set it to @param reset_uuid Instead of setting file to maria_uuid, set it to
0 to mark it as movable 0 to mark it as movable
*/ */
my_bool _ma_set_uuid(MARIA_HA *info, my_bool reset_uuid) my_bool _ma_set_uuid(MARIA_SHARE *share, my_bool reset_uuid)
{ {
uchar buff[MY_UUID_SIZE], *uuid; uchar buff[MY_UUID_SIZE], *uuid;
...@@ -567,7 +603,7 @@ my_bool _ma_set_uuid(MARIA_HA *info, my_bool reset_uuid) ...@@ -567,7 +603,7 @@ my_bool _ma_set_uuid(MARIA_HA *info, my_bool reset_uuid)
bzero(buff, sizeof(buff)); bzero(buff, sizeof(buff));
uuid= buff; uuid= buff;
} }
return (my_bool) my_pwrite(info->s->kfile.file, uuid, MY_UUID_SIZE, return (my_bool) my_pwrite(share->kfile.file, uuid, MY_UUID_SIZE,
mi_uint2korr(info->s->state.header.base_pos), mi_uint2korr(share->state.header.base_pos),
MYF(MY_NABP)); MYF(MY_NABP));
} }
...@@ -429,6 +429,8 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags) ...@@ -429,6 +429,8 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags)
HA_ERR_CRASHED_ON_REPAIR : HA_ERR_CRASHED_ON_USAGE); HA_ERR_CRASHED_ON_REPAIR : HA_ERR_CRASHED_ON_USAGE);
goto err; goto err;
} }
if (share->state.open_count)
share->open_count_not_zero_on_open= 1;
/* /*
We can ignore testing uuid if STATE_NOT_MOVABLE is set, as in this We can ignore testing uuid if STATE_NOT_MOVABLE is set, as in this
...@@ -790,7 +792,8 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags) ...@@ -790,7 +792,8 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags)
share->options|= HA_OPTION_READ_ONLY_DATA; share->options|= HA_OPTION_READ_ONLY_DATA;
share->is_log_table= FALSE; share->is_log_table= FALSE;
if (open_flags & HA_OPEN_TMP_TABLE) if (open_flags & HA_OPEN_TMP_TABLE ||
(share->options & HA_OPTION_TMP_TABLE))
{ {
share->options|= HA_OPTION_TMP_TABLE; share->options|= HA_OPTION_TMP_TABLE;
share->temporary= share->delay_key_write= 1; share->temporary= share->delay_key_write= 1;
...@@ -913,6 +916,19 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags) ...@@ -913,6 +916,19 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags)
share->lock.start_trans= _ma_block_start_trans_no_versioning; share->lock.start_trans= _ma_block_start_trans_no_versioning;
} }
} }
#endif
#ifdef SAFE_MUTEX
if (share->data_file_type == BLOCK_RECORD)
{
/*
We must have internal_lock before bitmap_lock because we call
_ma_flush_tables_files() with internal_lock locked.
*/
pthread_mutex_lock(&share->intern_lock);
pthread_mutex_lock(&share->bitmap.bitmap_lock);
pthread_mutex_unlock(&share->bitmap.bitmap_lock);
pthread_mutex_unlock(&share->intern_lock);
}
#endif #endif
/* /*
Memory mapping can only be requested after initializing intern_lock. Memory mapping can only be requested after initializing intern_lock.
...@@ -1251,7 +1267,8 @@ uint _ma_state_info_write(MARIA_SHARE *share, uint pWrite) ...@@ -1251,7 +1267,8 @@ uint _ma_state_info_write(MARIA_SHARE *share, uint pWrite)
res= _ma_state_info_write_sub(share->kfile.file, &share->state, pWrite); res= _ma_state_info_write_sub(share->kfile.file, &share->state, pWrite);
if (pWrite & MA_STATE_INFO_WRITE_LOCK) if (pWrite & MA_STATE_INFO_WRITE_LOCK)
pthread_mutex_unlock(&share->intern_lock); pthread_mutex_unlock(&share->intern_lock);
share->changed= 0; /* If open_count != 0 we have to write the state again at close */
share->changed= share->state.open_count != 0;
return res; return res;
} }
......
...@@ -1380,6 +1380,8 @@ static void link_block(PAGECACHE *pagecache, PAGECACHE_BLOCK_LINK *block, ...@@ -1380,6 +1380,8 @@ static void link_block(PAGECACHE *pagecache, PAGECACHE_BLOCK_LINK *block,
else else
{ {
/* The LRU chain is empty */ /* The LRU chain is empty */
/* QQ: Ask sanja if next line is correct; Should we really put block
in both chain if one chain is empty ? */
pagecache->used_last= pagecache->used_ins= block->next_used= block; pagecache->used_last= pagecache->used_ins= block->next_used= block;
block->prev_used= &block->next_used; block->prev_used= &block->next_used;
} }
...@@ -1803,6 +1805,7 @@ static PAGECACHE_HASH_LINK *get_hash_link(PAGECACHE *pagecache, ...@@ -1803,6 +1805,7 @@ static PAGECACHE_HASH_LINK *get_hash_link(PAGECACHE *pagecache,
link_hash(start, hash_link); link_hash(start, hash_link);
/* Register the request for the page */ /* Register the request for the page */
hash_link->requests++; hash_link->requests++;
DBUG_ASSERT(hash_link->block == 0);
} }
return hash_link; return hash_link;
...@@ -1824,7 +1827,10 @@ static PAGECACHE_HASH_LINK *get_hash_link(PAGECACHE *pagecache, ...@@ -1824,7 +1827,10 @@ static PAGECACHE_HASH_LINK *get_hash_link(PAGECACHE *pagecache,
wrmode <-> get for writing wrmode <-> get for writing
block_is_copied 1 if block will be copied from page cache under block_is_copied 1 if block will be copied from page cache under
the pagelock mutex. the pagelock mutex.
reg_req Register request to the page reg_req Register request to the page. Normally all pages
should be registered; The only time it's ok to
not register a page is when the page is already
pinned (and thus registered) by the same thread.
page_st out {PAGE_READ,PAGE_TO_BE_READ,PAGE_WAIT_TO_BE_READ} page_st out {PAGE_READ,PAGE_TO_BE_READ,PAGE_WAIT_TO_BE_READ}
RETURN VALUE RETURN VALUE
...@@ -2028,6 +2034,7 @@ static PAGECACHE_BLOCK_LINK *find_block(PAGECACHE *pagecache, ...@@ -2028,6 +2034,7 @@ static PAGECACHE_BLOCK_LINK *find_block(PAGECACHE *pagecache,
#ifndef DBUG_OFF #ifndef DBUG_OFF
block->type= PAGECACHE_EMPTY_PAGE; block->type= PAGECACHE_EMPTY_PAGE;
#endif #endif
DBUG_ASSERT(reg_req);
block->requests= 1; block->requests= 1;
block->temperature= PCBLOCK_COLD; block->temperature= PCBLOCK_COLD;
block->hits_left= init_hits_left; block->hits_left= init_hits_left;
...@@ -2068,12 +2075,17 @@ static PAGECACHE_BLOCK_LINK *find_block(PAGECACHE *pagecache, ...@@ -2068,12 +2075,17 @@ static PAGECACHE_BLOCK_LINK *find_block(PAGECACHE *pagecache,
} }
while (thread->next); while (thread->next);
thread->opt_info= NULL; thread->opt_info= NULL;
block= hash_link->block;
/*
Ensure that we are register this block (all blocks not used by this
thread has to be registered).
*/
DBUG_ASSERT(reg_req);
} }
else
#else #else
KEYCACHE_DBUG_ASSERT(pagecache->used_last); KEYCACHE_DBUG_ASSERT(pagecache->used_last);
#endif #endif
block= hash_link->block;
if (! block)
{ {
/* /*
Take the first block from the LRU chain Take the first block from the LRU chain
...@@ -3455,7 +3467,10 @@ uchar *pagecache_read(PAGECACHE *pagecache, ...@@ -3455,7 +3467,10 @@ uchar *pagecache_read(PAGECACHE *pagecache,
if (make_lock_and_pin(pagecache, block, if (make_lock_and_pin(pagecache, block,
lock_to_read[lock].unlock_lock, lock_to_read[lock].unlock_lock,
unlock_pin, FALSE)) unlock_pin, FALSE))
{
DBUG_ASSERT(0); DBUG_ASSERT(0);
return (uchar*) 0;
}
} }
/* /*
Link the block into the LRU chain if it's the last submitted request Link the block into the LRU chain if it's the last submitted request
...@@ -3959,7 +3974,10 @@ my_bool pagecache_write_part(PAGECACHE *pagecache, ...@@ -3959,7 +3974,10 @@ my_bool pagecache_write_part(PAGECACHE *pagecache,
inc_counter_for_resize_op(pagecache); inc_counter_for_resize_op(pagecache);
pagecache->global_cache_w_requests++; pagecache->global_cache_w_requests++;
/* See NOTE for pagecache_unlock about registering requests. */ /*
Here we register a request if the page was not already pinned.
See NOTE for pagecache_unlock about registering requests.
*/
reg_request= ((pin == PAGECACHE_PIN_LEFT_UNPINNED) || reg_request= ((pin == PAGECACHE_PIN_LEFT_UNPINNED) ||
(pin == PAGECACHE_PIN)); (pin == PAGECACHE_PIN));
block= find_block(pagecache, file, pageno, level, block= find_block(pagecache, file, pageno, level,
...@@ -4108,7 +4126,10 @@ my_bool pagecache_write_part(PAGECACHE *pagecache, ...@@ -4108,7 +4126,10 @@ my_bool pagecache_write_part(PAGECACHE *pagecache,
block->hash_link->requests--; block->hash_link->requests--;
/* See NOTE for pagecache_unlock about registering requests. */ /* See NOTE for pagecache_unlock about registering requests. */
if (pin == PAGECACHE_PIN_LEFT_UNPINNED || pin == PAGECACHE_UNPIN) if (pin == PAGECACHE_PIN_LEFT_UNPINNED || pin == PAGECACHE_UNPIN)
{
unreg_request(pagecache, block, 1); unreg_request(pagecache, block, 1);
DBUG_ASSERT(page_link == &fake_link);
}
else else
*page_link= block; *page_link= block;
......
...@@ -355,9 +355,7 @@ my_bool maria_flush_log_for_page(uchar *page, ...@@ -355,9 +355,7 @@ my_bool maria_flush_log_for_page(uchar *page,
uchar *data_ptr __attribute__((unused))) uchar *data_ptr __attribute__((unused)))
{ {
LSN lsn; LSN lsn;
#ifndef DBUG_OFF MARIA_SHARE *share= (MARIA_SHARE*) data_ptr;
const MARIA_SHARE *share= (MARIA_SHARE*) data_ptr;
#endif
DBUG_ENTER("maria_flush_log_for_page"); DBUG_ENTER("maria_flush_log_for_page");
/* share is 0 here only in unittest */ /* share is 0 here only in unittest */
DBUG_ASSERT(!share || (share->page_type == PAGECACHE_LSN_PAGE && DBUG_ASSERT(!share || (share->page_type == PAGECACHE_LSN_PAGE &&
...@@ -365,6 +363,12 @@ my_bool maria_flush_log_for_page(uchar *page, ...@@ -365,6 +363,12 @@ my_bool maria_flush_log_for_page(uchar *page,
lsn= lsn_korr(page); lsn= lsn_korr(page);
if (translog_flush(lsn)) if (translog_flush(lsn))
DBUG_RETURN(1); DBUG_RETURN(1);
/*
Now when log is written, it's safe to incremented 'open' counter for
the table so that we know it was not closed properly.
*/
if (share && !share->global_changed)
_ma_mark_file_changed_now(share);
DBUG_RETURN(0); DBUG_RETURN(0);
} }
......
...@@ -1306,6 +1306,7 @@ prototype_redo_exec_hook(FILE_ID) ...@@ -1306,6 +1306,7 @@ prototype_redo_exec_hook(FILE_ID)
/* let ma_close() mark the table properly closed */ /* let ma_close() mark the table properly closed */
info->s->state.open_count= 1; info->s->state.open_count= 1;
info->s->global_changed= 1; info->s->global_changed= 1;
info->s->changed= 1;
} }
if (maria_close(info)) if (maria_close(info))
{ {
...@@ -3430,6 +3431,7 @@ static int close_all_tables(void) ...@@ -3430,6 +3431,7 @@ static int close_all_tables(void)
/* let maria_close() mark the table properly closed */ /* let maria_close() mark the table properly closed */
info->s->state.open_count= 1; info->s->state.open_count= 1;
info->s->global_changed= 1; info->s->global_changed= 1;
info->s->changed= 1;
} }
prepare_table_for_close(info, addr); prepare_table_for_close(info, addr);
error|= maria_close(info); error|= maria_close(info);
......
...@@ -74,7 +74,8 @@ int maria_update(register MARIA_HA *info, const uchar *oldrec, uchar *newrec) ...@@ -74,7 +74,8 @@ int maria_update(register MARIA_HA *info, const uchar *oldrec, uchar *newrec)
goto err_end; goto err_end;
} }
} }
if (_ma_mark_file_changed(info))
if (_ma_mark_file_changed(share))
{ {
save_errno=my_errno; save_errno=my_errno;
goto err_end; goto err_end;
......
...@@ -120,7 +120,7 @@ int maria_write(MARIA_HA *info, uchar *record) ...@@ -120,7 +120,7 @@ int maria_write(MARIA_HA *info, uchar *record)
my_errno=HA_ERR_INDEX_FILE_FULL; my_errno=HA_ERR_INDEX_FILE_FULL;
goto err2; goto err2;
} }
if (_ma_mark_file_changed(info)) if (_ma_mark_file_changed(share))
goto err2; goto err2;
/* Calculate and check all unique constraints */ /* Calculate and check all unique constraints */
......
...@@ -41,7 +41,8 @@ static const char *set_collation_name, *opt_tmpdir, *opt_log_dir; ...@@ -41,7 +41,8 @@ static const char *set_collation_name, *opt_tmpdir, *opt_log_dir;
static CHARSET_INFO *set_collation; static CHARSET_INFO *set_collation;
static int stopwords_inited= 0; static int stopwords_inited= 0;
static MY_TMPDIR maria_chk_tmpdir; static MY_TMPDIR maria_chk_tmpdir;
static my_bool opt_transaction_logging, opt_debug, opt_require_control_file; static my_bool opt_transaction_logging, opt_debug;
static my_bool opt_ignore_control_file, opt_require_control_file;
static my_bool opt_warning_for_wrong_transid, opt_update_state; static my_bool opt_warning_for_wrong_transid, opt_update_state;
static const char *type_names[]= static const char *type_names[]=
...@@ -115,10 +116,11 @@ int main(int argc, char **argv) ...@@ -115,10 +116,11 @@ int main(int argc, char **argv)
maria_init(); maria_init();
maria_block_size= 0; /* Use block size from control file */ maria_block_size= 0; /* Use block size from control file */
if (ma_control_file_open(FALSE, opt_require_control_file || if (!opt_ignore_control_file &&
!(check_param.testflag & T_SILENT)) && (ma_control_file_open(FALSE, opt_require_control_file ||
(opt_require_control_file || !(check_param.testflag & T_SILENT)) &&
(opt_transaction_logging && (check_param.testflag & T_REP_ANY)))) (opt_require_control_file ||
(opt_transaction_logging && (check_param.testflag & T_REP_ANY)))))
{ {
error= 1; error= 1;
goto end; goto end;
...@@ -203,7 +205,8 @@ enum options_mc { ...@@ -203,7 +205,8 @@ enum options_mc {
OPT_SORT_KEY_BLOCKS, OPT_DECODE_BITS, OPT_FT_MIN_WORD_LEN, OPT_SORT_KEY_BLOCKS, OPT_DECODE_BITS, OPT_FT_MIN_WORD_LEN,
OPT_FT_MAX_WORD_LEN, OPT_FT_STOPWORD_FILE, OPT_FT_MAX_WORD_LEN, OPT_FT_STOPWORD_FILE,
OPT_MAX_RECORD_LENGTH, OPT_AUTO_CLOSE, OPT_STATS_METHOD, OPT_TRANSACTION_LOG, OPT_MAX_RECORD_LENGTH, OPT_AUTO_CLOSE, OPT_STATS_METHOD, OPT_TRANSACTION_LOG,
OPT_SKIP_SAFEMALLOC, OPT_ZEROFILL_KEEP_LSN, OPT_REQUIRE_CONTROL_FILE, OPT_SKIP_SAFEMALLOC, OPT_ZEROFILL_KEEP_LSN,
OPT_REQUIRE_CONTROL_FILE, OPT_IGNORE_CONTROL_FILE,
OPT_LOG_DIR, OPT_DATADIR, OPT_WARNING_FOR_WRONG_TRANSID OPT_LOG_DIR, OPT_DATADIR, OPT_WARNING_FOR_WRONG_TRANSID
}; };
...@@ -265,6 +268,10 @@ static struct my_option my_long_options[] = ...@@ -265,6 +268,10 @@ static struct my_option my_long_options[] =
{"information", 'i', {"information", 'i',
"Print statistics information about table that is checked.", "Print statistics information about table that is checked.",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{ "ignore-control-file", OPT_IGNORE_CONTROL_FILE,
"Ignore the control file",
(uchar**)&opt_ignore_control_file, 0, 0, GET_BOOL, NO_ARG,
0, 0, 0, 0, 0, 0},
{"keys-used", 'k', {"keys-used", 'k',
"Tell MARIA to update only some specific keys. # is a bit mask of which keys to use. This can be used to get faster inserts.", "Tell MARIA to update only some specific keys. # is a bit mask of which keys to use. This can be used to get faster inserts.",
&check_param.keys_in_use, &check_param.keys_in_use,
...@@ -452,6 +459,9 @@ static void usage(void) ...@@ -452,6 +459,9 @@ static void usage(void)
-?, --help Display this help and exit.\n\ -?, --help Display this help and exit.\n\
--datadir=path Path for control file (and logs if --logdir not used)\n\ --datadir=path Path for control file (and logs if --logdir not used)\n\
--logdir=path Path for log files\n\ --logdir=path Path for log files\n\
--ignore-control-file Don't open the control file. Only use this if you\n\
are sure the tables are not in use by another\n\
program!\n\
--require-control-file Abort if we can't find/read the maria_log_control\n\ --require-control-file Abort if we can't find/read the maria_log_control\n\
file\n\ file\n\
-s, --silent Only print errors. One can use two -s to make\n\ -s, --silent Only print errors. One can use two -s to make\n\
...@@ -493,7 +503,7 @@ static void usage(void) ...@@ -493,7 +503,7 @@ static void usage(void)
rid of warnings like 'table not properly closed'. If\n\ rid of warnings like 'table not properly closed'. If\n\
table was updated, update also the timestamp for when\n\ table was updated, update also the timestamp for when\n\
the check was made. This option is on by default!\n\ the check was made. This option is on by default!\n\
use --skip-update-state to disable.\n\ Use --skip-update-state to disable.\n\
--warning-for-wrong-transaction-id\n\ --warning-for-wrong-transaction-id\n\
Give a warning if we find a transaction id in the table that is bigger\n\ Give a warning if we find a transaction id in the table that is bigger\n\
than what exists in the control file. Use --skip-... to disable warning\n\ than what exists in the control file. Use --skip-... to disable warning\n\
......
...@@ -380,6 +380,11 @@ typedef struct st_maria_share ...@@ -380,6 +380,11 @@ typedef struct st_maria_share
my_bool temporary; my_bool temporary;
/* Below flag is needed to make log tables work with concurrent insert */ /* Below flag is needed to make log tables work with concurrent insert */
my_bool is_log_table; my_bool is_log_table;
/*
Set to 1 if open_count was wrong at open. Set to avoid asserts for
wrong open count on close.
*/
my_bool open_count_not_zero_on_open;
my_bool changed, /* If changed since lock */ my_bool changed, /* If changed since lock */
global_changed, /* If changed since open */ global_changed, /* If changed since open */
...@@ -921,12 +926,13 @@ extern my_bool _ma_ck_real_delete(register MARIA_HA *info, MARIA_KEY *key, ...@@ -921,12 +926,13 @@ extern my_bool _ma_ck_real_delete(register MARIA_HA *info, MARIA_KEY *key,
extern int _ma_readinfo(MARIA_HA *info, int lock_flag, int check_keybuffer); extern int _ma_readinfo(MARIA_HA *info, int lock_flag, int check_keybuffer);
extern int _ma_writeinfo(MARIA_HA *info, uint options); extern int _ma_writeinfo(MARIA_HA *info, uint options);
extern int _ma_test_if_changed(MARIA_HA *info); extern int _ma_test_if_changed(MARIA_HA *info);
extern int _ma_mark_file_changed(MARIA_HA *info); extern int _ma_mark_file_changed(MARIA_SHARE *info);
extern int _ma_mark_file_changed_now(MARIA_SHARE *info);
extern void _ma_mark_file_crashed(MARIA_SHARE *share); extern void _ma_mark_file_crashed(MARIA_SHARE *share);
void _ma_set_fatal_error(MARIA_SHARE *share, int error); void _ma_set_fatal_error(MARIA_SHARE *share, int error);
extern my_bool _ma_set_uuid(MARIA_HA *info, my_bool reset_uuid); extern my_bool _ma_set_uuid(MARIA_SHARE *info, my_bool reset_uuid);
extern my_bool _ma_check_if_zero(uchar *pos, size_t size); extern my_bool _ma_check_if_zero(uchar *pos, size_t size);
extern int _ma_decrement_open_count(MARIA_HA *info); extern int _ma_decrement_open_count(MARIA_HA *info, my_bool lock_table);
extern int _ma_check_index(MARIA_HA *info, int inx); extern int _ma_check_index(MARIA_HA *info, int inx);
extern int _ma_search(MARIA_HA *info, MARIA_KEY *key, uint32 nextflag, extern int _ma_search(MARIA_HA *info, MARIA_KEY *key, uint32 nextflag,
my_off_t pos); my_off_t pos);
...@@ -1181,6 +1187,7 @@ void _ma_remap_file(MARIA_HA *info, my_off_t size); ...@@ -1181,6 +1187,7 @@ void _ma_remap_file(MARIA_HA *info, my_off_t size);
MARIA_RECORD_POS _ma_write_init_default(MARIA_HA *info, const uchar *record); MARIA_RECORD_POS _ma_write_init_default(MARIA_HA *info, const uchar *record);
my_bool _ma_write_abort_default(MARIA_HA *info); my_bool _ma_write_abort_default(MARIA_HA *info);
int maria_delete_table_files(const char *name, myf sync_dir);
C_MODE_START C_MODE_START
#define MARIA_FLUSH_DATA 1 #define MARIA_FLUSH_DATA 1
......
...@@ -1471,7 +1471,7 @@ int ha_myisam::enable_indexes(uint mode) ...@@ -1471,7 +1471,7 @@ int ha_myisam::enable_indexes(uint mode)
} }
else if (mode == HA_KEY_SWITCH_NONUNIQ_SAVE) else if (mode == HA_KEY_SWITCH_NONUNIQ_SAVE)
{ {
THD *thd=current_thd; THD *thd= table->in_use;
HA_CHECK &param= *(HA_CHECK*) thd->alloc(sizeof(param)); HA_CHECK &param= *(HA_CHECK*) thd->alloc(sizeof(param));
const char *save_proc_info=thd->proc_info; const char *save_proc_info=thd->proc_info;
......
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