This commit is contained in:
Sergey Magidovich 2015-04-08 12:06:41 +03:00
commit e477d0f7d9
6 changed files with 87 additions and 1072 deletions

View File

@ -11,7 +11,7 @@ cat "$QUERIES_FILE" | sed "s/{table}/${TABLE}/g" | while read query; do
echo -n "["
for i in $(seq 1 $TRIES); do
RES=$(mysql -u root -h 127.0.0.1 -P 3306 --database=test -t -vvv -e "$query" 2>&1 | grep 'in set' | grep -oP '\d+\.\d+')
RES=$(mysql -u root -h 127.0.0.1 -P 3306 --database=test -t -vvv -e "$query" 2>&1 | grep ' set ' | grep -oP '\d+\.\d+')
[[ "$?" == "0" ]] && echo -n "$RES" || echo -n "null"
[[ "$i" != $TRIES ]] && echo -n ", "

View File

@ -1,3 +1,5 @@
Note: column store in MemSQL was introduced in Feb 2014.
http://www.memsql.com/download/
http://docs.memsql.com/docs/latest/setup/setup_onprem.html
wget http://download.memsql.com/8d9f4c4d99a547baa40ba097b171bd15/memsql-3.2.x86_64.deb

View File

@ -39,5 +39,5 @@ SELECT Title, count(*) AS PageViews FROM hits_10m WHERE CounterID = 34 AND Event
SELECT URL, count(*) AS PageViews FROM hits_10m WHERE CounterID = 34 AND EventDate >= DATE('2013-07-01') AND EventDate <= DATE('2013-07-31') AND NOT Refresh AND IsLink AND NOT IsDownload GROUP BY URL ORDER BY PageViews DESC LIMIT 1000;
SELECT TraficSourceID, SearchEngineID, AdvEngineID, CASE WHEN SearchEngineID = 0 AND AdvEngineID = 0 THEN Referer ELSE '' END AS Src, URL AS Dst, count(*) AS PageViews FROM hits_10m WHERE CounterID = 34 AND EventDate >= DATE('2013-07-01') AND EventDate <= DATE('2013-07-31') AND NOT Refresh GROUP BY TraficSourceID, SearchEngineID, AdvEngineID, Src, Dst ORDER BY PageViews DESC LIMIT 1000;
SELECT URLHash, EventDate, count(*) AS PageViews FROM hits_10m WHERE CounterID = 34 AND EventDate >= DATE('2013-07-01') AND EventDate <= DATE('2013-07-31') AND NOT Refresh AND TraficSourceID IN (-1, 6) AND RefererHash = 6202628419148573758 GROUP BY URLHash, EventDate ORDER BY PageViews DESC LIMIT 100000;
SELECT WindowClientWidth, WindowClientHeight, count(*) AS PageViews FROM hits_10m WHERE CounterID = 34 AND EventDate >= DATE('2013-07-01') AND EventDate <= DATE('2013-07-31') AND NOT Refresh AND NOT DontCountHits AND URLHash = 6202628419148573758 GROUP BY WindowClientWidth, WindowClientHeight ORDER BY PageViews DESC LIMIT 10000;
SELECT WindowClientWidth, WindowClientHeight, count(*) AS PageViews FROM hits_10m WHERE CounterID = 34 AND EventDate >= DATE('2013-07-01') AND EventDate <= DATE('2013-07-31') AND NOT Refresh AND NOT DontCountHits AND URLHash = 6202628419148573758 GROUP BY WindowClientWidth, WindowClientHeight ORDER BY PageViews DESC LIMIT 10000;
SELECT EventTime - INTERVAL SECOND(EventTime) SECOND AS Minute, count(*) AS PageViews FROM hits_10m WHERE CounterID = 34 AND EventDate >= DATE('2013-07-01') AND EventDate <= DATE('2013-07-02') AND NOT Refresh AND NOT DontCountHits GROUP BY Minute ORDER BY Minute;

View File

