Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
MariaDB
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
MariaDB
Commits
827fae79
Commit
827fae79
authored
May 10, 2007
by
kostja@vajra.(none)
Browse files
Options
Browse Files
Download
Plain Diff
Merge vajra.(none):/opt/local/work/mysql-5.0-21483
into vajra.(none):/opt/local/work/mysql-5.1-runtime
parents
770219c1
41239f1f
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
135 additions
and
59 deletions
+135
-59
sql/sql_insert.cc
sql/sql_insert.cc
+135
-59
No files found.
sql/sql_insert.cc
View file @
827fae79
...
@@ -384,6 +384,88 @@ void prepare_triggers_for_insert_stmt(TABLE *table)
...
@@ -384,6 +384,88 @@ void prepare_triggers_for_insert_stmt(TABLE *table)
}
}
/**
Upgrade table-level lock of INSERT statement to TL_WRITE if
a more concurrent lock is infeasible for some reason. This is
necessary for engines without internal locking support (MyISAM).
An engine with internal locking implementation might later
downgrade the lock in handler::store_lock() method.
*/
void
upgrade_lock_type
(
THD
*
thd
,
thr_lock_type
*
lock_type
,
enum_duplicates
duplic
,
bool
is_multi_insert
)
{
if
(
duplic
==
DUP_UPDATE
||
duplic
==
DUP_REPLACE
&&
*
lock_type
==
TL_WRITE_CONCURRENT_INSERT
)
{
*
lock_type
=
TL_WRITE
;
return
;
}
if
(
*
lock_type
==
TL_WRITE_DELAYED
)
{
#ifdef EMBEDDED_LIBRARY
/* No auxiliary threads in the embedded server. */
*
lock_type
=
TL_WRITE
;
return
;
#else
/*
We do not use delayed threads if:
- we're running in the safe mode or skip-new - the feature
is disabled in these modes
- we're running this query in statement level replication,
on a replication slave - because we must ensure serial
execution of queries on the slave
- it is INSERT .. ON DUPLICATE KEY UPDATE - in this case the
insert cannot be concurrent
*/
if
(
specialflag
&
(
SPECIAL_NO_NEW_FUNC
|
SPECIAL_SAFE_MODE
)
||
thd
->
slave_thread
||
thd
->
variables
.
max_insert_delayed_threads
==
0
)
{
*
lock_type
=
TL_WRITE
;
return
;
}
#endif
bool
log_on
=
(
thd
->
options
&
OPTION_BIN_LOG
||
!
(
thd
->
security_ctx
->
master_access
&
SUPER_ACL
));
if
(
global_system_variables
.
binlog_format
==
BINLOG_FORMAT_STMT
&&
log_on
&&
mysql_bin_log
.
is_open
()
&&
is_multi_insert
)
{
/*
Statement-based binary logging does not work in this case, because:
a) two concurrent statements may have their rows intermixed in the
queue, leading to autoincrement replication problems on slave (because
the values generated used for one statement don't depend only on the
value generated for the first row of this statement, so are not
replicable)
b) if first row of the statement has an error the full statement is
not binlogged, while next rows of the statement may be inserted.
c) if first row succeeds, statement is binlogged immediately with a
zero error code (i.e. "no error"), if then second row fails, query
will fail on slave too and slave will stop (wrongly believing that the
master got no error).
So we fallback to non-delayed INSERT.
Note that to be fully correct, we should test the "binlog format which
the delayed thread is going to use for this row". But in the common case
where the global binlog format is not changed and the session binlog
format may be changed, that is equal to the global binlog format.
We test it without mutex for speed reasons (condition rarely true), and
in the common case (global not changed) it is as good as without mutex;
if global value is changed, anyway there is uncertainty as the delayed
thread may be old and use the before-the-change value.
*/
*
lock_type
=
TL_WRITE
;
}
}
}
/**
INSERT statement implementation
*/
bool
mysql_insert
(
THD
*
thd
,
TABLE_LIST
*
table_list
,
bool
mysql_insert
(
THD
*
thd
,
TABLE_LIST
*
table_list
,
List
<
Item
>
&
fields
,
List
<
Item
>
&
fields
,
List
<
List_item
>
&
values_list
,
List
<
List_item
>
&
values_list
,
...
@@ -419,67 +501,31 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
...
@@ -419,67 +501,31 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
DBUG_ENTER
(
"mysql_insert"
);
DBUG_ENTER
(
"mysql_insert"
);
/*
/*
in safe mode or with skip-new change delayed insert to be regular
Upgrade lock type if the requested lock is incompatible with
if we are told to replace duplicates, the insert cannot be concurrent
the current connection mode or table operation.
delayed insert changed to regular in slave thread
*/
*/
#ifdef EMBEDDED_LIBRARY
upgrade_lock_type
(
thd
,
&
table_list
->
lock_type
,
duplic
,
if
(
lock_type
==
TL_WRITE_DELAYED
)
values_list
.
elements
>
1
);
lock_type
=
TL_WRITE
;
lock_type
=
table_list
->
lock_type
;
#else
if
((
lock_type
==
TL_WRITE_DELAYED
&&
((
specialflag
&
(
SPECIAL_NO_NEW_FUNC
|
SPECIAL_SAFE_MODE
))
||
thd
->
slave_thread
||
!
thd
->
variables
.
max_insert_delayed_threads
))
||
(
lock_type
==
TL_WRITE_CONCURRENT_INSERT
&&
duplic
==
DUP_REPLACE
)
||
(
duplic
==
DUP_UPDATE
))
lock_type
=
TL_WRITE
;
#endif
if
((
lock_type
==
TL_WRITE_DELAYED
)
&&
(
global_system_variables
.
binlog_format
==
BINLOG_FORMAT_STMT
)
&&
log_on
&&
mysql_bin_log
.
is_open
()
&&
(
values_list
.
elements
>
1
))
{
/*
/*
Statement-based binary logging does not work in this case, because:
We can't write-delayed into a table locked with LOCK TABLES:
a) two concurrent statements may have their rows intermixed in the
this will lead to a deadlock, since the delayed thread will
queue, leading to autoincrement replication problems on slave (because
never be able to get a lock on the table. QQQ: why not
the values generated used for one statement don't depend only on the
upgrade the lock here instead?
value generated for the first row of this statement, so are not
replicable)
b) if first row of the statement has an error the full statement is
not binlogged, while next rows of the statement may be inserted.
c) if first row succeeds, statement is binlogged immediately with a
zero error code (i.e. "no error"), if then second row fails, query
will fail on slave too and slave will stop (wrongly believing that the
master got no error).
So we fallback to non-delayed INSERT.
Note that to be fully correct, we should test the "binlog format which
the delayed thread is going to use for this row". But in the common case
where the global binlog format is not changed and the session binlog
format may be changed, that is equal to the global binlog format.
We test it without mutex for speed reasons (condition rarely true), and
in the common case (global not changed) it is as good as without mutex;
if global value is changed, anyway there is uncertainty as the delayed
thread may be old and use the before-the-change value.
*/
*/
lock_type
=
TL_WRITE
;
if
(
lock_type
==
TL_WRITE_DELAYED
&&
thd
->
locked_tables
&&
find_locked_table
(
thd
,
table_list
->
db
,
table_list
->
table_name
))
{
my_error
(
ER_DELAYED_INSERT_TABLE_LOCKED
,
MYF
(
0
),
table_list
->
table_name
);
DBUG_RETURN
(
TRUE
);
}
}
table_list
->
lock_type
=
lock_type
;
#ifndef EMBEDDED_LIBRARY
#ifndef EMBEDDED_LIBRARY
if
(
lock_type
==
TL_WRITE_DELAYED
)
if
(
lock_type
==
TL_WRITE_DELAYED
)
{
{
res
=
1
;
res
=
1
;
if
(
thd
->
locked_tables
)
{
DBUG_ASSERT
(
table_list
->
db
);
/* Must be set in the parser */
if
(
find_locked_table
(
thd
,
table_list
->
db
,
table_list
->
table_name
))
{
my_error
(
ER_DELAYED_INSERT_TABLE_LOCKED
,
MYF
(
0
),
table_list
->
table_name
);
DBUG_RETURN
(
TRUE
);
}
}
if
((
table
=
delayed_get_table
(
thd
,
table_list
))
&&
!
thd
->
is_fatal_error
)
if
((
table
=
delayed_get_table
(
thd
,
table_list
))
&&
!
thd
->
is_fatal_error
)
{
{
/*
/*
...
@@ -1502,6 +1548,12 @@ class delayed_row :public ilink {
...
@@ -1502,6 +1548,12 @@ class delayed_row :public ilink {
}
}
};
};
/**
delayed_insert - context of a thread responsible for delayed insert
into one table. When processing delayed inserts, we create an own
thread for every distinct table. Later on all delayed inserts directed
into that table are handled by a dedicated thread.
*/
class
delayed_insert
:
public
ilink
{
class
delayed_insert
:
public
ilink
{
uint
locks_in_memory
;
uint
locks_in_memory
;
...
@@ -1598,6 +1650,12 @@ class delayed_insert :public ilink {
...
@@ -1598,6 +1650,12 @@ class delayed_insert :public ilink {
I_List
<
delayed_insert
>
delayed_threads
;
I_List
<
delayed_insert
>
delayed_threads
;
/**
Return an instance of delayed insert thread that can handle
inserts into a given table, if it exists. Otherwise return NULL.
*/
static
delayed_insert
*
find_handler
(
THD
*
thd
,
TABLE_LIST
*
table_list
)
delayed_insert
*
find_handler
(
THD
*
thd
,
TABLE_LIST
*
table_list
)
{
{
thd
->
proc_info
=
"waiting for delay_list"
;
thd
->
proc_info
=
"waiting for delay_list"
;
...
@@ -1618,6 +1676,18 @@ delayed_insert *find_handler(THD *thd, TABLE_LIST *table_list)
...
@@ -1618,6 +1676,18 @@ delayed_insert *find_handler(THD *thd, TABLE_LIST *table_list)
}
}
/**
Attempt to find or create a delayed insert thread to handle inserts
into this table.
@return Return an instance of the table in the delayed thread
@retval NULL too many delayed threads OR
this thread ran out of resources OR
a newly created delayed insert thread ran out of resources OR
the delayed insert thread failed to open the table.
In the last three cases an error is set in THD.
*/
static
TABLE
*
delayed_get_table
(
THD
*
thd
,
TABLE_LIST
*
table_list
)
static
TABLE
*
delayed_get_table
(
THD
*
thd
,
TABLE_LIST
*
table_list
)
{
{
int
error
;
int
error
;
...
@@ -1726,11 +1796,17 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list)
...
@@ -1726,11 +1796,17 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list)
}
}
/*
/**
As we can't let many threads modify the same TABLE structure, we create
As we can't let many client threads modify the same TABLE
an own structure for each tread. This includes a row buffer to save the
structure of the dedicated delayed insert thread, we create an
column values and new fields that points to the new row buffer.
own structure for each client thread. This includes a row
The memory is allocated in the client thread and is freed automaticly.
buffer to save the column values and new fields that point to
the new row buffer. The memory is allocated in the client
thread and is freed automatically.
@pre This function is called from the client thread. Delayed
insert thread mutex must be acquired before invoking this
function.
*/
*/
TABLE
*
delayed_insert
::
get_local_table
(
THD
*
client_thd
)
TABLE
*
delayed_insert
::
get_local_table
(
THD
*
client_thd
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment