📅  最后修改于: 2023-12-03 15:30:37.695000             🧑  作者: Mango
在 EOSIO 开发中,多索引表是一个十分常用的数据存储方式。不过,当需要清空一张多索引表的全部数据时,通常会遇到不少困难。本文介绍了一种清除多索引表全部数据的方法,希望对 EOSIO 开发者有所帮助。
假设有一个名为 example
的合约,其中包含一个名为 mytable
的多索引表,其类型为 multi_index<"mytable"_n, examplestruct>
。当需要清空 mytable
内所有数据时,通常会尝试直接遍历表内元素并逐个删除,代码示例如下:
typedef eosio::multi_index<"mytable"_n, examplestruct> mytable_t;
mytable_t mytable(contract, contract.value);
// 删除 mytable 内所有数据
auto itr = mytable.begin();
while (itr != mytable.end()) {
itr = mytable.erase(itr);
}
但是,很多情况下这种方法并不适用。例如:
因此,我们需要一个更高效、资源消耗更少的清空多索引表的方法。
高效清空多索引表的方案是:使用系统提供的批量删除接口 eosio::multi_index::emplace
,在批量删除时创建一些虚拟的具有相同主键的行,直接利用批量删除接口删除这些虚拟行即可。
具体来说,我们可以在 example
合约中添加如下代码片段:
// 范围删除所有 existing 行, 通过创建多个不存在的行
uint64_t s = std::numeric_limits<uint64_t>::min();
uint64_t sk = std::numeric_limits<uint64_t>::min();
while (s < std::numeric_limits<uint64_t>::max() - BATCH_SIZE) {
auto end = s + BATCH_SIZE;
auto upper = mytable.upper_bound(s);
if (upper != mytable.begin()) {
--upper;
if (upper->key == sk) {
--upper;
if (upper != mytable.begin()) {
--upper;
}
}
s = mytable.erase(mytable.begin(), ++upper)->key;
sk = s;
} else {
sk = s = end;
}
mytable.emplace(get_self(), [&](auto& a){
a.key = s;
a.value = 0; // value 的类型为 uint64_t
});
}
auto upper = mytable.upper_bound(s);
if (upper != mytable.end() && upper->key != sk) {
mytable.erase(mytable.begin(), upper);
mytable.emplace(get_self(), [&](auto& a) {
a.key = std::numeric_limits<uint64_t>::max();
a.value = 0;
});
}
值得注意的是,在以上代码片段中,我们使用了一些 EOSIO 提供的一些内置类型极值,如 numeric_limits<uint64_t>::min()
和 numeric_limits<uint64_t>::max()
,这使得我们不必手动处理溢出边界的问题,避免了很多麻烦。
对于需要清空大量数据的多索引表,直接单个元素逐个删除的代价非常高,无法用于生产环境中。借助 eosio::multi_index::emplace
接口创建一些虚拟行,可以大幅提升清空表的效率,从而更加高效地使用 EOSIO 示例合约。