int CompactBlock::real_compact(LogicBlock* src, LogicBlock* dest) { assert(NULL != src && NULL != dest); BlockInfo dest_blk; BlockInfo* src_blk = src->get_block_info(); dest_blk.block_id_ = src_blk->block_id_; dest_blk.seq_no_ = src_blk->seq_no_; dest_blk.version_ = src_blk->version_; dest_blk.file_count_ = 0; dest_blk.size_ = 0; dest_blk.del_file_count_ = 0; dest_blk.del_size_ = 0; dest->set_last_update(time(NULL)); TBSYS_LOG(DEBUG, "compact block set last update. blockid: %u\n", dest->get_logic_block_id()); char* dest_buf = new char[MAX_COMPACT_READ_SIZE]; int32_t write_offset = 0, data_len = 0; int32_t w_file_offset = 0; RawMetaVec dest_metas; FileIterator* fit = new FileIterator(src); int ret = TFS_SUCCESS; while (fit->has_next()) { ret = fit->next(); if (TFS_SUCCESS != ret) { tbsys::gDeleteA(dest_buf); tbsys::gDelete(fit); return ret; } const FileInfo* pfinfo = fit->current_file_info(); if (pfinfo->flag_ & (FI_DELETED | FI_INVALID)) { continue; } FileInfo dfinfo = *pfinfo; dfinfo.offset_ = w_file_offset; // the size returned by FileIterator.current_file_info->size is // the size of file content!!! dfinfo.size_ = pfinfo->size_ + sizeof(FileInfo); dfinfo.usize_ = pfinfo->size_ + sizeof(FileInfo); w_file_offset += dfinfo.size_; dest_blk.file_count_++; dest_blk.size_ += dfinfo.size_; RawMeta tmp_meta; tmp_meta.set_file_id(dfinfo.id_); tmp_meta.set_size(dfinfo.size_); tmp_meta.set_offset(dfinfo.offset_); dest_metas.push_back(tmp_meta); // need flush write buffer if ((0 != data_len) && (fit->is_big_file() || data_len + dfinfo.size_ > MAX_COMPACT_READ_SIZE)) { TBSYS_LOG(DEBUG, "write one, blockid: %u, write offset: %d\n", dest->get_logic_block_id(), write_offset); ret = dest->write_raw_data(dest_buf, data_len, write_offset); if (TFS_SUCCESS != ret) { TBSYS_LOG(ERROR, "write raw data fail, blockid: %u, offset %d, readinglen: %d, ret :%d", dest->get_logic_block_id(), write_offset, data_len, ret); tbsys::gDeleteA(dest_buf); tbsys::gDelete(fit); return ret; } write_offset += data_len; data_len = 0; } if (fit->is_big_file()) { ret = write_big_file(src, dest, *pfinfo, dfinfo, write_offset); write_offset += dfinfo.size_; } else { memcpy(dest_buf + data_len, &dfinfo, sizeof(FileInfo)); int left_len = MAX_COMPACT_READ_SIZE - data_len; ret = fit->read_buffer(dest_buf + data_len + sizeof(FileInfo), left_len); data_len += dfinfo.size_; } if (TFS_SUCCESS != ret) { tbsys::gDeleteA(dest_buf); tbsys::gDelete(fit); return ret; } } // end of iterate if (0 != data_len) // flush the last buffer { TBSYS_LOG(DEBUG, "write one, blockid: %u, write offset: %d\n", dest->get_logic_block_id(), write_offset); ret = dest->write_raw_data(dest_buf, data_len, write_offset); if (TFS_SUCCESS != ret) { TBSYS_LOG(ERROR, "write raw data fail, blockid: %u, offset %d, readinglen: %d, ret :%d", dest->get_logic_block_id(), write_offset, data_len, ret); tbsys::gDeleteA(dest_buf); tbsys::gDelete(fit); return ret; } } tbsys::gDeleteA(dest_buf); tbsys::gDelete(fit); TBSYS_LOG(DEBUG, "compact write complete. blockid: %u\n", dest->get_logic_block_id()); ret = dest->batch_write_meta(&dest_blk, &dest_metas); if (TFS_SUCCESS != ret) { TBSYS_LOG(ERROR, "compact write segment meta failed. blockid: %u, meta size %zd\n", dest->get_logic_block_id(), dest_metas.size()); return ret; } TBSYS_LOG(DEBUG, "compact set dirty flag. blockid: %u\n", dest->get_logic_block_id()); ret = dest->set_block_dirty_type(C_DATA_CLEAN); if (TFS_SUCCESS != ret) { TBSYS_LOG(ERROR, "compact blockid: %u set dirty flag fail. ret: %d\n", dest->get_logic_block_id(), ret); return ret; } return TFS_SUCCESS; }