#include "ObjectCollector.h" #include "IKvStoreFrontend.h" #include const char object_collector_sig[] = "OBJECTCOLLECTOR"; bool CompressedWData::compress() { if (decompressed_length != std::string::npos) { assert(false); return false; } uLongf orig_compressed_data_size = compressBound(static_cast(data.size())); compressed_data = static_cast(malloc(orig_compressed_data_size)); if (compressed_data == nullptr) throw std::bad_alloc(); compressed_data_size = orig_compressed_data_size; if (::compress(compressed_data, &compressed_data_size, reinterpret_cast(data.data()), static_cast(data.size())) != Z_OK) { assert(false); return false; } if (orig_compressed_data_size != compressed_data_size) { compressed_data = static_cast(realloc(compressed_data, compressed_data_size)); } decompressed_length = data.size(); std::string().swap(data); rdata.reset(); return true; } bool CompressedWData::decompress() { if (decompressed_length == std::string::npos) { assert(false); return false; } data.resize(decompressed_length); uLongf new_decompressed_length = static_cast(decompressed_length); int rc; if ((rc = ::uncompress(reinterpret_cast(&data[0]), &new_decompressed_length, compressed_data, compressed_data_size)) != Z_OK) { assert(false); return false; } free(compressed_data); compressed_data = nullptr; compressed_data_size = 0; decompressed_length = std::string::npos; return true; } ObjectCollector::ObjectCollector(IKvStoreFrontend* frontend, const std::string& fn) : frontend(frontend) { std::unique_ptr in(Server->openFile(fn, MODE_READ)); if (!in) { has_error = true; return; } std::string sig = in->Read(sizeof(object_collector_sig)-1); if (sig != std::string(object_collector_sig)) { Server->Log("Object collector signature wrong: " + sig, LL_ERROR); has_error = true; return; } unsigned int header_size; if (in->Read(reinterpret_cast(&header_size), sizeof(header_size)) != sizeof(header_size)) { Server->Log("Error reading object collector header_size", LL_ERROR); has_error = true; return; } std::vector header_buf(header_size); if (in->Read(0, header_buf.data(), header_size) != header_size) { Server->Log("Error reading object collector header", LL_ERROR); has_error = true; return; } std::string md5 = Server->GenerateBinaryMD5(std::string(header_buf.data(), header_buf.size())); CRData header_data(header_buf.data(), header_buf.size()); header_data.incrementPtr(sizeof(object_collector_sig) - 1 + sizeof(header_size)); int64 n_trans_ids; if (!header_data.getVarInt(&task_id) || !header_data.getVarInt(&n_trans_ids)) { Server->Log("Error reading header -1", LL_ERROR); has_error = true; return; } for (int64 i = 0; i < n_trans_ids; ++i) { int64 trans_id; if (!header_data.getVarInt(&trans_id)) { Server->Log("Error reading trans id", LL_ERROR); has_error = true; return; } trans_ids.push_back(trans_id); } char mirrored_info; int64 t_stride_size; int64 t_global_transid; int64 n_backend_keys; if (!header_data.getVarInt(&t_global_transid) || !header_data.getVarInt(&n_backend_keys) || !header_data.getVarInt(&t_stride_size) || !header_data.getChar(&mirrored_info) || !header_data.getVarInt(&cd_id) || !header_data.getVarInt(&n_backend_keys) ) { Server->Log("Error reading header -2", LL_ERROR); has_error = true; return; } global_transid = t_global_transid; stride_size = t_stride_size; with_mirrored = mirrored_info != 0; std::vector > backend_key_lens; for (int64 i = 0; i < n_backend_keys; ++i) { int64 len; int64 dl; if (!header_data.getVarInt(&len) || !header_data.getVarInt(&dl)) { Server->Log("Error reading backend_key_lens", LL_ERROR); has_error = true; return; } backend_key_lens.push_back(std::make_pair(len, dl)); } int64 n_backend_locinfos; if (!header_data.getVarInt(&n_backend_locinfos)) { Server->Log("Error reading header -3", LL_ERROR); has_error = true; return; } std::vector > backend_locinfo_lens; for (int64 i = 0; i < n_backend_locinfos; ++i) { int64 len; int64 dl; if (!header_data.getVarInt(&len) || !header_data.getVarInt(&dl) ) { Server->Log("Error reading backend_locinfo_lens", LL_ERROR); has_error = true; return; } backend_locinfo_lens.push_back(std::make_pair(len, dl)); } int64 pos = header_size; for (auto it : backend_key_lens) { int64 len = it.first; int64 dl = it.second; char* buf = reinterpret_cast(malloc(len)); if (in->Read(pos, buf, static_cast<_u32>(len)) != len) { free(buf); Server->Log("Error reading backend keys", LL_ERROR); has_error = true; return; } auto nd = std::make_unique(dl == -1 ? std::string::npos : dl, reinterpret_cast(buf), static_cast(len)); backend_keys.push_back(std::move(nd)); pos += len; } for (auto it : backend_locinfo_lens) { int64 len = it.first; int64 dl = it.second; char* buf = reinterpret_cast(malloc(len)); if (in->Read(pos, buf, static_cast<_u32>(len)) != len) { free(buf); Server->Log("Error reading backend locinfo", LL_ERROR); has_error = true; return; } auto nd = std::make_unique(dl == -1 ? std::string::npos : dl, reinterpret_cast(buf), static_cast(len)); backend_locinfo.push_back(std::move(nd)); pos += len; } } void ObjectCollector::add(int64 transid, const std::string& tkey, const std::string& locinfo, bool mirrored) { if (n_backend_keys >= stride_size || curr_backend_keys == nullptr) { if (!backend_keys.empty()) { backend_keys[backend_keys.size() - 1]->compress(); } if (!backend_locinfo.empty()) { backend_locinfo[backend_locinfo.size() - 1]->compress(); } backend_keys.push_back(std::unique_ptr(new CompressedWData)); curr_backend_keys = backend_keys[backend_keys.size() - 1].get(); backend_locinfo.push_back(std::unique_ptr(new CompressedWData)); curr_backend_locinfo = backend_locinfo[backend_locinfo.size() - 1].get(); n_backend_keys = 0; size_t transid_size = 0; if (transid >= 1 >> 24) transid_size = 4; else if (transid >= 1 >> 16) transid_size = 3; else if (transid >= 1 >> 8) transid_size = 2; else if (transid > 0) transid_size = 1; if (with_mirrored) transid_size += 1; curr_backend_keys->reserve(stride_size * (tkey.size() + 1 + transid_size)); curr_backend_locinfo->reserve(stride_size * (backend_locinfo.size() + 1)); } ++n_backend_keys; if (transid >= 0) { curr_backend_keys->addVarInt(transid); } curr_backend_keys->addString2(tkey); curr_backend_locinfo->addString2(locinfo); if (with_mirrored) { curr_backend_keys->addChar(mirrored ? 1 : 0); } } void ObjectCollector::add(int64 transid, const std::string& tkey, bool mirrored) { if (n_backend_keys >= stride_size || curr_backend_keys == nullptr) { if (!backend_keys.empty()) { backend_keys[backend_keys.size() - 1]->compress(); } backend_keys.push_back(std::unique_ptr(new CompressedWData)); curr_backend_keys = backend_keys[backend_keys.size() - 1].get(); backend_locinfo.push_back(nullptr); n_backend_keys = 0; size_t transid_size = 0; if (transid >= 1 >> 24) transid_size = 4; else if (transid >= 1 >> 16) transid_size = 3; else if (transid >= 1 >> 8) transid_size = 2; else if (transid > 0) transid_size = 1; if (with_mirrored) transid_size += 1; curr_backend_keys->reserve(stride_size * (tkey.size() + 1 + transid_size)); } ++n_backend_keys; if (transid >= 0) { curr_backend_keys->addVarInt(transid); } curr_backend_keys->addString2(tkey); if (with_mirrored) { curr_backend_keys->addChar(mirrored ? 1 : 0); } } bool ObjectCollector::persist(int task_id, int64 completed, int64 active, const std::vector& trans_ids, const std::string& fn) { std::unique_ptr out_f(Server->openFile(fn, MODE_RW_CREATE)); if (!out_f) return false; CWData wd; wd.addBuffer(object_collector_sig, sizeof(object_collector_sig)-1); wd.addUInt(0); wd.addVarInt(task_id); wd.addVarInt(completed); wd.addVarInt(active); wd.addVarInt(trans_ids.size()); for (size_t trans_id : trans_ids) { wd.addVarInt(trans_id); } wd.addVarInt(global_transid); wd.addVarInt(n_backend_keys); wd.addVarInt(stride_size); wd.addChar(with_mirrored ? 1 : 0); wd.addVarInt(cd_id); wd.addVarInt(backend_keys.size()); for (auto& it : backend_keys) { wd.addVarInt(it->getCompressedDataLength()); size_t dl = it->getDecompressedDataLength(); wd.addVarInt(dl == std::string::npos ? -1 : dl); } wd.addVarInt(backend_locinfo.size()); for (auto& it : backend_locinfo) { wd.addVarInt(it->getCompressedDataLength()); size_t dl = it->getDecompressedDataLength(); wd.addVarInt(dl == std::string::npos ? -1 : dl); } unsigned int header_size = wd.getDataSize() + 16; memcpy(wd.getDataPtr(), &header_size, sizeof(header_size)); std::string md5 = Server->GenerateBinaryMD5(std::string(wd.getDataPtr(), wd.getDataSize())); wd.addBuffer(md5.data(), md5.size()); int64 pos = out_f->Size(); if (pos < 0) return false; if (out_f->Write(pos, wd.getDataPtr(), wd.getDataSize()) != wd.getDataSize()) return false; pos += wd.getDataSize(); for (auto& it : backend_keys) { if (out_f->Write(pos, it->getCompressedDataPtr(), static_cast<_u32>(it->getCompressedDataLength())) != it->getCompressedDataLength()) return false; pos += it->getCompressedDataLength(); } for (auto& it : backend_locinfo) { if (out_f->Write(pos, it->getCompressedDataPtr(), static_cast<_u32>(it->getCompressedDataLength())) != it->getCompressedDataLength()) return false; pos += it->getCompressedDataLength(); } return out_f->Sync(); } void ObjectCollector::finalize() { for (size_t i = 0; i < backend_keys.size(); ++i) { memsize += backend_keys[i]->compressed_capacity(); uncompressed_memsize += backend_keys[i]->uncompressed_capacity(); if (backend_locinfo[i] != nullptr) { memsize += backend_locinfo[i]->compressed_capacity(); uncompressed_memsize += backend_locinfo[i]->uncompressed_capacity(); } } int64 l_cd_id = cd_id; for (size_t i = 0; i < backend_keys.size(); ++i) { CompressedWData* rdata = backend_keys[i].get(); IKvStoreFrontend* cfrontend = frontend; bool c_with_mirrored = with_mirrored; if (global_transid >= 0) { int64 transid = global_transid; key_next_funs.push_back( [cfrontend, c_with_mirrored, transid, rdata, l_cd_id](IKvStoreBackend::key_next_action_t action, std::string* key) { if (action == IKvStoreBackend::key_next_action_t::clear) { rdata->clear_all(); assert(key == nullptr); return true; } if (action == IKvStoreBackend::key_next_action_t::reset) { rdata->getRData()->setStreampos(0); assert(key == nullptr); return true; } assert(action == IKvStoreBackend::key_next_action_t::next); std::string tkey; if (!rdata->getRData()->getStr2(&tkey)) { return false; } if (cfrontend != nullptr) { cfrontend->incr_total_del_ops(); *key = cfrontend->prefixKey(cfrontend->encodeKey(l_cd_id, tkey, transid)); } if (c_with_mirrored) { char mirrored; if (!rdata->getRData()->getChar(&mirrored)) { return false; } if (mirrored == 1) { cfrontend->log_del_mirror(*key); } } return true; }); } else { key_next_funs.push_back( [cfrontend, c_with_mirrored, rdata, l_cd_id](IKvStoreBackend::key_next_action_t action, std::string* key) { if (action == IKvStoreBackend::key_next_action_t::clear) { rdata->clear_all(); assert(key == nullptr); return true; } if (action == IKvStoreBackend::key_next_action_t::reset) { rdata->getRData()->setStreampos(0); assert(key == nullptr); return true; } assert(action == IKvStoreBackend::key_next_action_t::next); int64 transid; if (!rdata->getRData()->getVarInt(&transid)) { return false; } std::string tkey; if (!rdata->getRData()->getStr2(&tkey)) { rdata->compress(); return false; } cfrontend->incr_total_del_ops(); *key = cfrontend->prefixKey(cfrontend->encodeKey(l_cd_id, tkey, transid)); if (c_with_mirrored) { char mirrored; if (!rdata->getRData()->getChar(&mirrored)) { return false; } if (mirrored == 1) { cfrontend->log_del_mirror(*key); } } return true; }); } if (backend_locinfo[i] != nullptr) { CompressedWData* rdata = backend_locinfo[i].get(); locinfo_next_funs.push_back( [rdata](IKvStoreBackend::key_next_action_t action, std::string* locinfo) { if (action == IKvStoreBackend::key_next_action_t::clear) { assert(locinfo == nullptr); rdata->clear_all(); return true; } if (action == IKvStoreBackend::key_next_action_t::reset) { assert(locinfo == nullptr); rdata->getRData()->setStreampos(0); return true; } assert(action == IKvStoreBackend::key_next_action_t::next); if (!rdata->getRData()->getStr2(locinfo)) { return false; } return true; }); } else { locinfo_next_funs.push_back(nullptr); } } }