// For an insert, the copy should do an allocation for all uninlinable columns // This does not do any schema checks. They must match. void Tuple::Copy(const void *source, type::AbstractPool *pool) { const bool is_inlined = tuple_schema_->IsInlined(); const oid_t uninlineable_column_count = tuple_schema_->GetUninlinedColumnCount(); if (is_inlined) { // copy the data PL_MEMCPY(tuple_data_, source, tuple_schema_->GetLength()); } else { // copy the data PL_MEMCPY(tuple_data_, source, tuple_schema_->GetLength()); // Copy each uninlined column doing an allocation for copies. for (oid_t column_itr = 0; column_itr < uninlineable_column_count; column_itr++) { const oid_t unlineable_column_id = tuple_schema_->GetUninlinedColumn(column_itr); // Get original value from uninlined pool type::Value value = GetValue(unlineable_column_id); // Make a copy of the value at a new location in uninlined pool SetValue(unlineable_column_id, value, pool); } } }
Tile *Tile::CopyTile(BackendType backend_type) { auto schema = GetSchema(); bool tile_columns_inlined = schema->IsInlined(); auto allocated_tuple_count = GetAllocatedTupleCount(); // Create a shallow copy of the old tile TileGroupHeader *new_header = GetHeader(); Tile *new_tile = TileFactory::GetTile( backend_type, INVALID_OID, INVALID_OID, INVALID_OID, INVALID_OID, new_header, *schema, tile_group, allocated_tuple_count); PL_MEMCPY(static_cast<void *>(new_tile->data), static_cast<void *>(data), tile_size); // Do a deep copy if some column is uninlined, so that // the values in that column point to the new pool if (!tile_columns_inlined) { auto uninlined_col_cnt = schema->GetUninlinedColumnCount(); // Go over each uninlined column, making a deep copy for (oid_t col_itr = 0; col_itr < uninlined_col_cnt; col_itr++) { auto uninlined_col_offset = schema->GetUninlinedColumn(col_itr); // Copy the column over to the new tile group for (oid_t tuple_itr = 0; tuple_itr < allocated_tuple_count; tuple_itr++) { type::Value val = (new_tile->GetValue(tuple_itr, uninlined_col_offset)); new_tile->SetValue(val, tuple_itr, uninlined_col_offset); } } } return new_tile; }
void VarlenType::SerializeTo(const Value &val, char *storage, bool inlined UNUSED_ATTRIBUTE, AbstractPool *pool) const { uint32_t len = GetLength(val); char *data; if (len == PELOTON_VALUE_NULL) { data = nullptr; } else { uint32_t size = len + sizeof(uint32_t); data = (pool == nullptr) ? new char[size] : (char *)pool->Allocate(size); PL_MEMCPY(data, &len, sizeof(uint32_t)); PL_MEMCPY(data + sizeof(uint32_t), val.value_.varlen, size - sizeof(uint32_t)); } *reinterpret_cast<const char **>(storage) = data; }
bool Tile::SerializeHeaderTo(SerializeOutput &output) { std::size_t start; // Use the cache if possible if (column_header != NULL) { PL_ASSERT(column_header_size != INVALID_OID); output.WriteBytes(column_header, column_header_size); return true; } PL_ASSERT(column_header_size == INVALID_OID); // Skip header position start = output.Position(); output.WriteInt(-1); // Status code output.WriteByte(-128); // Column counts as a short output.WriteShort(static_cast<int16_t>(column_count)); // Write an array of column types as bytes for (oid_t column_itr = 0; column_itr < column_count; ++column_itr) { type::Type::TypeId type = schema.GetType(column_itr); output.WriteByte(static_cast<int8_t>(type)); } // Write the array of column names as strings // NOTE: strings are ASCII only in metadata (UTF-8 in table storage) for (oid_t column_itr = 0; column_itr < column_count; ++column_itr) { // Column name: Write (offset, length) for column definition, and string to // string table const std::string &name = GetColumnName(column_itr); // Column names can't be null, so length must be >= 0 int32_t length = static_cast<int32_t>(name.size()); PL_ASSERT(length >= 0); // this is standard string serialization for voltdb output.WriteInt(length); output.WriteBytes(name.data(), length); } // Write the header size which is a non-inclusive int size_t Position = output.Position(); column_header_size = static_cast<int32_t>(Position - start); int32_t non_inclusive_header_size = static_cast<int32_t>(column_header_size - sizeof(int32_t)); output.WriteIntAt(start, non_inclusive_header_size); // Cache the column header column_header = new char[column_header_size]; PL_MEMCPY(column_header, static_cast<const char *>(output.Data()) + start, column_header_size); return true; }
/** * Insert tuple at slot * NOTE : No checks, must be at valid slot. */ void Tile::InsertTuple(const oid_t tuple_offset, Tuple *tuple) { PL_ASSERT(tuple_offset < GetAllocatedTupleCount()); // Find slot location char *location = tuple_offset * tuple_length + data; // Copy over the tuple data into the tuple slot in the tile PL_MEMCPY(location, tuple->tuple_data_, tuple_length); }
/** * @brief Serialize given data * @return true if we serialize data otherwise false */ bool TupleRecord::Serialize(CopySerializeOutput &output) { bool status = true; output.Reset(); // Serialize the common variables such as database oid, table oid, etc. SerializeHeader(output); // Serialize other parts depends on type switch (GetType()) { case LOGRECORD_TYPE_WAL_TUPLE_INSERT: case LOGRECORD_TYPE_WAL_TUPLE_UPDATE: { storage::Tuple *tuple = (storage::Tuple *)data; tuple->SerializeTo(output); break; } case LOGRECORD_TYPE_WAL_TUPLE_DELETE: // Nothing to do here ! break; case LOGRECORD_TYPE_WBL_TUPLE_INSERT: case LOGRECORD_TYPE_WBL_TUPLE_DELETE: case LOGRECORD_TYPE_WBL_TUPLE_UPDATE: // Nothing to do here ! break; default: { LOG_TRACE("Unsupported TUPLE RECORD TYPE"); status = false; break; } } message_length = output.Size(); message = new char[message_length]; PL_MEMCPY(message, output.Data(), message_length); return status; }
/** * @brief Serialize given data * @return true if we serialize data otherwise false */ bool TransactionRecord::Serialize(CopySerializeOutput &output) { bool status = true; output.Reset(); // First, write out the log record type output.WriteEnumInSingleByte(log_record_type); // Then reserve 4 bytes for the header size to be written later size_t start = output.Position(); output.WriteInt(0); output.WriteLong(cid); // Write out the header now int32_t header_length = static_cast<int32_t>(output.Position() - start - sizeof(int32_t)); output.WriteIntAt(start, header_length); message_length = output.Size(); message = new char[message_length]; PL_MEMCPY(message, output.Data(), message_length); return status; }
/* * Channel is only invoked by protobuf rpc client. So this method is sending * request msg */ void RpcChannel::CallMethod( const google::protobuf::MethodDescriptor* method, google::protobuf::RpcController* controller, const google::protobuf::Message* request, UNUSED_ATTRIBUTE google::protobuf::Message* response, google::protobuf::Closure* done) { PL_ASSERT(request != nullptr); /* run call back function */ if (done != NULL) { done->Run(); } /* Get the rpc function name */ std::string methodname = std::string(method->full_name()); std::hash<std::string> string_hash_fn; /* Set the type */ uint16_t type = MSG_TYPE_REQ; /* Get the hashcode for the rpc function name */ /* we use unit64_t because we should specify the exact length */ uint64_t opcode = string_hash_fn(methodname); /* prepare the sending buf */ uint32_t msg_len = request->ByteSize() + OPCODELEN + TYPELEN; /* total length of the message: header length (4bytes) + message length * (8bytes + ...) */ PL_ASSERT(HEADERLEN == sizeof(msg_len)); char buf[HEADERLEN + msg_len]; /* copy the header into the buf */ PL_MEMCPY(buf, &msg_len, sizeof(msg_len)); /* copy the type into the buf, following the header */ PL_ASSERT(TYPELEN == sizeof(type)); PL_MEMCPY(buf + HEADERLEN, &type, TYPELEN); /* copy the hashcode into the buf, following the type */ PL_ASSERT(OPCODELEN == sizeof(opcode)); PL_MEMCPY(buf + HEADERLEN + TYPELEN, &opcode, OPCODELEN); /* call protobuf to serialize the request message into sending buf */ request->SerializeToArray(buf + HEADERLEN + TYPELEN + OPCODELEN, request->ByteSize()); /* * GET a connection to process the rpc send and recv. If there is a associated * connection * it will be returned. If not, a new connection will be created and connect * to server */ Connection* conn = ConnectionManager::GetInstance().CreateConn( addr_); // CreateConn is used for self connect // Connection* conn = ConnectionManager::GetInstance().GetConn(addr_); /* Connect to server with given address */ if (conn == NULL) { LOG_TRACE("Can't get connection"); // rpc client use this info to decide whether re-send the message controller->SetFailed("Connect Error"); return; } /* write data into sending buffer, when using libevent we don't need loop send */ if (conn->AddToWriteBuffer(buf, HEADERLEN + msg_len) == false) { LOG_TRACE("Write data Error"); return; } }