Exemplo n.º 1
0
/**
 * @brief updates a set of columns
 * @return true on success, false otherwise.
 */
bool UpdateExecutor::DExecute() {
  PL_ASSERT(children_.size() == 1);
  PL_ASSERT(executor_context_);

  // We are scanning over a logical tile.
  LOG_TRACE("Update executor :: 1 child ");

  if (!children_[0]->Execute()) {
    return false;
  }

  std::unique_ptr<LogicalTile> source_tile(children_[0]->GetOutput());

  auto &pos_lists = source_tile.get()->GetPositionLists();
  storage::Tile *tile = source_tile->GetBaseTile(0);
  storage::TileGroup *tile_group = tile->GetTileGroup();
  storage::TileGroupHeader *tile_group_header = tile_group->GetHeader();
  auto tile_group_id = tile_group->GetTileGroupId();

  auto &transaction_manager =
      concurrency::TransactionManagerFactory::GetInstance();

  // Update tuples in given table
  for (oid_t visible_tuple_id : *source_tile) {
    oid_t physical_tuple_id = pos_lists[0][visible_tuple_id];

    ItemPointer old_location(tile_group_id, physical_tuple_id);

    LOG_TRACE("Visible Tuple id : %u, Physical Tuple id : %u ",
              visible_tuple_id, physical_tuple_id);

    if (transaction_manager.IsOwner(tile_group_header, physical_tuple_id) ==
        true) {
      // Make a copy of the original tuple and allocate a new tuple
      expression::ContainerTuple<storage::TileGroup> old_tuple(
          tile_group, physical_tuple_id);
      // Create a temp copy
      std::unique_ptr<storage::Tuple> new_tuple(
          new storage::Tuple(target_table_->GetSchema(), true));
      // Execute the projections
      // FIXME: reduce memory copy by doing inplace update
      project_info_->Evaluate(new_tuple.get(), &old_tuple, nullptr,
                              executor_context_);


      // Current rb segment is OK, just overwrite the tuple in place
      tile_group->CopyTuple(new_tuple.get(), physical_tuple_id);
      transaction_manager.PerformUpdate(old_location);

    } else if (transaction_manager.IsOwnable(tile_group_header,
                                             physical_tuple_id) == true) {
      // if the tuple is not owned by any transaction and is visible to current
      // transaction.

      if (transaction_manager.AcquireOwnership(tile_group_header, tile_group_id,
                                               physical_tuple_id) == false) {
        LOG_TRACE("Fail to insert new tuple. Set txn failure.");
        transaction_manager.SetTransactionResult(Result::RESULT_FAILURE);
        return false;
      }
      // if it is the latest version and not locked by other threads, then
      // insert a new version.
      std::unique_ptr<storage::Tuple> new_tuple(
          new storage::Tuple(target_table_->GetSchema(), true));

      // Make a copy of the original tuple and allocate a new tuple
      expression::ContainerTuple<storage::TileGroup> old_tuple(
          tile_group, physical_tuple_id);
      // Execute the projections
      project_info_->Evaluate(new_tuple.get(), &old_tuple, nullptr,
                              executor_context_);

      // finally insert updated tuple into the table
      ItemPointer new_location =
          target_table_->InsertVersion(new_tuple.get());

      // FIXME: PerformUpdate() will not be executed if the insertion failed,
      // There is a write lock acquired, but since it is not in the write set,
      // because we haven't yet put them into the write set.
      // the acquired lock can't be released when the txn is aborted.
      if (new_location.IsNull() == true) {
        LOG_TRACE("Fail to insert new tuple. Set txn failure.");
        transaction_manager.SetTransactionResult(Result::RESULT_FAILURE);
        return false;
      }

      LOG_TRACE("perform update old location: %u, %u", old_location.block,
                old_location.offset);
      LOG_TRACE("perform update new location: %u, %u", new_location.block,
                new_location.offset);
      transaction_manager.PerformUpdate(old_location, new_location);


      // TODO: Why don't we also do this in the if branch above?
      executor_context_->num_processed += 1;  // updated one
    } else {
      // transaction should be aborted as we cannot update the latest version.
      LOG_TRACE("Fail to update tuple. Set txn failure.");
      transaction_manager.SetTransactionResult(Result::RESULT_FAILURE);
      return false;
    }
  }
  return true;
}
Exemplo n.º 2
0
/**
 * @brief Delete the table tuples using the position list in the logical tile.
 *
 * If truncate is on, then it will truncate the table itself.
 * @return true on success, false otherwise.
 */
