1 overview
在RedisGraph的整体架构中,非常简略的概括了RedisGraph的图存储模型:
- RedisGraph使用DataBlock来存储node和edge的属性。
- RedisGraph使用稀疏矩阵来表示图,稀疏矩阵的存储格式为按行压缩的稀疏矩阵(Compressed Sparse Row Matrix, CSR_Matrix)。
DataBlock是如何存储node和edge的属性的?使用稀疏矩阵表示图的具体设计有哪些?本文关注RedisGraph的图存储模型。
2 DataBlock
DataBlock是一种容器数据结构,用于存储同一类型的item。简单理解,DataBlock是一种数组,可以根据index对Block进行查询,只不过是,这个数组设计比较复杂,需要支持高效率的增删查改以及resize操作。
在RedisGraph中,DataBlock的用途之一是存储node和edge的属性(key-value键值对)。
2.1 the implement of DataBlock
首先,我们看一下DataBlock这个数据结构的定义:
typedef struct {
uint64_t itemCount; // Number of items stored in datablock.
uint64_t itemCap; // Number of items datablock can hold.
uint64_t blockCap; // Number of items a single block can hold.
uint blockCount; // Number of blocks in datablock.
uint itemSize; // Size of a single item in bytes.
Block **blocks; // Array of blocks.
uint64_t *deletedIdx; // Array of free indicies.
fpDestructor destructor; // Function pointer to a clean-up function of an item.
} DataBlock;
typedef struct Block {
size_t itemSize; // Size of a single item in bytes.
struct Block *next; // Pointer to next block.
unsigned char data[]; // Item array. MUST BE LAST MEMBER OF THE STRUCT!
} Block;
- 一个包含16个item、4个Block的的DataBlock如下图所示:
-
DataBlock要求每一个item的size相同,一般只存储同一种类型的item。
-
每一个item的第一个bit,用于表示item是否被删除,itemSize = sizeof(item)+1。
-
blockCount 表示为block的数量。blockCount = itemCap/blockCap。
-
当DataBlock的容量不足的时候,就会对DataBlock扩容,增加一个Block。此时,会
realloc()
blocks数组,将新增的Block指针加到blocks数组末尾。仅支持扩容,不支持缩容。 -
deletedIdx是一个队列,用于暂时存放被释放的item的index。当需要分配新的item的空间时,则优先从deletedIdx取空闲的item的index。
-
Block中存在指向下一个Block的指针。目的是,方便对DataBlock进行遍历操作。
-
查询的时间复杂度为O(1)。
对于查询DataBlock中第idx个item:
Block *block = idx / dataBlock->blockCap; idx = idx % dataBlock->blockCap; void* target_item = block->data + (idx * block->itemSize);
-
总的来说,DataBlock是一个增删查改均十分高效的容器数据结构。
2.2 DataBlock for graph store
#define NODE_CREATION_BUFFER_DEFAULT 16384
未完待续