diff --git a/ydb/core/scheme/scheme_tablecell.cpp b/ydb/core/scheme/scheme_tablecell.cpp index 77c0e3319196..1cb11cb1b9d9 100644 --- a/ydb/core/scheme/scheme_tablecell.cpp +++ b/ydb/core/scheme/scheme_tablecell.cpp @@ -258,6 +258,45 @@ bool TSerializedCellVec::DoTryParse(const TString& data) { return TryDeserializeCellVec(data, Buf, Cells); } +bool TSerializedCellVec::UnsafeAppendCells(TConstArrayRef cells, TString& serializedCellVec) { + if (Y_UNLIKELY(cells.size() == 0)) { + return true; + } + + if (!serializedCellVec) { + TSerializedCellVec::Serialize(serializedCellVec, cells); + return true; + } + + const char* buf = serializedCellVec.data(); + const char* bufEnd = serializedCellVec.data() + serializedCellVec.size(); + const size_t bufSize = bufEnd - buf; + + if (Y_UNLIKELY(bufSize < static_cast(sizeof(ui16)))) { + return false; + } + + ui16 cellCount = ReadUnaligned(buf); + cellCount += cells.size(); + + size_t newSize = serializedCellVec.size(); + + for (auto& cell : cells) { + newSize += sizeof(TCellHeader) + cell.Size(); + } + + serializedCellVec.ReserveAndResize(newSize); + + char* mutableBuf = serializedCellVec.Detach(); + char* oldBufEnd = mutableBuf + bufSize; + + WriteUnaligned(mutableBuf, cellCount); + + SerializeCellVecBody(cells, oldBufEnd, nullptr); + + return true; +} + TSerializedCellMatrix::TSerializedCellMatrix(TConstArrayRef cells, ui32 rowCount, ui16 colCount) : RowCount(rowCount), ColCount(colCount) { diff --git a/ydb/core/scheme/scheme_tablecell.h b/ydb/core/scheme/scheme_tablecell.h index 752be860abc6..5ce8d5515cc2 100644 --- a/ydb/core/scheme/scheme_tablecell.h +++ b/ydb/core/scheme/scheme_tablecell.h @@ -555,6 +555,9 @@ class TSerializedCellVec { return Cells; } + // read headers, assuming the buf is correct and append additional cells at the end + static bool UnsafeAppendCells(TConstArrayRef cells, TString& serializedCellVec); + static void Serialize(TString& res, TConstArrayRef cells); static TString Serialize(TConstArrayRef cells); diff --git a/ydb/core/scheme/scheme_tablecell_ut.cpp b/ydb/core/scheme/scheme_tablecell_ut.cpp index ae780b8cfc5f..e842cf5268e4 100644 --- a/ydb/core/scheme/scheme_tablecell_ut.cpp +++ b/ydb/core/scheme/scheme_tablecell_ut.cpp @@ -507,4 +507,37 @@ Y_UNIT_TEST_SUITE(Scheme) { } } } + + Y_UNIT_TEST(UnsafeAppend) { + TString appended = TSerializedCellVec::Serialize({}); + + UNIT_ASSERT(TSerializedCellVec::UnsafeAppendCells({}, appended)); + + UNIT_ASSERT_EQUAL(appended.size(), 0); + + ui64 intVal = 42; + char bigStrVal[] = "This is a large string value that shouldn't be inlined"; + + TVector cells; + cells.emplace_back(TCell::Make(intVal)); + cells.emplace_back(bigStrVal, sizeof(bigStrVal)); + + UNIT_ASSERT(TSerializedCellVec::UnsafeAppendCells(cells, appended)); + TString serialized = TSerializedCellVec::Serialize(cells); + + UNIT_ASSERT_VALUES_EQUAL(appended, serialized); + + UNIT_ASSERT(TSerializedCellVec::UnsafeAppendCells(cells, appended)); + + cells.emplace_back(TCell::Make(intVal)); + cells.emplace_back(bigStrVal, sizeof(bigStrVal)); + + serialized = TSerializedCellVec::Serialize(cells); + + UNIT_ASSERT_VALUES_EQUAL(appended, serialized); + + appended.resize(1); + + UNIT_ASSERT(!TSerializedCellVec::UnsafeAppendCells(cells, appended)); + } }