Commit 55aa4f20 authored by joreland@mysql.com's avatar joreland@mysql.com

Merge mysql.com:/home/jonas/src/mysql-5.0

into mysql.com:/home/jonas/src/mysql-5.0-ndb
parents 3605cead a45702c3
......@@ -538,6 +538,7 @@ myisam/test2.MYD
myisam/test2.MYI
mysql-4.0.2-alpha-pc-linux-gnu-i686.tar.gz
mysql-4.0.2-alpha.tar.gz
mysql-5.0.2-alpha.tar.gz
mysql-max-4.0.2-alpha-pc-linux-gnu-i686.tar.gz
mysql-test/gmon.out
mysql-test/install_test_db
......@@ -816,7 +817,11 @@ scripts/mysqldumpslow
scripts/mysqlhotcopy
scripts/safe_mysqld
select_test
server-tools/instance-manager/client.c
server-tools/instance-manager/client_settings.h
server-tools/instance-manager/errmsg.c
server-tools/instance-manager/mysqlmanager
server-tools/instance-manager/thr_alarm.c
sql-bench/Results-linux/ATIS-mysql_bdb-Linux_2.2.14_my_SMP_i686
sql-bench/bench-count-distinct
sql-bench/bench-init.pl
......
......@@ -411,6 +411,9 @@ btr_search_update_hash_ref(
ut_ad(rw_lock_own(&(block->lock), RW_LOCK_SHARED)
|| rw_lock_own(&(block->lock), RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
ut_ad(buf_block_align(btr_cur_get_rec(cursor)) == block);
ut_a(!block->is_hashed || block->index == cursor->index);
if (block->is_hashed
&& (info->n_hash_potential > 0)
&& (block->curr_n_fields == info->n_fields)
......@@ -923,6 +926,19 @@ btr_search_drop_page_hash_index(
{
hash_table_t* table;
buf_block_t* block;
ulint n_fields;
ulint n_bytes;
rec_t* rec;
rec_t* sup;
ulint fold;
ulint prev_fold;
dulint tree_id;
ulint n_cached;
ulint n_recs;
ulint* folds;
ulint i;
mem_heap_t* heap;
ulint* offsets;
#ifdef UNIV_SYNC_DEBUG
ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_SHARED));
......@@ -948,17 +964,79 @@ btr_search_drop_page_hash_index(
|| (block->buf_fix_count == 0));
#endif /* UNIV_SYNC_DEBUG */
ut_a(block->curr_n_fields + block->curr_n_bytes > 0);
n_fields = block->curr_n_fields;
n_bytes = block->curr_n_bytes;
ut_a(n_fields + n_bytes > 0);
rw_lock_s_unlock(&btr_search_latch);
n_recs = page_get_n_recs(page);
/* Calculate and cache fold values into an array for fast deletion
from the hash index */
folds = mem_alloc(n_recs * sizeof(ulint));
n_cached = 0;
sup = page_get_supremum_rec(page);
rec = page_get_infimum_rec(page);
rec = page_rec_get_next(rec);
if (rec != sup) {
ut_a(n_fields <= rec_get_n_fields(rec, block->index));
if (n_bytes > 0) {
ut_a(n_fields < rec_get_n_fields(rec, block->index));
}
}
tree_id = btr_page_get_index_id(page);
prev_fold = 0;
heap = mem_heap_create(100);
offsets = NULL;
while (rec != sup) {
/* FIXME: in a mixed tree, not all records may have enough
ordering fields: */
offsets = rec_reget_offsets(rec, block->index,
offsets, n_fields + (n_bytes > 0), heap);
fold = rec_fold(rec, offsets, n_fields, n_bytes, tree_id);
if (fold == prev_fold && prev_fold != 0) {
goto next_rec;
}
/* Remove all hash nodes pointing to this page from the
hash chain */
folds[n_cached] = fold;
n_cached++;
next_rec:
rec = page_rec_get_next(rec);
prev_fold = fold;
}
mem_heap_free(heap);
rw_lock_x_lock(&btr_search_latch);
ha_remove_all_nodes_to_page(table, page);
for (i = 0; i < n_cached; i++) {
ha_remove_all_nodes_to_page(table, folds[i], page);
}
block->is_hashed = FALSE;
block->index = NULL;
rw_lock_x_unlock(&btr_search_latch);
mem_free(folds);
}
/************************************************************************
......@@ -1170,6 +1248,7 @@ btr_search_build_page_hash_index(
block->curr_n_fields = n_fields;
block->curr_n_bytes = n_bytes;
block->curr_side = side;
block->index = index;
for (i = 0; i < n_cached; i++) {
......@@ -1215,6 +1294,8 @@ btr_search_move_or_delete_hash_entries(
ut_ad(rw_lock_own(&(block->lock), RW_LOCK_EX));
ut_ad(rw_lock_own(&(new_block->lock), RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
ut_a(!new_block->is_hashed || new_block->index == index);
ut_a(!block->is_hashed || block->index == index);
rw_lock_s_lock(&btr_search_latch);
......@@ -1284,6 +1365,7 @@ btr_search_update_hash_on_delete(
return;
}
ut_a(block->index == cursor->index);
ut_a(block->curr_n_fields + block->curr_n_bytes > 0);
table = btr_search_sys->hash_index;
......@@ -1329,6 +1411,8 @@ btr_search_update_hash_node_on_insert(
return;
}
ut_a(block->index == cursor->index);
rw_lock_x_lock(&btr_search_latch);
if ((cursor->flag == BTR_CUR_HASH)
......@@ -1394,6 +1478,8 @@ btr_search_update_hash_on_insert(
return;
}
ut_a(block->index == cursor->index);
tree_id = ((cursor->index)->tree)->id;
n_fields = block->curr_n_fields;
......@@ -1499,10 +1585,9 @@ btr_search_update_hash_on_insert(
Validates the search system. */
ibool
btr_search_validate(
/*================*/
btr_search_validate(void)
/*=====================*/
/* out: TRUE if ok */
dict_index_t* index) /* in: record descriptor */
{
buf_block_t* block;
page_t* page;
......@@ -1521,8 +1606,9 @@ btr_search_validate(
while (node != NULL) {
block = buf_block_align(node->data);
page = buf_frame_align(node->data);
offsets = rec_reget_offsets((rec_t*) node->data, index,
offsets, block->curr_n_fields
offsets = rec_reget_offsets((rec_t*) node->data,
block->index, offsets,
block->curr_n_fields
+ (block->curr_n_bytes > 0), heap);
if (!block->is_hashed
......
......@@ -460,12 +460,12 @@ buf_block_init(
block->file_page_was_freed = FALSE;
block->check_index_page_at_flush = FALSE;
block->index = NULL;
block->in_free_list = FALSE;
block->in_LRU_list = FALSE;
block->n_pointers = 0;
block->hash_nodes = NULL;
rw_lock_create(&(block->lock));
ut_ad(rw_lock_validate(&(block->lock)));
......@@ -1536,6 +1536,7 @@ buf_page_init(
block->offset = offset;
block->check_index_page_at_flush = FALSE;
block->index = NULL;
block->lock_hash_val = lock_rec_hash(space, offset);
block->lock_mutex = NULL;
......
......@@ -823,7 +823,6 @@ buf_LRU_block_free_non_file_page(
|| (block->state == BUF_BLOCK_READY_FOR_USE));
ut_a(block->n_pointers == 0);
ut_a(block->hash_nodes == NULL);
ut_a(!block->in_free_list);
block->state = BUF_BLOCK_NOT_USED;
......
......@@ -65,53 +65,10 @@ ha_create(
return(table);
}
/*****************************************************************
Removes an adaptive hash index node from the doubly linked list of hash nodes
for the buffer block. */
UNIV_INLINE
void
ha_remove_buf_block_node(
/*=====================*/
buf_block_t* block, /* in: buffer block */
ha_node_t* node) /* in: an adaptive hash index node */
{
if (node == block->hash_nodes) {
block->hash_nodes = node->next_for_block;
}
if (node->prev_for_block != NULL) {
(node->prev_for_block)->next_for_block = node->next_for_block;
}
if (node->next_for_block != NULL) {
(node->next_for_block)->prev_for_block = node->prev_for_block;
}
}
/*****************************************************************
Adds an adaptive hash index node to the start of the doubly linked list of
hash nodes for the buffer block. */
UNIV_INLINE
void
ha_add_buf_block_node(
/*==================*/
buf_block_t* block, /* in: buffer block */
ha_node_t* node) /* in: an adaptive hash index node */
{
node->next_for_block = block->hash_nodes;
node->prev_for_block = NULL;
block->hash_nodes = node;
if (node->next_for_block != NULL) {
(node->next_for_block)->prev_for_block = node;
}
}
/*****************************************************************
Inserts an entry into a hash table. If an entry with the same fold number
is found, its node is updated to point to the new data, and no new node
is inserted. This function is only used in the adaptive hash index. */
is inserted. */
ibool
ha_insert_for_fold(
......@@ -127,7 +84,6 @@ ha_insert_for_fold(
{
hash_cell_t* cell;
ha_node_t* node;
buf_block_t* block;
ha_node_t* prev_node;
buf_block_t* prev_block;
ulint hash;
......@@ -136,9 +92,6 @@ ha_insert_for_fold(
#ifdef UNIV_SYNC_DEBUG
ut_ad(!table->mutexes || mutex_own(hash_get_mutex(table, fold)));
#endif /* UNIV_SYNC_DEBUG */
block = buf_block_align(data);
hash = hash_calc_hash(fold, table);
cell = hash_get_nth_cell(table, hash);
......@@ -151,15 +104,7 @@ ha_insert_for_fold(
prev_block = buf_block_align(prev_node->data);
ut_a(prev_block->n_pointers > 0);
prev_block->n_pointers--;
block->n_pointers++;
if (prev_block != block) {
ha_remove_buf_block_node(prev_block,
prev_node);
ha_add_buf_block_node(block,
prev_node);
}
buf_block_align(data)->n_pointers++;
}
prev_node->data = data;
......@@ -186,9 +131,7 @@ ha_insert_for_fold(
ha_node_set_data(node, data);
if (table->adaptive) {
block->n_pointers++;
ha_add_buf_block_node(block, node);
buf_block_align(data)->n_pointers++;
}
node->fold = fold;
......@@ -223,15 +166,9 @@ ha_delete_hash_node(
hash_table_t* table, /* in: hash table */
ha_node_t* del_node) /* in: node to be deleted */
{
buf_block_t* block;
if (table->adaptive) {
block = buf_block_align(del_node->data);
ut_a(block->n_pointers > 0);
block->n_pointers--;
ha_remove_buf_block_node(block, del_node);
ut_a(buf_block_align(del_node->data)->n_pointers > 0);
buf_block_align(del_node->data)->n_pointers--;
}
HASH_DELETE_AND_COMPACT(ha_node_t, next, table, del_node);
......@@ -272,8 +209,6 @@ ha_search_and_update_if_found(
void* data, /* in: pointer to the data */
void* new_data)/* in: new pointer to the data */
{
buf_block_t* old_block;
buf_block_t* block;
ha_node_t* node;
#ifdef UNIV_SYNC_DEBUG
......@@ -285,15 +220,8 @@ ha_search_and_update_if_found(
if (node) {
if (table->adaptive) {
ut_a(buf_block_align(node->data)->n_pointers > 0);
old_block = buf_block_align(node->data);
ut_a(old_block->n_pointers > 0);
old_block->n_pointers--;
ha_remove_buf_block_node(old_block, node);
block = buf_block_align(new_data);
block->n_pointers++;
ha_add_buf_block_node(block, node);
buf_block_align(node->data)->n_pointers--;
buf_block_align(new_data)->n_pointers++;
}
node->data = new_data;
......@@ -308,25 +236,43 @@ void
ha_remove_all_nodes_to_page(
/*========================*/
hash_table_t* table, /* in: hash table */
ulint fold, /* in: fold value */
page_t* page) /* in: buffer page */
{
buf_block_t* block;
ha_node_t* node;
block = buf_block_align(page);
node = block->hash_nodes;
#ifdef UNIV_SYNC_DEBUG
ut_ad(!table->mutexes || mutex_own(hash_get_mutex(table, fold)));
#endif /* UNIV_SYNC_DEBUG */
node = ha_chain_get_first(table, fold);
while (node) {
if (buf_frame_align(ha_node_get_data(node)) == page) {
/* Remove the hash node */
ha_delete_hash_node(table, node);
node = block->hash_nodes;
/* Start again from the first node in the chain
because the deletion may compact the heap of
nodes and move other nodes! */
node = ha_chain_get_first(table, fold);
} else {
node = ha_chain_get_next(node);
}
}
#ifdef UNIV_DEBUG
/* Check that all nodes really got deleted */
ut_a(block->n_pointers == 0);
ut_a(block->hash_nodes == NULL);
node = ha_chain_get_first(table, fold);
while (node) {
ut_a(buf_frame_align(ha_node_get_data(node)) != page);
node = ha_chain_get_next(node);
}
#endif
}
/*****************************************************************
......@@ -406,7 +352,6 @@ ha_print_info(
n_bufs++;
}
fprintf(file, ", node heap has %lu buffer(s)\n",
(ulong) n_bufs);
fprintf(file, ", node heap has %lu buffer(s)\n", (ulong) n_bufs);
}
}
......@@ -2812,7 +2812,6 @@ ibuf_insert_to_index_page(
rec_t* rec;
page_t* bitmap_page;
ulint old_bits;
mem_heap_t* heap;
ut_ad(ibuf_inside());
ut_ad(dtuple_check_typed(entry));
......@@ -2824,12 +2823,9 @@ ibuf_insert_to_index_page(
goto dump;
}
heap = mem_heap_create(100);
rec = page_rec_get_next(page_get_infimum_rec(page));
if (rec_offs_n_fields(rec_get_offsets(rec, index, ULINT_UNDEFINED,
heap)) != dtuple_get_n_fields(entry)) {
mem_heap_free(heap);
if (rec_get_n_fields(rec, index) != dtuple_get_n_fields(entry)) {
fputs(
"InnoDB: Trying to insert a record from the insert buffer to an index page\n"
"InnoDB: but the number of fields does not match!\n", stderr);
......@@ -2847,7 +2843,6 @@ ibuf_insert_to_index_page(
return;
}
mem_heap_free(heap);
low_match = page_cur_search(page, index, entry,
PAGE_CUR_LE, &page_cur);
......
......@@ -130,10 +130,9 @@ btr_search_update_hash_on_delete(
Validates the search system. */
ibool
btr_search_validate(
/*================*/
btr_search_validate(void);
/*======================*/
/* out: TRUE if ok */
dict_index_t* index); /* in: record descriptor */
/* Search info directions */
#define BTR_SEA_NO_DIRECTION 1
......
......@@ -29,7 +29,6 @@ Created 11/5/1995 Heikki Tuuri
#include "buf0types.h"
#include "sync0rw.h"
#include "hash0hash.h"
#include "ha0ha.h"
#include "ut0byte.h"
#include "os0proc.h"
......@@ -740,6 +739,8 @@ struct buf_block_struct{
buffer pool which are index pages,
but this flag is not set because
we do not keep track of all pages */
dict_index_t* index; /* index for which the adaptive
hash index has been created */
/* 2. Page flushing fields */
UT_LIST_NODE_T(buf_block_t) flush_list;
......@@ -826,7 +827,7 @@ struct buf_block_struct{
records with the same prefix should be
indexed in the hash index */
/* The following 6 fields are protected by btr_search_latch: */
/* The following 4 fields are protected by btr_search_latch: */
ibool is_hashed; /* TRUE if hash index has already been
built on this page; note that it does
......@@ -843,11 +844,6 @@ struct buf_block_struct{
ulint curr_side; /* BTR_SEARCH_LEFT_SIDE or
BTR_SEARCH_RIGHT_SIDE in hash
indexing */
ha_node_t* hash_nodes; /* a doubly linked list of hash nodes
for this buffer block; this points to
the first node in the list if any;
note that we do not use UT_LST_ macros
to manipulate this list */
/* 6. Debug fields */
#ifdef UNIV_SYNC_DEBUG
rw_lock_t debug_latch; /* in the debug version, each thread
......
......@@ -54,7 +54,7 @@ ha_create(
/*****************************************************************
Inserts an entry into a hash table. If an entry with the same fold number
is found, its node is updated to point to the new data, and no new node
is inserted. This function is only used in the adaptive hash index. */
is inserted. */
ibool
ha_insert_for_fold(
......@@ -111,6 +111,7 @@ void
ha_remove_all_nodes_to_page(
/*========================*/
hash_table_t* table, /* in: hash table */
ulint fold, /* in: fold value */
page_t* page); /* in: buffer page */
/*****************************************************************
Validates a hash table. */
......@@ -133,18 +134,9 @@ ha_print_info(
typedef struct ha_node_struct ha_node_t;
struct ha_node_struct {
ha_node_t* next; /* next chain node; NULL if none */
ha_node_t* next; /* next chain node or NULL if none */
void* data; /* pointer to the data */
ulint fold; /* fold value for the data */
ha_node_t* next_for_block;/* in an adaptive hash index
(btr0sea.c), a doubly linked list of hash
nodes for the buffer block; these nodes
contain pointers to index records on the
page; in the last node this field is NULL;
note that we do not use UT_LST_ macros
to manipulate this list */
ha_node_t* prev_for_block;/* pointer to the previous node; in the
first node NULL */
};
#ifndef UNIV_NONINL
......
......@@ -166,7 +166,7 @@ hash_get_n_cells(
/***********************************************************************
Deletes a struct which is stored in the heap of the hash table, and compacts
the heap. The fold value must be stored in the struct NODE in a field named
'fold'. This macro is only used for the adaptive hash index. */
'fold'. */
#define HASH_DELETE_AND_COMPACT(TYPE, NAME, TABLE, NODE)\
do {\
......@@ -191,23 +191,11 @@ do {\
/* Copy the top node in place of NODE */\
\
*(NODE) = *top_node111;\
\
/* Update the adaptive hash list of the buffer block that\
corresponds to the top node */\
if (top_node111->next_for_block != NULL) {\
(top_node111->next_for_block)->prev_for_block = NODE;\
}\
\
if (top_node111->prev_for_block != NULL) {\
(top_node111->prev_for_block)->next_for_block = NODE;\
} else {\
buf_block_align(top_node111->data)->hash_nodes = NODE;\
}\
\
/* Look for the hash pointer to the top node, to update it */\
\
cell111 = hash_get_nth_cell(TABLE,\
hash_calc_hash(top_node111->fold, TABLE));\
\
/* Look for the pointer to the top node, to update it */\
\
if (cell111->node == top_node111) {\
/* The top node is the first in the chain */\
......
......@@ -1928,9 +1928,8 @@ row_ins_index_entry_low(
buf_frame_align(btr_cur_get_rec(&cursor))));
if (!page_rec_is_supremum(first_rec)) {
offsets = rec_get_offsets(first_rec, index,
ULINT_UNDEFINED, heap);
ut_a(rec_offs_n_fields(offsets) == dtuple_get_n_fields(entry));
ut_a(rec_get_n_fields(first_rec, index)
== dtuple_get_n_fields(entry));
}
n_unique = dict_index_get_n_unique(index);
......
......@@ -3398,7 +3398,7 @@ row_check_table_for_mysql(
/* We validate also the whole adaptive hash index for all tables
at every CHECK TABLE */
if (!btr_search_validate(index)) {
if (!btr_search_validate()) {
ret = DB_ERROR;
}
......
......@@ -91,11 +91,11 @@ ab a ab a a
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` varchar(2) NOT NULL default '',
`c2` varchar(2) NOT NULL default '',
`c3` varchar(2) NOT NULL default '',
`c4` varchar(2) NOT NULL default '',
`c5` varchar(2) NOT NULL default ''
`c1` varbinary(2) NOT NULL default '',
`c2` varbinary(2) NOT NULL default '',
`c3` varbinary(2) NOT NULL default '',
`c4` varbinary(2) NOT NULL default '',
`c5` varbinary(2) NOT NULL default ''
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
select
......
......@@ -124,7 +124,7 @@ create table t1 select date_format("2004-01-19 10:10:10", "%Y-%m-%d");
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`date_format("2004-01-19 10:10:10", "%Y-%m-%d")` binary(10) default NULL
`date_format("2004-01-19 10:10:10", "%Y-%m-%d")` varbinary(10) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
select * from t1;
date_format("2004-01-19 10:10:10", "%Y-%m-%d")
......
......@@ -611,7 +611,7 @@ t1 CREATE TABLE `t1` (
`substring(_latin2'ab',1)` varchar(2) character set latin2 NOT NULL default '',
`insert(_latin2'abcd',2,3,_latin2'ef')` varchar(6) character set latin2 NOT NULL default '',
`replace(_latin2'abcd',_latin2'b',_latin2'B')` varchar(4) character set latin2 NOT NULL default '',
`encode('abcd','ab')` binary(4) NOT NULL default ''
`encode('abcd','ab')` varbinary(4) NOT NULL default ''
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
select SUBSTR('abcdefg',3,2);
......
......@@ -1775,7 +1775,7 @@ t5 CREATE TABLE `t5` (
`param03` double default NULL,
`const04` varchar(3) NOT NULL default '',
`param04` longtext,
`const05` binary(3) NOT NULL default '',
`const05` varbinary(3) NOT NULL default '',
`param05` longblob,
`const06` varchar(10) NOT NULL default '',
`param06` longtext,
......
......@@ -1758,7 +1758,7 @@ t5 CREATE TABLE `t5` (
`param03` double default NULL,
`const04` varchar(3) NOT NULL default '',
`param04` longtext,
`const05` binary(3) NOT NULL default '',
`const05` varbinary(3) NOT NULL default '',
`param05` longblob,
`const06` varchar(10) NOT NULL default '',
`param06` longtext,
......
......@@ -1759,7 +1759,7 @@ t5 CREATE TABLE `t5` (
`param03` double default NULL,
`const04` varchar(3) NOT NULL default '',
`param04` longtext,
`const05` binary(3) NOT NULL default '',
`const05` varbinary(3) NOT NULL default '',
`param05` longblob,
`const06` varchar(10) NOT NULL default '',
`param06` longtext,
......
......@@ -1758,7 +1758,7 @@ t5 CREATE TABLE `t5` (
`param03` double default NULL,
`const04` varchar(3) NOT NULL default '',
`param04` longtext,
`const05` binary(3) NOT NULL default '',
`const05` varbinary(3) NOT NULL default '',
`param05` longblob,
`const06` varchar(10) NOT NULL default '',
`param06` longtext,
......
......@@ -272,7 +272,7 @@ auto bigint(17) unsigned NULL PRI 0 select,insert,update,references
t1 bigint(1) NULL 0 select,insert,update,references
t2 varchar(1) latin1_swedish_ci select,insert,update,references
t3 varchar(256) latin1_swedish_ci select,insert,update,references
t4 varchar(256) NULL select,insert,update,references
t4 varbinary(256) NULL select,insert,update,references
t5 longtext latin1_swedish_ci select,insert,update,references
t6 longblob NULL select,insert,update,references
t7 char(0) latin1_swedish_ci select,insert,update,references
......
......@@ -655,7 +655,7 @@ f
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`f` binary(24) default NULL
`f` varbinary(24) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 SELECT y from t2 UNION select da from t2;
......@@ -666,7 +666,7 @@ y
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`y` binary(10) default NULL
`y` varbinary(10) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 SELECT y from t2 UNION select dt from t2;
......@@ -677,7 +677,7 @@ y
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`y` binary(19) default NULL
`y` varbinary(19) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 SELECT da from t2 UNION select dt from t2;
......@@ -699,7 +699,7 @@ testc
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`dt` binary(19) default NULL
`dt` varbinary(19) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 SELECT dt from t2 UNION select sv from t2;
......@@ -710,7 +710,7 @@ testv
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`dt` binary(19) default NULL
`dt` varbinary(19) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 SELECT sc from t2 UNION select sv from t2;
......
......@@ -1272,10 +1272,6 @@ Backup::createAttributeMask(TablePtr tabPtr,
jam();
AttributePtr attr;
table.attributes.getPtr(attr, i);
if(attr.p->data.key != 0){
jam();
continue;
}
mask.set(i);
}
}
......@@ -2961,12 +2957,9 @@ Backup::parseTableDescription(Signal* signal, BackupRecordPtr ptr, Uint32 len)
tabPtr.p->schemaVersion = tmpTab.TableVersion;
tabPtr.p->noOfAttributes = tmpTab.NoOfAttributes;
tabPtr.p->noOfKeys = tmpTab.NoOfKeyAttr;
tabPtr.p->noOfNull = 0;
tabPtr.p->noOfVariable = 0; // Computed while iterating over attribs
tabPtr.p->sz_FixedKeys = 0; // Computed while iterating over attribs
tabPtr.p->sz_FixedAttributes = 0; // Computed while iterating over attribs
tabPtr.p->variableKeyId = RNIL; // Computed while iterating over attribs
tabPtr.p->triggerIds[0] = ILLEGAL_TRIGGER_ID;
tabPtr.p->triggerIds[1] = ILLEGAL_TRIGGER_ID;
tabPtr.p->triggerIds[2] = ILLEGAL_TRIGGER_ID;
......@@ -3001,7 +2994,6 @@ Backup::parseTableDescription(Signal* signal, BackupRecordPtr ptr, Uint32 len)
attrPtr.p->data.nullable = tmp.AttributeNullableFlag;
attrPtr.p->data.fixed = (tmp.AttributeArraySize != 0);
attrPtr.p->data.key = tmp.AttributeKeyFlag;
attrPtr.p->data.sz32 = sz32;
/**
......@@ -3009,12 +3001,7 @@ Backup::parseTableDescription(Signal* signal, BackupRecordPtr ptr, Uint32 len)
* 1) Fixed
* 2) Nullable
* 3) Variable
* 4) Fixed key
* 5) Variable key
*/
if(attrPtr.p->data.key == false) {
jam();
if(attrPtr.p->data.fixed == true && attrPtr.p->data.nullable == false) {
jam();
attrPtr.p->data.offset = tabPtr.p->sz_FixedAttributes;
......@@ -3036,25 +3023,6 @@ Backup::parseTableDescription(Signal* signal, BackupRecordPtr ptr, Uint32 len)
ndbrequire(0);
}//if
} else if(attrPtr.p->data.key == true) {
jam();
ndbrequire(attrPtr.p->data.nullable == false);
if(attrPtr.p->data.fixed == true) { // Fixed key
jam();
tabPtr.p->sz_FixedKeys += sz32;
}//if
if(attrPtr.p->data.fixed == false) { // Variable key
jam();
attrPtr.p->data.offset = 0;
tabPtr.p->noOfVariable++;
ndbrequire(tabPtr.p->variableKeyId == RNIL); // Only one variable key
tabPtr.p->variableKeyId = attrPtr.i;
ndbrequire(0);
}//if
}//if
it.next(); // Move Past EndOfAttribute
}//for
return tabPtr;
......@@ -3362,7 +3330,7 @@ Backup::execBACKUP_FRAGMENT_REQ(Signal* signal)
Table & table = * tabPtr.p;
ScanFragReq * req = (ScanFragReq *)signal->getDataPtrSend();
const Uint32 parallelism = 16;
const Uint32 attrLen = 5 + table.noOfAttributes - table.noOfKeys;
const Uint32 attrLen = 5 + table.noOfAttributes;
req->senderData = filePtr.i;
req->resultRef = reference();
......@@ -3373,7 +3341,7 @@ Backup::execBACKUP_FRAGMENT_REQ(Signal* signal)
req->tableId = table.tableId;
ScanFragReq::setLockMode(req->requestInfo, 0);
ScanFragReq::setHoldLockFlag(req->requestInfo, 0);
ScanFragReq::setKeyinfoFlag(req->requestInfo, 1);
ScanFragReq::setKeyinfoFlag(req->requestInfo, 0);
ScanFragReq::setAttrLen(req->requestInfo,attrLen);
req->transId1 = 0;
req->transId2 = (BACKUP << 20) + (getOwnNodeId() << 8);
......@@ -3388,7 +3356,7 @@ Backup::execBACKUP_FRAGMENT_REQ(Signal* signal)
signal->theData[2] = (BACKUP << 20) + (getOwnNodeId() << 8);
// Return all
signal->theData[3] = table.noOfAttributes - table.noOfKeys;
signal->theData[3] = table.noOfAttributes;
signal->theData[4] = 0;
signal->theData[5] = 0;
signal->theData[6] = 0;
......@@ -3400,10 +3368,6 @@ Backup::execBACKUP_FRAGMENT_REQ(Signal* signal)
jam();
AttributePtr attr;
table.attributes.getPtr(attr, i);
if(attr.p->data.key != 0) {
jam();
continue;
}//if
AttributeHeader::init(&signal->theData[dataPos], i, 0);
dataPos++;
......@@ -3513,64 +3477,19 @@ Backup::execTRANSID_AI(Signal* signal)
}
}
void
Backup::execKEYINFO20(Signal* signal)
{
jamEntry();
const Uint32 filePtrI = signal->theData[0];
const Uint32 keyLen = signal->theData[1];
//const Uint32 scanInfo = signal->theData[2];
//const Uint32 transId1 = signal->theData[3];
//const Uint32 transId2 = signal->theData[4];
const Uint32 dataLen = signal->length() - 5;
BackupFilePtr filePtr;
c_backupFilePool.getPtr(filePtr, filePtrI);
OperationRecord & op = filePtr.p->operation;
/**
* Unpack data
*/
ndbrequire(keyLen == dataLen);
const Uint32 * src = &signal->theData[5];
const Uint32 klFixed = op.getFixedKeySize();
ndbrequire(keyLen >= klFixed);
Uint32 * dst = op.newKey();
memcpy(dst, src, klFixed << 2);
const Uint32 szLeft = (keyLen - klFixed);
if(szLeft > 0) {
jam();
src += klFixed;
dst = op.newVariableKey(szLeft);
memcpy(dst, src, (szLeft << 2));
ndbrequire(0);
}//if
if(op.finished()){
jam();
op.newRecord(op.dst);
}
}
void
Backup::OperationRecord::init(const TablePtr & ptr)
{
tablePtr = ptr.i;
noOfAttributes = (ptr.p->noOfAttributes - ptr.p->noOfKeys) + 1;
variableKeyId = ptr.p->variableKeyId;
noOfAttributes = ptr.p->noOfAttributes;
sz_Bitmask = (ptr.p->noOfNull + 31) >> 5;
sz_FixedKeys = ptr.p->sz_FixedKeys;
sz_FixedAttribs = ptr.p->sz_FixedAttributes;
if(ptr.p->noOfVariable == 0) {
jam();
maxRecordSize = 1 + sz_Bitmask + sz_FixedKeys + sz_FixedAttribs;
maxRecordSize = 1 + sz_Bitmask + sz_FixedAttribs;
} else {
jam();
maxRecordSize =
......
......@@ -76,7 +76,6 @@ protected:
*/
void execSCAN_HBREP(Signal* signal);
void execTRANSID_AI(Signal* signal);
void execKEYINFO20(Signal* signal);
void execSCAN_FRAGREF(Signal* signal);
void execSCAN_FRAGCONF(Signal* signal);
......@@ -172,8 +171,8 @@ public:
struct Data {
Uint8 nullable;
Uint8 fixed;
Uint8 key;
Uint8 unused;
Uint8 unused2;
Uint32 sz32; // No of 32 bit words
Uint32 offset; // Relative DataFixedAttributes/DataFixedKeys
Uint32 offsetNull; // In NullBitmask
......@@ -199,12 +198,9 @@ public:
Uint32 frag_mask;
Uint32 tableType;
Uint32 noOfNull;
Uint32 noOfKeys;
Uint32 noOfAttributes;
Uint32 noOfVariable;
Uint32 sz_FixedKeys;
Uint32 sz_FixedAttributes;
Uint32 variableKeyId;
Uint32 triggerIds[3];
bool triggerAllocated[3];
......@@ -224,7 +220,6 @@ public:
* Once per table
*/
void init(const TablePtr & ptr);
inline Uint32 getFixedKeySize() const { return sz_FixedKeys; }
/**
* Once per fragment
......@@ -247,23 +242,19 @@ public:
/**
* Per attribute
*/
Uint32 * newKey();
void nullAttribute(Uint32 nullOffset);
Uint32 * newNullable(Uint32 attrId, Uint32 sz);
Uint32 * newAttrib(Uint32 offset, Uint32 sz);
Uint32 * newVariable(Uint32 id, Uint32 sz);
Uint32 * newVariableKey(Uint32 sz);
private:
Uint32* base;
Uint32* dst_Length;
Uint32* dst_Bitmask;
Uint32* dst_FixedKeys;
Uint32* dst_FixedAttribs;
BackupFormat::DataFile::VariableData* dst_VariableData;
Uint32 noOfAttributes; // No of Attributes
Uint32 variableKeyId; // Id of variable key
Uint32 attrLeft; // No of attributes left
Uint32 opNoDone;
......@@ -289,7 +280,6 @@ public:
* sizes of part
*/
Uint32 sz_Bitmask;
Uint32 sz_FixedKeys;
Uint32 sz_FixedAttribs;
public:
......@@ -629,7 +619,6 @@ Backup::OperationRecord::newRecord(Uint32 * p){
base = p;
dst_Length = p; p += 1;
dst_Bitmask = p; p += sz_Bitmask;
dst_FixedKeys = p; p += sz_FixedKeys;
dst_FixedAttribs = p; p += sz_FixedAttribs;
dst_VariableData = (BackupFormat::DataFile::VariableData*)p;
BitmaskImpl::clear(sz_Bitmask, dst_Bitmask);
......@@ -646,14 +635,6 @@ Backup::OperationRecord::newAttrib(Uint32 offset, Uint32 sz){
return dst;
}
inline
Uint32 *
Backup::OperationRecord::newKey(){
attrLeft --;
attrSzLeft = 0;
return dst_FixedKeys;
}
inline
void
Backup::OperationRecord::nullAttribute(Uint32 offsetNull){
......@@ -692,21 +673,6 @@ Backup::OperationRecord::newVariable(Uint32 id, Uint32 sz){
return dst;
}
inline
Uint32 *
Backup::OperationRecord::newVariableKey(Uint32 sz){
attrLeft--;
attrSzLeft = 0;
attrSzTotal += sz;
dst = &dst_VariableData->Data[0];
dst_VariableData->Sz = htonl(sz);
dst_VariableData->Id = htonl(variableKeyId);
dst_VariableData = (BackupFormat::DataFile::VariableData *)(dst + sz);
return dst;
}
inline
bool
Backup::OperationRecord::finished(){
......@@ -714,7 +680,7 @@ Backup::OperationRecord::finished(){
return false;
}
opLen += attrSzTotal + sz_FixedKeys;
opLen += attrSzTotal;
opNoDone++;
scanStop = dst = (Uint32 *)dst_VariableData;
......
......@@ -127,7 +127,6 @@ Backup::Backup(const Configuration & conf) :
addRecSignal(GSN_SCAN_HBREP, &Backup::execSCAN_HBREP);
addRecSignal(GSN_TRANSID_AI, &Backup::execTRANSID_AI);
addRecSignal(GSN_KEYINFO20, &Backup::execKEYINFO20);
addRecSignal(GSN_SCAN_FRAGREF, &Backup::execSCAN_FRAGREF);
addRecSignal(GSN_SCAN_FRAGCONF, &Backup::execSCAN_FRAGCONF);
......
......@@ -192,13 +192,14 @@ RestoreMetaData::readGCPEntry() {
return true;
}
TableS::TableS(NdbTableImpl* tableImpl)
TableS::TableS(Uint32 version, NdbTableImpl* tableImpl)
: m_dictTable(tableImpl)
{
m_dictTable = tableImpl;
m_noOfNullable = m_nullBitmaskSize = 0;
m_auto_val_id= ~(Uint32)0;
m_max_auto_val= 0;
backupVersion = version;
for (int i = 0; i < tableImpl->getNoOfColumns(); i++)
createAttr(tableImpl->getColumn(i));
......@@ -226,11 +227,10 @@ RestoreMetaData::parseTableDescriptor(const Uint32 * data, Uint32 len)
debug << "parseTableInfo " << tableImpl->getName() << " done" << endl;
TableS * table = new TableS(tableImpl);
TableS * table = new TableS(m_fileHeader.NdbVersion, tableImpl);
if(table == NULL) {
return false;
}
table->setBackupVersion(m_fileHeader.NdbVersion);
debug << "Parsed table id " << table->getTableId() << endl;
debug << "Parsed table #attr " << table->getNoOfAttributes() << endl;
......@@ -699,7 +699,7 @@ void TableS::createAttr(NdbDictionary::Column *column)
if (d->m_column->getAutoIncrement())
m_auto_val_id= d->attrId;
if(d->m_column->getPrimaryKey() /* && not variable */)
if(d->m_column->getPrimaryKey() && backupVersion <= MAKE_VERSION(4,1,7))
{
m_fixedKeys.push_back(d);
return;
......
......@@ -140,7 +140,7 @@ class TableS {
public:
class NdbDictionary::Table* m_dictTable;
TableS (class NdbTableImpl* dictTable);
TableS (Uint32 version, class NdbTableImpl* dictTable);
~TableS();
Uint32 getTableId() const {
......
......@@ -258,6 +258,13 @@ main(int argc, char** argv)
ndbout << "Failed to read " << metaData.getFilename() << endl << endl;
return -1;
}
const BackupFormat::FileHeader & tmp = metaData.getFileHeader();
const Uint32 version = tmp.NdbVersion;
ndbout << "Ndb version in backup files: "
<< getVersionString(version, 0) << endl;
/**
* check wheater we can restore the backup (right version).
*/
......
# Copyright (C) 2004 MySQL AB
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
INCLUDES= -I$(top_srcdir)/include
DEFS= -DMYSQL_INSTANCE_MANAGER -DMYSQL_SERVER
# As all autoconf variables depend from ${prefix} and being resolved only when
# make is run, we can't put these defines to a header file (e.g. to
# make is run, we can not put these defines to a header file (e.g. to
# default_options.h, generated from default_options.h.in)
# See automake/autoconf docs for details
noinst_LIBRARIES= liboptions.a
noinst_LIBRARIES= liboptions.a libnet.a
liboptions_a_CPPFLAGS= $(CPPFLAGS) \
-DDEFAULT_PID_FILE_NAME="$(localstatedir)/mysqlmanager.pid" \
-DDEFAULT_LOG_FILE_NAME="$(localstatedir)/mysqlmanager.log" \
-DDEFAULT_SOCKET_FILE_NAME="$(localstatedir)/mysqlmanager.sock"
-DDEFAULT_SOCKET_FILE_NAME="$(localstatedir)/mysqlmanager.sock" \
-DDEFAULT_PASSWORD_FILE_NAME="$(sysconfdir)/mysqlmanager.passwd" \
-DDEFAULT_MYSQLD_PATH="$(bindir)/mysqld$(EXEEXT)" \
-DDEFAULT_USER="root" \
-DDEFAULT_PASSWORD="" \
-DDEFAULT_MONITORING_INTERVAL="5" \
-DDEFAULT_PORT="33006" \
-DPROTOCOL_VERSION=@PROTOCOL_VERSION@
liboptions_a_SOURCES= options.h options.cc priv.h priv.cc
# MySQL sometimes uses symlinks to reuse code
# All symlinked files are grouped in libnet.a
liboptions_a_SOURCES= options.h options.cc
nodist_libnet_a_SOURCES= net_serv.cc client_settings.h
libnet_a_LIBADD= $(top_builddir)/sql/password.$(OBJEXT) \
$(top_builddir)/sql/pack.$(OBJEXT) \
$(top_builddir)/sql/sql_state.$(OBJEXT) \
$(top_builddir)/sql/mini_client_errors.$(OBJEXT)\
$(top_builddir)/sql/client.$(OBJEXT)
bin_PROGRAMS = mysqlmanager
CLEANFILES= net_serv.cc client_settings.h
mysqlmanager_SOURCES= mysqlmanager.cc manager.h manager.cc log.h log.cc \
listener.h listener.cc \
thread_repository.h thread_repository.cc
net_serv.cc: Makefile
rm -f $(srcdir)/net_serv.cc
@LN_CP_F@ $(top_srcdir)/sql/net_serv.cc $(srcdir)/net_serv.cc
client_settings.h: Makefile
rm -f $(srcdir)/client_settings.h
@LN_CP_F@ $(top_srcdir)/sql/client_settings.h $(srcdir)/client_settings.h
bin_PROGRAMS= mysqlmanager
mysqlmanager_SOURCES= command.cc command.h mysqlmanager.cc \
manager.h manager.cc log.h log.cc \
thread_registry.h thread_registry.cc \
listener.h listener.cc protocol.h protocol.cc \
mysql_connection.h mysql_connection.cc \
user_map.h user_map.cc \
messages.h messages.cc \
commands.h commands.cc \
factory.h factory.cc \
instance.h instance.cc \
instance_map.h instance_map.cc\
instance_options.h instance_options.cc \
buffer.h buffer.cc parse.cc parse.h \
guardian.cc guardian.h \
mysql_manager_error.h client_func.c
mysqlmanager_LDADD= liboptions.a \
libnet.a \
$(top_builddir)/vio/libvio.a \
$(top_builddir)/mysys/libmysys.a \
$(top_builddir)/strings/libmystrings.a \
$(top_builddir)/dbug/libdbug.a
$(top_builddir)/dbug/libdbug.a \
@openssl_libs@ @ZLIB_LIBS@
tags:
ctags -R *.h *.cc
......
/* Copyright (C) 2004 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifdef __GNUC__
#pragma implementation
#endif
#include "buffer.h"
#include <m_string.h>
/*
Puts the given string to the buffer.
SYNOPSYS
append()
position start position in the buffer
string string to be put in the buffer
len_arg the length of the string. This way we can avoid some
strlens.
DESCRIPTION
The method puts a string into the buffer, starting from position .
In the case when the buffer is too small it reallocs the buffer. The
total size of the buffer is restricted with 16.
RETURN
0 - ok
1 - The buffer came to 16Mb barrier
*/
int Buffer::append(uint position, const char *string, uint len_arg)
{
if (reserve(position, len_arg))
return 1;
strnmov(buffer + position, string, len_arg);
return 0;
}
/*
Checks whether the current buffer size is ok to put a string of the length
"len_arg" starting from "position" and reallocs it if no.
SYNOPSYS
reserve()
position the number starting byte on the buffer to store a buffer
len_arg the length of the string.
DESCRIPTION
The method checks whether it is possible to pus a string of teh "len_arg"
length into the buffer, starting from "position" byte. In the case when the
buffer is too small it reallocs the buffer. The total size of the buffer is
restricted with 16 Mb.
RETURN
0 - ok
1 - The buffer came to 16Mb barrier
*/
int Buffer::reserve(uint position, uint len_arg)
{
if (position + len_arg >= MAX_BUFFER_SIZE)
goto err;
if (position + len_arg>= buffer_size)
{
buffer= (char *) realloc(buffer,
min(MAX_BUFFER_SIZE,
max((uint) (buffer_size*1.5),
position + len_arg)));
if (buffer= NULL)
goto err;
buffer_size= (uint) (buffer_size*1.5);
}
return 0;
err:
return 1;
}
#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_BUFFER_H
#define INCLUDES_MYSQL_INSTANCE_MANAGER_BUFFER_H
/* Copyright (C) 2004 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <my_global.h>
#ifdef __GNUC__
#pragma interface
#endif
/*
This class is a simple implementation of the buffer of varying size.
It is used to store MySQL client-server protocol packets. This is why
the maximum buffer size if 16Mb. (See internals manual section
7. MySQL Client/Server Protocol)
*/
class Buffer
{
private:
enum { BUFFER_INITIAL_SIZE= 4096 };
/* maximum buffer size is 16Mb */
enum { MAX_BUFFER_SIZE= 16777216 };
size_t buffer_size;
public:
Buffer()
{
buffer=(char *) malloc(BUFFER_INITIAL_SIZE);
buffer_size= BUFFER_INITIAL_SIZE;
}
~Buffer()
{
free(buffer);
}
public:
char *buffer;
int append(uint position, const char *string, uint len_arg);
int reserve(uint position, uint len_arg);
};
#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_BUFFER_H */
#include <my_global.h>
#include <my_sys.h>
#include <mysql.h>
/*
Currently we cannot use libmysqlclient directly becouse of the linking
issues. Here we provide needed libmysqlclient functions.
TODO: to think how to use libmysqlclient code instead of copy&paste.
The other possible solution is to use simple_command directly.
*/
const char * STDCALL
mysql_get_server_info(MYSQL *mysql)
{
return((char*) mysql->server_version);
}
int STDCALL
mysql_ping(MYSQL *mysql)
{
DBUG_ENTER("mysql_ping");
DBUG_RETURN(simple_command(mysql,COM_PING,0,0,0));
}
int STDCALL
mysql_shutdown(MYSQL *mysql, enum mysql_enum_shutdown_level shutdown_level)
{
uchar level[1];
DBUG_ENTER("mysql_shutdown");
level[0]= (uchar) shutdown_level;
DBUG_RETURN(simple_command(mysql, COM_SHUTDOWN, (char *)level, 1, 0));
}
/* Copyright (C) 2004 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifdef __GNUC__
#pragma implementation
#endif
#include "command.h"
Command::Command(Instance_map *instance_map_arg)
:instance_map(instance_map_arg)
{}
Command::~Command()
{}
#ifdef __GNUC__
FIX_GCC_LINKING_PROBLEM
#endif
#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_COMMAND_H
#define INCLUDES_MYSQL_INSTANCE_MANAGER_COMMAND_H
/* Copyright (C) 2004 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifdef __GNUC__
#pragma interface
#endif
#include <my_global.h>
/* Class responsible for allocation of im commands. */
class Instance_map;
/*
Command - entry point for any command.
GangOf4: 'Command' design pattern
*/
class Command
{
public:
Command(Instance_map *instance_map_arg= 0);
virtual ~Command();
/* method of executing: */
virtual int execute(struct st_net *net, ulong connection_id) = 0;
protected:
Instance_map *instance_map;
};
#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_COMMAND_H */
This diff is collapsed.
#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_COMMANDS_H
#define INCLUDES_MYSQL_INSTANCE_MANAGER_COMMANDS_H
/* Copyright (C) 2004 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "instance.h"
#include "my_global.h"
/*
Print all instances of this instance manager.
Grammar: SHOW ISTANCES
*/
class Show_instances : public Command
{
public:
Show_instances(Instance_map *instance_map_arg): Command(instance_map_arg)
{}
int do_command(struct st_net *net);
int execute(struct st_net *net, ulong connection_id);
};
/*
Reread configuration file and refresh instance map.
Grammar: FLUSH INSTANCES
*/
class Flush_instances : public Command
{
public:
Flush_instances(Instance_map *instance_map_arg): Command(instance_map_arg)
{}
int execute(struct st_net *net, ulong connection_id);
};
/*
Print status of an instance.
Grammar: SHOW ISTANCE STATUS <instance_name>
*/
class Show_instance_status : public Command
{
public:
Show_instance_status(Instance_map *instance_map_arg, const char *name, uint len);
int do_command(struct st_net *net, const char *instance_name);
int execute(struct st_net *net, ulong connection_id);
const char *instance_name;
};
/*
Print options if chosen instance.
Grammar: SHOW INSTANCE OPTIONS <instance_name>
*/
class Show_instance_options : public Command
{
public:
Show_instance_options(Instance_map *instance_map_arg, const char *name, uint len);
int execute(struct st_net *net, ulong connection_id);
int do_command(struct st_net *net, const char *instance_name);
const char *instance_name;
};
/*
Start an instance.
Grammar: START INSTANCE <instance_name>
*/
class Start_instance : public Command
{
public:
Start_instance(Instance_map *instance_map_arg, const char *name, uint len);
int execute(struct st_net *net, ulong connection_id);
const char *instance_name;
Instance *instance;
};
/*
Stop an instance.
Grammar: STOP INSTANCE <instance_name>
*/
class Stop_instance : public Command
{
public:
Stop_instance(Instance_map *instance_map_arg, const char *name, uint len);
Instance *instance;
int execute(struct st_net *net, ulong connection_id);
const char *instance_name;
};
/*
Syntax error command. This command is issued if parser reported a syntax error.
We need it to distinguish the parse error and the situation when parser internal
error occured. E.g. parsing failed because we hadn't had enought memory. In the
latter case parse_command() should return an error.
*/
class Syntax_error : public Command
{
public:
int execute(struct st_net *net, ulong connection_id);
};
#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_COMMANDS_H */
/* Copyright (C) 2004 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "factory.h"
#include "my_global.h"
#include <stdio.h>
#include <ctype.h>
Show_instances *Command_factory::new_Show_instances()
{
return new Show_instances(&instance_map);
}
Flush_instances *Command_factory::new_Flush_instances()
{
return new Flush_instances(&instance_map);
}
Show_instance_status *Command_factory::
new_Show_instance_status(const char *name, uint len)
{
return new Show_instance_status(&instance_map, name, len);
}
Show_instance_options *Command_factory::
new_Show_instance_options(const char *name, uint len)
{
return new Show_instance_options(&instance_map, name, len);
}
Start_instance *Command_factory::
new_Start_instance(const char *name, uint len)
{
return new Start_instance(&instance_map, name, len);
}
Stop_instance *Command_factory::new_Stop_instance(const char *name, uint len)
{
return new Stop_instance(&instance_map, name, len);
}
Syntax_error *Command_factory::new_Syntax_error()
{
return new Syntax_error();
}
#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_FACTORY_H
#define INCLUDES_MYSQL_INSTANCE_MANAGER_FACTORY_H
/* Copyright (C) 2004 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "command.h"
#include "commands.h"
#include "instance_map.h"
/*
This class could be used to handle various protocols. We could pass to
the parser various derived classes. I.e Mylsq_command_factory,
Http_command_factory e.t.c. Also see comment in the instance_map.cc
*/
class Command_factory
{
public:
Command_factory(Instance_map &instance_map): instance_map(instance_map)
{}
Show_instances *new_Show_instances ();
Show_instance_status *new_Show_instance_status (const char *name, uint len);
Show_instance_options *new_Show_instance_options (const char *name, uint len);
Start_instance *new_Start_instance (const char *name, uint len);
Stop_instance *new_Stop_instance (const char *name, uint len);
Flush_instances *new_Flush_instances ();
Syntax_error *new_Syntax_error ();
Instance_map &instance_map;
};
#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_FACTORY_H */
/* Copyright (C) 2004 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifdef __GNUC__
#pragma implementation
#endif
#include "guardian.h"
#include "instance_map.h"
#include "mysql_manager_error.h"
#include "log.h"
#include <string.h>
C_MODE_START
pthread_handler_decl(guardian, arg)
{
Guardian_thread *guardian_thread= (Guardian_thread *) arg;
guardian_thread->run();
return 0;
}
C_MODE_END
Guardian_thread::Guardian_thread(Thread_registry &thread_registry_arg,
Instance_map *instance_map_arg,
uint monitoring_interval_arg) :
Guardian_thread_args(thread_registry_arg, instance_map_arg,
monitoring_interval_arg),
thread_info(pthread_self())
{
pthread_mutex_init(&LOCK_guardian, 0);
thread_registry.register_thread(&thread_info);
init_alloc_root(&alloc, MEM_ROOT_BLOCK_SIZE, 0);
guarded_instances= NULL;
starting_instances= NULL;
}
Guardian_thread::~Guardian_thread()
{
/* delay guardian destruction to the moment when no one needs it */
pthread_mutex_lock(&LOCK_guardian);
free_root(&alloc, MYF(0));
thread_registry.unregister_thread(&thread_info);
pthread_mutex_unlock(&LOCK_guardian);
pthread_mutex_destroy(&LOCK_guardian);
}
/*
Run guardian thread
SYNOPSYS
run()
DESCRIPTION
Check for all guarded instances and restart them if needed. If everything
is fine go and sleep for some time.
*/
void Guardian_thread::run()
{
Instance *instance;
LIST *loop;
my_thread_init();
while (!thread_registry.is_shutdown())
{
pthread_mutex_lock(&LOCK_guardian);
loop= guarded_instances;
while (loop != NULL)
{
instance= (Instance *) loop->data;
/* instance-> start already checks whether instance is running */
if (instance->start() != ER_INSTANCE_ALREADY_STARTED)
log_info("guardian attempted to restart instance %s",
instance->options.instance_name);
loop= loop->next;
}
move_to_list(&starting_instances, &guarded_instances);
pthread_mutex_unlock(&LOCK_guardian);
sleep(monitoring_interval);
}
my_thread_end();
}
int Guardian_thread::start()
{
Instance *instance;
Instance_map::Iterator iterator(instance_map);
instance_map->lock();
while (instance= iterator.next())
{
if ((instance->options.is_guarded != NULL) && (instance->is_running()))
if (guard(instance))
return 1;
}
instance_map->unlock();
return 0;
}
/*
Start instance guarding
SYNOPSYS
guard()
instance the instance to be guarded
DESCRIPTION
The instance is added to the list of starting instances. Then after one guardian
loop it is moved to the guarded instances list. Usually guard() is called after we
start an instance, so we need to give some time to the instance to start.
RETURN
0 - ok
1 - error occured
*/
int Guardian_thread::guard(Instance *instance)
{
return add_instance_to_list(instance, &starting_instances);
}
void Guardian_thread::move_to_list(LIST **from, LIST **to)
{
LIST *tmp;
while (*from)
{
tmp= rest(*from);
*to= list_add(*to, *from);
*from= tmp;
}
}
int Guardian_thread::add_instance_to_list(Instance *instance, LIST **list)
{
LIST *node;
node= (LIST *) alloc_root(&alloc, sizeof(LIST));
if (node == NULL)
return 1;
/* we store the pointers to instances from the instance_map's MEM_ROOT */
node->data= (void *) instance;
pthread_mutex_lock(&LOCK_guardian);
*list= list_add(*list, node);
pthread_mutex_unlock(&LOCK_guardian);
return 0;
}
/*
TODO: perhaps it would make sense to create a pool of the LIST elements
elements and give them upon request. Now we are loosing a bit of memory when
guarded instance was stopped and then restarted (since we cannot free just
a piece of the MEM_ROOT).
*/
int Guardian_thread::stop_guard(Instance *instance)
{
LIST *node;
pthread_mutex_lock(&LOCK_guardian);
node= guarded_instances;
while (node != NULL)
{
/*
We compare only pointers, as we always use pointers from the
instance_map's MEM_ROOT.
*/
if ((Instance *) node->data == instance)
{
guarded_instances= list_delete(guarded_instances, node);
pthread_mutex_unlock(&LOCK_guardian);
return 0;
}
else
node= node->next;
}
pthread_mutex_unlock(&LOCK_guardian);
/* if there is nothing to delete it is also fine */
return 0;
}
#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_GUARDIAN_H
#define INCLUDES_MYSQL_INSTANCE_MANAGER_GUARDIAN_H
/* Copyright (C) 2004 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <my_global.h>
#include <my_sys.h>
#include <my_list.h>
#ifdef __GNUC__
#pragma interface
#endif
class Instance_map;
#include "thread_registry.h"
#include "instance.h"
C_MODE_START
pthread_handler_decl(guardian, arg);
C_MODE_END
struct Guardian_thread_args
{
Thread_registry &thread_registry;
Instance_map *instance_map;
uint monitoring_interval;
Guardian_thread_args(Thread_registry &thread_registry_arg,
Instance_map *instance_map_arg,
uint monitoring_interval_arg) :
thread_registry(thread_registry_arg),
instance_map(instance_map_arg),
monitoring_interval(monitoring_interval_arg)
{}
};
/*
The guardian thread is responsible for monitoring and restarting of guarded
instances.
*/
class Guardian_thread: public Guardian_thread_args
{
public:
Guardian_thread(Thread_registry &thread_registry_arg,
Instance_map *instance_map_arg,
uint monitoring_interval_arg);
~Guardian_thread();
void run();
int init();
int start();
int guard(Instance *instance);
int stop_guard(Instance *instance);
private:
int add_instance_to_list(Instance *instance, LIST **list);
void move_to_list(LIST **from, LIST **to);
private:
pthread_mutex_t LOCK_guardian;
Thread_info thread_info;
LIST *guarded_instances;
LIST *starting_instances;
MEM_ROOT alloc;
enum { MEM_ROOT_BLOCK_SIZE= 512 };
};
#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_GUARDIAN_H */
/* Copyright (C) 2004 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifdef __GNUC__
#pragma implementation
#endif
#include "instance.h"
#include "mysql_manager_error.h"
#include "log.h"
#include <my_sys.h>
#include <signal.h>
#include <m_string.h>
#include <sys/wait.h>
/*
The method starts an instance.
SYNOPSYS
start()
RETURN
0 ok
ER_CANNOT_START_INSTANCE Cannot start instance
ER_INSTANCE_ALREADY_STARTED The instance on the specified port/socket
is already started
*/
int Instance::start()
{
pid_t pid;
if (!is_running())
{
log_info("trying to start instance %s", options.instance_name);
switch (pid= fork()) {
case 0:
if (fork()) /* zombie protection */
exit(0); /* parent goes bye-bye */
else
{
execv(options.mysqld_path, options.argv);
exit(1);
}
case -1:
return ER_CANNOT_START_INSTANCE;
default:
waitpid(pid, NULL, 0);
return 0;
}
}
/* the instance is started already */
return ER_INSTANCE_ALREADY_STARTED;
}
int Instance::cleanup()
{
/*
We cannot close connection in destructor, as mysql_close needs alarm
services which are definitely unavailaible at the time of destructor
call.
*/
if (is_connected)
mysql_close(&mysql);
return 0;
}
Instance::~Instance()
{
pthread_mutex_destroy(&LOCK_instance);
}
bool Instance::is_running()
{
uint port;
const char *socket;
if (options.mysqld_port)
port= atoi(strchr(options.mysqld_port, '=') + 1);
if (options.mysqld_socket)
socket= strchr(options.mysqld_socket, '=') + 1;
pthread_mutex_lock(&LOCK_instance);
if (!is_connected)
{
mysql_init(&mysql);
if (mysql_real_connect(&mysql, LOCAL_HOST, options.mysqld_user,
options.mysqld_password,
NullS, port,
socket, 0))
{
is_connected= TRUE;
pthread_mutex_unlock(&LOCK_instance);
return TRUE;
}
mysql_close(&mysql);
pthread_mutex_unlock(&LOCK_instance);
return FALSE;
}
else if (!mysql_ping(&mysql))
{
pthread_mutex_unlock(&LOCK_instance);
return TRUE;
}
pthread_mutex_unlock(&LOCK_instance);
return FALSE;
}
/*
Stop an instance.
SYNOPSYS
stop()
RETURN:
0 ok
ER_INSTANCE_IS_NOT_STARTED Looks like the instance it is not started
ER_STOP_INSTANCE mysql_shutdown reported an error
*/
int Instance::stop()
{
if (is_running())
{
if (mysql_shutdown(&mysql, SHUTDOWN_DEFAULT))
goto err;
mysql_close(&mysql);
is_connected= FALSE;
return 0;
}
return ER_INSTANCE_IS_NOT_STARTED;
err:
return ER_STOP_INSTANCE;
}
/*
We execute this function to initialize instance parameters.
Return value: 0 - ok. 1 - unable to init DYNAMIC_ARRAY.
*/
int Instance::init(const char *name_arg)
{
pthread_mutex_init(&LOCK_instance, 0);
return options.init(name_arg);
}
#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_H
#define INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_H
/* Copyright (C) 2004 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <my_global.h>
#include <my_sys.h>
#include <mysql.h>
#include "instance_options.h"
#ifdef __GNUC__
#pragma interface
#endif
class Instance
{
public:
Instance(): is_connected(FALSE)
{}
~Instance();
int init(const char *name);
/* check if the instance is running and set up mysql connection if yes */
bool is_running();
int start();
int stop();
int cleanup();
public:
Instance_options options;
/* connection to the instance */
MYSQL mysql;
private:
/*
Mutex protecting the instance. Currently we use it to avoid the
double start of the instance. This happens when the instance is starting
and we issue the start command once more.
*/
pthread_mutex_t LOCK_instance;
/* Here we store the state of the following connection */
bool is_connected;
};
#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_H */
/* Copyright (C) 2004 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifdef __GNUC__
#pragma implementation
#endif
#include "instance_map.h"
#include "buffer.h"
#include "instance.h"
#include <m_ctype.h>
#include <my_sys.h>
#include <mysql_com.h>
#include <m_string.h>
/*
Note: As we are going to suppost different types of connections,
we shouldn't have connection-specific functions. To avoid it we could
put such functions to the Command-derived class instead.
The command could be easily constructed for a specific connection if
we would provide a special factory for each connection.
*/
C_MODE_START
/* Procedure needed for HASH initialization */
static byte* get_instance_key(const byte* u, uint* len,
my_bool __attribute__((unused)) t)
{
const Instance *instance= (const Instance *) u;
*len= instance->options.instance_name_len;
return (byte *) instance->options.instance_name;
}
static void delete_instance(void *u)
{
Instance *instance= (Instance *) u;
delete instance;
}
/*
The option handler to pass to the process_default_option_files finction.
SYNOPSYS
process_option()
ctx Handler context. Here it is an instance_map structure.
group_name The name of the group the option belongs to.
option The very option to be processed. It is already
prepared to be used in argv (has -- prefix)
DESCRIPTION
This handler checks whether a group is an instance group and adds
an option to the appropriate instance class. If this is the first
occurence of an instance name, we'll also create the instance
with such name and add it to the instance map.
RETURN
0 - ok
1 - error occured
*/
static int process_option(void * ctx, const char *group, const char *option)
{
Instance_map *map= NULL;
Instance *instance= NULL;
static const char prefix[]= { 'm', 'y', 's', 'q', 'l', 'd' };
map = (Instance_map*) ctx;
if (strncmp(group, prefix, sizeof prefix) == 0 &&
(my_isdigit(default_charset_info, group[sizeof prefix])))
{
if ((instance= map->find(group, strlen(group))) == NULL)
{
if ((instance= new Instance) == 0)
goto err_new_instance;
if (instance->init(group))
goto err;
if (map->add_instance(instance))
goto err;
}
if (instance->options.add_option(option))
goto err;
}
return 0;
err:
delete instance;
err_new_instance:
return 1;
}
C_MODE_END
Instance_map::Instance_map(const char *default_mysqld_path_arg,
const char *default_admin_user_arg,
const char *default_admin_password_arg)
{
mysqld_path= default_mysqld_path_arg;
user= default_admin_user_arg;
password= default_admin_password_arg;
pthread_mutex_init(&LOCK_instance_map, 0);
}
int Instance_map::init()
{
if (hash_init(&hash, default_charset_info, START_HASH_SIZE, 0, 0,
get_instance_key, delete_instance, 0))
return 1;
return 0;
}
Instance_map::~Instance_map()
{
pthread_mutex_lock(&LOCK_instance_map);
hash_free(&hash);
pthread_mutex_unlock(&LOCK_instance_map);
pthread_mutex_destroy(&LOCK_instance_map);
}
int Instance_map::lock()
{
return pthread_mutex_lock(&LOCK_instance_map);
}
int Instance_map::unlock()
{
return pthread_mutex_unlock(&LOCK_instance_map);
}
int Instance_map::flush_instances()
{
int rc;
pthread_mutex_lock(&LOCK_instance_map);
hash_free(&hash);
hash_init(&hash, default_charset_info, START_HASH_SIZE, 0, 0,
get_instance_key, delete_instance, 0);
pthread_mutex_unlock(&LOCK_instance_map);
rc= load();
return rc;
}
int Instance_map::add_instance(Instance *instance)
{
return my_hash_insert(&hash, (byte *) instance);
}
Instance *
Instance_map::find(const char *name, uint name_len)
{
Instance *instance;
pthread_mutex_lock(&LOCK_instance_map);
instance= (Instance *) hash_search(&hash, (byte *) name, name_len);
pthread_mutex_unlock(&LOCK_instance_map);
return instance;
}
void Instance_map::complete_initialization()
{
Instance *instance;
uint i= 0;
while (i < hash.records)
{
instance= (Instance *) hash_element(&hash, i);
instance->options.complete_initialization(mysqld_path, user, password);
i++;
}
}
int Instance_map::cleanup()
{
Instance *instance;
uint i= 0;
while (i < hash.records)
{
instance= (Instance *) hash_element(&hash, i);
instance->cleanup();
i++;
}
}
Instance *
Instance_map::find(uint instance_number)
{
Instance *instance;
char name[80];
sprintf(name, "mysqld%i", instance_number);
pthread_mutex_lock(&LOCK_instance_map);
instance= (Instance *) hash_search(&hash, (byte *) name, strlen(name));
pthread_mutex_unlock(&LOCK_instance_map);
return instance;
}
/* load options from config files and create appropriate instance structures */
int Instance_map::load()
{
int error;
error= process_default_option_files("my", process_option, (void *) this);
complete_initialization();
return error;
}
/*--- Implementaton of the Instance map iterator class ---*/
void Instance_map::Iterator::go_to_first()
{
current_instance=0;
}
Instance *Instance_map::Iterator::next()
{
if (current_instance < instance_map->hash.records)
return (Instance *) hash_element(&instance_map->hash, current_instance++);
else
return NULL;
}
#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_MAP_H
#define INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_MAP_H
/* Copyright (C) 2004 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <my_global.h>
#include <my_sys.h>
#include <hash.h>
#ifdef __GNUC__
#pragma interface
#endif
#include "protocol.h"
#include "guardian.h"
class Instance;
extern int load_all_groups(char ***groups, const char *filename);
extern void free_groups(char **groups);
/*
Instance_map - stores all existing instances
*/
class Instance_map
{
friend class Iterator;
public:
/* Instance_map iterator */
class Iterator
{
private:
uint current_instance;
Instance_map *instance_map;
public:
Iterator(Instance_map *instance_map_arg) :
current_instance(0), instance_map(instance_map_arg)
{}
void go_to_first();
Instance *next();
};
public:
/* returns a pointer to the instance or NULL, if there is no such instance */
Instance *find(const char *name, uint name_len);
Instance *find(uint instance_number);
int flush_instances();
int cleanup();
int lock();
int unlock();
int init();
Instance_map(const char *default_mysqld_path_arg,
const char *default_admin_user_arg,
const char *default_admin_password_arg);
~Instance_map();
/* loads options from config files */
int load();
/* adds instance to internal hash */
int add_instance(Instance *instance);
/* inits instances argv's after all options have been loaded */
void complete_initialization();
public:
const char *mysqld_path;
/* user an password to shutdown MySQL */
const char *user;
const char *password;
Guardian_thread *guardian;
private:
enum { START_HASH_SIZE = 16 };
pthread_mutex_t LOCK_instance_map;
HASH hash;
};
#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_MAP_H */
/* Copyright (C) 2004 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifdef __GNUC__
#pragma implementation
#endif
#include "instance_options.h"
#include <my_sys.h>
#include <mysql.h>
#include <signal.h>
#include <m_string.h>
int Instance_options::complete_initialization(const char *default_path,
const char *default_user,
const char *default_password)
{
/* we need to reserve space for the final zero + possible default options */
if (!(argv= (char**) alloc_root(&alloc, (options_array.elements + 1
+ MAX_NUMBER_OF_DEFAULT_OPTIONS) * sizeof(char*))))
goto err;
if (mysqld_path == NULL)
{
if (!(mysqld_path= strdup_root(&alloc, default_path)))
goto err;
}
/* this option must be first in the argv */
if (add_to_argv(mysqld_path))
goto err;
/* the following options are not for argv */
if (mysqld_user == NULL)
{
if (!(mysqld_user= strdup_root(&alloc, default_user)))
goto err;
}
if (mysqld_password == NULL)
{
if (!(mysqld_password= strdup_root(&alloc, default_password)))
goto err;
}
memcpy((gptr) (argv + filled_default_options), options_array.buffer,
options_array.elements*sizeof(char*));
argv[filled_default_options + options_array.elements]= 0;
return 0;
err:
return 1;
}
/*
Assigns given value to the appropriate option from the class.
SYNOPSYS
add_option()
option string with the option prefixed by --
DESCRIPTION
The method is called from the option handling routine.
RETURN
0 - ok
1 - error occured
*/
int Instance_options::add_option(const char* option)
{
char *tmp;
enum { SAVE_VALUE= 1, SAVE_WHOLE, SAVE_WHOLE_AND_ADD };
struct selected_options_st
{
const char *name;
uint length;
const char **value;
uint type;
} options[]=
{
{"--socket=", 9, &mysqld_socket, SAVE_WHOLE_AND_ADD},
{"--port=", 7, &mysqld_port, SAVE_WHOLE_AND_ADD},
{"--datadir=", 10, &mysqld_datadir, SAVE_WHOLE_AND_ADD},
{"--bind-address=", 15, &mysqld_bind_address, SAVE_WHOLE_AND_ADD},
{"--pid-file=", 11, &mysqld_pid_file, SAVE_WHOLE_AND_ADD},
{"--mysqld_path=", 14, &mysqld_path, SAVE_VALUE},
{"--admin_user=", 13, &mysqld_user, SAVE_VALUE},
{"--admin_password=", 17, &mysqld_password, SAVE_VALUE},
{"--guarded", 9, &is_guarded, SAVE_WHOLE},
{NULL, 0, NULL, 0}
};
struct selected_options_st *selected_options;
if (!(tmp= strdup_root(&alloc, option)))
goto err;
for (selected_options= options; selected_options->name; selected_options++)
{
if (!strncmp(tmp, selected_options->name, selected_options->length))
switch(selected_options->type){
case SAVE_WHOLE_AND_ADD:
*(selected_options->value)= tmp;
insert_dynamic(&options_array,(gptr) &tmp);
return 0;
case SAVE_VALUE:
*(selected_options->value)= strchr(tmp, '=') + 1;
return 0;
case SAVE_WHOLE:
*(selected_options->value)= tmp;
return 0;
defaut:
break;
}
}
return 0;
err:
return 1;
}
int Instance_options::add_to_argv(const char* option)
{
DBUG_ASSERT(filled_default_options < MAX_NUMBER_OF_DEFAULT_OPTIONS);
if (option != NULL)
argv[filled_default_options++]= (char *) option;
return 0;
}
/*
We execute this function to initialize some options.
Return value: 0 - ok. 1 - unable to allocate memory.
*/
int Instance_options::init(const char *instance_name_arg)
{
instance_name_len= strlen(instance_name_arg);
init_alloc_root(&alloc, MEM_ROOT_BLOCK_SIZE, 0);
if (my_init_dynamic_array(&options_array, sizeof(char *), 0, 32))
goto err;
if (!(instance_name= strmake_root(&alloc, (char *) instance_name_arg,
instance_name_len)))
goto err;
return 0;
err:
return 1;
}
Instance_options::~Instance_options()
{
free_root(&alloc, MYF(0));
delete_dynamic(&options_array);
}
#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_OPTIONS_H
#define INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_OPTIONS_H
/* Copyright (C) 2004 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <my_global.h>
#include <my_sys.h>
#ifdef __GNUC__
#pragma interface
#endif
/*
This class contains options of an instance and methods to operate them.
We do not provide this class with the means of synchronization as it is
supposed that options for instances are all loaded at once during the
instance_map initilization and we do not change them later. This way we
don't have to synchronize between threads.
*/
class Instance_options
{
public:
Instance_options() :
mysqld_socket(0), mysqld_datadir(0), mysqld_bind_address(0),
mysqld_pid_file(0), mysqld_port(0), mysqld_path(0), mysqld_user(0),
mysqld_password(0), is_guarded(0), filled_default_options(0)
{}
~Instance_options();
/* fills in argv */
int complete_initialization(const char *default_path,
const char *default_user,
const char *default_password);
int add_option(const char* option);
int init(const char *instance_name_arg);
public:
enum { MAX_NUMBER_OF_DEFAULT_OPTIONS= 1 };
enum { MEM_ROOT_BLOCK_SIZE= 512 };
char **argv;
/* We need the some options, so we store them as a separate pointers */
const char *mysqld_socket;
const char *mysqld_datadir;
const char *mysqld_bind_address;
const char *mysqld_pid_file;
const char *mysqld_port;
uint instance_name_len;
const char *instance_name;
const char *mysqld_path;
const char *mysqld_user;
const char *mysqld_password;
const char *is_guarded;
DYNAMIC_ARRAY options_array;
private:
int add_to_argv(const char *option);
private:
uint filled_default_options;
MEM_ROOT alloc;
};
#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_OPTIONS_H */
This diff is collapsed.
#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_LISTENER_H
#define INCLUDES_MYSQL_INSTANCE_MANAGER_LISTENER_H
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
/* Copyright (C) 2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -23,23 +23,34 @@
#include <my_global.h>
#include <my_pthread.h>
C_MODE_START
pthread_handler_decl(listener, arg);
C_MODE_END
class Thread_repository;
class Thread_registry;
class Options;
class User_map;
class Instance_map;
struct Listener_thread_args
{
Thread_repository &thread_repository;
const char *socket_file_name;
Listener_thread_args(Thread_repository &thread_repository_arg,
const char *socket_file_name_arg) :
thread_repository(thread_repository_arg),
socket_file_name(socket_file_name_arg) {}
Thread_registry &thread_registry;
const Options &options;
const User_map &user_map;
Instance_map &instance_map;
Listener_thread_args(Thread_registry &thread_registry_arg,
const Options &options_arg,
const User_map &user_map_arg,
Instance_map &instance_map_arg) :
thread_registry(thread_registry_arg)
,options(options_arg)
,user_map(user_map_arg)
,instance_map(instance_map_arg)
{}
};
#endif
#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_LISTENER_H
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
/* Copyright (C) 2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -139,7 +139,7 @@ void print_error(const char *format, ...)
}
/*
init_logs()
log_init()
RETURN VALUE
0 ok
!0 error
......
#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_LOG_H
#define INCLUDES_MYSQL_INSTANCE_MANAGER_LOG_H
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
/* Copyright (C) 2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -22,11 +22,8 @@
Two logging streams are supported: error log and info log. Additionally
libdbug may be used for debug information output.
ANSI C buffered I/O is used to perform logging.
Logging may be performed in two modes:
- console application mode (default), stdout/stderr is used for logging
init_logs() must be called to initialize logging environment
- daemon mode, without controlling terminal, call
init_logs_in_daemon_mode() to initialize
Logging is performed via stdout/stder, so one can reopen them to point to
ordinary files. To initialize loggin environment log_init() must be called.
Rationale:
- no MYSQL_LOG as it has BIN mode, and not easy to fetch from sql_class.h
......
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
/* Copyright (C) 2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -17,46 +17,175 @@
#include "manager.h"
#include <my_global.h>
#include <my_sys.h>
#include <m_string.h>
#include <signal.h>
#include <thr_alarm.h>
#include "thread_repository.h"
#include "thread_registry.h"
#include "listener.h"
#include "instance_map.h"
#include "options.h"
#include "user_map.h"
#include "log.h"
#include "guardian.h"
static int create_pid_file(const char *pid_file_name)
{
if (FILE *pid_file= my_fopen(pid_file_name,
O_WRONLY | O_CREAT | O_BINARY, MYF(0)))
{
fprintf(pid_file, "%d\n", (int) getpid());
my_fclose(pid_file, MYF(0));
}
else
{
log_error("can't create pid file %s: errno=%d, %s",
pid_file_name, errno, strerror(errno));
return 1;
}
return 0;
}
void manager(const char *socket_file_name)
/*
manager - entry point to the main instance manager process: start
listener thread, write pid file and enter into signal handling.
See also comments in mysqlmanager.cc to picture general Instance Manager
architecture.
*/
void manager(const Options &options)
{
Thread_repository thread_repository;
Listener_thread_args listener_args(thread_repository, socket_file_name);
Thread_registry thread_registry;
/*
All objects created in the manager() function live as long as
thread_registry lives, and thread_registry is alive until there are
working threads.
*/
User_map user_map;
Instance_map instance_map(options.default_mysqld_path,
options.default_admin_user,
options.default_admin_password);
Guardian_thread guardian_thread(thread_registry,
&instance_map,
options.monitoring_interval);
Listener_thread_args listener_args(thread_registry, options, user_map,
instance_map);
instance_map.guardian= &guardian_thread;
if (instance_map.init() || user_map.init() || instance_map.load() ||
user_map.load(options.password_file_name))
return;
/* write pid file */
if (create_pid_file(options.pid_file_name))
return;
/* block signals */
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGTERM);
sigaddset(&mask, SIGPIPE);
sigaddset(&mask, SIGHUP);
/*
We want this signal to be blocked in all theads but the signal
one. It is needed for the thr_alarm subsystem to work.
*/
sigaddset(&mask,THR_SERVER_ALARM);
/* all new threads will inherite this signal mask */
pthread_sigmask(SIG_BLOCK, &mask, NULL);
{
/* create the listener */
{
pthread_t listener_thd_id;
pthread_attr_t listener_thd_attr;
int rc;
pthread_attr_init(&listener_thd_attr);
pthread_attr_setdetachstate(&listener_thd_attr, PTHREAD_CREATE_DETACHED);
if (pthread_create(&listener_thd_id, &listener_thd_attr, listener,
&listener_args))
die("manager(): pthread_create(listener) failed");
rc= pthread_create(&listener_thd_id, &listener_thd_attr, listener,
&listener_args);
pthread_attr_destroy(&listener_thd_attr);
if (rc)
{
log_error("manager(): pthread_create(listener) failed");
goto err;
}
}
/* create guardian thread */
{
pthread_t guardian_thd_id;
pthread_attr_t guardian_thd_attr;
int rc;
pthread_attr_init(&guardian_thd_attr);
pthread_attr_setdetachstate(&guardian_thd_attr, PTHREAD_CREATE_DETACHED);
rc= pthread_create(&guardian_thd_id, &guardian_thd_attr, guardian,
&guardian_thread);
pthread_attr_destroy(&guardian_thd_attr);
if (rc)
{
log_error("manager(): pthread_create(guardian) failed");
goto err;
}
}
/*
To work nicely with LinuxThreads, the signal thread is the first thread
in the process.
*/
int signo;
my_sigwait(&mask, &signo);
thread_repository.deliver_shutdown();
bool shutdown_complete;
shutdown_complete= FALSE;
/*
In our case the signal thread also implements functions of alarm thread.
Here we init alarm thread functionality. We suppose that we won't have
more then 10 alarms at the same time.
*/
init_thr_alarm(10);
/*
Now we can init the list of guarded instances. We have to do it after
alarm structures initialization as we have to use net_* functions while
making the list. And they in their turn need alarms for timeout suppport.
*/
guardian_thread.start();
signal(SIGPIPE, SIG_IGN);
while (!shutdown_complete)
{
sigwait(&mask, &signo);
switch (signo)
{
case THR_SERVER_ALARM:
process_alarm(signo);
break;
default:
thread_registry.deliver_shutdown();
shutdown_complete= TRUE;
break;
}
}
err:
/* delete the pid file */
my_delete(options.pid_file_name, MYF(0));
/* close permanent connections to the running instances */
instance_map.cleanup();
/* free alarm structures */
end_thr_alarm(1);
/* don't pthread_exit to kill all threads who did not shut down in time */
}
#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_MANAGER_H
#define INCLUDES_MYSQL_INSTANCE_MANAGER_MANAGER_H
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
/* Copyright (C) 2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -16,6 +16,8 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
void manager(const char *socket_file_name);
class Options;
void manager(const Options &options);
#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_MANAGER_H
/* Copyright (C) 2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "messages.h"
#include <my_global.h>
#include <mysql_com.h>
#include <assert.h>
static const char *mysqld_error_message(unsigned sql_errno)
{
switch (sql_errno) {
case ER_HANDSHAKE_ERROR:
return "Bad handshake";
case ER_OUT_OF_RESOURCES:
return "Out of memory; Check if mysqld or some other process"
" uses all available memory. If not you may have to use"
" 'ulimit' to allow mysqld to use more memory or you can"
" add more swap space";
case ER_ACCESS_DENIED_ERROR:
return "Access denied. Bad username/password pair";
case ER_NOT_SUPPORTED_AUTH_MODE:
return "Client does not support authentication protocol requested by"
" server; consider upgrading MySQL client";
case ER_UNKNOWN_COM_ERROR:
return "Unknown command";
case ER_SYNTAX_ERROR:
return "You have an error in your command syntax. Check the manual that"
" corresponds to your MySQL Instance Manager version for the right"
" syntax to use";
case ER_BAD_INSTANCE_NAME:
return "Bad instance name. Check that the instance with such a name exists";
case ER_INSTANCE_IS_NOT_STARTED:
return "Cannot stop instance. Perhaps the instance is not started or you"
" have specified wrong username/password in the config file";
case ER_INSTANCE_ALREADY_STARTED:
return "The instance is already started";
case ER_CANNOT_START_INSTANCE:
return "Cannot start instance. Possible reasons are wrong instance options"
" or resources shortage";
case ER_STOP_INSTANCE:
return "Cannot stop instance";
default:
DBUG_ASSERT(0);
return 0;
}
}
const char *message(unsigned sql_errno)
{
return mysqld_error_message(sql_errno);
}
const char *errno_to_sqlstate(unsigned sql_errno)
{
return mysql_errno_to_sqlstate(sql_errno);
}
#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_MESSAGES_H
#define INCLUDES_MYSQL_INSTANCE_MANAGER_MESSAGES_H
/* Copyright (C) 2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "mysqld_error.h"
#include "mysql_manager_error.h"
const char *message(unsigned sql_errno);
const char *errno_to_sqlstate(unsigned sql_errno);
#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_MESSAGES_H
This diff is collapsed.
#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_CONNECTION_H
#define INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_CONNECTION_H
/* Copyright (C) 2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifdef __GNUC__
#pragma interface
#endif
#include <my_global.h>
#include <my_pthread.h>
C_MODE_START
pthread_handler_decl(mysql_connection, arg);
C_MODE_END
class Thread_registry;
class User_map;
class Instance_map;
struct st_vio;
struct Mysql_connection_thread_args
{
struct st_vio *vio;
Thread_registry &thread_registry;
const User_map &user_map;
ulong connection_id;
Instance_map &instance_map;
Mysql_connection_thread_args(struct st_vio *vio_arg,
Thread_registry &thread_registry_arg,
const User_map &user_map_arg,
ulong connection_id_arg,
Instance_map &instance_map_arg) :
vio(vio_arg)
,thread_registry(thread_registry_arg)
,user_map(user_map_arg)
,connection_id(connection_id_arg)
,instance_map(instance_map_arg)
{}
};
#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_CONNECTION_H
#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_MANAGER_ERROR_H
#define INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_MANAGER_ERROR_H
/* Copyright (C) 2004 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Definefile for instance manager error messagenumbers */
#define ER_BAD_INSTANCE_NAME 3000
#define ER_INSTANCE_IS_NOT_STARTED 3001
#define ER_INSTANCE_ALREADY_STARTED 3002
#define ER_CANNOT_START_INSTANCE 3003
#define ER_STOP_INSTANCE 3004
#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_MANAGER_ERROR_H */
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
/* Copyright (C) 2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -14,20 +14,21 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "manager.h"
#include "options.h"
#include "log.h"
#include <my_global.h>
#include <my_sys.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "manager.h"
#include "options.h"
#include "log.h"
/*
Few notes about the Instance Manager architecture:
Few notes about Instance Manager architecture:
Instance Manager consisits of two processes: the angel process, and the
instance manager process. Responsibilities of the angel process is to
monitor the instance manager process, and restart it in case of
......@@ -37,7 +38,7 @@
subsystems (thread sets):
- the signal handling thread: it's responsibilities are to handle
user signals and propogate them to the other threads. All other threads
are accounted in the signal handler thread Thread Repository.
are accounted in the signal handler thread Thread Registry.
- the listener: listens all sockets. There is a listening
socket for each (mysql, http, snmp, rendezvous (?)) subsystem.
- mysql subsystem: Instance Manager acts like an ordinary MySQL Server,
......@@ -70,11 +71,12 @@ int main(int argc, char *argv[])
options.load(argc, argv);
if (options.run_as_service)
{
/* forks, and returns only in child */
daemonize(options.log_file_name);
/* forks again, and returns only in child: parent becomes angel */
angel(options);
}
else
manager(options.log_file_name);
manager(options);
return 0;
}
......@@ -90,6 +92,7 @@ static void init_environment(char *progname)
MY_INIT(progname);
log_init();
umask(0117);
srand(time(0));
}
......@@ -159,16 +162,14 @@ void reap_child(int __attribute__((unused)) signo)
child_status= CHILD_NEED_RESPAWN;
else
/*
As we reap_child is not called for SIGSTOP, we should be here only
As reap_child is not called for SIGSTOP, we should be here only
if the child exited normally.
*/
child_status= CHILD_EXIT_ANGEL;
}
}
/* Not static to reuse it in childs */
volatile sig_atomic_t is_terminated= 0;
static volatile sig_atomic_t is_terminated= 0;
/*
Signal handler for terminate signals - SIGTERM, SIGHUP, SIGINT.
......@@ -225,8 +226,8 @@ static void angel(const Options &options)
sigaction(SIGTERM, &sa_term_out, 0);
sigaction(SIGINT, &sa_int_out, 0);
sigaction(SIGHUP, &sa_hup_out, 0);
manager(options.socket_file_name);
/* Here we return to main, and fall into manager */
break;
default: // parent, success
while (child_status == CHILD_OK && is_terminated == 0)
sigsuspend(&zeromask);
......@@ -240,6 +241,12 @@ static void angel(const Options &options)
sleep(1); /* don't respawn too fast */
goto spawn;
}
/* mysqlmanager successfully exited, let's silently evaporate */
/*
mysqlmanager successfully exited, let's silently evaporate
If we return to main we fall into the manager() function, so let's
simply exit().
*/
exit(0);
}
}
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
/* Copyright (C) 2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -24,6 +24,7 @@
#include <my_sys.h>
#include <my_getopt.h>
#include "priv.h"
#define QUOTE2(x) #x
#define QUOTE(x) QUOTE2(x)
......@@ -32,6 +33,13 @@ char Options::run_as_service;
const char *Options::log_file_name= QUOTE(DEFAULT_LOG_FILE_NAME);
const char *Options::pid_file_name= QUOTE(DEFAULT_PID_FILE_NAME);
const char *Options::socket_file_name= QUOTE(DEFAULT_SOCKET_FILE_NAME);
const char *Options::password_file_name= QUOTE(DEFAULT_PASSWORD_FILE_NAME);
const char *Options::default_mysqld_path= QUOTE(DEFAULT_MYSQLD_PATH);
const char *Options::default_admin_user= QUOTE(DEFAULT_USER);
const char *Options::default_admin_password= QUOTE(DEFAULT_PASSWORD);
const char *Options::bind_address= 0; /* No default value */
uint Options::monitoring_interval= DEFAULT_MONITORING_INTERVAL;
uint Options::port_number= DEFAULT_PORT;
/*
List of options, accepted by the instance manager.
......@@ -42,7 +50,16 @@ enum options {
OPT_LOG= 256,
OPT_PID_FILE,
OPT_SOCKET,
OPT_RUN_AS_SERVICE
OPT_PASSWORD_FILE,
OPT_MYSQLD_PATH,
OPT_RUN_AS_SERVICE,
OPT_USER,
OPT_PASSWORD,
OPT_DEFAULT_ADMIN_USER,
OPT_DEFAULT_ADMIN_PASSWORD,
OPT_MONITORING_INTERVAL,
OPT_PORT,
OPT_BIND_ADDRESS
};
static struct my_option my_long_options[] =
......@@ -62,6 +79,43 @@ static struct my_option my_long_options[] =
(gptr *) &Options::socket_file_name, (gptr *) &Options::socket_file_name,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
{ "bind-address", OPT_BIND_ADDRESS, "Bind address to use for connection.",
(gptr *) &Options::bind_address, (gptr *) &Options::bind_address,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
{ "port", OPT_PORT, "Port number to use for connections",
(gptr *) &Options::port_number, (gptr *) &Options::port_number,
0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
{ "password-file", OPT_PASSWORD_FILE, "Look for Instane Manager users"
" and passwords here.",
(gptr *) &Options::password_file_name,
(gptr *) &Options::password_file_name,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
{ "default-mysqld-path", OPT_MYSQLD_PATH, "Where to look for MySQL"
" Server binary.",
(gptr *) &Options::default_mysqld_path, (gptr *) &Options::default_mysqld_path,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
{ "default-admin-user", OPT_DEFAULT_ADMIN_USER, "Username to shutdown MySQL"
" instances.",
(gptr *) &Options::default_admin_user,
(gptr *) &Options::default_admin_user,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
{ "default-admin-password", OPT_DEFAULT_ADMIN_PASSWORD, "Password to"
"shutdown MySQL instances.",
(gptr *) &Options::default_admin_password,
(gptr *) &Options::default_admin_password,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
{ "monitoring-interval", OPT_MONITORING_INTERVAL, "Interval to monitor instances"
" in seconds.",
(gptr *) &Options::monitoring_interval,
(gptr *) &Options::monitoring_interval,
0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
{ "run-as-service", OPT_RUN_AS_SERVICE,
"Daemonize and start angel process.", (gptr *) &Options::run_as_service,
0, 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0 },
......@@ -74,15 +128,26 @@ static struct my_option my_long_options[] =
static void version()
{
static const char mysqlmanager_version[] = "0.1-alpha";
printf("%s Ver %s for %s on %s\n", my_progname, mysqlmanager_version,
SYSTEM_TYPE, MACHINE_TYPE);
}
static const char *default_groups[]= { "mysql", "manager", 0 };
static void usage()
{
version();
printf("Copyright (C) 2003, 2004 MySQL AB\n"
"This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n"
"and you are welcome to modify and redistribute it under the GPL license\n");
printf("Usage: %s [OPTIONS] \n", my_progname);
my_print_help(my_long_options);
print_defaults("my", default_groups);
my_print_variables(my_long_options);
}
C_MODE_START
......@@ -117,6 +182,9 @@ C_MODE_END
void Options::load(int argc, char **argv)
{
/* config-file options are prepended to command-line ones */
load_defaults("my", default_groups, &argc, &argv);
if (int rc= handle_options(&argc, &argv, my_long_options, get_one_option))
exit(rc);
}
......
#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_OPTIONS_H
#define INCLUDES_MYSQL_INSTANCE_MANAGER_OPTIONS_H
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
/* Copyright (C) 2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -24,6 +24,7 @@
Options - all possible options for the instance manager grouped in one
struct.
*/
#include <my_global.h>
struct Options
{
......@@ -31,6 +32,13 @@ struct Options
static const char *log_file_name;
static const char *pid_file_name;
static const char *socket_file_name;
static const char *password_file_name;
static const char *default_mysqld_path;
static const char *default_admin_user;
static const char *default_admin_password;
static uint monitoring_interval;
static uint port_number;
static const char *bind_address;
static void load(int argc, char **argv);
};
......
/* Copyright (C) 2004 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "parse.h"
#include <string.h>
enum Token
{
TOK_FLUSH = 0,
TOK_INSTANCE,
TOK_INSTANCES,
TOK_OPTIONS,
TOK_START,
TOK_STATUS,
TOK_STOP,
TOK_SHOW,
TOK_NOT_FOUND, // must be after all tokens
TOK_END
};
struct tokens_st
{
uint length;
const char *tok_name;
};
static struct tokens_st tokens[]= {
{5, "FLUSH"},
{8, "INSTANCE"},
{9, "INSTANCES"},
{7, "OPTIONS"},
{5, "START"},
{6, "STATUS"},
{4, "STOP"},
{4, "SHOW"}
};
/*
tries to find next word in the text
if found, returns the beginning and puts word length to word_len argument.
if not found returns pointer to first non-space or to '\0', word_len == 0
*/
inline void get_word(const char **text, uint *word_len)
{
const char *word_end;
/* skip space */
while (my_isspace(default_charset_info, **text))
++(*text);
word_end= *text;
while (my_isalnum(default_charset_info, *word_end))
++word_end;
*word_len= word_end - *text;
}
/*
Returns token no if word corresponds to some token, otherwise returns
TOK_NOT_FOUND
*/
inline Token find_token(const char *word, uint word_len)
{
int i= 0;
do
{
if (my_strnncoll(default_charset_info, (const uchar *) tokens[i].tok_name,
tokens[i].length, (const uchar *) word, word_len) == 0)
break;
}
while (++i < TOK_NOT_FOUND);
return (Token) i;
}
Token get_token(const char **text, uint *word_len)
{
get_word(text, word_len);
if (*word_len)
return find_token(*text, *word_len);
return TOK_END;
}
Token shift_token(const char **text, uint *word_len)
{
Token save= get_token(text, word_len);
(*text)+= *word_len;
return save;
}
void print_token(const char *token, uint tok_len)
{
for (uint i= 0; i < tok_len; ++i)
printf("%c", token[i]);
}
int get_text_id(const char **text, uint *word_len, const char **id)
{
get_word(text, word_len);
if (word_len == 0)
return 1;
*id= *text;
return 0;
}
Command *parse_command(Command_factory *factory, const char *text)
{
uint word_len;
const char *instance_name;
uint instance_name_len;
Command *command;
const char *saved_text= text;
Token tok1= shift_token(&text, &word_len);
switch (tok1) {
case TOK_START: // fallthrough
case TOK_STOP:
if (shift_token(&text, &word_len) != TOK_INSTANCE)
goto syntax_error;
get_word(&text, &word_len);
if (word_len == 0)
goto syntax_error;
instance_name= text;
instance_name_len= word_len;
text+= word_len;
/* it should be the end of command */
get_word(&text, &word_len);
if (word_len)
goto syntax_error;
command= (tok1 == TOK_START) ? (Command *)
factory->new_Start_instance(instance_name, instance_name_len):
(Command *)
factory->new_Stop_instance(instance_name, instance_name_len);
break;
case TOK_FLUSH:
if (shift_token(&text, &word_len) != TOK_INSTANCES)
goto syntax_error;
get_word(&text, &word_len);
if (word_len)
goto syntax_error;
command= factory->new_Flush_instances();
break;
case TOK_SHOW:
switch (shift_token(&text, &word_len)) {
case TOK_INSTANCES:
get_word(&text, &word_len);
if (word_len)
goto syntax_error;
command= factory->new_Show_instances();
break;
case TOK_INSTANCE:
switch (Token tok2= shift_token(&text, &word_len)) {
case TOK_OPTIONS:
case TOK_STATUS:
get_text_id(&text, &instance_name_len, &instance_name);
text+= instance_name_len;
get_word(&text, &word_len);
if (word_len)
goto syntax_error;
command= (tok2 == TOK_STATUS) ? (Command *)
factory->new_Show_instance_status(instance_name,
instance_name_len):
(Command *)
factory->new_Show_instance_options(instance_name,
instance_name_len);
break;
default:
goto syntax_error;
}
break;
default:
goto syntax_error;
}
break;
default:
syntax_error:
command= factory->new_Syntax_error();
}
return command;
}
#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_PARSE_H
#define INCLUDES_MYSQL_INSTANCE_MANAGER_PARSE_H
/* Copyright (C) 2004 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "factory.h"
Command *parse_command(Command_factory *factory, const char *text);
#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_PARSE_H */
/* Copyright (C) 2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "priv.h"
const char mysqlmanager_version[] = "0.2-alpha";
const int mysqlmanager_version_length= sizeof(mysqlmanager_version) - 1;
const unsigned char protocol_version= PROTOCOL_VERSION;
unsigned long net_buffer_length= 16384;
unsigned long max_allowed_packet= 16384;
unsigned long net_read_timeout= 30; // same as in mysqld
unsigned long net_write_timeout= 60; // same as in mysqld
unsigned long net_retry_count= 10; // same as in mysqld
/* needed by net_serv.cc */
unsigned int test_flags= 0;
unsigned long bytes_sent = 0L, bytes_received = 0L;
unsigned long mysqld_net_retry_count = 10L;
unsigned long open_files_limit;
#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_PRIV_H
#define INCLUDES_MYSQL_INSTANCE_MANAGER_PRIV_H
/* Copyright (C) 2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
extern const char mysqlmanager_version[];
extern const int mysqlmanager_version_length;
/* MySQL client-server protocol version: substituted from configure */
extern const unsigned char protocol_version;
/*
These variables are used in MySQL subsystem to work with mysql clients
To be moved to a config file/options one day.
*/
/* Buffer length for TCP/IP and socket communication */
extern unsigned long net_buffer_length;
/* Maximum allowed incoming/ougoung packet length */
extern unsigned long max_allowed_packet;
/*
Number of seconds to wait for more data from a connection before aborting
the read
*/
extern unsigned long net_read_timeout;
/*
Number of seconds to wait for a block to be written to a connection
before aborting the write.
*/
extern unsigned long net_write_timeout;
/*
If a read on a communication port is interrupted, retry this many times
before giving up.
*/
extern unsigned long net_retry_count;
extern unsigned int test_flags;
extern unsigned long bytes_sent, bytes_received;
extern unsigned long mysqld_net_retry_count;
extern unsigned long open_files_limit;
#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_PRIV_H
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -681,6 +681,8 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
nctx->set_oindex(i, static_cast<Item_splocal *>(it)->get_offset());
}
}
// Clean up the joins before closing the tables.
thd->lex->unit.cleanup();
// Close tables opened for subselect in argument list
close_thread_tables(thd);
......
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