Exemplo n.º 1
0
// 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);
    }
  }
}
Exemplo n.º 2
0
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;
}
Exemplo n.º 3
0
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;
}
Exemplo n.º 4
0
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;
}
Exemplo n.º 5
0
/**
 * 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);
}
Exemplo n.º 6
0
/**
 * @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;
}
Exemplo n.º 7
0
/**
 * @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;
}
Exemplo n.º 8
0
/*
 * 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;
  }
}