Skip to content

Commit db42db4

Browse files
authored
Some fixes in vector index schema (#12727)
* Rename vector index impl table column constants to make them more convinient and less confusing (e.g. single constant for ParentColumn, important for future kqp rewrite rules) * Rename `__ydb_embedding` column to `__ydb_centroid` column, because it makes more sense * Add missed not null property for vector index impl table columns
1 parent f3c9a60 commit db42db4

12 files changed

+91
-86
lines changed

ydb/core/base/table_index.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -115,17 +115,17 @@ bool IsCompatibleIndex(NKikimrSchemeOp::EIndexType indexType, const TTableColumn
115115
return false;
116116
}
117117

118-
if (Contains(table.Keys, NTableVectorKmeansTreeIndex::PostingTable_ParentColumn)) {
119-
explain = TStringBuilder() << "table key column shouldn't have a reserved name: " << NTableVectorKmeansTreeIndex::PostingTable_ParentColumn;
118+
if (Contains(table.Keys, NTableVectorKmeansTreeIndex::ParentColumn)) {
119+
explain = TStringBuilder() << "table key column shouldn't have a reserved name: " << NTableVectorKmeansTreeIndex::ParentColumn;
120120
return false;
121121
}
122-
if (Contains(index.KeyColumns, NTableVectorKmeansTreeIndex::PostingTable_ParentColumn)) {
122+
if (Contains(index.KeyColumns, NTableVectorKmeansTreeIndex::ParentColumn)) {
123123
// This isn't really needed, but it will be really strange to have column with such name but different meaning
124-
explain = TStringBuilder() << "index key column shouldn't have a reserved name: " << NTableVectorKmeansTreeIndex::PostingTable_ParentColumn;
124+
explain = TStringBuilder() << "index key column shouldn't have a reserved name: " << NTableVectorKmeansTreeIndex::ParentColumn;
125125
return false;
126126
}
127-
if (Contains(index.DataColumns, NTableVectorKmeansTreeIndex::PostingTable_ParentColumn)) {
128-
explain = TStringBuilder() << "index data column shouldn't have a reserved name: " << NTableVectorKmeansTreeIndex::PostingTable_ParentColumn;
127+
if (Contains(index.DataColumns, NTableVectorKmeansTreeIndex::ParentColumn)) {
128+
explain = TStringBuilder() << "index data column shouldn't have a reserved name: " << NTableVectorKmeansTreeIndex::ParentColumn;
129129
return false;
130130
}
131131
}

ydb/core/base/table_vector_index.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,18 @@ namespace NKikimr::NTableIndex::NTableVectorKmeansTreeIndex {
44

55
// Vector KmeansTree index tables description
66

7+
// Level and Posting tables
8+
inline constexpr const char* ParentColumn = "__ydb_parent";
9+
710
// Level table
811
inline constexpr const char* LevelTable = "indexImplLevelTable";
9-
inline constexpr const char* LevelTable_ParentColumn = "__ydb_parent";
10-
inline constexpr const char* LevelTable_IdColumn = "__ydb_id";
11-
inline constexpr const char* LevelTable_EmbeddingColumn = "__ydb_embedding";
12+
inline constexpr const char* IdColumn = "__ydb_id";
13+
inline constexpr const char* CentroidColumn = "__ydb_centroid";
1214

1315
// Posting table
1416
inline constexpr const char* PostingTable = "indexImplPostingTable";
15-
inline constexpr const char* PostingTable_ParentColumn = LevelTable_ParentColumn;
1617

17-
inline constexpr const char* BuildPostingTableSuffix0 = "0build";
18-
inline constexpr const char* BuildPostingTableSuffix1 = "1build";
18+
inline constexpr const char* BuildSuffix0 = "0build";
19+
inline constexpr const char* BuildSuffix1 = "1build";
1920

2021
}

ydb/core/base/ut/table_index_ut.cpp

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,16 @@ Y_UNIT_TEST_SUITE (TableIndex) {
2727
UNIT_ASSERT_STRINGS_EQUAL(explain, "");
2828

2929
{
30-
const TTableColumns Table2{{"PK", "DATA", NTableVectorKmeansTreeIndex::PostingTable_ParentColumn}, {"PK"}};
30+
const TTableColumns Table2{{"PK", "DATA", NTableVectorKmeansTreeIndex::ParentColumn}, {"PK"}};
3131

32-
UNIT_ASSERT(IsCompatibleIndex(type, Table2, {{NTableVectorKmeansTreeIndex::PostingTable_ParentColumn}, {}}, explain));
32+
UNIT_ASSERT(IsCompatibleIndex(type, Table2, {{NTableVectorKmeansTreeIndex::ParentColumn}, {}}, explain));
3333
UNIT_ASSERT_STRINGS_EQUAL(explain, "");
3434

35-
UNIT_ASSERT(IsCompatibleIndex(type, Table2, {{"DATA"}, {NTableVectorKmeansTreeIndex::PostingTable_ParentColumn}}, explain));
35+
UNIT_ASSERT(IsCompatibleIndex(type, Table2, {{"DATA"}, {NTableVectorKmeansTreeIndex::ParentColumn}}, explain));
3636
UNIT_ASSERT_STRINGS_EQUAL(explain, "");
3737
}
3838
{
39-
const TTableColumns Table3{{"PK", "DATA", NTableVectorKmeansTreeIndex::PostingTable_ParentColumn}, {NTableVectorKmeansTreeIndex::PostingTable_ParentColumn}};
39+
const TTableColumns Table3{{"PK", "DATA", NTableVectorKmeansTreeIndex::ParentColumn}, {NTableVectorKmeansTreeIndex::ParentColumn}};
4040

4141
UNIT_ASSERT(IsCompatibleIndex(type, Table3, {{"DATA"}, {}}, explain));
4242
UNIT_ASSERT_STRINGS_EQUAL(explain, "");
@@ -118,19 +118,19 @@ Y_UNIT_TEST_SUITE (TableIndex) {
118118
UNIT_ASSERT_STRINGS_EQUAL(explain, "the same column can't be used as key and data column for one index, for example PK2");
119119

120120
{
121-
const TTableColumns Table2{{"PK", "DATA", NTableVectorKmeansTreeIndex::PostingTable_ParentColumn}, {"PK"}};
121+
const TTableColumns Table2{{"PK", "DATA", NTableVectorKmeansTreeIndex::ParentColumn}, {"PK"}};
122122

123-
UNIT_ASSERT(!IsCompatibleIndex(type, Table2, {{NTableVectorKmeansTreeIndex::PostingTable_ParentColumn}, {}}, explain));
124-
UNIT_ASSERT_STRINGS_EQUAL(explain, TStringBuilder() << "index key column shouldn't have a reserved name: " << NTableVectorKmeansTreeIndex::PostingTable_ParentColumn);
123+
UNIT_ASSERT(!IsCompatibleIndex(type, Table2, {{NTableVectorKmeansTreeIndex::ParentColumn}, {}}, explain));
124+
UNIT_ASSERT_STRINGS_EQUAL(explain, TStringBuilder() << "index key column shouldn't have a reserved name: " << NTableVectorKmeansTreeIndex::ParentColumn);
125125

126-
UNIT_ASSERT(!IsCompatibleIndex(type, Table2, {{"DATA"}, {NTableVectorKmeansTreeIndex::PostingTable_ParentColumn}}, explain));
127-
UNIT_ASSERT_STRINGS_EQUAL(explain, TStringBuilder() << "index data column shouldn't have a reserved name: " << NTableVectorKmeansTreeIndex::PostingTable_ParentColumn);
126+
UNIT_ASSERT(!IsCompatibleIndex(type, Table2, {{"DATA"}, {NTableVectorKmeansTreeIndex::ParentColumn}}, explain));
127+
UNIT_ASSERT_STRINGS_EQUAL(explain, TStringBuilder() << "index data column shouldn't have a reserved name: " << NTableVectorKmeansTreeIndex::ParentColumn);
128128
}
129129
{
130-
const TTableColumns Table3{{"PK", "DATA", NTableVectorKmeansTreeIndex::PostingTable_ParentColumn}, {NTableVectorKmeansTreeIndex::PostingTable_ParentColumn}};
130+
const TTableColumns Table3{{"PK", "DATA", NTableVectorKmeansTreeIndex::ParentColumn}, {NTableVectorKmeansTreeIndex::ParentColumn}};
131131

132132
UNIT_ASSERT(!IsCompatibleIndex(type, Table3, {{"DATA"}, {}}, explain));
133-
UNIT_ASSERT_STRINGS_EQUAL(explain, TStringBuilder() << "table key column shouldn't have a reserved name: " << NTableVectorKmeansTreeIndex::PostingTable_ParentColumn);
133+
UNIT_ASSERT_STRINGS_EQUAL(explain, TStringBuilder() << "table key column shouldn't have a reserved name: " << NTableVectorKmeansTreeIndex::ParentColumn);
134134
}
135135
}
136136
}

ydb/core/tx/datashard/datashard_ut_local_kmeans.cpp

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -183,9 +183,9 @@ Y_UNIT_TEST_SUITE (TTxDataShardLocalKMeansScan) {
183183
{
184184
options.AllowSystemColumnNames(true);
185185
options.Columns({
186-
{LevelTable_ParentColumn, "Uint32", true, true},
187-
{LevelTable_IdColumn, "Uint32", true, true},
188-
{LevelTable_EmbeddingColumn, "String", false, true},
186+
{ParentColumn, "Uint32", true, true},
187+
{IdColumn, "Uint32", true, true},
188+
{CentroidColumn, "String", false, true},
189189
});
190190
CreateShardedTable(server, sender, "/Root", "table-level", options);
191191
}
@@ -194,7 +194,7 @@ Y_UNIT_TEST_SUITE (TTxDataShardLocalKMeansScan) {
194194
{
195195
options.AllowSystemColumnNames(true);
196196
options.Columns({
197-
{PostingTable_ParentColumn, "Uint32", true, true},
197+
{ParentColumn, "Uint32", true, true},
198198
{"key", "Uint32", true, true},
199199
{"data", "String", false, false},
200200
});
@@ -206,7 +206,7 @@ Y_UNIT_TEST_SUITE (TTxDataShardLocalKMeansScan) {
206206
{
207207
options.AllowSystemColumnNames(true);
208208
options.Columns({
209-
{PostingTable_ParentColumn, "Uint32", true, true},
209+
{ParentColumn, "Uint32", true, true},
210210
{"key", "Uint32", true, true},
211211
{"embedding", "String", false, false},
212212
{"data", "String", false, false},
@@ -350,8 +350,8 @@ Y_UNIT_TEST_SUITE (TTxDataShardLocalKMeansScan) {
350350
auto [level, posting] = DoLocalKMeans(server, sender, 0, seed, k,
351351
NKikimrTxDataShard::TEvLocalKMeansRequest::UPLOAD_MAIN_TO_POSTING,
352352
VectorIndexSettings::VECTOR_TYPE_UINT8, distance);
353-
UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 0, __ydb_id = 1, __ydb_embedding = mm\3\n"
354-
"__ydb_parent = 0, __ydb_id = 2, __ydb_embedding = 11\3\n");
353+
UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 0, __ydb_id = 1, __ydb_centroid = mm\3\n"
354+
"__ydb_parent = 0, __ydb_id = 2, __ydb_centroid = 11\3\n");
355355
UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 1, key = 4, data = four\n"
356356
"__ydb_parent = 1, key = 5, data = five\n"
357357
"__ydb_parent = 2, key = 1, data = one\n"
@@ -365,8 +365,8 @@ Y_UNIT_TEST_SUITE (TTxDataShardLocalKMeansScan) {
365365
auto [level, posting] = DoLocalKMeans(server, sender, 0, seed, k,
366366
NKikimrTxDataShard::TEvLocalKMeansRequest::UPLOAD_MAIN_TO_POSTING,
367367
VectorIndexSettings::VECTOR_TYPE_UINT8, distance);
368-
UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 0, __ydb_id = 1, __ydb_embedding = 11\3\n"
369-
"__ydb_parent = 0, __ydb_id = 2, __ydb_embedding = mm\3\n");
368+
UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 0, __ydb_id = 1, __ydb_centroid = 11\3\n"
369+
"__ydb_parent = 0, __ydb_id = 2, __ydb_centroid = mm\3\n");
370370
UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 1, key = 1, data = one\n"
371371
"__ydb_parent = 1, key = 2, data = two\n"
372372
"__ydb_parent = 1, key = 3, data = three\n"
@@ -381,7 +381,7 @@ Y_UNIT_TEST_SUITE (TTxDataShardLocalKMeansScan) {
381381
auto [level, posting] = DoLocalKMeans(server, sender, 0, seed, k,
382382
NKikimrTxDataShard::TEvLocalKMeansRequest::UPLOAD_MAIN_TO_POSTING,
383383
VectorIndexSettings::VECTOR_TYPE_UINT8, similarity);
384-
UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 0, __ydb_id = 1, __ydb_embedding = II\3\n");
384+
UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 0, __ydb_id = 1, __ydb_centroid = II\3\n");
385385
UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 1, key = 1, data = one\n"
386386
"__ydb_parent = 1, key = 2, data = two\n"
387387
"__ydb_parent = 1, key = 3, data = three\n"
@@ -440,8 +440,8 @@ Y_UNIT_TEST_SUITE (TTxDataShardLocalKMeansScan) {
440440
auto [level, posting] = DoLocalKMeans(server, sender, 0, seed, k,
441441
NKikimrTxDataShard::TEvLocalKMeansRequest::UPLOAD_MAIN_TO_BUILD,
442442
VectorIndexSettings::VECTOR_TYPE_UINT8, distance);
443-
UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 0, __ydb_id = 1, __ydb_embedding = mm\3\n"
444-
"__ydb_parent = 0, __ydb_id = 2, __ydb_embedding = 11\3\n");
443+
UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 0, __ydb_id = 1, __ydb_centroid = mm\3\n"
444+
"__ydb_parent = 0, __ydb_id = 2, __ydb_centroid = 11\3\n");
445445
UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 1, key = 4, embedding = \x65\x65\3, data = four\n"
446446
"__ydb_parent = 1, key = 5, embedding = \x75\x75\3, data = five\n"
447447
"__ydb_parent = 2, key = 1, embedding = \x30\x30\3, data = one\n"
@@ -455,8 +455,8 @@ Y_UNIT_TEST_SUITE (TTxDataShardLocalKMeansScan) {
455455
auto [level, posting] = DoLocalKMeans(server, sender, 0, seed, k,
456456
NKikimrTxDataShard::TEvLocalKMeansRequest::UPLOAD_MAIN_TO_BUILD,
457457
VectorIndexSettings::VECTOR_TYPE_UINT8, distance);
458-
UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 0, __ydb_id = 1, __ydb_embedding = 11\3\n"
459-
"__ydb_parent = 0, __ydb_id = 2, __ydb_embedding = mm\3\n");
458+
UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 0, __ydb_id = 1, __ydb_centroid = 11\3\n"
459+
"__ydb_parent = 0, __ydb_id = 2, __ydb_centroid = mm\3\n");
460460
UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 1, key = 1, embedding = \x30\x30\3, data = one\n"
461461
"__ydb_parent = 1, key = 2, embedding = \x31\x31\3, data = two\n"
462462
"__ydb_parent = 1, key = 3, embedding = \x32\x32\3, data = three\n"
@@ -471,7 +471,7 @@ Y_UNIT_TEST_SUITE (TTxDataShardLocalKMeansScan) {
471471
auto [level, posting] = DoLocalKMeans(server, sender, 0, seed, k,
472472
NKikimrTxDataShard::TEvLocalKMeansRequest::UPLOAD_MAIN_TO_BUILD,
473473
VectorIndexSettings::VECTOR_TYPE_UINT8, similarity);
474-
UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 0, __ydb_id = 1, __ydb_embedding = II\3\n");
474+
UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 0, __ydb_id = 1, __ydb_centroid = II\3\n");
475475
UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 1, key = 1, embedding = \x30\x30\3, data = one\n"
476476
"__ydb_parent = 1, key = 2, embedding = \x31\x31\3, data = two\n"
477477
"__ydb_parent = 1, key = 3, embedding = \x32\x32\3, data = three\n"
@@ -532,8 +532,8 @@ Y_UNIT_TEST_SUITE (TTxDataShardLocalKMeansScan) {
532532
auto [level, posting] = DoLocalKMeans(server, sender, 40, seed, k,
533533
NKikimrTxDataShard::TEvLocalKMeansRequest::UPLOAD_BUILD_TO_POSTING,
534534
VectorIndexSettings::VECTOR_TYPE_UINT8, distance);
535-
UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 40, __ydb_id = 41, __ydb_embedding = mm\3\n"
536-
"__ydb_parent = 40, __ydb_id = 42, __ydb_embedding = 11\3\n");
535+
UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 40, __ydb_id = 41, __ydb_centroid = mm\3\n"
536+
"__ydb_parent = 40, __ydb_id = 42, __ydb_centroid = 11\3\n");
537537
UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 41, key = 4, data = four\n"
538538
"__ydb_parent = 41, key = 5, data = five\n"
539539
"__ydb_parent = 42, key = 1, data = one\n"
@@ -547,8 +547,8 @@ Y_UNIT_TEST_SUITE (TTxDataShardLocalKMeansScan) {
547547
auto [level, posting] = DoLocalKMeans(server, sender, 40, seed, k,
548548
NKikimrTxDataShard::TEvLocalKMeansRequest::UPLOAD_BUILD_TO_POSTING,
549549
VectorIndexSettings::VECTOR_TYPE_UINT8, distance);
550-
UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 40, __ydb_id = 41, __ydb_embedding = 11\3\n"
551-
"__ydb_parent = 40, __ydb_id = 42, __ydb_embedding = mm\3\n");
550+
UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 40, __ydb_id = 41, __ydb_centroid = 11\3\n"
551+
"__ydb_parent = 40, __ydb_id = 42, __ydb_centroid = mm\3\n");
552552
UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 41, key = 1, data = one\n"
553553
"__ydb_parent = 41, key = 2, data = two\n"
554554
"__ydb_parent = 41, key = 3, data = three\n"
@@ -563,7 +563,7 @@ Y_UNIT_TEST_SUITE (TTxDataShardLocalKMeansScan) {
563563
auto [level, posting] = DoLocalKMeans(server, sender, 40, seed, k,
564564
NKikimrTxDataShard::TEvLocalKMeansRequest::UPLOAD_BUILD_TO_POSTING,
565565
VectorIndexSettings::VECTOR_TYPE_UINT8, similarity);
566-
UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 40, __ydb_id = 41, __ydb_embedding = II\3\n");
566+
UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 40, __ydb_id = 41, __ydb_centroid = II\3\n");
567567
UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 41, key = 1, data = one\n"
568568
"__ydb_parent = 41, key = 2, data = two\n"
569569
"__ydb_parent = 41, key = 3, data = three\n"
@@ -624,8 +624,8 @@ Y_UNIT_TEST_SUITE (TTxDataShardLocalKMeansScan) {
624624
auto [level, posting] = DoLocalKMeans(server, sender, 40, seed, k,
625625
NKikimrTxDataShard::TEvLocalKMeansRequest::UPLOAD_BUILD_TO_BUILD,
626626
VectorIndexSettings::VECTOR_TYPE_UINT8, distance);
627-
UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 40, __ydb_id = 41, __ydb_embedding = mm\3\n"
628-
"__ydb_parent = 40, __ydb_id = 42, __ydb_embedding = 11\3\n");
627+
UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 40, __ydb_id = 41, __ydb_centroid = mm\3\n"
628+
"__ydb_parent = 40, __ydb_id = 42, __ydb_centroid = 11\3\n");
629629
UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 41, key = 4, embedding = \x65\x65\3, data = four\n"
630630
"__ydb_parent = 41, key = 5, embedding = \x75\x75\3, data = five\n"
631631
"__ydb_parent = 42, key = 1, embedding = \x30\x30\3, data = one\n"
@@ -639,8 +639,8 @@ Y_UNIT_TEST_SUITE (TTxDataShardLocalKMeansScan) {
639639
auto [level, posting] = DoLocalKMeans(server, sender, 40, seed, k,
640640
NKikimrTxDataShard::TEvLocalKMeansRequest::UPLOAD_BUILD_TO_BUILD,
641641
VectorIndexSettings::VECTOR_TYPE_UINT8, distance);
642-
UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 40, __ydb_id = 41, __ydb_embedding = 11\3\n"
643-
"__ydb_parent = 40, __ydb_id = 42, __ydb_embedding = mm\3\n");
642+
UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 40, __ydb_id = 41, __ydb_centroid = 11\3\n"
643+
"__ydb_parent = 40, __ydb_id = 42, __ydb_centroid = mm\3\n");
644644
UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 41, key = 1, embedding = \x30\x30\3, data = one\n"
645645
"__ydb_parent = 41, key = 2, embedding = \x31\x31\3, data = two\n"
646646
"__ydb_parent = 41, key = 3, embedding = \x32\x32\3, data = three\n"
@@ -655,7 +655,7 @@ Y_UNIT_TEST_SUITE (TTxDataShardLocalKMeansScan) {
655655
auto [level, posting] = DoLocalKMeans(server, sender, 40, seed, k,
656656
NKikimrTxDataShard::TEvLocalKMeansRequest::UPLOAD_BUILD_TO_BUILD,
657657
VectorIndexSettings::VECTOR_TYPE_UINT8, similarity);
658-
UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 40, __ydb_id = 41, __ydb_embedding = II\3\n");
658+
UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 40, __ydb_id = 41, __ydb_centroid = II\3\n");
659659
UNIT_ASSERT_VALUES_EQUAL(posting, "__ydb_parent = 41, key = 1, embedding = \x30\x30\3, data = one\n"
660660
"__ydb_parent = 41, key = 2, embedding = \x31\x31\3, data = two\n"
661661
"__ydb_parent = 41, key = 3, embedding = \x32\x32\3, data = three\n"

0 commit comments

Comments
 (0)