Skip to content

Commit

Permalink
#423: Truncate indexes when truncating a table
Browse files Browse the repository at this point in the history
Summary: This revision modifies YugaByte DB to truncate secondary indexes when truncating a YCQL table.

Test Plan: TestTruncate.testTruncateWithIndex

Reviewers: bharat

Reviewed By: bharat

Subscribers: bogdan, yql

Differential Revision: https://phabricator.dev.yugabyte.com/D5281
  • Loading branch information
robertpang committed Aug 7, 2018
1 parent 827a539 commit 03a3e47
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 19 deletions.
30 changes: 30 additions & 0 deletions java/yb-cql/src/test/java/org/yb/cql/TestTruncate.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;

import java.util.*;

public class TestTruncate extends BaseCQLTest {

@Test
Expand Down Expand Up @@ -48,6 +50,34 @@ public void testTruncate() throws Exception {
assertNull(session.execute("select * from test_empty_truncate;").one());
}

@Test
public void testTruncateWithIndex() throws Exception {
// Create table with index.
session.execute("create table test_truncate_index (k int primary key, v int) " +
"with transactions = { 'enabled' : true };");
session.execute("create index test_truncate_index_idx on test_truncate_index (v);");

// Insert rows and verify.
final int ROW_COUNT = 100;
HashSet<String> results = new HashSet<>();
for (int i = 0; i < ROW_COUNT; i++) {
session.execute("insert into test_truncate_index (k, v) values (?, ?);",
Integer.valueOf(i), Integer.valueOf(1000 + i));
results.add(String.format("Row[%d, %d]", i, 1000 + i));
}
assertQuery("select * from test_truncate_index;", results);

// Truncate rows, insert new ones and verify.
session.execute("truncate table test_truncate_index;");
results.clear();
for (int i = ROW_COUNT; i < ROW_COUNT * 2; i++) {
session.execute("insert into test_truncate_index (k, v) values (?, ?);",
Integer.valueOf(i), Integer.valueOf(1000 + i));
results.add(String.format("Row[%d, %d]", i, 1000 + i));
}
assertQuery("select * from test_truncate_index;", results);
}

@Test
public void testInvalidTruncate() throws Exception {
runInvalidStmt("truncate table invalid_namespace.test_truncate;");
Expand Down
58 changes: 39 additions & 19 deletions src/yb/master/catalog_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2100,29 +2100,49 @@ Status CatalogManager::TruncateTable(const TruncateTableRequestPB* req,
RETURN_NOT_OK(CheckOnline());

for (int i = 0; i < req->table_ids_size(); i++) {
const auto& table_id = req->table_ids(i);
// Lookup the table and verify if it exists.
TRACE("Looking up table");
scoped_refptr<TableInfo> table = FindPtrOrNull(table_ids_map_, table_id);
if (table == nullptr) {
Status s = STATUS(NotFound, Substitute("The table for table_id $0 does not exist", table_id));
return SetupError(resp->mutable_error(), MasterErrorPB::TABLE_NOT_FOUND, s);
}
RETURN_NOT_OK(TruncateTable(req->table_ids(i), false /* is_index */, resp, rpc));
}

TRACE("Locking table");
auto l = table->LockForRead();
if (l->data().started_deleting() || l->data().is_deleted()) {
Status s = STATUS(NotFound, Substitute("The table $0 does not exist", table->ToString()));
return SetupError(resp->mutable_error(), MasterErrorPB::TABLE_NOT_FOUND, s);
}
return Status::OK();
}

// Send a Truncate() request to each tablet in the table.
SendTruncateTableRequest(table);
Status CatalogManager::TruncateTable(const TableId& table_id,
const bool is_index,
TruncateTableResponsePB* resp,
rpc::RpcContext* rpc) {
const char* table_type = is_index ? "index" : "table";

LOG(INFO) << "Successfully initiated TRUNCATE for " << table->ToString() << " per request from "
<< RequestorString(rpc);
background_tasks_->Wake();
// Lookup the table and verify if it exists.
TRACE(Substitute("Looking up $0", table_type));
scoped_refptr<TableInfo> table = FindPtrOrNull(table_ids_map_, table_id);
if (table == nullptr) {
Status s = STATUS(NotFound, Substitute("The table for $0 id $1 does not exist",
table_type, table_id));
return SetupError(resp->mutable_error(), MasterErrorPB::TABLE_NOT_FOUND, s);
}

TRACE(Substitute("Locking $0", table_type));
auto l = table->LockForRead();
DCHECK(is_index == !l->data().pb.indexed_table_id().empty());
if (l->data().started_deleting() || l->data().is_deleted()) {
Status s = STATUS(NotFound, Substitute("The $0 $1 does not exist",
table_type, table->ToString()));
return SetupError(resp->mutable_error(), MasterErrorPB::TABLE_NOT_FOUND, s);
}

// Send a Truncate() request to each tablet in the table.
SendTruncateTableRequest(table);

LOG(INFO) << "Successfully initiated TRUNCATE for " << table->ToString() << " per request from "
<< RequestorString(rpc);
background_tasks_->Wake();

// Truncate indexes also.
DCHECK(!is_index || l->data().pb.indexes().empty()) << "indexes should be empty for index table";
for (const auto& index_info : l->data().pb.indexes()) {
RETURN_NOT_OK(TruncateTable(index_info.table_id(), true /* is_index */, resp, rpc));
}

return Status::OK();
}

Expand Down
6 changes: 6 additions & 0 deletions src/yb/master/catalog_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -1356,6 +1356,12 @@ class CatalogManager : public tserver::TabletPeerLookupIf {
// Start the background task to send the TruncateTable() RPC to the leader for this tablet.
void SendTruncateTabletRequest(const scoped_refptr<TabletInfo>& tablet);

// Truncate the specified table/index.
CHECKED_STATUS TruncateTable(const TableId& table_id,
bool is_index,
TruncateTableResponsePB* resp,
rpc::RpcContext* rpc);

// Delete the specified table in memory. The TableInfo, DeletedTableInfo and lock of the deleted
// table are appended to the lists. The caller will be responsible for committing the change and
// deleting the actual table and tablets.
Expand Down

0 comments on commit 03a3e47

Please sign in to comment.