1
0
Files
irix-657m-src/eoe/cmd/sss/ssdb/ssdbserver/sql/lock.cc
2022-09-29 17:59:04 +03:00

316 lines
8.0 KiB
C++

/* Copyright (C) 1979-1996 TcX AB & Monty Program KB & Detron HB
This software is distributed with NO WARRANTY OF ANY KIND. No author or
distributor accepts any responsibility for the consequences of using it, or
for whether it serves any particular purpose or works at all, unless he or
she says so in writing. Refer to the Free Public License (the "License")
for full details.
Every copy of this file must include a copy of the License, normally in a
plain ASCII text file named PUBLIC. The License grants you the right to
copy, modify and redistribute this file, but only under certain conditions
described in the License. Among other things, the License requires that
the copyright notice and this notice be preserved on all copies. */
/* locking functions for mysql */
#include "mysql_priv.h"
#include <hash.h>
#ifndef MASTER
#include "../srclib/merge/mrgdef.h" /* Includes isam & thr_lock */
#else
#include "../merge/mrgdef.h"
#endif
extern HASH open_cache;
static MYSQL_LOCK *get_lock_data(TABLE **table,uint count,bool unlock=0);
static int lock_databases(TABLE **table,uint count);
static int unlock_databases(TABLE **table,uint count);
MYSQL_LOCK *mysql_lock_tables(THD *thd,TABLE **tables,uint count)
{
MYSQL_LOCK *sql_lock;
thd->locked=1;
for (;;)
{
if ((sql_lock = get_lock_data(tables,count)))
{
if (thr_multi_lock(sql_lock->locks,sql_lock->lock_count))
{
thd->some_tables_deleted=1; // Try again
}
else
{
thd->proc_info="System lock";
if (lock_databases(tables,count))
{
thr_multi_unlock(sql_lock->locks,sql_lock->lock_count);
my_free((gptr) sql_lock,MYF(0));
sql_lock=0;
thd->proc_info=0;
break;
}
thd->proc_info=0;
}
}
if (!thd->some_tables_deleted)
break;
/* some table was altered or deleted. reopen tables marked deleted */
mysql_unlock_tables(sql_lock);
sql_lock=0;
if (wait_for_tables(thd))
break; // Couldn't open tables
}
thd->locked=0;
if (thd->killed)
{
my_error(ER_SERVER_SHUTDOWN,MYF(0));
if (sql_lock)
{
mysql_unlock_tables(sql_lock);
sql_lock=0;
}
}
return sql_lock;
}
static int lock_databases(TABLE **tables,uint count)
{
reg1 uint i;
int lock_type,error;
DBUG_ENTER("lock_databases");
for (i=1 ; i <= count ; i++, tables++)
{
lock_type=F_WRLCK; /* Lock exclusive */
if ((*tables)->db_stat & HA_READ_ONLY ||
(*tables)->reginfo.lock_type == TL_READ ||
(*tables)->reginfo.lock_type == TL_READ_HIGH_PRIORITY)
lock_type=F_RDLCK;
if ((error=ha_lock((*tables),lock_type)))
{
for ( ; i-- ; tables--)
VOID(ha_lock((*tables),F_UNLCK));
my_error(ER_CANT_LOCK,MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG),error);
DBUG_RETURN(error);
}
else
(*tables)->db_stat &= ~ HA_BLOCK_LOCK;
}
DBUG_RETURN(0);
}
void mysql_unlock_tables(MYSQL_LOCK *sql_lock)
{
VOID(unlock_databases(sql_lock->table,sql_lock->table_count));
thr_multi_unlock(sql_lock->locks,sql_lock->lock_count);
my_free((gptr) sql_lock,MYF(0));
}
/*
Unlock some of the tables locked by mysql_lock_tables
This will work even if get_lock_data fails (next unlock will free all)
*/
void mysql_unlock_some_tables(TABLE **table,uint count)
{
MYSQL_LOCK *sql_lock;
if ((sql_lock = get_lock_data(table,count,1)))
mysql_unlock_tables(sql_lock);
VOID(unlock_databases(table,count));
}
/*
** unlock all tables locked for read.
*/
void mysql_unlock_read_tables(MYSQL_LOCK *sql_lock)
{
uint i,found;
/* Move all write locked tables first */
TABLE **table=sql_lock->table;
for (i=found=0 ; i < sql_lock->table_count ; i++)
{
if ((uint) sql_lock->table[i]->reginfo.lock_type >= TL_WRITE_ALLOW_READ)
{
swap(TABLE *,*table,sql_lock->table[i]);
table++;
found++;
}
}
/* Unlock all read locked tables */
if (i != found)
{
VOID(unlock_databases(table,i-found));
sql_lock->table_count-=found;
}
/* Do the same thing to MySQL memory locks */
THR_LOCK_DATA **lock=sql_lock->locks;
for (i=found=0 ; i < sql_lock->lock_count ; i++)
{
if (sql_lock->locks[i]->type >= TL_WRITE_ALLOW_READ)
{
swap(THR_LOCK_DATA *,*lock,sql_lock->locks[i]);
lock++;
found++;
}
}
if (i != found)
{
thr_multi_unlock(lock,sql_lock->lock_count-found);
sql_lock->lock_count-=found;
}
}
void mysql_lock_remove(MYSQL_LOCK *locked,TABLE *table)
{
mysql_unlock_some_tables(&table,1);
reg1 uint i;
for (i=0; i < locked->table_count; i++)
{
if (locked->table[i] == table)
{
locked->table_count--;
bmove((char*) (locked->table+i),
(char*) (locked->table+i+1),
(locked->table_count-i)* sizeof(TABLE*));
break;
}
}
THR_LOCK_DATA **prev=locked->locks;
for (i=0 ; i < locked->lock_count ; i++)
{
if (locked->locks[i]->type != TL_UNLOCK)
*prev++ = locked->locks[i];
}
locked->lock_count=(prev - locked->locks);
}
/* abort all other threads waiting to get lock in table */
void mysql_lock_abort(TABLE *table)
{
MYSQL_LOCK *locked;
if ((locked = get_lock_data(&table,1,1)))
{
for (uint i=0; i < locked->table_count; i++)
thr_abort_locks(locked->locks[i]->lock);
my_free((gptr) locked,MYF(0));
}
}
MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b)
{
MYSQL_LOCK *sql_lock;
DBUG_ENTER("mysql_lock_merge");
if (!(sql_lock= (MYSQL_LOCK*)
my_malloc(sizeof(*sql_lock)+
sizeof(THR_LOCK_DATA*)*(a->lock_count+b->lock_count)+
sizeof(TABLE*)*(a->table_count+b->table_count),MYF(MY_WME))))
DBUG_RETURN(0); // Fatal error
sql_lock->lock_count=a->lock_count+b->lock_count;
sql_lock->table_count=a->table_count+b->table_count;
sql_lock->locks=(THR_LOCK_DATA**) (sql_lock+1);
sql_lock->table=(TABLE**) (sql_lock->locks+sql_lock->lock_count);
memcpy(sql_lock->locks,a->locks,a->lock_count*sizeof(*a->locks));
memcpy(sql_lock->locks+a->lock_count,b->locks,
b->lock_count*sizeof(*b->locks));
memcpy(sql_lock->table,a->table,a->table_count*sizeof(*a->table));
memcpy(sql_lock->table+a->table_count,b->table,
b->table_count*sizeof(*b->table));
my_free((gptr) a,MYF(0));
my_free((gptr) b,MYF(0));
return sql_lock;
}
/* unlock a set of databases */
static int unlock_databases(TABLE **table,uint count)
{
int error,error_code;
DBUG_ENTER("unlock_databases");
error_code=0;
for (; count-- ; table++)
{
if ((error=ha_lock((*table),F_UNLCK)))
error_code=error;
}
if (error_code)
my_error(ER_CANT_LOCK,MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG),error_code);
DBUG_RETURN(error_code);
}
/*
** Get lock structures from table structs and initialize locks
*/
static MYSQL_LOCK *get_lock_data(TABLE **table,uint count,bool get_old_locks)
{
uint i,tables;
enum thr_lock_type lock_type;
MYSQL_LOCK *sql_lock;
THR_LOCK_DATA **locks;
for (i=tables=0 ; i < count ; i++)
{
if (table[i]->db_type == DB_TYPE_MRG_ISAM)
{
MRG_INFO *db= (MRG_INFO*) table[i]->file;
tables+=db->tables;
}
else if (table[i]->db_type == DB_TYPE_ISAM)
tables++;
}
if (!(sql_lock= (MYSQL_LOCK*)
my_malloc(sizeof(*sql_lock)+
sizeof(THR_LOCK_DATA*)*tables+sizeof(table)*count,MYF(0))))
return 0;
locks=sql_lock->locks=(THR_LOCK_DATA**) (sql_lock+1);
sql_lock->table=(TABLE**) (locks+tables);
sql_lock->table_count=count;
sql_lock->lock_count=tables;
memcpy(sql_lock->table,table,sizeof(table[0])*count);
for (i=0 ; i < count ; i++)
{
lock_type= table[i]->reginfo.lock_type;
if (table[i]->db_type == DB_TYPE_MRG_ISAM)
{
MRG_INFO *db= (MRG_INFO*) table[i]->file;
MRG_TABLE *file;
for (file=db->open_tables ; file != db->end_table ; file++)
{
*(locks++)= &file->table->lock;
if (file->table->lock.type == TL_UNLOCK && !get_old_locks)
file->table->lock.type=lock_type;
}
}
else if (table[i]->db_type == DB_TYPE_ISAM)
{
N_INFO *db=(N_INFO*) table[i]->file;
*(locks++)= &db->lock;
if (db->lock.type == TL_UNLOCK && !get_old_locks)
db->lock.type=lock_type;
}
}
return sql_lock;
}