diff options
author | kostja@bodhi.(none) <> | 2007-07-27 16:37:29 +0400 |
---|---|---|
committer | kostja@bodhi.(none) <> | 2007-07-27 16:37:29 +0400 |
commit | 11c57540f73aa42099c3036498644bb41def1dbd (patch) | |
tree | 222b968f3296750c8756393cb2779dcfb1da2784 /sql/handler.h | |
parent | 9f8593e81c99425a028d416854a172543a6f706d (diff) | |
download | mariadb-git-11c57540f73aa42099c3036498644bb41def1dbd.tar.gz |
A fix and a test case for Bug#24918 drop table and lock / inconsistent
between perm and temp tables. Review fixes.
The original bug report complains that if we locked a temporary table
with LOCK TABLES statement, we would not leave LOCK TABLES mode
when this temporary table is dropped.
Additionally, the bug was escalated when it was discovered than
when a temporary transactional table that was previously
locked with LOCK TABLES statement was dropped, futher actions with
this table, such as UNLOCK TABLES, would lead to a crash.
The problem originates from incomplete support of transactional temporary
tables. When we added calls to handler::store_lock()/handler::external_lock()
to operations that work with such tables, we only covered the normal
server code flow and did not cover LOCK TABLES mode.
In LOCK TABLES mode, ::external_lock(LOCK) would sometimes be called without
matching ::external_lock(UNLOCK), e.g. when a transactional temporary table
was dropped. Additionally, this table would be left in the list of LOCKed
TABLES.
The patch aims to address this inadequacy. Now, whenever an instance
of 'handler' is destroyed, we assert that it was priorly
external_lock(UNLOCK)-ed. All the places that violate this assert
were fixed.
This patch introduces no changes in behavior -- the discrepancy in
behavior will be fixed when we start calling ::store_lock()/::external_lock()
for all tables, regardless whether they are transactional or not,
temporary or not.
Diffstat (limited to 'sql/handler.h')
-rw-r--r-- | sql/handler.h | 40 |
1 files changed, 37 insertions, 3 deletions
diff --git a/sql/handler.h b/sql/handler.h index a3767573178..cd9f9a91008 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -508,6 +508,29 @@ class handler :public Sql_alloc */ virtual int rnd_init(bool scan) =0; virtual int rnd_end() { return 0; } + /** + Is not invoked for non-transactional temporary tables. + + Tells the storage engine that we intend to read or write data + from the table. This call is prefixed with a call to handler::store_lock() + and is invoked only for those handler instances that stored the lock. + + Calls to rnd_init/index_init are prefixed with this call. When table + IO is complete, we call external_lock(F_UNLCK). + A storage engine writer should expect that each call to + ::external_lock(F_[RD|WR]LOCK is followed by a call to + ::external_lock(F_UNLCK). If it is not, it is a bug in MySQL. + + The name and signature originate from the first implementation + in MyISAM, which would call fcntl to set/clear an advisory + lock on the data file in this method. + + @param lock_type F_RDLCK, F_WRLCK, F_UNLCK + + @return non-0 in case of failure, 0 in case of success. + When lock_type is F_UNLCK, the return value is ignored. + */ + virtual int external_lock(THD *thd, int lock_type) { return 0; } public: const handlerton *ht; /* storage engine of this handler */ @@ -548,6 +571,7 @@ public: uint raid_type,raid_chunks; FT_INFO *ft_handler; enum {NONE=0, INDEX, RND} inited; + bool locked; bool auto_increment_column_changed; bool implicit_emptied; /* Can be !=0 only if HEAP */ const COND *pushed_cond; @@ -560,10 +584,11 @@ public: create_time(0), check_time(0), update_time(0), key_used_on_scan(MAX_KEY), active_index(MAX_KEY), ref_length(sizeof(my_off_t)), block_size(0), - raid_type(0), ft_handler(0), inited(NONE), implicit_emptied(0), + raid_type(0), ft_handler(0), inited(NONE), + locked(FALSE), implicit_emptied(0), pushed_cond(NULL) {} - virtual ~handler(void) { /* TODO: DBUG_ASSERT(inited == NONE); */ } + virtual ~handler(void) { DBUG_ASSERT(locked == FALSE); /* TODO: DBUG_ASSERT(inited == NONE); */ } virtual handler *clone(MEM_ROOT *mem_root); int ha_open(const char *name, int mode, int test_if_locked); void adjust_next_insert_id_after_explicit_value(ulonglong nr); @@ -597,6 +622,13 @@ public: virtual const char *index_type(uint key_number) { DBUG_ASSERT(0); return "";} + int ha_external_lock(THD *thd, int lock_type) + { + int rc; + DBUG_ENTER("ha_external_lock"); + locked= lock_type != F_UNLCK; + DBUG_RETURN(external_lock(thd, lock_type)); + } int ha_index_init(uint idx) { DBUG_ENTER("ha_index_init"); @@ -689,7 +721,6 @@ public: virtual int extra_opt(enum ha_extra_function operation, ulong cache_size) { return extra(operation); } virtual int reset() { return extra(HA_EXTRA_RESET); } - virtual int external_lock(THD *thd, int lock_type) { return 0; } virtual void unlock_row() {} virtual int start_stmt(THD *thd, thr_lock_type lock_type) {return 0;} /* @@ -837,6 +868,9 @@ public: /* lock_count() can be more than one if the table is a MERGE */ virtual uint lock_count(void) const { return 1; } + /** + Is not invoked for non-transactional temporary tables. + */ virtual THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, enum thr_lock_type lock_type)=0; |