bool DeleteExecutor::DExecute() {
  PL_ASSERT(target_table_);
  // Retrieve next tile.
  if (!children_[0]->Execute()) {
    return false;
  }

  std::unique_ptr<LogicalTile> source_tile(children_[0]->GetOutput());

  auto &pos_lists = source_tile.get()->GetPositionLists();

  auto &transaction_manager =
      concurrency::TransactionManagerFactory::GetInstance();

  auto current_txn = executor_context_->GetTransaction();

  LOG_TRACE("Source tile : %p Tuples : %lu ", source_tile.get(),
            source_tile->GetTupleCount());

  LOG_TRACE("Source tile info: %s", source_tile->GetInfo().c_str());

  LOG_TRACE("Transaction ID: %" PRId64,
            executor_context_->GetTransaction()->GetTransactionId());

  auto executor_pool = executor_context_->GetPool();
  auto target_table_schema = target_table_->GetSchema();
  auto column_count = target_table_schema->GetColumnCount();

  trigger::TriggerList *trigger_list = target_table_->GetTriggerList();
  if (trigger_list != nullptr) {
    LOG_TRACE("size of trigger list in target table: %d",
              trigger_list->GetTriggerListSize());
    if (trigger_list->HasTriggerType(TriggerType::BEFORE_DELETE_STATEMENT)) {
      LOG_TRACE("target table has per-statement-before-delete triggers!");
      trigger_list->ExecTriggers(TriggerType::BEFORE_DELETE_STATEMENT,
                                 current_txn);
    }
  }

  // Delete each tuple
  for (oid_t visible_tuple_id : *source_tile) {
    storage::TileGroup *tile_group =
        source_tile->GetBaseTile(0)->GetTileGroup();
    storage::TileGroupHeader *tile_group_header = tile_group->GetHeader();

    oid_t physical_tuple_id = pos_lists[0][visible_tuple_id];

    ItemPointer old_location(tile_group->GetTileGroupId(), physical_tuple_id);

    LOG_TRACE("Visible Tuple id : %u, Physical Tuple id : %u ",
              visible_tuple_id, physical_tuple_id);

    // if running at snapshot isolation,
    // then we need to retrieve the latest version of this tuple.
    if (current_txn->GetIsolationLevel() == IsolationLevelType::SNAPSHOT) {
      old_location = *(tile_group_header->GetIndirection(physical_tuple_id));

      auto &manager = catalog::Manager::GetInstance();
      tile_group = manager.GetTileGroup(old_location.block).get();
      tile_group_header = tile_group->GetHeader();

      physical_tuple_id = old_location.offset;
    }

    ContainerTuple<storage::TileGroup> old_tuple(tile_group, physical_tuple_id);
    storage::Tuple prev_tuple(target_table_->GetSchema(), true);

    // Get a copy of the old tuple
    for (oid_t column_itr = 0; column_itr < target_table_schema->GetColumnCount(); column_itr++) {
      type::Value val = (old_tuple.GetValue(column_itr));
      prev_tuple.SetValue(column_itr, val, executor_context_->GetPool());
    }

    // Check the foreign key source table
    if (target_table_->CheckForeignKeySrcAndCascade(&prev_tuple,
                                                    nullptr,
                                                    current_txn,
                                                    executor_context_,
                                                    false) == false)
    {
      transaction_manager.SetTransactionResult(current_txn,
                                              peloton::ResultType::FAILURE);
      return false;
    }

    bool is_owner = transaction_manager.IsOwner(current_txn, tile_group_header,
                                                physical_tuple_id);

    bool is_written = transaction_manager.IsWritten(
        current_txn, tile_group_header, physical_tuple_id);

    // if the current transaction is the creator of this version.
    // which means the current transaction has already updated the version.

    std::unique_ptr<storage::Tuple> real_tuple(
        new storage::Tuple(target_table_schema, true));
    bool tuple_is_materialzed = false;

    // check whether there are per-row-before-delete triggers on this table
    // using trigger catalog
    if (trigger_list != nullptr) {
      LOG_TRACE("size of trigger list in target table: %d",
                trigger_list->GetTriggerListSize());
      if (trigger_list->HasTriggerType(TriggerType::BEFORE_DELETE_ROW)) {
        ContainerTuple<LogicalTile> logical_tile_tuple(source_tile.get(),
                                                       visible_tuple_id);
        // Materialize the logical tile tuple
        for (oid_t column_itr = 0; column_itr < column_count; column_itr++) {
          type::Value val = (logical_tile_tuple.GetValue(column_itr));
          real_tuple->SetValue(column_itr, val, executor_pool);
        }
        tuple_is_materialzed = true;
        LOG_TRACE("target table has per-row-before-delete triggers!");
        trigger_list->ExecTriggers(TriggerType::BEFORE_DELETE_ROW, current_txn,
                                   real_tuple.get(), executor_context_);
      }
    }

    if (is_owner == true && is_written == true) {
      // if the transaction is the owner of the tuple, then directly update in
      // place.
      LOG_TRACE("The current transaction is the owner of the tuple");
      transaction_manager.PerformDelete(current_txn, old_location);
    } else {
      bool is_ownable = is_owner ||
                        transaction_manager.IsOwnable(
                            current_txn, tile_group_header, physical_tuple_id);

      if (is_ownable == true) {
        // if the tuple is not owned by any transaction and is visible to
        // current transaction.
        LOG_TRACE("Thread is not the owner of the tuple, but still visible");

        bool acquire_ownership_success =
            is_owner ||
            transaction_manager.AcquireOwnership(current_txn, tile_group_header,
                                                 physical_tuple_id);

        if (acquire_ownership_success == false) {
          transaction_manager.SetTransactionResult(current_txn,
                                                   ResultType::FAILURE);
          return false;
        }
        // if it is the latest version and not locked by other threads, then
        // insert an empty version.
        ItemPointer new_location = target_table_->InsertEmptyVersion();

        // PerformDelete() will not be executed if the insertion failed.
        // There is a write lock acquired, but since it is not in the write set,
        // because we haven't yet put them into the write set.
        // the acquired lock can't be released when the txn is aborted.
        // the YieldOwnership() function helps us release the acquired write
        // lock.
        if (new_location.IsNull() == true) {
          LOG_TRACE("Fail to insert new tuple. Set txn failure.");
          if (is_owner == false) {
            // If the ownership is acquire inside this update executor, we
            // release it here
            transaction_manager.YieldOwnership(current_txn, tile_group_header,
                                               physical_tuple_id);
          }
          transaction_manager.SetTransactionResult(current_txn,
                                                   ResultType::FAILURE);
          return false;
        }
        transaction_manager.PerformDelete(current_txn, old_location,
                                          new_location);

        executor_context_->num_processed += 1;  // deleted one
      } else {
        // transaction should be aborted as we cannot update the latest version.
        LOG_TRACE("Fail to update tuple. Set txn failure.");
        transaction_manager.SetTransactionResult(current_txn,
                                                 ResultType::FAILURE);
        return false;
      }
    }
    // execute after-delete-row triggers and
    // record on-commit-delete-row triggers into current transaction
    if (trigger_list != nullptr) {
      LOG_TRACE("size of trigger list in target table: %d",
                trigger_list->GetTriggerListSize());
      if (trigger_list->HasTriggerType(TriggerType::AFTER_DELETE_ROW) ||
          trigger_list->HasTriggerType(TriggerType::ON_COMMIT_DELETE_ROW)) {
        if (!tuple_is_materialzed) {
          ContainerTuple<LogicalTile> logical_tile_tuple(source_tile.get(),
                                                         visible_tuple_id);
          // Materialize the logical tile tuple
          for (oid_t column_itr = 0; column_itr < column_count; column_itr++) {
            type::Value val = (logical_tile_tuple.GetValue(column_itr));
            real_tuple->SetValue(column_itr, val, executor_pool);
          }
        }
        if (trigger_list->HasTriggerType(TriggerType::AFTER_DELETE_ROW)) {
          LOG_TRACE("target table has per-row-after-delete triggers!");
          trigger_list->ExecTriggers(TriggerType::AFTER_DELETE_ROW, current_txn,
                                     real_tuple.get(), executor_context_);
        }
        if (trigger_list->HasTriggerType(TriggerType::ON_COMMIT_DELETE_ROW)) {
          LOG_TRACE("target table has per-row-on-commit-delete triggers!");
          trigger_list->ExecTriggers(TriggerType::ON_COMMIT_DELETE_ROW,
                                     current_txn, real_tuple.get(),
                                     executor_context_);
        }
      }
    }
  }
  // execute after-delete-statement triggers and
  // record on-commit-delete-statement triggers into current transaction
  if (trigger_list != nullptr) {
    LOG_TRACE("size of trigger list in target table: %d",
              trigger_list->GetTriggerListSize());
    if (trigger_list->HasTriggerType(TriggerType::AFTER_DELETE_STATEMENT)) {
      LOG_TRACE("target table has per-statement-after-delete triggers!");
      trigger_list->ExecTriggers(TriggerType::AFTER_DELETE_STATEMENT,
                                 current_txn);
    }
    if (trigger_list->HasTriggerType(TriggerType::ON_COMMIT_DELETE_STATEMENT)) {
      LOG_TRACE("target table has per-statement-on-commit-delete triggers!");
      trigger_list->ExecTriggers(TriggerType::ON_COMMIT_DELETE_STATEMENT,
                                 current_txn);
    }
  }
  return true;
}
Exemplo n.º 3
0
/**
 * @brief Delete the table tuples using the position list in the logical tile.
 *
 * If truncate is on, then it will truncate the table itself.
 * @return true on success, false otherwise.
 */