@ -110,7 +110,11 @@ public:
*/
TableFullWriteLockPtr lockForAlter()
{
return std::make_pair(lockDataForAlter(), lockStructureForAlter());
/// Порядок вычисления важен.
auto data_lock = lockDataForAlter();
auto structure_lock = lockStructureForAlter();
return {std::move(data_lock), std::move(structure_lock)};
}
/** Не дает изменять данные в таблице. (Более того, не дает посмотреть на структуру таблицы с намерением изменить данные).

View File

@ -26,6 +26,37 @@ InterpreterRenameQuery::InterpreterRenameQuery(ASTPtr query_ptr_, Context & cont
}
struct RenameDescription
{
RenameDescription(const ASTRenameQuery::Element & elem, const String & path, const String & current_database) :
from_database_name(elem.from.database.empty() ? current_database : elem.from.database),
from_database_name_escaped(escapeForFileName(from_database_name)),
from_table_name(elem.from.table),
from_table_name_escaped(escapeForFileName(from_table_name)),
from_metadata_path(path + "metadata/" + from_database_name_escaped + "/"
+ (!from_table_name.empty() ? from_table_name_escaped + ".sql" : "")),
to_database_name(elem.to.database.empty() ? current_database : elem.to.database),
to_database_name_escaped(escapeForFileName(to_database_name)),
to_table_name(elem.to.table),
to_table_name_escaped(escapeForFileName(to_table_name)),
to_metadata_path(path + "metadata/" + to_database_name_escaped + "/"
+ (!to_table_name.empty() ? to_table_name_escaped + ".sql" : ""))
{}
String from_database_name;
String from_database_name_escaped;
String from_table_name;
String from_table_name_escaped;
String from_metadata_path;
String to_database_name;
String to_database_name_escaped;
String to_table_name;
String to_table_name_escaped;
String to_metadata_path;
};
void InterpreterRenameQuery::execute()
{
String path = context.getPath();
@ -37,38 +68,59 @@ void InterpreterRenameQuery::execute()
* или состояние может стать неконсистентным. (Это имеет смысл исправить.)
*/
for (ASTRenameQuery::Elements::const_iterator it = rename.elements.begin(); it != rename.elements.end(); ++it)
std::vector<RenameDescription> descriptions;
descriptions.reserve(rename.elements.size());
/// Для того, чтобы захватывать блокировки таблиц в одном и том же порядке в разных RENAME-ах.
struct UniqueTableName
{
String from_database_name = it->from.database.empty() ? current_database : it->from.database;
String from_database_name_escaped = escapeForFileName(from_database_name);
String from_table_name = it->from.table;
String from_table_name_escaped = escapeForFileName(from_table_name);
String from_metadata_path = path + "metadata/" + from_database_name_escaped + "/" + (!from_table_name.empty() ? from_table_name_escaped + ".sql" : "");
String database_name;
String table_name;
String to_database_name = it->to.database.empty() ? current_database : it->to.database;
String to_database_name_escaped = escapeForFileName(to_database_name);
String to_table_name = it->to.table;
String to_table_name_escaped = escapeForFileName(to_table_name);
String to_metadata_path = path + "metadata/" + to_database_name_escaped + "/" + (!to_table_name.empty() ? to_table_name_escaped + ".sql" : "");
UniqueTableName(const String & database_name_, const String & table_name_)
: database_name(database_name_), table_name(table_name_) {}
/// Заблокировать таблицу нужно при незаблокированном контексте.
StoragePtr table = context.getTable(from_database_name, from_table_name);
auto table_lock = table->lockForAlter();
bool operator< (const UniqueTableName & rhs) const
{
return std::tie(database_name, table_name) < std::tie(rhs.database_name, rhs.table_name);
}
};
/** Все таблицы переименовываются под глобальной блокировкой. */
Poco::ScopedLock<Poco::Mutex> lock(context.getMutex());
std::set<UniqueTableName> unique_tables;
context.assertTableDoesntExist(to_database_name, to_table_name);
for (const auto & elem : rename.elements)
{
descriptions.emplace_back(elem, path, current_database);
unique_tables.emplace(descriptions.back().from_database_name, descriptions.back().from_table_name);
}
std::vector<IStorage::TableFullWriteLockPtr> locks;
locks.reserve(unique_tables.size());
for (const auto & names : unique_tables)
if (auto table = context.tryGetTable(names.database_name, names.table_name))
locks.emplace_back(table->lockForAlter());
/** Все таблицы заблокированы. Теперь можно блокировать Context. Порядок важен, чтобы избежать deadlock-ов.
* Это обеспечивает атомарность всех указанных RENAME с точки зрения пользователя СУБД,
* но лишь в случаях, когда в процессе переименования не было исключений и сервер не падал.
*/
Poco::ScopedLock<Poco::Mutex> lock(context.getMutex());
for (const auto & elem : descriptions)
{
context.assertTableDoesntExist(elem.to_database_name, elem.to_table_name);
/// Уведомляем таблицу о том, что она переименовывается. Если таблица не поддерживает переименование - кинется исключение.
table->rename(path + "data/" + to_database_name_escaped + "/", to_database_name, to_table_name);
StoragePtr table = context.getTable(elem.from_database_name, elem.from_table_name);
table->rename(path + "data/" + elem.to_database_name_escaped + "/", elem.to_database_name, elem.to_table_name);
/// Пишем новый файл с метаданными.
{
String create_query;
{
ReadBufferFromFile in(from_metadata_path, 1024);
ReadBufferFromFile in(elem.from_metadata_path, 1024);
WriteBufferFromString out(create_query);
copyData(in, out);
}
@ -82,22 +134,22 @@ void InterpreterRenameQuery::execute()
/// Распарсенный запрос должен заканчиваться на конец входных данных или на точку с запятой.
if (!parse_res || (pos != end && *pos != ';'))
throw Exception(getSyntaxErrorMessage(parse_res, create_query.data(), end, pos, expected, "in file " + from_metadata_path),
throw Exception(getSyntaxErrorMessage(parse_res, create_query.data(), end, pos, expected, "in file " + elem.from_metadata_path),
ErrorCodes::SYNTAX_ERROR);
typeid_cast<ASTCreateQuery &>(*ast).table = to_table_name;
typeid_cast<ASTCreateQuery &>(*ast).table = elem.to_table_name;
Poco::FileOutputStream ostr(to_metadata_path);
Poco::FileOutputStream ostr(elem.to_metadata_path);
formatAST(*ast, ostr, 0, false);
ostr << '\n';
}
/// Переименовываем таблицу в контексте.
context.addTable(to_database_name, to_table_name,
context.detachTable(from_database_name, from_table_name));
context.addTable(elem.to_database_name, elem.to_table_name,
context.detachTable(elem.from_database_name, elem.from_table_name));
/// Удаляем старый файл с метаданными.
Poco::File(from_metadata_path).remove();
Poco::File(elem.from_metadata_path).remove();
}
}