【EOS源代码】EOS中的Multi-index

EOS中用了Multi-index,这是一种区块链下的数据永久存储和查询方式,其实原理和普通的数据库中的行与列的定义本质上是一样的,虽然我们平时看到数据库是行与列,以及数据,但底层的数据存储方式,假定是采用C++的话,无非是一行一个对象,每列都是一个属性,而对象的ID,也就是数据库的primary key。
EOS之中数据存储的方式是一样的,不同的是,对于每一个object,有一个基础的index,该Index是uint64_t,其排列按升序排列,而又定义了很多不同种类的seconde_key, 每个代表行的object中有iterator, 在second index/key 中遍历查找。
最终action 的内容都需要存储在DB中,才能成为永久性存储数据,而multi-index API提供了EOS的block 和数据库的接口。


640.jpeg

eosio::multi-index 是从boost::multi-index 继承扩展的
其定义比较奇特,hpp 的内容定义在:~/eos/libraries/chain/include/eosio/chain/multi_index_includes.hpp
而实现在另一个hpp文件中:(是不是写错文件后缀名了??)
~/eos/contracts/eosiolib/multi_index.hpp

其中需要注意的是emplace函数,find, get 等等,他们负责和chainbase 的交互。


      template<typename Lambda>
      const_iterator emplace( uint64_t payer, Lambda&& constructor ) {
         using namespace _multi_index_detail;

         eosio_assert( _code == current_receiver(), "cannot create objects in table of another contract" ); // Quick fix for mutating db using multi_index that shouldn't allow mutation. Real fix can come in RC2.

         auto itm = std::make_unique<item>( this, [&]( auto& i ){
            T& obj = static_cast<T&>(i);
            constructor( obj );

            size_t size = pack_size( obj );

            //using malloc/free here potentially is not exception-safe, although WASM doesn't support exceptions
            void* buffer = max_stack_buffer_size < size ? malloc(size) : alloca(size);

            datastream<char*> ds( (char*)buffer, size );
            ds << obj;

            auto pk = obj.primary_key();

            i.__primary_itr = db_store_i64( _scope, TableName, payer, pk, buffer, size );

            if ( max_stack_buffer_size < size ) {
               free(buffer);
            }

            if( pk >= _next_primary_key )
               _next_primary_key = (pk >= no_available_primary_key) ? no_available_primary_key : (pk + 1);

            hana::for_each( _indices, [&]( auto& idx ) {
               typedef typename decltype(+hana::at_c<0>(idx))::type index_type;

               i.__iters[index_type::number()] = secondary_index_db_functions<typename index_type::secondary_key_type>::db_idx_store( _scope, index_type::name(), payer, obj.primary_key(), index_type::extract_secondary_key(obj) );
            });
         });

         const item* ptr = itm.get();
         auto pk   = itm->primary_key();
         auto pitr = itm->__primary_itr;

         _items_vector.emplace_back( std::move(itm), pk, pitr );

         return {this, ptr};
      }

emplace 函数所做的事情,简单总结如下:
用primary key调用db_store_i64函数将数据存储到chainbase中,如果没有second key, 创建second key. emplace 返回一个主键的迭代器。

后续在检索中继续使用了db_find_i64, 进行查询,从而完成和chainbase的交互。

参考文档:
https://developers.eos.io/eosio-cpp/docs/db-api

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容