bool DeleteExecutor::DExecute() {
  PL_ASSERT(target_table_);
  // Retrieve next tile.
  if (!children_[0]->Execute()) {
    return false;
  }

  std::unique_ptr<LogicalTile> source_tile(children_[0]->GetOutput());

  auto &pos_lists = source_tile.get()->GetPositionLists();
  storage::Tile *tile = source_tile->GetBaseTile(0);
  storage::TileGroup *tile_group = tile->GetTileGroup();
  storage::TileGroupHeader *tile_group_header = tile_group->GetHeader();
  auto tile_group_id = tile_group->GetTileGroupId();

  auto &transaction_manager =
      concurrency::TransactionManagerFactory::GetInstance();

  auto current_txn = executor_context_->GetTransaction();

  LOG_TRACE("Source tile : %p Tuples : %lu ", source_tile.get(),
            source_tile->GetTupleCount());

  LOG_TRACE("Source tile info: %s", source_tile->GetInfo().c_str());

  LOG_TRACE("Transaction ID: %lu",
            executor_context_->GetTransaction()->GetTransactionId());

  // Delete each tuple
  for (oid_t visible_tuple_id : *source_tile) {
    oid_t physical_tuple_id = pos_lists[0][visible_tuple_id];

    ItemPointer old_location(tile_group_id, physical_tuple_id);

    LOG_TRACE("Visible Tuple id : %u, Physical Tuple id : %u ",
              visible_tuple_id, physical_tuple_id);

    bool is_owner = 
        transaction_manager.IsOwner(current_txn, tile_group_header, physical_tuple_id);
    bool is_written =
      transaction_manager.IsWritten(current_txn, tile_group_header, physical_tuple_id);
    PL_ASSERT((is_owner == false && is_written == true) == false);

    if (is_owner == true && is_written == true) {
      // if the thread is the owner of the tuple, then directly update in place.
      LOG_TRACE("Thread is owner of the tuple");
      transaction_manager.PerformDelete(current_txn, old_location);

    } else {

      bool is_ownable = is_owner ||
          transaction_manager.IsOwnable(current_txn, tile_group_header, physical_tuple_id);

      if (is_ownable == true) {
        // if the tuple is not owned by any transaction and is visible to current
        // transaction.
      	LOG_TRACE("Thread is not the owner of the tuple, but still visible");

        bool acquire_ownership_success = is_owner ||
            transaction_manager.AcquireOwnership(current_txn, tile_group_header, physical_tuple_id);


        if (acquire_ownership_success == false) {
          transaction_manager.SetTransactionResult(current_txn, Result::RESULT_FAILURE);
          return false;
        }
        // if it is the latest version and not locked by other threads, then
        // insert an empty version.
        ItemPointer new_location = target_table_->InsertEmptyVersion();

        // PerformUpdate() will not be executed if the insertion failed.
        // There is a write lock acquired, but since it is not in the write set,
        // because we haven't yet put them into the write set.
        // the acquired lock can't be released when the txn is aborted.
        // the YieldOwnership() function helps us release the acquired write lock.
        if (new_location.IsNull() == true) {
          LOG_TRACE("Fail to insert new tuple. Set txn failure.");
          if (is_owner == false) {
            // If the ownership is acquire inside this update executor, we release it here
            transaction_manager.YieldOwnership(current_txn, tile_group_id, physical_tuple_id);
          }
          transaction_manager.SetTransactionResult(current_txn, Result::RESULT_FAILURE);
          return false;
        }
        transaction_manager.PerformDelete(current_txn, old_location, new_location);

        executor_context_->num_processed += 1;  // deleted one

      } else {
        // transaction should be aborted as we cannot update the latest version.
        LOG_TRACE("Fail to update tuple. Set txn failure.");
        transaction_manager.SetTransactionResult(current_txn, Result::RESULT_FAILURE);
        return false;
      }
    }
  }

  return true;
}