miniob - drop table 实现解析
代码部分主要添加在:
drop table 与create table相反,要清理掉所有创建表和表相关联的资源,比如描述表的文件、数据文件以及索引等相关数据和文件。
sql流转到default_storge阶段的时候,在处理sql的函数中,新增一个drop_table的case。
drop table就是删除表,在create table t
时,会新建一个t.table文件,同时为了存储数据也会新建一个t.data文件存储下来。同时创建索引的时候,也会创建记录索引数据的文件,在删除表时也要一起删除掉。
那么删除表,就需要删除t.table文件、t.data文件和关联的索引文件。
同时由于buffer pool的存在,在新建表和插入数据的时候,会写入buffer pool缓存。所以drop table,不仅需要删除文件,也需要清空buffer pool ,防止在数据没落盘的时候,再建立同名表,仍然可以查询到数据。
如果建立了索引,比如t_id on t(id),那么也会新建一个t_id.index文件,也需要删除这个文件。
这些东西全部清空,那么就完成了drop table。
具体的代码实现如下:
在default_storage_stage.cpp 中的处理SQL语句的case中增加一个
case SCF_DROP_TABLE: {
const DropTable& drop_table = sql->sstr[sql->q_size-1].drop_table; // 拿到要drop 的表
rc = handler_->drop_table(current_db,drop_table.relation_name); // 调用drop table接口,drop table要在handler中实现
snprintf(response,sizeof(response),"%s\n", rc == RC::SUCCESS ? "SUCCESS" : "FAILURE"); // 返回结果,带不带换行符都可以
}
break;
在default_handler.cpp文件中,实现handler的drop_table接口:
RC DefaultHandler::drop_table(const char *dbname, const char *relation_name) {
Db *db = find_db(dbname); // 这是原有的代码,用来查找对应的数据库,不过目前只有一个库
if(db == nullptr) {
return RC::SCHEMA_DB_NOT_OPENED;
}
return db->drop_table(relation_name); // 直接调用db的删掉接口
}
在db.cpp中,实现drop_table接口
RC Db::drop_table(const char* table_name)
{
auto it = opened_tables_.find(table_name);
if (it == opened_tables_.end())
{
return SCHEMA_TABLE_NOT_EXIST; // 找不到表,要返回错误,测试程序中也会校验这种场景
}
Table* table = it->second;
RC rc = table->destroy(path_.c_str()); // 让表自己销毁资源
if(rc != RC::SUCCESS) return rc;
opened_tables_.erase(it); // 删除成功的话,从表list中将它删除
delete table;
return RC::SUCCESS;
}
table.cpp中清理文件和相关数据
RC Table::destroy(const char* dir) {
RC rc = sync();//刷新所有脏页
if(rc != RC::SUCCESS) return rc;
std::string path = table_meta_file(dir, name());
if(unlink(path.c_str()) != 0) {
LOG_ERROR("Failed to remove meta file=%s, errno=%d", path.c_str(), errno);
return RC::GENERIC_ERROR;
}
std::string data_file = std::string(dir) + "/" + name() + TABLE_DATA_SUFFIX;
if(unlink(data_file.c_str()) != 0) { // 删除描述表元数据的文件
LOG_ERROR("Failed to remove data file=%s, errno=%d", data_file.c_str(), errno);
return RC::GENERIC_ERROR;
}
std::string text_data_file = std::string(dir) + "/" + name() + TABLE_TEXT_DATA_SUFFIX;
if(unlink(text_data_file.c_str()) != 0) { // 删除表实现text字段的数据文件(后续实现了text case时需要考虑,最开始可以不考虑这个逻辑)
LOG_ERROR("Failed to remove text data file=%s, errno=%d", text_data_file.c_str(), errno);
return RC::GENERIC_ERROR;
}
const int index_num = table_meta_.index_num();
for (int i = 0; i < index_num; i++) { // 清理所有的索引相关文件数据与索引元数据
((BplusTreeIndex*)indexes_[i])->close();
const IndexMeta* index_meta = table_meta_.index(i);
std::string index_file = index_data_file(dir, name(), index_meta->name());
if(unlink(index_file.c_str()) != 0) {
LOG_ERROR("Failed to remove index file=%s, errno=%d", index_file.c_str(), errno);
return RC::GENERIC_ERROR;
}
}
return RC::SUCCESS;
}