function apdqc_truncate_table in Asynchronous Prefetch Database Query Cache 7
Empties out a database table in a non metadata locking fashion.
Parameters
string $table: Name of the table you wish to truncate.
1 call to apdqc_truncate_table()
- APDQCache::clear in ./
apdqc.cache.inc - Implements DrupalCacheInterface::clear().
File
- ./
apdqc.mysql.inc, line 892 - APDQC Database interface code for MySQL database servers.
Code
function apdqc_truncate_table($table) {
// Make sure the $mysqli object is available.
$mysqli = apdqc_get_db_object(array(
$table,
), array(
'*',
));
if (empty($mysqli)) {
return db_truncate($table)
->execute();
}
// TRUNCATE is not a transaction safe statement if the table being cleared was
// used in any query inside of a transaction since it is a DDL statement which
// results in a metadata lock. Always use the slower, but non locking
// transactional, DELETE on the cache_field table.
if (Database::getConnection()
->inTransaction() || variable_get('cache_no_truncate', CACHE_NO_TRUNCATE) || $table === 'cache_field') {
$query = Database::getConnection()
->prefixTables("DELETE FROM {" . db_escape_table($table) . "}");
$result = apdqc_query(array(
$table,
), array(
'*',
), $query);
if (is_string($result) && $result === 'NO DB') {
return db_truncate($table)
->execute();
}
return;
}
// No Op if table is empty.
$real_table_name = Database::getConnection()
->prefixTables("{" . db_escape_table($table) . "}");
$results = $mysqli
->query("SELECT 1 FROM {$real_table_name} LIMIT 1");
if (!empty($results) && $results instanceof mysqli_result) {
$empty_table = $results
->fetch_row();
}
if (empty($results) || empty($empty_table)) {
return;
}
// Renaming tables is a lot faster than truncate. Rename and then do an
// async Truncate so we don't get stalled.
// Make sure truncated table exists before trying to use it.
$real_table_name_truncated = Database::getConnection()
->prefixTables("{" . db_escape_table($table) . "__truncated_table}");
// Remove any values from the *__truncated_table if needed.
$results = $mysqli
->query("SELECT 1 FROM {$real_table_name_truncated} LIMIT 1");
if ($results === FALSE) {
// Create truncated table if it does not exist.
$mysqli
->query("CREATE TABLE IF NOT EXISTS {$real_table_name_truncated} LIKE {$real_table_name}");
// Set to empty since this table was just created.
$db_row = NULL;
}
else {
// mysqli_result::fetch_row returns NULL when there are no more rows.
$db_row = $results
->fetch_row();
}
if (!is_null($db_row)) {
// Empty the truncated_table since it is not empty.
$result = apdqc_query(array(
$real_table_name_truncated,
), array(
'*',
), "TRUNCATE {$real_table_name_truncated}");
if (is_string($result) && $result === 'NO DB') {
return db_truncate($table)
->execute();
}
}
// Use rename so the truncate happens at the end of this request.
$real_table_name_temp = Database::getConnection()
->prefixTables("{" . db_escape_table($table) . "__temp_table}");
$query = "\n RENAME TABLE {$real_table_name} TO {$real_table_name_temp},\n {$real_table_name_truncated} TO {$real_table_name},\n {$real_table_name_temp} TO {$real_table_name_truncated}\n ";
$mysqli
->query($query, MYSQLI_ASYNC);
if (apdqc_kill_metadata_lock($mysqli->thread_id)) {
// Use DELETE FROM syntax, as TRUNCATE is locking the database.
$query = "DELETE FROM " . $real_table_name . "";
$result = apdqc_query(array(
$table,
), array(
'*',
), $query);
if (is_string($result) && $result === 'NO DB') {
return db_truncate($table)
->execute();
}
// Return here as the table has been emptied.
return;
}
// Run an async TRUNCATE.
apdqc_query(array(
$real_table_name_truncated,
), array(
'*',
), "TRUNCATE {$real_table_name_truncated}", array(
'async' => TRUE,
));
}