#include <algorithm>
#include <mutex>
#include <utility>
#include <vector>
#include "common/data_chunk/data_chunk.h"
#include "common/exception/runtime.h"
#include "common/system_config.h"
#include "common/types/types.h"
#include "function/export/export_function.h"
#include "main/client_context.h"
#include "processor/operator/persistent/writer/parquet/parquet_writer.h"
#include "processor/result/factorized_table.h"
#include "storage/buffer_manager/memory_manager.h"
#include "storage/table/ice_disk_constants.h"
using namespace lbug::common;
using namespace lbug::processor;
using namespace lbug::storage;
namespace lbug {
namespace function {
struct IndptrExportBindData : public ExportFuncBindData {
std::vector<lbug_parquet::format::KeyValue> keyValueMetadata;
IndptrExportBindData(std::vector<std::string> names, std::string fileName,
std::vector<lbug_parquet::format::KeyValue> keyValueMetadata = {})
: ExportFuncBindData{std::move(names), std::move(fileName)},
keyValueMetadata{std::move(keyValueMetadata)} {}
std::unique_ptr<ExportFuncBindData> copy() const override {
auto bindData =
std::make_unique<IndptrExportBindData>(columnNames, fileName, keyValueMetadata);
bindData->types = LogicalType::copy(types);
return bindData;
}
};
struct IndptrExportLocalState final : public ExportFuncLocalState {
std::vector<std::pair<int64_t, int64_t>> pairs;
};
struct IndptrExportSharedState final : public ExportFuncSharedState {
std::vector<std::pair<int64_t, int64_t>> pairs;
std::mutex mtx;
std::string fileName;
std::vector<lbug_parquet::format::KeyValue> keyValueMetadata;
main::ClientContext* context = nullptr;
void init(main::ClientContext& context_, const ExportFuncBindData& bindData) override {
context = &context_;
fileName = bindData.fileName;
keyValueMetadata = bindData.constCast<IndptrExportBindData>().keyValueMetadata;
}
};
static std::unique_ptr<ExportFuncBindData> bindFunc(ExportFuncBindInput& bindInput) {
std::vector<lbug_parquet::format::KeyValue> keyValues;
for (auto& [name, value] : bindInput.parsingOptions) {
if (name == storage::IceDiskConstants::VERSION_METADATA_KEY) {
if (value.getDataType().getLogicalTypeID() != LogicalTypeID::STRING) {
throw RuntimeException{
std::format("Parquet {} option expects a string value, got: {}.",
storage::IceDiskConstants::VERSION_METADATA_KEY,
value.getDataType().toString())};
}
lbug_parquet::format::KeyValue kv;
kv.__set_key(std::string(storage::IceDiskConstants::VERSION_METADATA_KEY));
kv.__set_value(value.getValue<std::string>());
keyValues.push_back(std::move(kv));
}
}
return std::make_unique<IndptrExportBindData>(bindInput.columnNames, bindInput.filePath,
std::move(keyValues));
}
static std::unique_ptr<ExportFuncLocalState> initLocalStateFunc(main::ClientContext& ,
const ExportFuncBindData& , std::vector<bool> ) {
return std::make_unique<IndptrExportLocalState>();
}
static std::shared_ptr<ExportFuncSharedState> createSharedStateFunc() {
return std::make_shared<IndptrExportSharedState>();
}
static void initSharedStateFunc(ExportFuncSharedState& sharedState, main::ClientContext& context,
const ExportFuncBindData& bindData) {
sharedState.init(context, bindData);
}
static void sinkFunc(ExportFuncSharedState& , ExportFuncLocalState& localState,
const ExportFuncBindData& ,
std::vector<std::shared_ptr<ValueVector>> inputVectors) {
if (inputVectors.size() < 2) {
return;
}
auto& local = localState.cast<IndptrExportLocalState>();
auto* srcVec = inputVectors[0].get();
auto* degVec = inputVectors[1].get();
if (srcVec->state->isFlat()) {
auto pos = srcVec->state->getSelVector()[0];
local.pairs.emplace_back(srcVec->getValue<int64_t>(pos), degVec->getValue<int64_t>(pos));
return;
}
auto& sel = srcVec->state->getSelVector();
for (auto i = 0u; i < sel.getSelSize(); i++) {
auto pos = sel[i];
local.pairs.emplace_back(srcVec->getValue<int64_t>(pos), degVec->getValue<int64_t>(pos));
}
}
static void combineFunc(ExportFuncSharedState& sharedState, ExportFuncLocalState& localState) {
auto& shared = sharedState.cast<IndptrExportSharedState>();
auto& local = localState.cast<IndptrExportLocalState>();
std::lock_guard lock(shared.mtx);
shared.pairs.insert(shared.pairs.end(), local.pairs.begin(), local.pairs.end());
}
static void finalizeFunc(ExportFuncSharedState& sharedState) {
auto& shared = sharedState.cast<IndptrExportSharedState>();
std::sort(shared.pairs.begin(), shared.pairs.end(),
[](const auto& a, const auto& b) { return a.first < b.first; });
std::vector<int64_t> ptr;
ptr.reserve(shared.pairs.size() + 1);
ptr.push_back(0);
for (auto& [_, degree] : shared.pairs) {
ptr.push_back(ptr.back() + degree);
}
auto mm = MemoryManager::Get(*shared.context);
auto tableSchema = FactorizedTableSchema();
tableSchema.appendColumn(
ColumnSchema(true, 1 , (uint32_t)sizeof(overflow_value_t)));
auto outFT = FactorizedTable(mm, tableSchema.copy());
auto vec = std::make_shared<ValueVector>(LogicalType::INT64(), mm);
vec->setState(std::make_shared<DataChunkState>());
size_t offset = 0;
while (offset < ptr.size()) {
auto chunkSize = std::min<size_t>(ptr.size() - offset, DEFAULT_VECTOR_CAPACITY);
for (size_t i = 0; i < chunkSize; i++) {
vec->setValue<int64_t>(i, ptr[offset + i]);
}
vec->state->getSelVectorUnsafe().setToUnfiltered(chunkSize);
outFT.append({vec.get()});
offset += chunkSize;
}
std::vector<LogicalType> ptrTypes;
ptrTypes.push_back(LogicalType::INT64());
auto writer = std::make_unique<ParquetWriter>(shared.fileName, std::move(ptrTypes),
std::vector<std::string>{"ptr"}, lbug_parquet::format::CompressionCodec::SNAPPY,
shared.context, shared.keyValueMetadata);
writer->flush(outFT);
writer->finalize();
}
function_set IndptrExportFunction::getFunctionSet() {
function_set functionSet;
auto exportFunc = std::make_unique<ExportFunction>(name);
exportFunc->initLocalState = initLocalStateFunc;
exportFunc->createSharedState = createSharedStateFunc;
exportFunc->initSharedState = initSharedStateFunc;
exportFunc->sink = sinkFunc;
exportFunc->combine = combineFunc;
exportFunc->finalize = finalizeFunc;
exportFunc->bind = bindFunc;
functionSet.push_back(std::move(exportFunc));
return functionSet;
}
} }