Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Debug: Add find key debug invoker #8853

Merged
merged 45 commits into from
Mar 26, 2024
Merged
Show file tree
Hide file tree
Changes from 44 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
d0820f1
init
CalvinNeo Mar 20, 2024
5de4f38
some debug
CalvinNeo Mar 20, 2024
5c69e1c
ICE
CalvinNeo Mar 21, 2024
49103c7
fmt
CalvinNeo Mar 21, 2024
0346039
remove genKey
CalvinNeo Mar 21, 2024
95d170f
1
CalvinNeo Mar 21, 2024
7b27fe4
fmt
CalvinNeo Mar 21, 2024
c943a82
fmt2
CalvinNeo Mar 21, 2024
8abdf59
fmt
CalvinNeo Mar 22, 2024
68890ba
fix
CalvinNeo Mar 22, 2024
f2c6a5a
f
CalvinNeo Mar 22, 2024
062fcf8
z
CalvinNeo Mar 22, 2024
583fff9
f
CalvinNeo Mar 22, 2024
2c7cd9a
fff
CalvinNeo Mar 22, 2024
ecfae28
fff
CalvinNeo Mar 22, 2024
fe16413
z
CalvinNeo Mar 22, 2024
ad99e25
Update dbms/src/Debug/dbgKVStore/dbgFuncInvestigator.cpp
CalvinNeo Mar 22, 2024
03680fe
Update dbms/src/Debug/dbgKVStore/dbgFuncInvestigator.cpp
CalvinNeo Mar 22, 2024
832fbd6
Update dbms/src/Debug/MockTiDB.cpp
CalvinNeo Mar 22, 2024
2e75eeb
fix
CalvinNeo Mar 22, 2024
acc4137
Merge branch 'o11y1' of ssh://github.com/CalvinNeo/tics into o11y1
CalvinNeo Mar 22, 2024
f31705b
Update dbms/src/Debug/dbgKVStore/dbgFuncInvestigator.cpp
CalvinNeo Mar 22, 2024
0f5c986
fix
CalvinNeo Mar 22, 2024
46a9bc1
Merge branch 'o11y1' of ssh://github.com/CalvinNeo/tics into o11y1
CalvinNeo Mar 22, 2024
a1c93d2
a
CalvinNeo Mar 25, 2024
cf12c0b
fix
CalvinNeo Mar 25, 2024
24ee148
z
CalvinNeo Mar 25, 2024
1cbcbf8
Merge remote-tracking branch 'upstream/master' into o11y1
CalvinNeo Mar 25, 2024
892fd5e
Merge branch 'master' into o11y1
CalvinNeo Mar 25, 2024
c36aa29
remove tikv range
CalvinNeo Mar 25, 2024
05323d5
Merge branch 'o11y1' of ssh://github.com/CalvinNeo/tics into o11y1
CalvinNeo Mar 25, 2024
f43325a
tname
CalvinNeo Mar 25, 2024
39cf3cb
Merge branch 'master' into o11y1
CalvinNeo Mar 25, 2024
535f125
Update dbms/src/Debug/dbgKVStore/dbgFuncInvestigator.cpp
CalvinNeo Mar 25, 2024
1b18b88
Update dbms/src/Debug/dbgKVStore/dbgFuncInvestigator.cpp
CalvinNeo Mar 25, 2024
404ea1b
Update dbms/src/Debug/dbgKVStore/dbgFuncInvestigator.cpp
CalvinNeo Mar 25, 2024
9e7720a
cmt
CalvinNeo Mar 25, 2024
6adbd98
Merge branch 'o11y1' of ssh://github.com/CalvinNeo/tics into o11y1
CalvinNeo Mar 25, 2024
c22d135
Update dbms/src/Debug/dbgKVStore/dbgFuncInvestigator.cpp
CalvinNeo Mar 25, 2024
a192707
z
CalvinNeo Mar 25, 2024
532794f
Merge branch 'o11y1' of ssh://github.com/CalvinNeo/tics into o11y1
CalvinNeo Mar 25, 2024
181f588
z
CalvinNeo Mar 25, 2024
f7ba62d
fix release
CalvinNeo Mar 26, 2024
fb04618
Merge branch 'master' into o11y1
CalvinNeo Mar 26, 2024
45de44d
Apply suggestions from code review
JaySon-Huang Mar 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion contrib/tiflash-proxy-cmake/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,28 @@ if (CMAKE_BUILD_TYPE_UC STREQUAL "DEBUG" OR SAN_DEBUG)
set(_TIFLASH_PROXY_BUILD_PROFILE "debug")
if (ENABLE_JEMALLOC)
if (APPLE)
message(STATUS "Don't enable proxy's jemalloc(AppleOS)")
JaySon-Huang marked this conversation as resolved.
Show resolved Hide resolved
set(_TIFLASH_PROXY_MAKE_COMMAND make debug)
else()
message(STATUS "Enable proxy's jemalloc")
JaySon-Huang marked this conversation as resolved.
Show resolved Hide resolved
set(_TIFLASH_PROXY_MAKE_COMMAND ENABLE_FEATURES="external-jemalloc" make debug)
endif()
else()
message(STATUS "Don't enable proxy's jemalloc")
JaySon-Huang marked this conversation as resolved.
Show resolved Hide resolved
set(_TIFLASH_PROXY_MAKE_COMMAND make debug)
endif()
else()
set(_TIFLASH_PROXY_BUILD_PROFILE "release")
if (ENABLE_JEMALLOC)
set(_TIFLASH_PROXY_MAKE_COMMAND ENABLE_FEATURES="external-jemalloc" make release)
if (APPLE)
message(STATUS "Don't enable proxy's jemalloc(AppleOS)")
JaySon-Huang marked this conversation as resolved.
Show resolved Hide resolved
set(_TIFLASH_PROXY_MAKE_COMMAND make release)
else()
message(STATUS "Enable proxy's jemalloc")
JaySon-Huang marked this conversation as resolved.
Show resolved Hide resolved
set(_TIFLASH_PROXY_MAKE_COMMAND ENABLE_FEATURES="external-jemalloc" make release)
endif()
else()
message(STATUS "Don't enable proxy's jemalloc")
JaySon-Huang marked this conversation as resolved.
Show resolved Hide resolved
set(_TIFLASH_PROXY_MAKE_COMMAND make release)
endif()
endif()
Expand Down
2 changes: 1 addition & 1 deletion dbms/src/Common/TiFlashMetrics.h
Original file line number Diff line number Diff line change
Expand Up @@ -545,7 +545,7 @@ static_assert(RAFT_REGION_BIG_WRITE_THRES * 4 < RAFT_REGION_BIG_WRITE_MAX, "Inva
F(type_key_not_in_region, {{"type", "key_not_in_region"}}), \
F(type_tikv_server_issue, {{"type", "tikv_server_issue"}}), \
F(type_tikv_lock, {{"type", "tikv_lock"}}), \
F(type_other, {{"type", "write"}})) \
F(type_other, {{"type", "other"}})) \
/* required by DBaaS */ \
M(tiflash_server_info, \
"Indicate the tiflash server info, and the value is the start timestamp (s).", \
Expand Down
5 changes: 5 additions & 0 deletions dbms/src/Debug/DBGInvoker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <Debug/dbgFuncMockTiDBTable.h>
#include <Debug/dbgFuncSchema.h>
#include <Debug/dbgFuncSchemaName.h>
#include <Debug/dbgKVStore/dbgFuncInvestigator.h>
#include <Debug/dbgKVStore/dbgFuncMockRaftCommand.h>
#include <Debug/dbgKVStore/dbgFuncRegion.h>
#include <Parsers/ASTLiteral.h>
Expand Down Expand Up @@ -108,6 +109,10 @@ DBGInvoker::DBGInvoker()
MockRaftCommand::dbgFuncRegionSnapshotPreHandleDTFilesWithHandles);
regSchemalessFunc("region_snapshot_apply_file", /* */ MockRaftCommand::dbgFuncRegionSnapshotApplyDTFiles);
regSchemalessFunc("region_ingest_sst", MockRaftCommand::dbgFuncIngestSST);
// Test whether a PK exists in KVStore.
regSchemalessFunc("find_key_kvstore", dbgFuncFindKey);
// Test whether a PK exists in DT.
regSchemafulFunc("find_key_dt", dbgFuncFindKeyDt);

