swoole_table的构造函数用于创建内存表。
swoole_table->__construct(int $size, float $conflict_proportion = 0.2)
$size
参数指定表格的最大行数,如果$size
不是为2
的N次方,如1024
、8192
,65536
等,底层会自动调整为接近的一个数字,如果小于1024则默认成1024,即1024是最小值table
占用的内存总数为 (结构体长度 + KEY长度64字节 + 行尺寸$size
) * (1.2预留20%作为hash冲突) * (列尺寸),如果机器内存不足table会创建失败set
操作能存储的最大行数与$size
正相关,但不完全一致,如$size
为1024实际可存储的行数小于1024
- swoole_table基于行锁,所以单次set/get/del在多线程/多进程的环境下是安全的
- set/get/del是原子操作,用户代码中不需要担心数据加锁和同步的问题
我们分析下其流程。
PHP_METHOD(swoole_table, __construct)
{
long table_size;
double conflict_proportion = SW_TABLE_CONFLICT_PROPORTION;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|d", &table_size, &conflict_proportion) == FAILURE)
{
RETURN_FALSE;
}
swTable *table = swTable_new(table_size, conflict_proportion);
if (table == NULL)
{
zend_throw_exception(swoole_exception_class_entry_ptr, "global memory allocation failure.", SW_ERROR_MALLOC_FAIL TSRMLS_CC);
RETURN_FALSE;
}
swoole_set_object(getThis(), table);
}
swTable* swTable_new(uint32_t rows_size, float conflict_proportion)
{
if (rows_size >= 0x80000000)
{
rows_size = 0x80000000;
}
else
{
uint32_t i = 10;
while ((1U << i) < rows_size)
{
i++;
}
rows_size = 1 << i;
}
if (conflict_proportion > 1.0)
{
conflict_proportion = 1.0;
}
else if (conflict_proportion < SW_TABLE_CONFLICT_PROPORTION)
{
conflict_proportion = SW_TABLE_CONFLICT_PROPORTION;
}
swTable *table = SwooleG.memory_pool->alloc(SwooleG.memory_pool, sizeof(swTable));
if (table == NULL)
{
return NULL;
}
if (swMutex_create(&table->lock, 1) < 0)
{
swWarn("mutex create failed.");
return NULL;
}
table->iterator = sw_malloc(sizeof(swTable_iterator));
if (!table->iterator)
{
swWarn("malloc failed.");
return NULL;
}
table->columns = swHashMap_new(SW_HASHMAP_INIT_BUCKET_N, (swHashMap_dtor)swTableColumn_free);
if (!table->columns)
{
return NULL;
}
table->size = rows_size;
table->mask = rows_size - 1;
table->conflict_proportion = conflict_proportion;
bzero(table->iterator, sizeof(swTable_iterator));
table->memory = NULL;
return table;
}