void safe_hash_change(SAFE_HASH *hash, uchar *old_data, uchar *new_data) { SAFE_HASH_ENTRY *entry, *next; DBUG_ENTER("safe_hash_change"); mysql_rwlock_wrlock(&hash->mutex); for (entry= hash->root ; entry ; entry= next) { next= entry->next; if (entry->data == old_data) { if (new_data == hash->default_value) { if ((*entry->prev= entry->next)) entry->next->prev= entry->prev; my_hash_delete(&hash->hash, (uchar*) entry); } else entry->data= new_data; } } mysql_rwlock_unlock(&hash->mutex); DBUG_VOID_RETURN; }
int mi_lock_database(MI_INFO *info, int lock_type) { int error; uint count; MYISAM_SHARE *share=info->s; DBUG_ENTER("mi_lock_database"); DBUG_PRINT("enter",("lock_type: %d old lock %d r_locks: %u w_locks: %u " "global_changed: %d open_count: %u name: '%s'", lock_type, info->lock_type, share->r_locks, share->w_locks, share->global_changed, share->state.open_count, share->index_file_name)); if (share->options & HA_OPTION_READ_ONLY_DATA || info->lock_type == lock_type) DBUG_RETURN(0); if (lock_type == F_EXTRA_LCK) /* Used by TMP tables */ { ++share->w_locks; ++share->tot_locks; info->lock_type= lock_type; info->s->in_use= list_add(info->s->in_use, &info->in_use); DBUG_RETURN(0); } error= 0; mysql_mutex_lock(&share->intern_lock); if (share->kfile >= 0) /* May only be false on windows */ { switch (lock_type) { case F_UNLCK: ftparser_call_deinitializer(info); if (info->lock_type == F_RDLCK) count= --share->r_locks; else count= --share->w_locks; --share->tot_locks; if (info->lock_type == F_WRLCK && !share->w_locks && !share->delay_key_write && flush_key_blocks(share->key_cache, keycache_thread_var(), share->kfile,FLUSH_KEEP)) { error=my_errno(); mi_print_error(info->s, HA_ERR_CRASHED); mi_mark_crashed(info); /* Mark that table must be checked */ } if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED)) { if (end_io_cache(&info->rec_cache)) { error=my_errno(); mi_print_error(info->s, HA_ERR_CRASHED); mi_mark_crashed(info); } } if (!count) { DBUG_PRINT("info",("changed: %u w_locks: %u", (uint) share->changed, share->w_locks)); if (share->changed && !share->w_locks) { if ((info->s->mmaped_length != info->s->state.state.data_file_length) && (info->s->nonmmaped_inserts > MAX_NONMAPPED_INSERTS)) { if (info->s->concurrent_insert) mysql_rwlock_wrlock(&info->s->mmap_lock); mi_remap_file(info, info->s->state.state.data_file_length); info->s->nonmmaped_inserts= 0; if (info->s->concurrent_insert) mysql_rwlock_unlock(&info->s->mmap_lock); } share->state.process= share->last_process=share->this_process; share->state.unique= info->last_unique= info->this_unique; share->state.update_count= info->last_loop= ++info->this_loop; if (mi_state_info_write(share->kfile, &share->state, 1)) error=my_errno(); share->changed=0; if (myisam_flush) { if (mysql_file_sync(share->kfile, MYF(0))) error= my_errno(); if (mysql_file_sync(info->dfile, MYF(0))) error= my_errno(); } else share->not_flushed=1; if (error) { mi_print_error(info->s, HA_ERR_CRASHED); mi_mark_crashed(info); } } if (info->lock_type != F_EXTRA_LCK) { if (share->r_locks) { /* Only read locks left */ if (my_lock(share->kfile,F_RDLCK,0L,F_TO_EOF, MYF(MY_WME | MY_SEEK_NOT_DONE)) && !error) error=my_errno(); } else if (!share->w_locks) { /* No more locks */ if (my_lock(share->kfile,F_UNLCK,0L,F_TO_EOF, MYF(MY_WME | MY_SEEK_NOT_DONE)) && !error) error=my_errno(); } } } info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED); info->lock_type= F_UNLCK; info->s->in_use= list_delete(info->s->in_use, &info->in_use); break; case F_RDLCK: if (info->lock_type == F_WRLCK) { /* Change RW to READONLY mysqld does not turn write locks to read locks, so we're never here in mysqld. */ if (share->w_locks == 1) { if (my_lock(share->kfile,lock_type,0L,F_TO_EOF, MYF(MY_SEEK_NOT_DONE))) { error=my_errno(); break; } } share->w_locks--; share->r_locks++; info->lock_type=lock_type; break; } if (!share->r_locks && !share->w_locks) { if (my_lock(share->kfile,lock_type,0L,F_TO_EOF, info->lock_wait | MY_SEEK_NOT_DONE)) { error=my_errno(); break; } if (mi_state_info_read_dsk(share->kfile, &share->state, 1)) { error=my_errno(); (void) my_lock(share->kfile,F_UNLCK,0L,F_TO_EOF,MYF(MY_SEEK_NOT_DONE)); set_my_errno(error); break; } } (void) _mi_test_if_changed(info); share->r_locks++; share->tot_locks++; info->lock_type=lock_type; info->s->in_use= list_add(info->s->in_use, &info->in_use); break; case F_WRLCK: if (info->lock_type == F_RDLCK) { /* Change READONLY to RW */ if (share->r_locks == 1) { if (my_lock(share->kfile,lock_type,0L,F_TO_EOF, MYF(info->lock_wait | MY_SEEK_NOT_DONE))) { error=my_errno(); break; } share->r_locks--; share->w_locks++; info->lock_type=lock_type; break; } } if (!(share->options & HA_OPTION_READ_ONLY_DATA)) { if (!share->w_locks) { if (my_lock(share->kfile,lock_type,0L,F_TO_EOF, info->lock_wait | MY_SEEK_NOT_DONE)) { error=my_errno(); break; } if (!share->r_locks) { if (mi_state_info_read_dsk(share->kfile, &share->state, 1)) { error=my_errno(); (void) my_lock(share->kfile,F_UNLCK,0L,F_TO_EOF, info->lock_wait | MY_SEEK_NOT_DONE); set_my_errno(error); break; } } } } (void) _mi_test_if_changed(info); info->lock_type=lock_type; info->invalidator=info->s->invalidator; share->w_locks++; share->tot_locks++; info->s->in_use= list_add(info->s->in_use, &info->in_use); break; default: break; /* Impossible */ } } #ifdef _WIN32 else { /* Check for bad file descriptors if this table is part of a merge union. Failing to capture this may cause a crash on windows if the table is renamed and later on referenced by the merge table. */ if( info->owned_by_merge && (info->s)->kfile < 0 ) { error = HA_ERR_NO_SUCH_TABLE; } } #endif mysql_mutex_unlock(&share->intern_lock); DBUG_RETURN(error); } /* mi_lock_database */
my_bool safe_hash_set(SAFE_HASH *hash, const uchar *key, uint length, uchar *data) { SAFE_HASH_ENTRY *entry; my_bool error= 0; DBUG_ENTER("safe_hash_set"); DBUG_PRINT("enter",("key: %.*s data: 0x%lx", length, key, (long) data)); mysql_rwlock_wrlock(&hash->mutex); entry= (SAFE_HASH_ENTRY*) my_hash_search(&hash->hash, key, length); if (data == hash->default_value) { /* The key is to be associated with the default entry. In this case we can just delete the entry (if it existed) from the hash as a search will return the default entry */ if (!entry) /* nothing to do */ goto end; /* unlink entry from list */ if ((*entry->prev= entry->next)) entry->next->prev= entry->prev; my_hash_delete(&hash->hash, (uchar*) entry); goto end; } if (entry) { /* Entry existed; Just change the pointer to point at the new data */ entry->data= data; } else { if (!(entry= (SAFE_HASH_ENTRY *) my_malloc(sizeof(*entry) + length, MYF(MY_WME)))) { error= 1; goto end; } entry->key= (uchar*) (entry +1); memcpy((char*) entry->key, (char*) key, length); entry->length= length; entry->data= data; /* Link entry to list */ if ((entry->next= hash->root)) entry->next->prev= &entry->next; entry->prev= &hash->root; hash->root= entry; if (my_hash_insert(&hash->hash, (uchar*) entry)) { /* This can only happen if hash got out of memory */ my_free(entry); error= 1; goto end; } } end: mysql_rwlock_unlock(&hash->mutex); DBUG_RETURN(error); }