regSchemalessFunc("init_fail_point", DbgFailPointFunc::dbgInitFailPoint);
regSchemalessFunc("enable_fail_point", DbgFailPointFunc::dbgEnableFailPoint);
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion dbms/src/Debug/MockTiDB.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -771,7 +771,7 @@ TablePtr MockTiDB::getTableByNameInternal(const String & database_name, const St
auto it = tables_by_name.find(qualified_name);
if (it == tables_by_name.end())
{
throw Exception("Mock TiDB table " + qualified_name + " does not exists", ErrorCodes::UNKNOWN_TABLE);
throw Exception(ErrorCodes::UNKNOWN_TABLE, "Mock TiDB table {} does not exists", qualified_name);
}

return it->second;
Expand Down
308 changes: 308 additions & 0 deletions dbms/src/Debug/dbgKVStore/dbgFuncInvestigator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,308 @@
// Copyright 2024 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <Core/Field.h>
#include <DataStreams/StringStreamBlockInputStream.h>
#include <Debug/DAGProperties.h>
#include <Debug/MockTiDB.h>
#include <Debug/dbgKVStore/dbgFuncInvestigator.h>
#include <Debug/dbgKVStore/dbgRegion.h>
#include <Debug/dbgTools.h>
#include <Interpreters/Context.h>
#include <Interpreters/InterpreterCreateQuery.h>
#include <Interpreters/InterpreterSelectQuery.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/ASTLiteral.h>
#include <Parsers/ASTSelectQuery.h>
#include <Parsers/ParserCreateQuery.h>
#include <Parsers/ParserSelectQuery.h>
#include <Parsers/parseQuery.h>
#include <Storages/IManageableStorage.h>
#include <Storages/KVStore/KVStore.h>
#include <Storages/KVStore/MultiRaft/RegionData.h>
#include <Storages/KVStore/MultiRaft/RegionRangeKeys.h>
#include <Storages/KVStore/Region.h>
#include <Storages/KVStore/TMTContext.h>
#include <TiDB/Schema/TiDBSchemaManager.h>

#include <unordered_map>
#include <unordered_set>

namespace DB
{

struct MatchResult
{
String mapped_database_name;
String table_name;
std::vector<std::pair<UInt64, UInt64>> in_default;
std::vector<std::pair<UInt64, UInt64>> in_write;
std::vector<UInt64> in_lock;
std::unordered_map<UInt64, RegionPtr> regions;

String toString() const
{
FmtBuffer fmt_buf;
fmt_buf.fmtAppend("default_cf ");
fmt_buf.joinStr(
in_default.begin(),
in_default.end(),
[](const auto & a, const auto &) { return fmt::format("{}-{}", a.first, a.second); },
":");
fmt_buf.fmtAppend("; write_cf ");
fmt_buf.joinStr(
in_write.begin(),
in_write.end(),
[](const auto & a, const auto &) { return fmt::format("{}-{}", a.first, a.second); },
":");
fmt_buf.fmtAppend("; lock_cf ");
fmt_buf.joinStr(in_lock.begin(), in_lock.end(), ":");
for (const auto & [region_id, region] : regions)
{
fmt_buf.fmtAppend(
"; region {} {}, tikv_range: {}; ",
region_id,
region->getDebugString(),
region->getRange()->toDebugString());
}
return fmt_buf.toString();
}
};

/// 1. If the arg is [start1, end1], find all key-value pairs in this range;
/// 2. If the arg is [start1], make sure it is not a common handle, and we will only check the key-value pair by start1;
/// 3. If the arg is [start1, end1, start2, end2, ...], it must be a common handle, return all key-value pairs within the range.
void dbgFuncFindKey(Context & context, const ASTs & args, DBGInvoker::Printer output)
{
if (args.size() < 3)
throw Exception(
"Args not matched, should be: database-name, table-name, start1 [, start2, ..., end1, end2, ...]",
ErrorCodes::BAD_ARGUMENTS);

auto & tmt = context.getTMTContext();
auto & kvstore = *tmt.getKVStore();
MatchResult result;
const String & database_name_raw = typeid_cast<const ASTIdentifier &>(*args[0]).name;
const String & table_name = typeid_cast<const ASTIdentifier &>(*args[1]).name;

auto maybe_database_name = mappedDatabaseWithOptional(context, database_name_raw);
if (maybe_database_name == std::nullopt)
{
output(fmt::format("Database {} not found.", database_name_raw));
return;
}
result.mapped_database_name = maybe_database_name.value();
auto & mapped_database_name = result.mapped_database_name;
result.table_name = table_name;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we also need to map the table_name in tidb to get its name in TiFlash (which is t_${table_id})?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems tmt.getStorages().getByName(mapped_database_name, table_name, false) here takes the un-mapped name, which is not t_$tid, but its user name.


auto schema_syncer = tmt.getSchemaSyncerManager();
auto storage = tmt.getStorages().getByName(mapped_database_name, table_name, false);
if (storage == nullptr)
{
output(fmt::format("can't find table {} {}", mapped_database_name, table_name));
return;
}

auto table_info = storage->getTableInfo();
schema_syncer->syncTableSchema(context, table_info.keyspace_id, table_info.id);
if (table_info.partition.num > 0)
{
for (const auto & def : table_info.partition.definitions)
{
schema_syncer->syncTableSchema(context, table_info.keyspace_id, def.id);
}
}
Comment on lines +117 to +125
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we need to syncTableSchema here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sure we have the table info

Copy link
Contributor

@JinheLin JinheLin Mar 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to make sure have the table info?


auto table_id = table_info.id;

// tablePrefix_rowPrefix_tableID_rowID
TiKVKey start_key, end_key;
HandleID start_handle, end_handle;
Lloyd-Pottiger marked this conversation as resolved.
Show resolved Hide resolved

constexpr static size_t OFFSET = 2;
if (table_info.is_common_handle)
{
size_t arg_size = args.size() - OFFSET;
// The `start` and `end` argments should be provided in pair. Therefore, the number of arguments must be even.
if ((arg_size & 1) != 0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add some comments about this condition please.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think (arg_size % 2) != 0 maybe a more readable way and their execution efficiency is the same

{
throw Exception(
ErrorCodes::BAD_ARGUMENTS,
"Args not matched for common handle table, arg_size={}, should be: database-name, table-name, "
"start_col, [, start_col2, ..., end_col1, end_col2, ...]",
arg_size);
}
size_t handle_column_size = table_info.is_common_handle ? table_info.getPrimaryIndexInfo().idx_cols.size() : 1;
auto key_size = arg_size / 2;
std::vector<Field> start_field;
start_field.reserve(key_size);
std::vector<Field> end_field;
end_field.reserve(key_size);

for (size_t i = 0; i < handle_column_size; i++)
{
auto & column_info = table_info.columns[table_info.getPrimaryIndexInfo().idx_cols[i].offset];
auto start_datum = TiDB::DatumBumpy(
RegionBench::convertField(column_info, typeid_cast<const ASTLiteral &>(*args[OFFSET + i]).value),
column_info.tp);
start_field.emplace_back(start_datum.field());
auto end_datum = TiDB::DatumBumpy(
RegionBench::convertField(
column_info,
typeid_cast<const ASTLiteral &>(*args[OFFSET + key_size + i]).value),
column_info.tp);
end_field.emplace_back(end_datum.field());
}

start_key = RecordKVFormat::genKey(table_info, start_field);
end_key = RecordKVFormat::genKey(table_info, end_field);
}
else
{
start_handle = static_cast<HandleID>(safeGet<UInt64>(typeid_cast<const ASTLiteral &>(*args[OFFSET]).value));
start_key = RecordKVFormat::genKey(table_id, start_handle);
if (args.size() == 3)
{
end_handle = start_handle + 1;
}
else
{
end_handle
= static_cast<HandleID>(safeGet<UInt64>(typeid_cast<const ASTLiteral &>(*args[OFFSET + 1]).value));
}
Comment on lines +175 to +183
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to add a comment about the behavior at the beginning of this function.
When I see the end_handle is optional, I thought it would print all the following rows after start_handle. But here the logic is when the end_handle is ignored, it will only print one row.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

end_key = RecordKVFormat::genKey(table_id, end_handle);
}

auto range = RegionRangeKeys(TiKVKey::copyFrom(start_key), std::move(end_key));
auto regions = kvstore.getRegionsByRangeOverlap(range.comparableKeys());

for (const auto & [region_id, region] : regions)
{
auto r = RegionBench::DebugRegion(region);
const auto & data = r.debugData();

for (const auto & [k, v] : data.defaultCF().getData())
{
if (k.first == start_handle)
{
result.in_default.emplace_back(region_id, k.second);
}
}
for (const auto & [k, v] : data.writeCF().getData())
{
if (k.first == start_handle)
{
result.in_write.emplace_back(region_id, k.second);
}
}

auto lock_key = std::make_shared<const TiKVKey>(TiKVKey::copyFrom(start_key));
if (data.lockCF().getData().contains(
RegionLockCFDataTrait::Key{lock_key, std::string_view(lock_key->data(), lock_key->dataSize())}))
{
result.in_lock.emplace_back(region_id);
}
}
result.regions = regions;
output(fmt::format("find key result {}", result.toString()));
}

BlockInputStreamPtr dbgFuncFindKeyDt(Context & context, const ASTs & args)
{
if (args.size() < 4)
throw Exception(
"Args not matched, should be: database-name, table-name, key, value, [key2, value2, ...]",
ErrorCodes::BAD_ARGUMENTS);

auto & tmt = context.getTMTContext();
const String & database_name_raw = typeid_cast<const ASTIdentifier &>(*args[0]).name;
const String & table_name_raw = typeid_cast<const ASTIdentifier &>(*args[1]).name;

auto maybe_database_name = mappedDatabaseWithOptional(context, database_name_raw);
if (maybe_database_name == std::nullopt)
{
LOG_INFO(DB::Logger::get(), "Can't find database {}", database_name_raw);
return std::make_shared<StringStreamBlockInputStream>("Error");
}
auto mapped_database_name = maybe_database_name.value();
auto mapped_qualified_table_name = mappedTable(context, database_name_raw, table_name_raw);
auto mapped_table_name = mapped_qualified_table_name.second;

auto schema_syncer = tmt.getSchemaSyncerManager();
auto storage = tmt.getStorages().getByName(mapped_database_name, table_name_raw, false);
if (storage == nullptr)
{
LOG_INFO(DB::Logger::get(), "Can't find database and table {}.{}", mapped_database_name, mapped_table_name);
return std::make_shared<StringStreamBlockInputStream>("Error");
}

auto table_info = storage->getTableInfo();
schema_syncer->syncTableSchema(context, table_info.keyspace_id, table_info.id);
if (table_info.partition.num > 0)
{
for (const auto & def : table_info.partition.definitions)
{
schema_syncer->syncTableSchema(context, table_info.keyspace_id, def.id);
}
}

auto key = safeGet<String>(typeid_cast<const ASTLiteral &>(*args[2]).value);
auto value = safeGet<String>(typeid_cast<const ASTLiteral &>(*args[3]).value);

constexpr static size_t OFFSET = 4;
FmtBuffer fmt_buf;
auto key_size = args.size() - OFFSET;
if (key_size & 1)
Lloyd-Pottiger marked this conversation as resolved.
Show resolved Hide resolved
{
LOG_INFO(DB::Logger::get(), "Key-values should be in pair {}", database_name_raw, table_name_raw);
return std::make_shared<StringStreamBlockInputStream>("Error");
}
for (size_t i = 0; i != key_size / 2; i++)
{
auto k = safeGet<String>(typeid_cast<const ASTLiteral &>(*args[OFFSET + 2 * i]).value);
auto v = safeGet<String>(typeid_cast<const ASTLiteral &>(*args[OFFSET + 2 * i + 1]).value);
fmt_buf.fmtAppend(" and {} = {}", k, v);
}
String query;
if (table_info.is_common_handle && !table_info.pk_is_handle)
{
query = fmt::format(
"selraw *,_INTERNAL_VERSION,_INTERNAL_DELMARK,_tidb_rowid from {}.{} where {} = {}{}",
mapped_database_name,
mapped_table_name,
key,
value,
fmt_buf.toString());
}
else
{
query = fmt::format(
"selraw *,_INTERNAL_VERSION,_INTERNAL_DELMARK from {}.{} where {} = {}{}",
mapped_database_name,
mapped_table_name,
key,
value,
fmt_buf.toString());
}
LOG_INFO(DB::Logger::get(), "The query is {}", query);
ParserSelectQuery parser;
ASTPtr ast = parseQuery(parser, query.data(), query.data() + query.size(), "dbgFuncFindKeyDt", 0);

InterpreterSelectQuery interpreter(ast, context);
auto res = interpreter.execute();
return res.in;
}


} // namespace DB
Loading