Pushing all the Gemini changes above the table handler.
This commit is contained in:
parent
c4beb8321f
commit
ceac5f9227
@ -15,6 +15,10 @@ $make -k clean || true
|
|||||||
aclocal && autoheader && aclocal && automake && autoconf
|
aclocal && autoheader && aclocal && automake && autoconf
|
||||||
(cd bdb/dist && sh s_all)
|
(cd bdb/dist && sh s_all)
|
||||||
(cd innobase && aclocal && autoheader && aclocal && automake && autoconf)
|
(cd innobase && aclocal && autoheader && aclocal && automake && autoconf)
|
||||||
|
if [ -d gemini ]
|
||||||
|
then
|
||||||
|
(cd gemini && aclocal && autoheader && aclocal && automake && autoconf)
|
||||||
|
fi
|
||||||
|
|
||||||
CFLAGS=\"$cflags\" CXX=gcc CXXFLAGS=\"$cxxflags\" $configure"
|
CFLAGS=\"$cflags\" CXX=gcc CXXFLAGS=\"$cxxflags\" $configure"
|
||||||
|
|
||||||
|
@ -1 +1 @@
|
|||||||
mwagner@evoq.mwagner.org
|
mikef@nslinux.bedford.progress.com
|
||||||
|
893
Docs/manual.texi
893
Docs/manual.texi
@ -529,10 +529,25 @@ BDB or Berkeley_DB Tables
|
|||||||
|
|
||||||
GEMINI Tables
|
GEMINI Tables
|
||||||
|
|
||||||
* GEMINI overview::
|
* GEMINI Overview::
|
||||||
* GEMINI start::
|
* Using GEMINI Tables::
|
||||||
* GEMINI features::
|
|
||||||
* GEMINI TODO::
|
GEMINI Overview
|
||||||
|
|
||||||
|
* GEMINI Features::
|
||||||
|
* GEMINI Concepts::
|
||||||
|
* GEMINI Limitations::
|
||||||
|
|
||||||
|
Using GEMINI Tables
|
||||||
|
|
||||||
|
* Startup Options::
|
||||||
|
* Creating GEMINI Tables::
|
||||||
|
* Backing Up GEMINI Tables::
|
||||||
|
* Restoring GEMINI Tables::
|
||||||
|
* Using Auto_Increment Columns With GEMINI Tables::
|
||||||
|
* Performance Considerations::
|
||||||
|
* Sample Configurations::
|
||||||
|
* When To Use GEMINI Tables::
|
||||||
|
|
||||||
InnoDB Tables
|
InnoDB Tables
|
||||||
|
|
||||||
@ -10119,7 +10134,7 @@ If you are using BDB (Berkeley DB) tables, you should familiarize
|
|||||||
yourself with the different BDB specific startup options. @xref{BDB start}.
|
yourself with the different BDB specific startup options. @xref{BDB start}.
|
||||||
|
|
||||||
If you are using Gemini tables, refer to the Gemini-specific startup options.
|
If you are using Gemini tables, refer to the Gemini-specific startup options.
|
||||||
@xref{GEMINI start}.
|
@xref{Using GEMINI Tables}.
|
||||||
|
|
||||||
If you are using InnoDB tables, refer to the InnoDB-specific startup
|
If you are using InnoDB tables, refer to the InnoDB-specific startup
|
||||||
options. @xref{InnoDB start}.
|
options. @xref{InnoDB start}.
|
||||||
@ -18868,7 +18883,7 @@ When you insert a value of @code{NULL} (recommended) or @code{0} into an
|
|||||||
|
|
||||||
If you delete the row containing the maximum value for an
|
If you delete the row containing the maximum value for an
|
||||||
@code{AUTO_INCREMENT} column, the value will be reused with an
|
@code{AUTO_INCREMENT} column, the value will be reused with an
|
||||||
@code{ISAM}, @code{BDB} or @code{INNODB} table but not with a
|
@code{ISAM}, @code{GEMINI}, @code{BDB} or @code{INNODB} table but not with a
|
||||||
@code{MyISAM} table. If you delete all rows in the table with
|
@code{MyISAM} table. If you delete all rows in the table with
|
||||||
@code{DELETE FROM table_name} (without a @code{WHERE}) in
|
@code{DELETE FROM table_name} (without a @code{WHERE}) in
|
||||||
@code{AUTOCOMMIT} mode, the sequence starts over for both table types.
|
@code{AUTOCOMMIT} mode, the sequence starts over for both table types.
|
||||||
@ -24558,87 +24573,849 @@ not in @code{auto_commit} mode, until this problem is fixed (the fix is
|
|||||||
not trivial).
|
not trivial).
|
||||||
@end itemize
|
@end itemize
|
||||||
|
|
||||||
@cindex tables, @code{GEMINI}
|
@cindex GEMINI tables
|
||||||
@node GEMINI, InnoDB, BDB, Table types
|
@node GEMINI, InnoDB, BDB, Table types
|
||||||
@section GEMINI Tables
|
@section GEMINI Tables
|
||||||
|
|
||||||
|
@cindex GEMINI tables, overview
|
||||||
@menu
|
@menu
|
||||||
* GEMINI overview::
|
* GEMINI Overview::
|
||||||
* GEMINI start::
|
* Using GEMINI Tables::
|
||||||
* GEMINI features::
|
|
||||||
* GEMINI TODO::
|
|
||||||
@end menu
|
@end menu
|
||||||
|
|
||||||
@node GEMINI overview, GEMINI start, GEMINI, GEMINI
|
@node GEMINI Overview, Using GEMINI Tables, GEMINI, GEMINI
|
||||||
@subsection Overview of GEMINI tables
|
@subsection GEMINI Overview
|
||||||
|
|
||||||
The @code{GEMINI} table type is developed and supported by NuSphere Corporation
|
@code{GEMINI} is a transaction-safe table handler for @strong{MySQL}. It
|
||||||
(@uref{http://www.nusphere.com}). It features row-level locking, transaction
|
provides row-level locking, robust transaction support and reliable
|
||||||
support (@code{COMMIT} and @code{ROLLBACK}), and automatic crash recovery.
|
crash recovery. It is targeted for databases that need to handle heavy
|
||||||
|
multi-user updates typical of transaction processing applications while
|
||||||
|
still providing excellent performance for read-intensive operations. The
|
||||||
|
@code{GEMINI} table type is developed and supported by NuSphere
|
||||||
|
Corporation (see @url{http://www.nusphere.com}).
|
||||||
|
|
||||||
@code{GEMINI} tables will be included in some future @strong{MySQL} 3.23.X
|
@code{GEMINI} provides full ACID transaction properties (Atomic,
|
||||||
source distribution.
|
Consistent, Independent, and Durable) with a programming model that
|
||||||
|
includes support for statement atomicity and all four standard isolation
|
||||||
|
levels (Read Uncommitted, Read Committed, Repeatable Read, and
|
||||||
|
Serializable) defined in the SQL standard.
|
||||||
|
|
||||||
@node GEMINI start, GEMINI features, GEMINI overview, GEMINI
|
The @code{GEMINI} tables support row-level and table-level locking to
|
||||||
@subsection GEMINI startup options
|
increase concurrency in applications and allow reading of tables without
|
||||||
|
locking for maximum concurrency in a heavy update environment. The
|
||||||
|
transaction, locking, and recovery mechanisms are tightly integrated to
|
||||||
|
eliminate unnecessary administration overhead.
|
||||||
|
|
||||||
If you are running with @code{AUTOCOMMIT=0} then your changes in @code{GEMINI}
|
In general, if @code{GEMINI} tables are selected for an application, it
|
||||||
tables will not be updated until you execute @code{COMMIT}. Instead of commit
|
is recommended that all tables updated in the application be
|
||||||
you can execute @code{ROLLBACK} to forget your changes. @xref{COMMIT}.
|
@code{GEMINI} tables to provide well-defined system behavior. If
|
||||||
|
non-@code{GEMINI} tables are mixed into the application then, ACID
|
||||||
|
transaction properties cannot be maintained. While there are clearly
|
||||||
|
cases where mixing table types is appropriate, it should always be done
|
||||||
|
with careful consideration of the impact on transaction consistency and
|
||||||
|
recoverability needs of the application and underlying database.
|
||||||
|
|
||||||
If you are running with @code{AUTOCOMMIT=1} (the default), your changes
|
The @code{GEMINI} table type is derived from a successful commercial
|
||||||
will be committed immediately. You can start an extended transaction with
|
database and uses the storage kernel technology tightly integrated with
|
||||||
the @code{BEGIN WORK} SQL command, after which your changes will not be
|
@strong{MySQL} server. The basic @code{GEMINI} technology is in use by
|
||||||
committed until you execute @code{COMMIT} (or decide to @code{ROLLBACK}
|
millions of users worldwide in production environments today. This
|
||||||
the changes).
|
maturity allows @code{GEMINI} tables to provide a solution for those
|
||||||
|
users who require transaction-based behavior as part of their
|
||||||
|
applications.
|
||||||
|
|
||||||
The following options to @code{mysqld} can be used to change the behavior of
|
The @code{GEMINI} table handler supports a configurable data cache that
|
||||||
GEMINI tables:
|
allows a significant portion of any database to be maintained in memory
|
||||||
|
while still allowing durable updates.
|
||||||
|
|
||||||
@multitable @columnfractions .30 .70
|
@cindex GEMINI tables, features
|
||||||
@item @strong{Option} @tab @strong{Meaning}
|
@menu
|
||||||
@item @code{--gemini-full-recovery} @tab Default.
|
* GEMINI Features::
|
||||||
@item @code{--gemini-no-recovery} @tab Turn off recovery logging. Not recommended.
|
* GEMINI Concepts::
|
||||||
@item @code{--gemini-lazy-commit} @tab Relaxes the flush log at commit rule.
|
* GEMINI Limitations::
|
||||||
@item @code{--gemini-unbuffered-io} @tab All database writes bypass OS cache.
|
@end menu
|
||||||
@item @code{--skip-gemini} @tab Don't use Gemini.
|
|
||||||
@item @code{--O gemini_db_buffers=#} @tab Number of database buffers in database cache.
|
@node GEMINI Features, GEMINI Concepts, GEMINI Overview, GEMINI Overview
|
||||||
@item @code{--O gemini_connection_limit=#} @tab Maximum number of connections to Gemini.
|
@subsubsection GEMINI Features
|
||||||
@item @code{--O gemini_spin_retries=#} @tab Spin lock retries (optimization).
|
|
||||||
@item @code{--O gemini_io_threads=#} @tab Number of background I/O threads.
|
The following summarizes the major features provided by @code{GEMINI}
|
||||||
@item @code{--O gemini_lock_table_size=#} @tab Set the maximum number of locks. Default 4096.
|
tables.
|
||||||
|
|
||||||
|
@itemize @bullet
|
||||||
|
@item
|
||||||
|
Supports all optimization statistics used by the @strong{MySQL} optimizer
|
||||||
|
including table cardinality, index range estimates and multi-component
|
||||||
|
selectivity to insure optimal query performance.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Maintains exact cardinality information for each table so @code{SELECT
|
||||||
|
COUNT(*) FROM} table-name always returns an answer immediately.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Supports index-only queries; when index data is sufficient to resolve a
|
||||||
|
query no record data is read (for non character types).
|
||||||
|
|
||||||
|
@item
|
||||||
|
@code{GEMINI} uses block based I/O for better performance. There is no
|
||||||
|
performance penalty for using @code{VARCHAR} fields. The maximum record size is
|
||||||
|
currently 32K.
|
||||||
|
|
||||||
|
@item
|
||||||
|
The number of rows in a single @code{GEMINI} table can be 4 quintillion
|
||||||
|
(full use of 64 bits).
|
||||||
|
|
||||||
|
@item
|
||||||
|
Individual tables can be as large as 16 petabytes.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Locking is done at a record or row level rather than at table level
|
||||||
|
unless table locks are explicitly requested. When a row is inserted into
|
||||||
|
a table, other rows can be updated, inserted or deleted without waiting
|
||||||
|
for the inserted row to be committed.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Provides durable transactions backed by a crash recovery mechanism that
|
||||||
|
returns the database to a known consistent state in the event of an
|
||||||
|
unexpected failure.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Support for all isolation levels and statement atomicity defined in the
|
||||||
|
SQL standard.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Reliable Master Replication; the master database can survive system
|
||||||
|
failure and recover all committed transactions.
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
@cindex GEMINI tables, concepts
|
||||||
|
@node GEMINI Concepts, GEMINI Limitations, GEMINI Features, GEMINI Overview
|
||||||
|
@subsubsection GEMINI Concepts
|
||||||
|
|
||||||
|
This section highlights some of the important concepts behind
|
||||||
|
@code{GEMINI} and the @code{GEMINI} programming model, including:
|
||||||
|
|
||||||
|
@itemize @bullet
|
||||||
|
@item
|
||||||
|
ACID Transactions
|
||||||
|
@item
|
||||||
|
Transaction COMMIT/ROLLBACK
|
||||||
|
@item
|
||||||
|
Statement Atomicity
|
||||||
|
@item
|
||||||
|
Recovery
|
||||||
|
@item
|
||||||
|
Isolation Levels
|
||||||
|
@item
|
||||||
|
Row-Level Locking
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
These features are described below.
|
||||||
|
|
||||||
|
@cindex GEMINI tables, ACID transactions
|
||||||
|
@noindent
|
||||||
|
@strong{ACID Transactions}
|
||||||
|
|
||||||
|
ACID in the context of transactions is an acronym which stands for
|
||||||
|
@emph{Atomicity}, @emph{Consistency}, @emph{Isolation}, @emph{Durability}.
|
||||||
|
|
||||||
|
@multitable @columnfractions .25 .75
|
||||||
|
@item @sc{Attribute} @tab @sc{Description}
|
||||||
|
@item
|
||||||
|
@strong{Atomicity}
|
||||||
|
@tab A transaction allows for the grouping of one or more changes to
|
||||||
|
tables and rows in the database to form an atomic or indivisible
|
||||||
|
operation. That is, either all of the changes occur or none of them
|
||||||
|
do. If for any reason the transaction cannot be completed, everything
|
||||||
|
this transaction changed can be restored to the state it was in prior to
|
||||||
|
the start of the transaction via a rollback operation.
|
||||||
|
|
||||||
|
@item
|
||||||
|
@strong{Consistency}
|
||||||
|
@tab
|
||||||
|
Transactions always operate on a consistent view of the data and when
|
||||||
|
they end always leave the data in a consistent state. Data may be said to
|
||||||
|
be consistent as long as it conforms to a set of invariants, such as no
|
||||||
|
two rows in the customer table have the same customer ID and all orders
|
||||||
|
have an associated customer row. While a transaction executes, these
|
||||||
|
invariants may be violated, but no other transaction will be allowed to
|
||||||
|
see these inconsistencies, and all such inconsistencies will have been
|
||||||
|
eliminated by the time the transaction ends.
|
||||||
|
|
||||||
|
@item
|
||||||
|
@strong{Isolation}
|
||||||
|
@tab To a given transaction, it should appear as though it is running
|
||||||
|
all by itself on the database. The effects of concurrently running
|
||||||
|
transactions are invisible to this transaction, and the effects of this
|
||||||
|
transaction are invisible to others until the transaction is committed.
|
||||||
|
|
||||||
|
@item
|
||||||
|
@strong{Durability}
|
||||||
|
@tab Once a transaction is committed, its effects are guaranteed to
|
||||||
|
persist even in the event of subsequent system failures. Until the
|
||||||
|
transaction commits, not only are any changes made by that transaction
|
||||||
|
not durable, but are guaranteed not to persist in the face of a system
|
||||||
|
failures, as crash recovery will rollback their effects.
|
||||||
@end multitable
|
@end multitable
|
||||||
|
|
||||||
If you use @code{--skip-gemini}, @strong{MySQL} will not initialize the
|
@cindex GEMINI tables, COMMIT/ROLLBACK
|
||||||
Gemini table handler, saving memory; you cannot use Gemini tables if you
|
@noindent
|
||||||
use @code{--skip-gemini}.
|
@strong{Transaction COMMIT/ROLLBACK}
|
||||||
|
|
||||||
@node GEMINI features, GEMINI TODO, GEMINI start, GEMINI
|
As stated above, a transaction is a group of work being done to
|
||||||
@subsection Features of @code{GEMINI} tables:
|
data. Unless otherwise directed, @strong{MySQL} considers each statement
|
||||||
|
a transaction in itself. Multiple updates can be accomplished by placing
|
||||||
|
them in a single statement, however they are limited to a single table.
|
||||||
|
|
||||||
|
Applications tend to require more robust use of transaction
|
||||||
|
concepts. Take, for example, a system that processes an order: A row may
|
||||||
|
be inserted in an order table, additional rows may be added to an
|
||||||
|
order-line table, updates may be made to inventory tables, etc. It is
|
||||||
|
important that if the order completes, all the changes are made to all
|
||||||
|
the tables involved; likewise if the order fails, none of the changes to
|
||||||
|
the tables must occur. To facilitate this requirement, @strong{MySQL}
|
||||||
|
has syntax to start a transaction called @code{BEGIN WORK}. All
|
||||||
|
statements that occur after the @code{BEGIN WORK} statement are grouped
|
||||||
|
into a single transaction. The end of this transaction occurs when a
|
||||||
|
@code{COMMIT} or @code{ROLLBACK} statement is encountered. After the
|
||||||
|
@code{COMMIT} or @code{ROLLBACK} the system returns back to the behavior
|
||||||
|
before the @code{BEGIN WORK} statement was encountered where every
|
||||||
|
statement is a transaction.
|
||||||
|
|
||||||
|
To permanently turn off the behavior where every statement is a
|
||||||
|
transaction, @strong{MySQL} added a variable called
|
||||||
|
@code{AUTOCOMMIT}. The @code{AUTOCOMMIT} variable can have two values,
|
||||||
|
@code{1} and @code{0}. The mode where every statement is a transaction
|
||||||
|
is when @code{AUTOCOMMIT} is set to @code{1} (@code{AUTOCOMMIT=1}). When
|
||||||
|
@code{AUTOCOMMIT} is set to @code{0} (@code{AUTOCOMMIT=0}), then every
|
||||||
|
statement is part of the same transaction until the transaction end by
|
||||||
|
either @code{COMMIT} or @code{ROLLBACK}. Once a transaction completes, a
|
||||||
|
new transaction is immediately started and the process repeats.
|
||||||
|
|
||||||
|
Here is an example of the SQL statements that you may find in a typical
|
||||||
|
order:
|
||||||
|
|
||||||
|
@example
|
||||||
|
BEGIN WORK;
|
||||||
|
INSERT INTO order VALUES ...;
|
||||||
|
INSERT INTO order-lines VALUES ...;
|
||||||
|
INSERT INTO order-lines VALUES ...;
|
||||||
|
INSERT INTO order-lines VALUES ...;
|
||||||
|
UPDATE inventory WHERE ...;
|
||||||
|
COMMIT;
|
||||||
|
@end example
|
||||||
|
|
||||||
|
This example shows how to use the @code{BEGIN WORK} statement to start a
|
||||||
|
transaction. If the variable @code{AUTOCOMMIT} is set to @code{0}, then
|
||||||
|
a transaction would have been started already. In this case, the
|
||||||
|
@code{BEGIN WORK} commits the current transaction and starts a new one.
|
||||||
|
|
||||||
|
@cindex GEMINI tables, statement atomicity
|
||||||
|
@noindent
|
||||||
|
@strong{Statement Atomicity}
|
||||||
|
|
||||||
|
As mentioned above, when running with @code{AUTOCOMMIT} set to @code{1},
|
||||||
|
each statement executes as a single transaction. When a statement has an
|
||||||
|
error, then all changes make by the statement must be
|
||||||
|
undone. Transactions support this behavior. Non-transaction safe table
|
||||||
|
handlers would have a partial statement update where some of the changes
|
||||||
|
from the statement would be contained in the database and other changes
|
||||||
|
from the statement would not. Work would need to be done to manually
|
||||||
|
recover from the error.
|
||||||
|
|
||||||
|
@cindex GEMINI tables, recovery
|
||||||
|
@noindent
|
||||||
|
@strong{Recovery}
|
||||||
|
|
||||||
|
Transactions are the basis for database recovery. Recovery is what
|
||||||
|
supports the Durability attribute of the ACID transaction.
|
||||||
|
|
||||||
|
@code{GEMINI} uses a separate file called the Recovery Log located in
|
||||||
|
the @code{$DATADIR} directory named @code{gemini.rl}. This file
|
||||||
|
maintains the integrity of all the @code{GEMINI} tables. @code{GEMINI}
|
||||||
|
can not recover any data from non-@code{GEMINI} tables. In addition, the
|
||||||
|
@code{gemini.rl} file is used to rollback transactions in support of the
|
||||||
|
@code{ROLLBACK} statement.
|
||||||
|
|
||||||
|
In the event of a system failure, the next time the @strong{MySQL}
|
||||||
|
server is started, @code{GEMINI} will automatically go through its
|
||||||
|
crash recovery process. The result of crash recovery is that all the
|
||||||
|
@code{GEMINI} tables will contain the latest changes made to them, and
|
||||||
|
all transactions that were open at the time of the crash will have been
|
||||||
|
rolled back.
|
||||||
|
|
||||||
|
The @code{GEMINI} Recovery Log reuses space when it can. Space can be
|
||||||
|
reused when information in the Recovery Log is no longer needed for
|
||||||
|
crash recovery or rollback.
|
||||||
|
|
||||||
|
@cindex GEMINI tables, isolation levels
|
||||||
|
@noindent
|
||||||
|
@strong{Isolation Levels}
|
||||||
|
|
||||||
|
There are four isolation levels supported by @code{GEMINI}:
|
||||||
|
|
||||||
@itemize @bullet
|
@itemize @bullet
|
||||||
@item
|
@item
|
||||||
If a query result can be resolved solely from the index key, Gemini will
|
READ UNCOMMITTED
|
||||||
not read the actual row stored in the database.
|
|
||||||
@item
|
@item
|
||||||
Locking on Gemini tables is done at row level.
|
READ COMMITTED
|
||||||
@item
|
@item
|
||||||
@code{SELECT COUNT(*) FROM table_name} is fast; Gemini maintains a count
|
REPEATABLE READ
|
||||||
of the number of rows in the table.
|
@item
|
||||||
|
SERIALIZABLE
|
||||||
@end itemize
|
@end itemize
|
||||||
|
|
||||||
@node GEMINI TODO, , GEMINI features, GEMINI
|
These isolation levels apply only to shared locks obtained by select
|
||||||
@subsection Current limitations of @code{GEMINI} tables:
|
statements, excluding select for update. Statements that get exclusive
|
||||||
|
locks always retain those locks until the transaction commits or rolls
|
||||||
|
back.
|
||||||
|
|
||||||
|
By default, @code{GEMINI} operates at the @code{READ COMMITTED}
|
||||||
|
level. You can override the default using the following command:
|
||||||
|
|
||||||
|
@example
|
||||||
|
SET [GLOBAL | SESSION] TRANSACTION ISOLATION LEVEL [READ UNCOMMITTED |
|
||||||
|
READ COMMITTED | REPEATABLE READ | SERIALIZABLE ]
|
||||||
|
@end example
|
||||||
|
|
||||||
|
If the @code{SESSION} qualifier used, the specified isolation level
|
||||||
|
persists for the entire session. If the @code{GLOBAL} qualifier is used,
|
||||||
|
the specified isolation level is applied to all new connections from
|
||||||
|
this point forward. Note that the specified isolation level will not
|
||||||
|
change the behavior for existing connections including the connection
|
||||||
|
that exectues the @code{SET GLOBAL TRANSACTION ISOLATION LEVEL}
|
||||||
|
statement.
|
||||||
|
|
||||||
|
@multitable @columnfractions .30 .70
|
||||||
|
@item @sc{Isolation Level} @tab @sc{Description}
|
||||||
|
|
||||||
|
@item
|
||||||
|
@strong{READ UNCOMMITTED}
|
||||||
|
@tab Does not obtain any locks when reading rows. This means that if a
|
||||||
|
row is locked by another process in a transaction that has a more strict
|
||||||
|
isolation level, the @code{READ UNCOMMITTED} query will not wait until
|
||||||
|
the locks are released before reading the row. You will get an error if
|
||||||
|
attempt any updates while running at this isolation level.
|
||||||
|
|
||||||
|
@item
|
||||||
|
@strong{READ COMMITTED}
|
||||||
|
@tab Locks the requested rows long enough to copy the row from the
|
||||||
|
database block to the client row buffer. If a @code{READ COMMITTED}
|
||||||
|
query finds that a row is locked exclusively by another process, it will
|
||||||
|
wait until either the row has been released, or the lock timeout value
|
||||||
|
has expired.
|
||||||
|
|
||||||
|
@item
|
||||||
|
@strong{REPEATABLE READ}
|
||||||
|
@tab Locks all the rows needed to satisfy the query. These locks are
|
||||||
|
held until the transaction ends (commits or rolls back). If a
|
||||||
|
@code{REPEATABLE READ} query finds that a row is locked exclusively by
|
||||||
|
another process, it will wait until either the row has been released, or
|
||||||
|
the lock timeout value has expired.
|
||||||
|
|
||||||
|
@item
|
||||||
|
@strong{SERIALIZABLE}
|
||||||
|
@tab Locks the table that contains the rows needed to satisfy the
|
||||||
|
query. This lock is held until the transaction ends (commits or rolls
|
||||||
|
back). If a @code{SERIALIZABLE} query finds that a row is exclusively
|
||||||
|
locked by another process, it will wait until either the row has been
|
||||||
|
released, or the lock timeout value has expired.
|
||||||
|
@end multitable
|
||||||
|
|
||||||
|
The statements that get exclusive locks are @code{INSERT},
|
||||||
|
@code{UPDATE}, @code{DELETE} and @code{SELECT ... FOR UPDATE}. Select
|
||||||
|
statements without the @code{FOR UPDATE} qualifier get shared locks
|
||||||
|
which allow other not ''for update'' select statements to read the same
|
||||||
|
rows but block anyone trying to update the row from accessing it. Rows
|
||||||
|
or tables with exclusive locks block all access to the row from other
|
||||||
|
transactions until the transaction ends.
|
||||||
|
|
||||||
|
In general terms, the higher the Isolation level the more likelihood of
|
||||||
|
having concurrent locks and therefore lock conflicts. In such cases,
|
||||||
|
adjust the @code{-O gemini_lock_table_size} accordingly.
|
||||||
|
|
||||||
|
@cindex GEMINI tables, row-level locking
|
||||||
|
@noindent
|
||||||
|
@strong{Row-Level Locking}
|
||||||
|
|
||||||
|
@code{GEMINI} uses row locks, which allows high concurrency for requests
|
||||||
|
on the same table.
|
||||||
|
|
||||||
|
In order to avoid lock table overflow, SQL statements that require
|
||||||
|
applying locks to a large number of rows should either be run at the
|
||||||
|
serializable isolation level or should be covered by a lock table
|
||||||
|
statement.
|
||||||
|
|
||||||
|
Memory must be pre-allocated for the lock table. The mysqld server
|
||||||
|
startup option @code{-0 gemini_lock_table_size} can be used to adjust
|
||||||
|
the number of concurrent locks.
|
||||||
|
|
||||||
|
@cindex GEMINI tables, limitations
|
||||||
|
@node GEMINI Limitations, , GEMINI Concepts, GEMINI Overview
|
||||||
|
@subsubsection GEMINI Limitations
|
||||||
|
|
||||||
|
The following limitations are in effect for the current version of
|
||||||
|
@code{GEMINI}:
|
||||||
|
|
||||||
@itemize @bullet
|
@itemize @bullet
|
||||||
@item
|
@item
|
||||||
BLOB columns are not supported in @code{GEMINI} tables.
|
@code{DROP DATABASE} does not work with @code{GEMINI} tables; instead,
|
||||||
|
drop all the tables in the database first, then drop the database.
|
||||||
|
|
||||||
@item
|
@item
|
||||||
The maximum number of concurrent users accessing @code{GEMINI} tables is
|
Maximum number of @code{GEMINI} tables is 1012.
|
||||||
limited by @code{gemini_connection_limit}. The default is 100 users.
|
|
||||||
|
@item
|
||||||
|
Maximum number of @code{GEMINI} files a server can manage is 1012. Each
|
||||||
|
table consumes one file; an additional file is consumed if the table has
|
||||||
|
any indexes defined on it.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Maximum size of BLOBs is 16MB.
|
||||||
|
|
||||||
|
@item
|
||||||
|
@code{FULLTEXT} indexes are not supported with @code{GEMINI} tables.
|
||||||
|
|
||||||
|
@item
|
||||||
|
There is no support for multi-component @code{AUTO_INCREMENT} fields
|
||||||
|
that provide alternating values at the component level. If you try to
|
||||||
|
create such a field, @code{GEMINI} will refuse.
|
||||||
|
|
||||||
|
@item
|
||||||
|
@code{TEMPORARY TABLES} are not supported by @code{GEMINI}. The
|
||||||
|
statement @code{CREATE TEMPORARY TABLE ... TYPE=GEMINI} will generate
|
||||||
|
the response: @code{ERROR 1005: Can't create table '/tmp/#sqlxxxxx'
|
||||||
|
(errno: 0)}.
|
||||||
|
|
||||||
|
@item
|
||||||
|
@code{FLUSH TABLES} has not been implemented with @code{GEMINI} tables.
|
||||||
@end itemize
|
@end itemize
|
||||||
|
|
||||||
NuSphere is working on removing these limitations.
|
@cindex GEMINI tables, using
|
||||||
|
@node Using GEMINI Tables, , GEMINI Overview, GEMINI
|
||||||
|
@subsection Using GEMINI Tables
|
||||||
|
|
||||||
|
This section explains the various startup options you can use with
|
||||||
|
@code{GEMINI} tables, how to backup @code{GEMINI} tables, some
|
||||||
|
performance considerations and sample configurations, and a brief
|
||||||
|
discussion of when to use @code{GEMINI} tables.
|
||||||
|
|
||||||
|
Specifically, the topics covered in this section are:
|
||||||
|
|
||||||
|
@itemize @bullet
|
||||||
|
@item
|
||||||
|
Startup Options
|
||||||
|
@item
|
||||||
|
Creating @code{GEMINI} Tables
|
||||||
|
@item
|
||||||
|
Backing Up @code{GEMINI} Tables
|
||||||
|
@item
|
||||||
|
Using Auto_Increment Columns With @code{GEMINI} Tables
|
||||||
|
@item
|
||||||
|
Performance Considerations
|
||||||
|
@item
|
||||||
|
Sample Configurations
|
||||||
|
@item
|
||||||
|
When To Use @code{GEMINI} Tables
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
@cindex GEMINI tables, startup options
|
||||||
|
@menu
|
||||||
|
* Startup Options::
|
||||||
|
* Creating GEMINI Tables::
|
||||||
|
* Backing Up GEMINI Tables::
|
||||||
|
* Restoring GEMINI Tables::
|
||||||
|
* Using Auto_Increment Columns With GEMINI Tables::
|
||||||
|
* Performance Considerations::
|
||||||
|
* Sample Configurations::
|
||||||
|
* When To Use GEMINI Tables::
|
||||||
|
@end menu
|
||||||
|
|
||||||
|
@node Startup Options, Creating GEMINI Tables, Using GEMINI Tables, Using GEMINI Tables
|
||||||
|
@subsubsection Startup Options
|
||||||
|
|
||||||
|
The table below lists options to mysqld that can be used to change the
|
||||||
|
behavior of @code{GEMINI} tables.
|
||||||
|
|
||||||
|
@multitable @columnfractions .40 .60
|
||||||
|
@item @sc{Option} @tab @sc{Description}
|
||||||
|
|
||||||
|
@item
|
||||||
|
@code{--default-table-type=gemini}
|
||||||
|
@tab Sets the default table handler to be @code{GEMINI}. All create
|
||||||
|
table statements will create @code{GEMINI} tables unless otherwise
|
||||||
|
specified with @code{TYPE=@var{table-type}}. As noted above, there is
|
||||||
|
currently a limitation with @code{TEMPORARY} tables using @code{GEMINI}.
|
||||||
|
|
||||||
|
@item
|
||||||
|
@code{--gemini-flush-log-at-commit}
|
||||||
|
@tab Forces the recovery log buffers to be flushed after every
|
||||||
|
commit. This can have a serious performance penalty, so use with
|
||||||
|
caution.
|
||||||
|
|
||||||
|
@item
|
||||||
|
@code{--gemini-recovery=FULL | NONE | FORCE}
|
||||||
|
@tab Sets the recovery mode. Default is @code{FULL}. @code{NONE} is
|
||||||
|
useful for performing repeatable batch operations because the updates
|
||||||
|
are not recorded in the recovery log. @code{FORCE} skips crash recovery
|
||||||
|
upon startup; this corrupts the database, and should be used in
|
||||||
|
emergencies only.
|
||||||
|
|
||||||
|
@item
|
||||||
|
@code{--gemini-unbuffered-io}
|
||||||
|
@tab All database writes bypass the OS cache. This can provide a
|
||||||
|
performance boost on heavily updated systems where most of the dataset
|
||||||
|
being worked on is cached in memory with the @code{gemini_buffer_cache}
|
||||||
|
parameter.
|
||||||
|
|
||||||
|
@item
|
||||||
|
@code{--O gemini_buffer_cache=size}
|
||||||
|
@tab Amount of memory to allocate for database buffers, including Index
|
||||||
|
and Record information. It is recommended that this number be 10% of the
|
||||||
|
total size of all @code{GEMINI} tables. Do not exceed amount of memory
|
||||||
|
on the system!
|
||||||
|
|
||||||
|
@item
|
||||||
|
@code{--O gemini_connection_limit=#}
|
||||||
|
@tab Maximum number of connections to @code{GEMINI}; default is
|
||||||
|
@code{100}. Each connection consumes about 1K of memory.
|
||||||
|
|
||||||
|
@item
|
||||||
|
@code{--O gemini_io_threads=#}
|
||||||
|
@tab Number of background I/O threads; default is @code{2}. Increase the
|
||||||
|
number when using @code{--gemini-unbuffered-io}
|
||||||
|
|
||||||
|
@item
|
||||||
|
@code{--O gemini_lock_table_size=#}
|
||||||
|
@tab Sets the maximum number of concurrent locks; default is 4096. Using
|
||||||
|
@code{SET [ GLOBAL | SESSION ] TRANSACTION ISOLATION = ...} will
|
||||||
|
determine how long a program will hold row locks.
|
||||||
|
|
||||||
|
@item
|
||||||
|
@code{--O gemini_lock_wait_timeout=seconds}
|
||||||
|
@tab Number of seconds to wait for record locks when performing queries;
|
||||||
|
default is 10 seconds. Using @code{SET [ GLOBAL | SESSION ] TRANSACTION
|
||||||
|
ISOLATION = ...} will determine how long a program will hold row locks.
|
||||||
|
|
||||||
|
@item
|
||||||
|
@code{--skip-gemini}
|
||||||
|
@tab Do not use @code{GEMINI}. If you use @code{--skip-gemini}, @strong{MySQL}
|
||||||
|
will not initialize the @code{GEMINI} table handler, saving memory; you
|
||||||
|
cannot use @code{GEMINI} tables if you use @code{--skip-gemini}.
|
||||||
|
|
||||||
|
@item
|
||||||
|
@code{--transaction-isolation=READ-UNCOMMITTED | READ-COMMITTED | REPEATABLE-READ | SERIALIZABLE}
|
||||||
|
@tab Sets the GLOBAL transaction isolation level for all users that
|
||||||
|
connect to the server; can be overridden with the SET ISOLATION LEVEL
|
||||||
|
statement.
|
||||||
|
@end multitable
|
||||||
|
|
||||||
|
@cindex GEMINI tables, creating
|
||||||
|
@node Creating GEMINI Tables, Backing Up GEMINI Tables, Startup Options, Using GEMINI Tables
|
||||||
|
@subsubsection Creating GEMINI Tables
|
||||||
|
|
||||||
|
@code{GEMINI} tables can be created by either using the @code{CREATE
|
||||||
|
TABLE} syntax or the @code{ALTER TABLE} syntax.
|
||||||
|
|
||||||
|
@itemize @bullet
|
||||||
|
@item
|
||||||
|
The syntax for creating a @code{GEMINI} table is:
|
||||||
|
|
||||||
|
@example
|
||||||
|
CREATE TABLE @var{table-name} (....) TYPE=GEMINI;
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@item
|
||||||
|
The syntax to convert a table to @code{GEMINI} is:
|
||||||
|
|
||||||
|
@example
|
||||||
|
ALTER TABLE @var{table-name} TYPE=GEMINI;
|
||||||
|
@end example
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
@xref{Tutorial}, for more information on how to create and use
|
||||||
|
@code{MySQL} tables.
|
||||||
|
|
||||||
|
@cindex GEMINI tables, backing up
|
||||||
|
@node Backing Up GEMINI Tables, Restoring GEMINI Tables, Creating GEMINI Tables, Using GEMINI Tables
|
||||||
|
@subsubsection Backing Up GEMINI Tables
|
||||||
|
|
||||||
|
@code{GEMINI} supports both @code{BACKUP TABLE} and @code{RESTORE TABLE}
|
||||||
|
syntax. To learn more about how to use @code{BACKUP} and @code{RESTORE},
|
||||||
|
see @ref{BACKUP TABLE} and @ref{RESTORE TABLE}.
|
||||||
|
|
||||||
|
To backup @code{GEMINI} tables outside of the @code{MySQL} environment,
|
||||||
|
you must first shut down the @code{MySQL} server. Once the server is
|
||||||
|
shut down, you can copy the files associated with @code{GEMINI} to a
|
||||||
|
different location. The files that make up the @code{GEMINI} table
|
||||||
|
handler are:
|
||||||
|
|
||||||
|
@itemize @bullet
|
||||||
|
@item
|
||||||
|
All files associated with a table with a @code{.gmd} extention below the
|
||||||
|
@code{$DATADIR} directory. Such files include @code{@var{table}.gmd},
|
||||||
|
@code{@var{table}.gmi}, and @code{@var{table}.frm}
|
||||||
|
@item
|
||||||
|
@code{gemini.db} in the @code{$DATADIR} directory
|
||||||
|
@item
|
||||||
|
@code{gemini.rl} in the @code{$DATADIR} directory
|
||||||
|
@item
|
||||||
|
@code{gemini.lg} in the @code{$DATADIR} directory
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
All the @code{GEMINI} files must be copied together. You can not copy
|
||||||
|
just the @code{.gmi} and @code{.gmd} files to a different
|
||||||
|
@code{$DATADIR} and have them become part of a new database. You can
|
||||||
|
copy an entire @code{$DATADIR} directory to another location and start a
|
||||||
|
@strong{MySQL} server using the new @code{$DATADIR}.
|
||||||
|
|
||||||
|
@cindex GEMINI tables, restoring
|
||||||
|
@node Restoring GEMINI Tables, Using Auto_Increment Columns With GEMINI Tables, Backing Up GEMINI Tables, Using GEMINI Tables
|
||||||
|
@subsubsection Restoring GEMINI Tables
|
||||||
|
|
||||||
|
To restore @code{GEMINI} tables outside of the @code{MySQL} environment,
|
||||||
|
you must first shut down the @code{MySQL} server. Once the server is
|
||||||
|
shut down, you can remove all @code{GEMINI} files in the target
|
||||||
|
@code{$DATADIR} and then copy the files previously backed up into the
|
||||||
|
@code{$DATADIR} directory.
|
||||||
|
|
||||||
|
As mentioned above, the files that make up the @code{GEMINI} table
|
||||||
|
handler are:
|
||||||
|
|
||||||
|
@itemize @bullet
|
||||||
|
@item
|
||||||
|
All files associated with a table with a @code{.gmd} extention below the
|
||||||
|
@code{$DATADIR} directory. Such files include @code{@var{table}.gmd},
|
||||||
|
@code{@var{table}.gmi}, and @code{@var{table}.frm}
|
||||||
|
@item
|
||||||
|
@code{gemini.db} in the @code{$DATADIR} directory
|
||||||
|
@item
|
||||||
|
@code{gemini.rl} in the @code{$DATADIR} directory
|
||||||
|
@item
|
||||||
|
@code{gemini.lg} in the @code{$DATADIR} directory
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
When restoring a table, all the @code{GEMINI} files must be copied
|
||||||
|
together. You can not restore just the @code{.gmi} and @code{.gmd}
|
||||||
|
files.
|
||||||
|
|
||||||
|
@cindex GEMINI tables, auto_increment
|
||||||
|
@node Using Auto_Increment Columns With GEMINI Tables, Performance Considerations, Restoring GEMINI Tables, Using GEMINI Tables
|
||||||
|
@subsubsection Using Auto_Increment Columns With GEMINI Tables
|
||||||
|
|
||||||
|
As mentioned previously, @code{GEMINI} tables support row-level and
|
||||||
|
table-level locking to increase concurrency in applications and to allow
|
||||||
|
reading of tables without locking for maximum concurrency in heavy
|
||||||
|
update environments. This feature has several implications when working
|
||||||
|
with @code{auto_increment} tables.
|
||||||
|
|
||||||
|
In @code{MySQL}, when a column is defined as an @code{auto_increment}
|
||||||
|
column, and a row is inserted into the table with a @code{NULL} for the
|
||||||
|
column, the @code{auto_increment} column is updated to be 1 higher than
|
||||||
|
the highest value in the column.
|
||||||
|
|
||||||
|
With @code{MyISAM} tables, the @code{auto_increment} function is
|
||||||
|
implemented by looking in the index and finding the highest value and
|
||||||
|
adding 1 to it. This is possible because the entire @code{ISAM} table is
|
||||||
|
locked during the update period and the increment value is therefore
|
||||||
|
guaranteed to not be changing.
|
||||||
|
|
||||||
|
With @code{GEMINI} tables, the @code{auto_increment} function is
|
||||||
|
implemented by maintaining a counter in a separate location from the
|
||||||
|
table data. Instead of looking at the highest value in the table index,
|
||||||
|
@code{GEMINI} tables look at this separately maintained counter. This
|
||||||
|
means that in a transactional model, unlike the bottleneck inherent in
|
||||||
|
the @code{MyISAM} approach, @code{GEMINI} users do @b{not} have to wait
|
||||||
|
until the transaction that added the last value either commits or
|
||||||
|
rollbacks before looking at the value.
|
||||||
|
|
||||||
|
Two side-effects of the @code{GEMINI} implementation are:
|
||||||
|
|
||||||
|
@itemize @bullet
|
||||||
|
@item
|
||||||
|
If an insert is done where the column with the @code{auto_increment} is
|
||||||
|
specified, and this specified value is the highest value, @code{MyISAM}
|
||||||
|
uses it as its @code{auto_increment} value, and every subsequent insert
|
||||||
|
is based on this. By contrast, @code{GEMINI} does not use this value,
|
||||||
|
but instead uses the value maintained in the separate @code{GEMINI}
|
||||||
|
counter location.
|
||||||
|
|
||||||
|
@item
|
||||||
|
To set the counter to a specific value, you can use @code{SET
|
||||||
|
insert_id=#} and insert a new row in the table. However, as a general
|
||||||
|
rule, values should not be inserted into an @code{auto_increment}
|
||||||
|
column; the database manager should be maintaining this field, not the
|
||||||
|
application. @code{SET insert_id} is a recovery mechanism that should be
|
||||||
|
used in case of error only.
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
Note that if you delete the row containing the maximum value for an
|
||||||
|
@code{auto_increment} column, the value will be reused with a
|
||||||
|
@code{GEMINI} table but not with a @code{MyISAM} table.
|
||||||
|
|
||||||
|
See @ref{CREATE TABLE} for more information about creating
|
||||||
|
@code{auto_increment} columns.
|
||||||
|
|
||||||
|
@cindex GEMINI tables, peformance considerations
|
||||||
|
@node Performance Considerations, Sample Configurations, Using Auto_Increment Columns With GEMINI Tables, Using GEMINI Tables
|
||||||
|
@subsubsection Performance Considerations
|
||||||
|
|
||||||
|
In addition to designing the best possible application, configuration of
|
||||||
|
the data and the server startup parameters need to be considered. How
|
||||||
|
the hardware is being used can have a dramatic affect on how fast the
|
||||||
|
system will respond to queries. Disk Drives and Memory must both be
|
||||||
|
considered.
|
||||||
|
|
||||||
|
@noindent
|
||||||
|
@strong{Disk Drives}
|
||||||
|
|
||||||
|
For best performance, you want to spread the data out over as many disks
|
||||||
|
as possible. Using RAID 10 stripes work very well. If there are a lot of
|
||||||
|
updates then the recovery log (@code{gemini.rl}) should be on a
|
||||||
|
relatively quiet disk drive.
|
||||||
|
|
||||||
|
To spread the data out without using RAID 10, you can do the following:
|
||||||
|
|
||||||
|
@itemize @bullet
|
||||||
|
@item
|
||||||
|
Group all the tables into three categories: Heavy Use, Moderate Use,
|
||||||
|
Light Use.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Take the number of disk drives available and use a round-robin approach
|
||||||
|
to the three categories grouping the tables on a disk drive. The result
|
||||||
|
will be an equal distribution of Heavy/Moderate/Light tables assigned to
|
||||||
|
each disk drive.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Once the tables have been converted to @code{GEMINI} by using the
|
||||||
|
@code{ALTER TABLE <name> TYPE=GEMINI} statements, move (@code{mv}) the
|
||||||
|
@code{.gmd} and @code{.gmi} files to a different disk drive and link
|
||||||
|
(@code{ln -s}) them back to the original directory where the @code{.frm}
|
||||||
|
file resides.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Finally, move the @code{gemini.rl} file to its quiet disk location and link
|
||||||
|
the file back to the @code{$DATADIR} directory.
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
@noindent
|
||||||
|
@strong{Memory}
|
||||||
|
|
||||||
|
The more data that can be placed in memory the faster the access to the
|
||||||
|
data. Figure out how large the @code{GEMINI} data is by adding up the
|
||||||
|
@code{.gmd} and @code{.gmi} file sizes. If you can, put at least 10% of
|
||||||
|
the data into memory. You allocate memory for the rows and indexes by
|
||||||
|
using the @code{gemini_buffer_cache} startup parameter. For example:
|
||||||
|
|
||||||
|
@example
|
||||||
|
mysqld -O gemini_buffer_cache=800M
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@noindent
|
||||||
|
would allocate 800 MB of memory for the @code{GEMINI} buffer cache.
|
||||||
|
|
||||||
|
@cindex GEMINI tables, sample configurations
|
||||||
|
@node Sample Configurations, When To Use GEMINI Tables, Performance Considerations, Using GEMINI Tables
|
||||||
|
@subsubsection Sample Configurations
|
||||||
|
|
||||||
|
Based on the performance considerations above, we can look at some
|
||||||
|
examples for how to get the best performance out of the system when
|
||||||
|
using @code{GEMINI} tables.
|
||||||
|
|
||||||
|
@multitable @columnfractions .30 .70
|
||||||
|
@item @sc{Hardware} @tab @sc{Configuration}
|
||||||
|
@item
|
||||||
|
One CPU, 128MB memory, one disk drive
|
||||||
|
@tab Allocate 80MB of memory for reading and updating @code{GEMINI}
|
||||||
|
tables by starting the mysqld server with the following option:
|
||||||
|
|
||||||
|
@example
|
||||||
|
-O gemini_buffer_cache=80M
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@item
|
||||||
|
Two CPUs, 512MB memory, four disk drives
|
||||||
|
@tab Use RAID 10 to stripe the data across all available disks, or use
|
||||||
|
the method described in the performance considerations section,
|
||||||
|
above. Allocate 450MB of memory for reading/updating @code{GEMINI}
|
||||||
|
tables:
|
||||||
|
|
||||||
|
@example
|
||||||
|
-O gemini_buffer_cache=450M
|
||||||
|
@end example
|
||||||
|
@end multitable
|
||||||
|
|
||||||
|
@cindex GEMINI tables, when to use
|
||||||
|
@node When To Use GEMINI Tables, , Sample Configurations, Using GEMINI Tables
|
||||||
|
@subsubsection When To Use GEMINI Tables
|
||||||
|
|
||||||
|
Because the @code{GEMINI} table handler provides crash recovery and
|
||||||
|
transaction support, there is extra overhead that is not found in other
|
||||||
|
non-transaction safe table handlers. Here are some general guidelines
|
||||||
|
for when to employ @code{GEMINI} and when to use other non-transaction
|
||||||
|
safe tables (@code{NTST}).
|
||||||
|
|
||||||
|
@multitable @columnfractions .30 .25 .45
|
||||||
|
@item
|
||||||
|
@sc{Access Trends} @tab @sc{Table Type} @tab @sc{Reason}
|
||||||
|
@item
|
||||||
|
Read-only
|
||||||
|
@tab @code{NTST}
|
||||||
|
@tab Less overhead and faster
|
||||||
|
@item
|
||||||
|
Critical data
|
||||||
|
@tab @code{GEMINI}
|
||||||
|
@tab Crash recovery protection
|
||||||
|
@item
|
||||||
|
High concurrency
|
||||||
|
@tab @code{GEMINI}
|
||||||
|
@tab Row-level locking
|
||||||
|
@item
|
||||||
|
Heavy update
|
||||||
|
@tab @code{GEMINI}
|
||||||
|
@tab Row-level locking
|
||||||
|
@end multitable
|
||||||
|
|
||||||
|
The table below shows how a typical application schema could be defined.
|
||||||
|
|
||||||
|
@multitable @columnfractions .15 .30 .25 .30
|
||||||
|
@item
|
||||||
|
@sc{Table} @tab @sc{Contents} @tab @sc{Table Type} @tab @sc{Reason}
|
||||||
|
@item
|
||||||
|
account
|
||||||
|
@tab Customer account data
|
||||||
|
@tab @code{GEMINI}
|
||||||
|
@tab Critical data, heavy update
|
||||||
|
@item
|
||||||
|
order
|
||||||
|
@tab Orders for a customer
|
||||||
|
@tab @code{GEMINI}
|
||||||
|
@tab Critical data, heavy update
|
||||||
|
@item
|
||||||
|
orderline
|
||||||
|
@tab Orderline detail for an order
|
||||||
|
@tab @code{GEMINI}
|
||||||
|
@tab Critical data, heavy update
|
||||||
|
@item
|
||||||
|
invdesc
|
||||||
|
@tab Inventory description
|
||||||
|
@tab @code{NTST}
|
||||||
|
@tab Read-only, frequent access
|
||||||
|
@item
|
||||||
|
salesrep
|
||||||
|
@tab Sales rep information
|
||||||
|
@tab @code{NTST}
|
||||||
|
@tab Infrequent update
|
||||||
|
@item
|
||||||
|
inventory
|
||||||
|
@tab Inventory information
|
||||||
|
@tab @code{GEMINI}
|
||||||
|
@tab High concurrency, critical data
|
||||||
|
@item
|
||||||
|
config
|
||||||
|
@tab System configuration
|
||||||
|
@tab @code{NTST}
|
||||||
|
@tab Read-only
|
||||||
|
@end multitable
|
||||||
|
|
||||||
@node InnoDB, , GEMINI, Table types
|
@node InnoDB, , GEMINI, Table types
|
||||||
@section InnoDB Tables
|
@section InnoDB Tables
|
||||||
|
@ -999,10 +999,10 @@ dnl echo "DBG_GEM1: gemini='$gemini'"
|
|||||||
gemini_includes=
|
gemini_includes=
|
||||||
gemini_libs=
|
gemini_libs=
|
||||||
case "$gemini" in
|
case "$gemini" in
|
||||||
no | default | *)
|
no)
|
||||||
AC_MSG_RESULT([Not using Gemini DB])
|
AC_MSG_RESULT([Not using Gemini DB])
|
||||||
;;
|
;;
|
||||||
yes )
|
yes | default | *)
|
||||||
have_gemini_db="yes"
|
have_gemini_db="yes"
|
||||||
gemini_includes="-I../gemini/incl -I../gemini"
|
gemini_includes="-I../gemini/incl -I../gemini"
|
||||||
gemini_libs="\
|
gemini_libs="\
|
||||||
|
11
configure.in
11
configure.in
@ -2018,6 +2018,17 @@ EOF
|
|||||||
echo "END OF INNODB CONFIGURATION"
|
echo "END OF INNODB CONFIGURATION"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if test "X$have_gemini_db" = "Xyes"; then
|
||||||
|
sql_server_dirs="gemini $sql_server_dirs"
|
||||||
|
echo "CONFIGURING FOR GEMINI DB"
|
||||||
|
(cd gemini && sh ./configure) \
|
||||||
|
|| AC_MSG_ERROR([could not configure Gemini DB])
|
||||||
|
|
||||||
|
echo "END OF GEMINI DB CONFIGURATION"
|
||||||
|
|
||||||
|
AC_DEFINE(HAVE_GEMINI_DB)
|
||||||
|
fi
|
||||||
|
|
||||||
if test "$with_posix_threads" = "no" -o "$with_mit_threads" = "yes"
|
if test "$with_posix_threads" = "no" -o "$with_mit_threads" = "yes"
|
||||||
then
|
then
|
||||||
# MIT user level threads
|
# MIT user level threads
|
||||||
|
@ -213,6 +213,7 @@ enum ha_base_keytype {
|
|||||||
#define HA_ERR_CRASHED_ON_USAGE 145 /* Table must be repaired */
|
#define HA_ERR_CRASHED_ON_USAGE 145 /* Table must be repaired */
|
||||||
#define HA_ERR_LOCK_WAIT_TIMEOUT 146
|
#define HA_ERR_LOCK_WAIT_TIMEOUT 146
|
||||||
#define HA_ERR_LOCK_TABLE_FULL 147
|
#define HA_ERR_LOCK_TABLE_FULL 147
|
||||||
|
#define HA_ERR_READ_ONLY_TRANSACTION 148 /* Updates not allowed */
|
||||||
|
|
||||||
/* Other constants */
|
/* Other constants */
|
||||||
|
|
||||||
|
@ -205,4 +205,7 @@
|
|||||||
#define ER_SLAVE_THREAD 1202
|
#define ER_SLAVE_THREAD 1202
|
||||||
#define ER_TOO_MANY_USER_CONNECTIONS 1203
|
#define ER_TOO_MANY_USER_CONNECTIONS 1203
|
||||||
#define ER_SET_CONSTANTS_ONLY 1204
|
#define ER_SET_CONSTANTS_ONLY 1204
|
||||||
#define ER_ERROR_MESSAGES 205
|
#define ER_LOCK_WAIT_TIMEOUT 1205
|
||||||
|
#define ER_LOCK_TABLE_FULL 1206
|
||||||
|
#define ER_READ_ONLY_TRANSACTION 1207
|
||||||
|
#define ER_ERROR_MESSAGES 208
|
||||||
|
53
sql/field.cc
53
sql/field.cc
@ -4087,6 +4087,59 @@ const char *Field_blob::unpack(char *to, const char *from)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HAVE_GEMINI_DB
|
||||||
|
/* Blobs in Gemini tables are stored separately from the rows which contain
|
||||||
|
** them (except for tiny blobs, which are stored in the row). For all other
|
||||||
|
** blob types (blob, mediumblob, longblob), the row contains the length of
|
||||||
|
** the blob data and a blob id. These methods (pack_id, get_id, and
|
||||||
|
** unpack_id) handle packing and unpacking blob fields in Gemini rows.
|
||||||
|
*/
|
||||||
|
char *Field_blob::pack_id(char *to, const char *from, ulonglong id, uint max_length)
|
||||||
|
{
|
||||||
|
char *save=ptr;
|
||||||
|
ptr=(char*) from;
|
||||||
|
ulong length=get_length(); // Length of from string
|
||||||
|
if (length > max_length)
|
||||||
|
{
|
||||||
|
ptr=to;
|
||||||
|
length=max_length;
|
||||||
|
store_length(length); // Store max length
|
||||||
|
ptr=(char*) from;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
memcpy(to,from,packlength); // Copy length
|
||||||
|
if (length)
|
||||||
|
{
|
||||||
|
int8store(to+packlength, id);
|
||||||
|
}
|
||||||
|
ptr=save; // Restore org row pointer
|
||||||
|
return to+packlength+sizeof(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ulonglong Field_blob::get_id(const char *from)
|
||||||
|
{
|
||||||
|
ulonglong id = 0;
|
||||||
|
ulong length=get_length(from);
|
||||||
|
if (length)
|
||||||
|
longlongget(id, from+packlength);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char *Field_blob::unpack_id(char *to, const char *from, const char *bdata)
|
||||||
|
{
|
||||||
|
memcpy(to,from,packlength);
|
||||||
|
ulong length=get_length(from);
|
||||||
|
from+=packlength;
|
||||||
|
if (length)
|
||||||
|
memcpy_fixed(to+packlength, &bdata, sizeof(bdata));
|
||||||
|
else
|
||||||
|
bzero(to+packlength,sizeof(bdata));
|
||||||
|
return from+sizeof(ulonglong);
|
||||||
|
}
|
||||||
|
#endif /* HAVE_GEMINI_DB */
|
||||||
|
|
||||||
/* Keys for blobs are like keys on varchars */
|
/* Keys for blobs are like keys on varchars */
|
||||||
|
|
||||||
int Field_blob::pack_cmp(const char *a, const char *b, uint key_length)
|
int Field_blob::pack_cmp(const char *a, const char *b, uint key_length)
|
||||||
|
@ -869,6 +869,13 @@ public:
|
|||||||
}
|
}
|
||||||
char *pack(char *to, const char *from, uint max_length= ~(uint) 0);
|
char *pack(char *to, const char *from, uint max_length= ~(uint) 0);
|
||||||
const char *unpack(char *to, const char *from);
|
const char *unpack(char *to, const char *from);
|
||||||
|
#ifdef HAVE_GEMINI_DB
|
||||||
|
char *pack_id(char *to, const char *from, ulonglong id,
|
||||||
|
uint max_length= ~(uint) 0);
|
||||||
|
ulonglong get_id(const char *from);
|
||||||
|
const char *unpack_id(char *to, const char *from, const char *bdata);
|
||||||
|
enum_field_types blobtype() { return (packlength == 1 ? FIELD_TYPE_TINY_BLOB : FIELD_TYPE_BLOB);}
|
||||||
|
#endif
|
||||||
char *pack_key(char *to, const char *from, uint max_length);
|
char *pack_key(char *to, const char *from, uint max_length);
|
||||||
char *pack_key_from_key_image(char* to, const char *from, uint max_length);
|
char *pack_key_from_key_image(char* to, const char *from, uint max_length);
|
||||||
int pack_cmp(const char *a, const char *b, uint key_length);
|
int pack_cmp(const char *a, const char *b, uint key_length);
|
||||||
|
1368
sql/ha_gemini.cc
1368
sql/ha_gemini.cc
File diff suppressed because it is too large
Load Diff
@ -19,17 +19,26 @@
|
|||||||
#pragma interface /* gcc class implementation */
|
#pragma interface /* gcc class implementation */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "gem_global.h"
|
||||||
#include "dstd.h"
|
#include "dstd.h"
|
||||||
#include "dsmpub.h"
|
#include "dsmpub.h"
|
||||||
|
|
||||||
/* class for the the gemini handler */
|
/* class for the the gemini handler */
|
||||||
|
|
||||||
enum enum_key_string_options{KEY_CREATE,KEY_DELETE,KEY_CHECK};
|
enum enum_key_string_options{KEY_CREATE,KEY_DELETE,KEY_CHECK};
|
||||||
|
typedef struct st_gemini_share {
|
||||||
|
ha_rows *rec_per_key;
|
||||||
|
THR_LOCK lock;
|
||||||
|
pthread_mutex_t mutex;
|
||||||
|
char *table_name;
|
||||||
|
uint table_name_length,use_count;
|
||||||
|
} GEM_SHARE;
|
||||||
|
|
||||||
#define READ_UNCOMMITED 0
|
typedef struct gemBlobDesc
|
||||||
#define READ_COMMITED 1
|
{
|
||||||
#define REPEATABLE_READ 2
|
dsmBlobId_t blobId;
|
||||||
#define SERIALIZEABLE 3
|
dsmBuffer_t *pBlob;
|
||||||
|
} gemBlobDesc_t;
|
||||||
|
|
||||||
class ha_gemini: public handler
|
class ha_gemini: public handler
|
||||||
{
|
{
|
||||||
@ -38,7 +47,7 @@ class ha_gemini: public handler
|
|||||||
uint int_option_flag;
|
uint int_option_flag;
|
||||||
int tableNumber;
|
int tableNumber;
|
||||||
dsmIndex_t *pindexNumbers; // dsm object numbers for the indexes on this table
|
dsmIndex_t *pindexNumbers; // dsm object numbers for the indexes on this table
|
||||||
unsigned long lastRowid;
|
dsmRecid_t lastRowid;
|
||||||
uint last_dup_key;
|
uint last_dup_key;
|
||||||
bool fixed_length_row, key_read, using_ignore;
|
bool fixed_length_row, key_read, using_ignore;
|
||||||
byte *rec_buff;
|
byte *rec_buff;
|
||||||
@ -46,10 +55,12 @@ class ha_gemini: public handler
|
|||||||
dsmKey_t *pbracketLimit;
|
dsmKey_t *pbracketLimit;
|
||||||
dsmKey_t *pfoundKey;
|
dsmKey_t *pfoundKey;
|
||||||
dsmMask_t tableStatus; // Crashed/repair status
|
dsmMask_t tableStatus; // Crashed/repair status
|
||||||
|
gemBlobDesc_t *pBlobDescs;
|
||||||
|
|
||||||
int index_open(char *tableName);
|
int index_open(char *tableName);
|
||||||
int pack_row(byte **prow, int *ppackedLength, const byte *record);
|
int pack_row(byte **prow, int *ppackedLength, const byte *record,
|
||||||
void unpack_row(char *record, char *prow);
|
bool update);
|
||||||
|
int unpack_row(char *record, char *prow);
|
||||||
int findRow(THD *thd, dsmMask_t findMode, byte *buf);
|
int findRow(THD *thd, dsmMask_t findMode, byte *buf);
|
||||||
int fetch_row(void *gemini_context, const byte *buf);
|
int fetch_row(void *gemini_context, const byte *buf);
|
||||||
int handleIndexEntries(const byte * record, dsmRecid_t recid,
|
int handleIndexEntries(const byte * record, dsmRecid_t recid,
|
||||||
@ -70,24 +81,28 @@ class ha_gemini: public handler
|
|||||||
void unpack_key(char *record, dsmKey_t *key, uint index);
|
void unpack_key(char *record, dsmKey_t *key, uint index);
|
||||||
|
|
||||||
int key_cmp(uint keynr, const byte * old_row,
|
int key_cmp(uint keynr, const byte * old_row,
|
||||||
const byte * new_row);
|
const byte * new_row, bool updateStats);
|
||||||
|
|
||||||
|
int saveKeyStats(THD *thd);
|
||||||
|
void get_index_stats(THD *thd);
|
||||||
|
|
||||||
short cursorId; /* cursorId of active index cursor if any */
|
short cursorId; /* cursorId of active index cursor if any */
|
||||||
dsmMask_t lockMode; /* Shared or exclusive */
|
dsmMask_t lockMode; /* Shared or exclusive */
|
||||||
|
|
||||||
/* FIXFIX Don't know why we need this because I don't know what
|
/* FIXFIX Don't know why we need this because I don't know what
|
||||||
store_lock method does but we core dump without this */
|
store_lock method does but we core dump without this */
|
||||||
THR_LOCK alock;
|
|
||||||
THR_LOCK_DATA lock;
|
THR_LOCK_DATA lock;
|
||||||
|
GEM_SHARE *share;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ha_gemini(TABLE *table): handler(table), file(0),
|
ha_gemini(TABLE *table): handler(table), file(0),
|
||||||
int_option_flag(HA_READ_NEXT | HA_READ_PREV |
|
int_option_flag(HA_READ_NEXT | HA_READ_PREV |
|
||||||
HA_REC_NOT_IN_SEQ |
|
HA_REC_NOT_IN_SEQ |
|
||||||
HA_KEYPOS_TO_RNDPOS | HA_READ_ORDER | HA_LASTKEY_ORDER |
|
HA_KEYPOS_TO_RNDPOS | HA_READ_ORDER | HA_LASTKEY_ORDER |
|
||||||
HA_LONGLONG_KEYS | HA_NULL_KEY | HA_HAVE_KEY_READ_ONLY |
|
HA_LONGLONG_KEYS | HA_NULL_KEY | HA_HAVE_KEY_READ_ONLY |
|
||||||
HA_NO_BLOBS | HA_NO_TEMP_TABLES |
|
HA_BLOB_KEY |
|
||||||
/* HA_BLOB_KEY | */ /*HA_NOT_EXACT_COUNT | */
|
HA_NO_TEMP_TABLES | HA_NO_FULLTEXT_KEY |
|
||||||
|
/*HA_NOT_EXACT_COUNT | */
|
||||||
/*HA_KEY_READ_WRONG_STR |*/ HA_DROP_BEFORE_CREATE),
|
/*HA_KEY_READ_WRONG_STR |*/ HA_DROP_BEFORE_CREATE),
|
||||||
pbracketBase(0),pbracketLimit(0),pfoundKey(0),
|
pbracketBase(0),pbracketLimit(0),pfoundKey(0),
|
||||||
cursorId(0)
|
cursorId(0)
|
||||||
@ -100,7 +115,7 @@ class ha_gemini: public handler
|
|||||||
uint max_record_length() const { return MAXRECSZ; }
|
uint max_record_length() const { return MAXRECSZ; }
|
||||||
uint max_keys() const { return MAX_KEY-1; }
|
uint max_keys() const { return MAX_KEY-1; }
|
||||||
uint max_key_parts() const { return MAX_REF_PARTS; }
|
uint max_key_parts() const { return MAX_REF_PARTS; }
|
||||||
uint max_key_length() const { return MAXKEYSZ; }
|
uint max_key_length() const { return MAXKEYSZ / 2; }
|
||||||
bool fast_key_read() { return 1;}
|
bool fast_key_read() { return 1;}
|
||||||
bool has_transactions() { return 1;}
|
bool has_transactions() { return 1;}
|
||||||
|
|
||||||
@ -129,8 +144,12 @@ class ha_gemini: public handler
|
|||||||
void info(uint);
|
void info(uint);
|
||||||
int extra(enum ha_extra_function operation);
|
int extra(enum ha_extra_function operation);
|
||||||
int reset(void);
|
int reset(void);
|
||||||
|
int analyze(THD* thd, HA_CHECK_OPT* check_opt);
|
||||||
int check(THD* thd, HA_CHECK_OPT* check_opt);
|
int check(THD* thd, HA_CHECK_OPT* check_opt);
|
||||||
int repair(THD* thd, HA_CHECK_OPT* check_opt);
|
int repair(THD* thd, HA_CHECK_OPT* check_opt);
|
||||||
|
int restore(THD* thd, HA_CHECK_OPT* check_opt);
|
||||||
|
int backup(THD* thd, HA_CHECK_OPT* check_opt);
|
||||||
|
int optimize(THD* thd, HA_CHECK_OPT* check_opt);
|
||||||
int external_lock(THD *thd, int lock_type);
|
int external_lock(THD *thd, int lock_type);
|
||||||
virtual longlong get_auto_increment();
|
virtual longlong get_auto_increment();
|
||||||
void position(byte *record);
|
void position(byte *record);
|
||||||
@ -139,7 +158,7 @@ class ha_gemini: public handler
|
|||||||
enum ha_rkey_function start_search_flag,
|
enum ha_rkey_function start_search_flag,
|
||||||
const byte *end_key,uint end_key_len,
|
const byte *end_key,uint end_key_len,
|
||||||
enum ha_rkey_function end_search_flag);
|
enum ha_rkey_function end_search_flag);
|
||||||
|
void update_create_info(HA_CREATE_INFO *create_info);
|
||||||
int create(const char *name, register TABLE *form,
|
int create(const char *name, register TABLE *form,
|
||||||
HA_CREATE_INFO *create_info);
|
HA_CREATE_INFO *create_info);
|
||||||
int delete_table(const char *name);
|
int delete_table(const char *name);
|
||||||
@ -167,6 +186,7 @@ extern long gemini_locktablesize;
|
|||||||
extern long gemini_lock_wait_timeout;
|
extern long gemini_lock_wait_timeout;
|
||||||
extern long gemini_spin_retries;
|
extern long gemini_spin_retries;
|
||||||
extern long gemini_connection_limit;
|
extern long gemini_connection_limit;
|
||||||
|
extern char *gemini_basedir;
|
||||||
extern TYPELIB gemini_recovery_typelib;
|
extern TYPELIB gemini_recovery_typelib;
|
||||||
extern ulong gemini_recovery_options;
|
extern ulong gemini_recovery_options;
|
||||||
|
|
||||||
@ -175,12 +195,13 @@ bool gemini_end(void);
|
|||||||
bool gemini_flush_logs(void);
|
bool gemini_flush_logs(void);
|
||||||
int gemini_commit(THD *thd);
|
int gemini_commit(THD *thd);
|
||||||
int gemini_rollback(THD *thd);
|
int gemini_rollback(THD *thd);
|
||||||
|
int gemini_recovery_logging(THD *thd, bool on);
|
||||||
void gemini_disconnect(THD *thd);
|
void gemini_disconnect(THD *thd);
|
||||||
int gemini_rollback_to_savepoint(THD *thd);
|
int gemini_rollback_to_savepoint(THD *thd);
|
||||||
int gemini_parse_table_name(const char *fullname, char *dbname, char *tabname);
|
int gemini_parse_table_name(const char *fullname, char *dbname, char *tabname);
|
||||||
int gemini_is_vst(const char *pname);
|
int gemini_is_vst(const char *pname);
|
||||||
int gemini_set_option_long(int optid, long optval);
|
int gemini_set_option_long(int optid, long optval);
|
||||||
|
|
||||||
const int gemini_blocksize = 8192;
|
const int gemini_blocksize = BLKSIZE;
|
||||||
const int gemini_recbits = 7;
|
const int gemini_recbits = DEFAULT_RECBITS;
|
||||||
|
|
||||||
|
@ -694,6 +694,15 @@ void handler::print_error(int error, myf errflag)
|
|||||||
case HA_ERR_RECORD_FILE_FULL:
|
case HA_ERR_RECORD_FILE_FULL:
|
||||||
textno=ER_RECORD_FILE_FULL;
|
textno=ER_RECORD_FILE_FULL;
|
||||||
break;
|
break;
|
||||||
|
case HA_ERR_LOCK_WAIT_TIMEOUT:
|
||||||
|
textno=ER_LOCK_WAIT_TIMEOUT;
|
||||||
|
break;
|
||||||
|
case HA_ERR_LOCK_TABLE_FULL:
|
||||||
|
textno=ER_LOCK_TABLE_FULL;
|
||||||
|
break;
|
||||||
|
case HA_ERR_READ_ONLY_TRANSACTION:
|
||||||
|
textno=ER_READ_ONLY_TRANSACTION;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
my_error(ER_GET_ERRNO,errflag,error);
|
my_error(ER_GET_ERRNO,errflag,error);
|
||||||
@ -757,6 +766,25 @@ int ha_commit_rename(THD *thd)
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Tell the handler to turn on or off logging to the handler's
|
||||||
|
recovery log
|
||||||
|
*/
|
||||||
|
int ha_recovery_logging(THD *thd, bool on)
|
||||||
|
{
|
||||||
|
int error=0;
|
||||||
|
|
||||||
|
DBUG_ENTER("ha_recovery_logging");
|
||||||
|
#ifdef USING_TRANSACTIONS
|
||||||
|
if (opt_using_transactions)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_GEMINI_DB
|
||||||
|
error = gemini_recovery_logging(thd, on);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
DBUG_RETURN(error);
|
||||||
|
}
|
||||||
|
|
||||||
int handler::index_next_same(byte *buf, const byte *key, uint keylen)
|
int handler::index_next_same(byte *buf, const byte *key, uint keylen)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
|
@ -74,6 +74,7 @@
|
|||||||
#define HA_NOT_DELETE_WITH_CACHE (HA_NOT_READ_AFTER_KEY*2)
|
#define HA_NOT_DELETE_WITH_CACHE (HA_NOT_READ_AFTER_KEY*2)
|
||||||
#define HA_NO_TEMP_TABLES (HA_NOT_DELETE_WITH_CACHE*2)
|
#define HA_NO_TEMP_TABLES (HA_NOT_DELETE_WITH_CACHE*2)
|
||||||
#define HA_NO_PREFIX_CHAR_KEYS (HA_NO_TEMP_TABLES*2)
|
#define HA_NO_PREFIX_CHAR_KEYS (HA_NO_TEMP_TABLES*2)
|
||||||
|
#define HA_NO_FULLTEXT_KEY (HA_NO_PREFIX_CHAR_KEYS*2)
|
||||||
|
|
||||||
/* Parameters for open() (in register form->filestat) */
|
/* Parameters for open() (in register form->filestat) */
|
||||||
/* HA_GET_INFO does a implicit HA_ABORT_IF_LOCKED */
|
/* HA_GET_INFO does a implicit HA_ABORT_IF_LOCKED */
|
||||||
@ -353,3 +354,4 @@ int ha_autocommit_or_rollback(THD *thd, int error);
|
|||||||
void ha_set_spin_retries(uint retries);
|
void ha_set_spin_retries(uint retries);
|
||||||
bool ha_flush_logs(void);
|
bool ha_flush_logs(void);
|
||||||
int ha_commit_rename(THD *thd);
|
int ha_commit_rename(THD *thd);
|
||||||
|
int ha_recovery_logging(THD *thd, bool on);
|
||||||
|
26
sql/lock.cc
26
sql/lock.cc
@ -35,6 +35,7 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table,uint count,
|
|||||||
bool unlock, TABLE **write_locked);
|
bool unlock, TABLE **write_locked);
|
||||||
static int lock_external(TABLE **table,uint count);
|
static int lock_external(TABLE **table,uint count);
|
||||||
static int unlock_external(THD *thd, TABLE **table,uint count);
|
static int unlock_external(THD *thd, TABLE **table,uint count);
|
||||||
|
static void print_lock_error(int error);
|
||||||
|
|
||||||
|
|
||||||
MYSQL_LOCK *mysql_lock_tables(THD *thd,TABLE **tables,uint count)
|
MYSQL_LOCK *mysql_lock_tables(THD *thd,TABLE **tables,uint count)
|
||||||
@ -154,7 +155,7 @@ static int lock_external(TABLE **tables,uint count)
|
|||||||
(*tables)->file->external_lock(thd, F_UNLCK);
|
(*tables)->file->external_lock(thd, F_UNLCK);
|
||||||
(*tables)->current_lock=F_UNLCK;
|
(*tables)->current_lock=F_UNLCK;
|
||||||
}
|
}
|
||||||
my_error(ER_CANT_LOCK,MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG),error);
|
print_lock_error(error);
|
||||||
DBUG_RETURN(error);
|
DBUG_RETURN(error);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -325,7 +326,7 @@ static int unlock_external(THD *thd, TABLE **table,uint count)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (error_code)
|
if (error_code)
|
||||||
my_error(ER_CANT_LOCK,MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG),error_code);
|
print_lock_error(error_code);
|
||||||
DBUG_RETURN(error_code);
|
DBUG_RETURN(error_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -480,3 +481,24 @@ bool wait_for_locked_table_names(THD *thd, TABLE_LIST *table_list)
|
|||||||
}
|
}
|
||||||
DBUG_RETURN(result);
|
DBUG_RETURN(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void print_lock_error(int error)
|
||||||
|
{
|
||||||
|
int textno;
|
||||||
|
DBUG_ENTER("print_lock_error");
|
||||||
|
|
||||||
|
switch (error) {
|
||||||
|
case HA_ERR_LOCK_WAIT_TIMEOUT:
|
||||||
|
textno=ER_LOCK_WAIT_TIMEOUT;
|
||||||
|
break;
|
||||||
|
case HA_ERR_READ_ONLY_TRANSACTION:
|
||||||
|
textno=ER_READ_ONLY_TRANSACTION;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
textno=ER_CANT_LOCK;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
my_error(textno,MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG),error);
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -215,3 +215,6 @@
|
|||||||
"Could not create slave thread, check system resources",
|
"Could not create slave thread, check system resources",
|
||||||
"User %-.64s has already more than 'max_user_connections' active connections",
|
"User %-.64s has already more than 'max_user_connections' active connections",
|
||||||
"You may only use constant expressions with SET",
|
"You may only use constant expressions with SET",
|
||||||
|
"Lock wait timeout exceeded",
|
||||||
|
"The total number of locks exceeds the lock table size",
|
||||||
|
"Update locks cannot be acquired during a READ UNCOMMITTED transaction",
|
||||||
|
@ -209,3 +209,6 @@
|
|||||||
"Could not create slave thread, check system resources",
|
"Could not create slave thread, check system resources",
|
||||||
"User %-.64s has already more than 'max_user_connections' active connections",
|
"User %-.64s has already more than 'max_user_connections' active connections",
|
||||||
"You may only use constant expressions with SET",
|
"You may only use constant expressions with SET",
|
||||||
|
"Lock wait timeout exceeded",
|
||||||
|
"The total number of locks exceeds the lock table size",
|
||||||
|
"Update locks cannot be acquired during a READ UNCOMMITTED transaction",
|
||||||
|
@ -206,3 +206,6 @@
|
|||||||
"Could not create slave thread, check system resources",
|
"Could not create slave thread, check system resources",
|
||||||
"User %-.64s has already more than 'max_user_connections' active connections",
|
"User %-.64s has already more than 'max_user_connections' active connections",
|
||||||
"You may only use constant expressions with SET",
|
"You may only use constant expressions with SET",
|
||||||
|
"Lock wait timeout exceeded",
|
||||||
|
"The total number of locks exceeds the lock table size",
|
||||||
|
"Update locks cannot be acquired during a READ UNCOMMITTED transaction",
|
||||||
|
@ -206,3 +206,6 @@
|
|||||||
"Could not create slave thread, check system resources",
|
"Could not create slave thread, check system resources",
|
||||||
"User %-.64s has already more than 'max_user_connections' active connections",
|
"User %-.64s has already more than 'max_user_connections' active connections",
|
||||||
"You may only use constant expressions with SET",
|
"You may only use constant expressions with SET",
|
||||||
|
"Lock wait timeout exceeded",
|
||||||
|
"The total number of locks exceeds the lock table size",
|
||||||
|
"Update locks cannot be acquired during a READ UNCOMMITTED transaction",
|
||||||
|
@ -210,3 +210,6 @@
|
|||||||
"Could not create slave thread, check system resources",
|
"Could not create slave thread, check system resources",
|
||||||
"User %-.64s has already more than 'max_user_connections' active connections",
|
"User %-.64s has already more than 'max_user_connections' active connections",
|
||||||
"You may only use constant expressions with SET",
|
"You may only use constant expressions with SET",
|
||||||
|
"Lock wait timeout exceeded",
|
||||||
|
"The total number of locks exceeds the lock table size",
|
||||||
|
"Update locks cannot be acquired during a READ UNCOMMITTED transaction",
|
||||||
|
@ -206,3 +206,6 @@
|
|||||||
"Could not create slave thread, check system resources",
|
"Could not create slave thread, check system resources",
|
||||||
"User %-.64s has already more than 'max_user_connections' active connections",
|
"User %-.64s has already more than 'max_user_connections' active connections",
|
||||||
"You may only use constant expressions with SET",
|
"You may only use constant expressions with SET",
|
||||||
|
"Lock wait timeout exceeded",
|
||||||
|
"The total number of locks exceeds the lock table size",
|
||||||
|
"Update locks cannot be acquired during a READ UNCOMMITTED transaction",
|
||||||
|
@ -209,3 +209,6 @@
|
|||||||
"Could not create slave thread, check system resources",
|
"Could not create slave thread, check system resources",
|
||||||
"User %-.64s has already more than 'max_user_connections' active connections",
|
"User %-.64s has already more than 'max_user_connections' active connections",
|
||||||
"You may only use constant expressions with SET",
|
"You may only use constant expressions with SET",
|
||||||
|
"Lock wait timeout exceeded",
|
||||||
|
"The total number of locks exceeds the lock table size",
|
||||||
|
"Update locks cannot be acquired during a READ UNCOMMITTED transaction",
|
||||||
|
@ -206,3 +206,6 @@
|
|||||||
"Could not create slave thread, check system resources",
|
"Could not create slave thread, check system resources",
|
||||||
"User %-.64s has already more than 'max_user_connections' active connections",
|
"User %-.64s has already more than 'max_user_connections' active connections",
|
||||||
"You may only use constant expressions with SET",
|
"You may only use constant expressions with SET",
|
||||||
|
"Lock wait timeout exceeded",
|
||||||
|
"The total number of locks exceeds the lock table size",
|
||||||
|
"Update locks cannot be acquired during a READ UNCOMMITTED transaction",
|
||||||
|
@ -208,3 +208,6 @@
|
|||||||
"Could not create slave thread, check system resources",
|
"Could not create slave thread, check system resources",
|
||||||
"User %-.64s has already more than 'max_user_connections' active connections",
|
"User %-.64s has already more than 'max_user_connections' active connections",
|
||||||
"You may only use constant expressions with SET",
|
"You may only use constant expressions with SET",
|
||||||
|
"Lock wait timeout exceeded",
|
||||||
|
"The total number of locks exceeds the lock table size",
|
||||||
|
"Update locks cannot be acquired during a READ UNCOMMITTED transaction",
|
||||||
|
@ -206,3 +206,6 @@
|
|||||||
"Could not create slave thread, check system resources",
|
"Could not create slave thread, check system resources",
|
||||||
"User %-.64s has already more than 'max_user_connections' active connections",
|
"User %-.64s has already more than 'max_user_connections' active connections",
|
||||||
"You may only use constant expressions with SET",
|
"You may only use constant expressions with SET",
|
||||||
|
"Lock wait timeout exceeded",
|
||||||
|
"The total number of locks exceeds the lock table size",
|
||||||
|
"Update locks cannot be acquired during a READ UNCOMMITTED transaction",
|
||||||
|
@ -208,3 +208,6 @@
|
|||||||
"Could not create slave thread, check system resources",
|
"Could not create slave thread, check system resources",
|
||||||
"User %-.64s has already more than 'max_user_connections' active connections",
|
"User %-.64s has already more than 'max_user_connections' active connections",
|
||||||
"You may only use constant expressions with SET",
|
"You may only use constant expressions with SET",
|
||||||
|
"Lock wait timeout exceeded",
|
||||||
|
"The total number of locks exceeds the lock table size",
|
||||||
|
"Update locks cannot be acquired during a READ UNCOMMITTED transaction",
|
||||||
|
@ -206,3 +206,6 @@
|
|||||||
"Could not create slave thread, check system resources",
|
"Could not create slave thread, check system resources",
|
||||||
"User %-.64s has already more than 'max_user_connections' active connections",
|
"User %-.64s has already more than 'max_user_connections' active connections",
|
||||||
"You may only use constant expressions with SET",
|
"You may only use constant expressions with SET",
|
||||||
|
"Lock wait timeout exceeded",
|
||||||
|
"The total number of locks exceeds the lock table size",
|
||||||
|
"Update locks cannot be acquired during a READ UNCOMMITTED transaction",
|
||||||
|
@ -208,3 +208,6 @@
|
|||||||
"Could not create slave thread, check system resources",
|
"Could not create slave thread, check system resources",
|
||||||
"User %-.64s has already more than 'max_user_connections' active connections",
|
"User %-.64s has already more than 'max_user_connections' active connections",
|
||||||
"You may only use constant expressions with SET",
|
"You may only use constant expressions with SET",
|
||||||
|
"Lock wait timeout exceeded",
|
||||||
|
"The total number of locks exceeds the lock table size",
|
||||||
|
"Update locks cannot be acquired during a READ UNCOMMITTED transaction",
|
||||||
|
@ -208,3 +208,6 @@
|
|||||||
"Could not create slave thread, check system resources",
|
"Could not create slave thread, check system resources",
|
||||||
"User %-.64s has already more than 'max_user_connections' active connections",
|
"User %-.64s has already more than 'max_user_connections' active connections",
|
||||||
"You may only use constant expressions with SET",
|
"You may only use constant expressions with SET",
|
||||||
|
"Lock wait timeout exceeded",
|
||||||
|
"The total number of locks exceeds the lock table size",
|
||||||
|
"Update locks cannot be acquired during a READ UNCOMMITTED transaction",
|
||||||
|
@ -210,3 +210,6 @@
|
|||||||
"Could not create slave thread, check system resources",
|
"Could not create slave thread, check system resources",
|
||||||
"User %-.64s has already more than 'max_user_connections' active connections",
|
"User %-.64s has already more than 'max_user_connections' active connections",
|
||||||
"You may only use constant expressions with SET",
|
"You may only use constant expressions with SET",
|
||||||
|
"Lock wait timeout exceeded",
|
||||||
|
"The total number of locks exceeds the lock table size",
|
||||||
|
"Update locks cannot be acquired during a READ UNCOMMITTED transaction",
|
||||||
|
@ -206,3 +206,6 @@
|
|||||||
"Could not create slave thread, check system resources",
|
"Could not create slave thread, check system resources",
|
||||||
"User %-.64s has already more than 'max_user_connections' active connections",
|
"User %-.64s has already more than 'max_user_connections' active connections",
|
||||||
"You may only use constant expressions with SET",
|
"You may only use constant expressions with SET",
|
||||||
|
"Lock wait timeout exceeded",
|
||||||
|
"The total number of locks exceeds the lock table size",
|
||||||
|
"Update locks cannot be acquired during a READ UNCOMMITTED transaction",
|
||||||
|
@ -210,3 +210,6 @@
|
|||||||
"Could not create slave thread, check system resources",
|
"Could not create slave thread, check system resources",
|
||||||
"User %-.64s has already more than 'max_user_connections' active connections",
|
"User %-.64s has already more than 'max_user_connections' active connections",
|
||||||
"You may only use constant expressions with SET",
|
"You may only use constant expressions with SET",
|
||||||
|
"Lock wait timeout exceeded",
|
||||||
|
"The total number of locks exceeds the lock table size",
|
||||||
|
"Update locks cannot be acquired during a READ UNCOMMITTED transaction",
|
||||||
|
@ -209,3 +209,6 @@
|
|||||||
"îÅ ÍÏÇÕ ÓÏÚÄÁÔØ ÐÒÏÃÅÓÓ SLAVE, ÐÒÏ×ÅÒØÔÅ ÓÉÓÔÅÍÎÙÅ ÒÅÓÕÒÓÙ",
|
"îÅ ÍÏÇÕ ÓÏÚÄÁÔØ ÐÒÏÃÅÓÓ SLAVE, ÐÒÏ×ÅÒØÔÅ ÓÉÓÔÅÍÎÙÅ ÒÅÓÕÒÓÙ",
|
||||||
"User %-.64s has already more than 'max_user_connections' active connections",
|
"User %-.64s has already more than 'max_user_connections' active connections",
|
||||||
"You may only use constant expressions with SET",
|
"You may only use constant expressions with SET",
|
||||||
|
"Lock wait timeout exceeded",
|
||||||
|
"The total number of locks exceeds the lock table size",
|
||||||
|
"Update locks cannot be acquired during a READ UNCOMMITTED transaction",
|
||||||
|
@ -214,3 +214,6 @@
|
|||||||
"Could not create slave thread, check system resources",
|
"Could not create slave thread, check system resources",
|
||||||
"User %-.64s has already more than 'max_user_connections' active connections",
|
"User %-.64s has already more than 'max_user_connections' active connections",
|
||||||
"You may only use constant expressions with SET",
|
"You may only use constant expressions with SET",
|
||||||
|
"Lock wait timeout exceeded",
|
||||||
|
"The total number of locks exceeds the lock table size",
|
||||||
|
"Update locks cannot be acquired during a READ UNCOMMITTED transaction",
|
||||||
|
@ -207,3 +207,6 @@
|
|||||||
"Could not create slave thread, check system resources",
|
"Could not create slave thread, check system resources",
|
||||||
"User %-.64s has already more than 'max_user_connections' active connections",
|
"User %-.64s has already more than 'max_user_connections' active connections",
|
||||||
"You may only use constant expressions with SET",
|
"You may only use constant expressions with SET",
|
||||||
|
"Lock wait timeout exceeded",
|
||||||
|
"The total number of locks exceeds the lock table size",
|
||||||
|
"Update locks cannot be acquired during a READ UNCOMMITTED transaction",
|
||||||
|
@ -206,3 +206,6 @@
|
|||||||
"Kunde inte starta en tråd för replikering",
|
"Kunde inte starta en tråd för replikering",
|
||||||
"Användare '%-.64s' har redan 'max_user_connections' aktiva inloggningar",
|
"Användare '%-.64s' har redan 'max_user_connections' aktiva inloggningar",
|
||||||
"Du kan endast använda konstant-uttryck med SET",
|
"Du kan endast använda konstant-uttryck med SET",
|
||||||
|
"Lock wait timeout exceeded",
|
||||||
|
"The total number of locks exceeds the lock table size",
|
||||||
|
"Update locks cannot be acquired during a READ UNCOMMITTED transaction",
|
||||||
|
@ -1388,11 +1388,6 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
|
|||||||
bool refresh;
|
bool refresh;
|
||||||
DBUG_ENTER("open_ltable");
|
DBUG_ENTER("open_ltable");
|
||||||
|
|
||||||
#ifdef __WIN__
|
|
||||||
/* Win32 can't drop a file that is open */
|
|
||||||
if (lock_type == TL_WRITE_ALLOW_READ)
|
|
||||||
lock_type= TL_WRITE;
|
|
||||||
#endif
|
|
||||||
thd->proc_info="Opening table";
|
thd->proc_info="Opening table";
|
||||||
while (!(table=open_table(thd,table_list->db ? table_list->db : thd->db,
|
while (!(table=open_table(thd,table_list->db ? table_list->db : thd->db,
|
||||||
table_list->real_name,table_list->name,
|
table_list->real_name,table_list->name,
|
||||||
@ -1400,6 +1395,19 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
|
|||||||
if (table)
|
if (table)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
|
#ifdef __WIN__
|
||||||
|
/* Win32 can't drop a file that is open */
|
||||||
|
if (lock_type == TL_WRITE_ALLOW_READ
|
||||||
|
#ifdef HAVE_GEMINI_DB
|
||||||
|
&& table->db_type != DB_TYPE_GEMINI
|
||||||
|
#endif /* HAVE_GEMINI_DB */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
lock_type= TL_WRITE;
|
||||||
|
}
|
||||||
|
#endif /* __WIN__ */
|
||||||
|
|
||||||
table_list->table=table;
|
table_list->table=table;
|
||||||
table->grant= table_list->grant;
|
table->grant= table_list->grant;
|
||||||
if (thd->locked_tables)
|
if (thd->locked_tables)
|
||||||
|
@ -423,6 +423,13 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
|
|||||||
column->field_name);
|
column->field_name);
|
||||||
DBUG_RETURN(-1);
|
DBUG_RETURN(-1);
|
||||||
}
|
}
|
||||||
|
if (key->type == Key::FULLTEXT &&
|
||||||
|
(file->option_flag() & HA_NO_FULLTEXT_KEY))
|
||||||
|
{
|
||||||
|
my_printf_error(ER_WRONG_KEY_COLUMN, ER(ER_WRONG_KEY_COLUMN), MYF(0),
|
||||||
|
column->field_name);
|
||||||
|
DBUG_RETURN(-1);
|
||||||
|
}
|
||||||
if (f_is_blob(sql_field->pack_flag))
|
if (f_is_blob(sql_field->pack_flag))
|
||||||
{
|
{
|
||||||
if (!(file->option_flag() & HA_BLOB_KEY))
|
if (!(file->option_flag() & HA_BLOB_KEY))
|
||||||
@ -1678,6 +1685,16 @@ copy_data_between_tables(TABLE *from,TABLE *to,
|
|||||||
goto err;
|
goto err;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Turn off recovery logging since rollback of an
|
||||||
|
alter table is to delete the new table so there
|
||||||
|
is no need to log the changes to it. */
|
||||||
|
error = ha_recovery_logging(thd,false);
|
||||||
|
if(error)
|
||||||
|
{
|
||||||
|
error = 1;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
init_read_record(&info, thd, from, (SQL_SELECT *) 0, 1,1);
|
init_read_record(&info, thd, from, (SQL_SELECT *) 0, 1,1);
|
||||||
if (handle_duplicates == DUP_IGNORE ||
|
if (handle_duplicates == DUP_IGNORE ||
|
||||||
handle_duplicates == DUP_REPLACE)
|
handle_duplicates == DUP_REPLACE)
|
||||||
@ -1723,6 +1740,7 @@ copy_data_between_tables(TABLE *from,TABLE *to,
|
|||||||
if (to->file->activate_all_index(thd))
|
if (to->file->activate_all_index(thd))
|
||||||
error=1;
|
error=1;
|
||||||
|
|
||||||
|
tmp_error = ha_recovery_logging(thd,true);
|
||||||
/*
|
/*
|
||||||
Ensure that the new table is saved properly to disk so that we
|
Ensure that the new table is saved properly to disk so that we
|
||||||
can do a rename
|
can do a rename
|
||||||
@ -1734,6 +1752,7 @@ copy_data_between_tables(TABLE *from,TABLE *to,
|
|||||||
if (to->file->external_lock(thd,F_UNLCK))
|
if (to->file->external_lock(thd,F_UNLCK))
|
||||||
error=1;
|
error=1;
|
||||||
err:
|
err:
|
||||||
|
tmp_error = ha_recovery_logging(thd,true);
|
||||||
free_io_cache(from);
|
free_io_cache(from);
|
||||||
*copied= found_count;
|
*copied= found_count;
|
||||||
*deleted=delete_count;
|
*deleted=delete_count;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user