dmitry Tue, 20 Apr 2010 10:49:22 +0000 Revision: http://svn.php.net/viewvc?view=revision&revision=298202
Log: Added an optimization which saves memory and emalloc/efree calls for empty HashTables Changed paths: U php/php-src/trunk/NEWS U php/php-src/trunk/Zend/zend_hash.c Modified: php/php-src/trunk/NEWS =================================================================== --- php/php-src/trunk/NEWS 2010-04-20 10:44:19 UTC (rev 298201) +++ php/php-src/trunk/NEWS 2010-04-20 10:49:22 UTC (rev 298202) @@ -4,6 +4,8 @@ - Upgraded bundled sqlite to version 3.6.23.1. (Ilia) - Upgraded bundled PCRE to version 8.02. (Ilia) +- Added an optimization which saves memory and emalloc/efree calls for empty + HashTables (Stas, Dmitry) - Added Tokyo Cabinet abstract DB support to ext/dba. (Michael Maclean) - Added Jenkins's one-at-a-time hash support to ext/hash. (Martin Jansen) - Added FNV-1 hash support to ext/hash. (Michael Maclean) Modified: php/php-src/trunk/Zend/zend_hash.c =================================================================== --- php/php-src/trunk/Zend/zend_hash.c 2010-04-20 10:44:19 UTC (rev 298201) +++ php/php-src/trunk/Zend/zend_hash.c 2010-04-20 10:49:22 UTC (rev 298202) @@ -132,12 +132,18 @@ (p)->pDataPtr=NULL; \ } +#define CHECK_INIT(ht) do { \ + if (UNEXPECTED((ht)->nTableMask == 0)) { \ + (ht)->nTableMask = (ht)->nTableSize - 1; \ + (ht)->arBuckets = (Bucket **) pecalloc((ht)->nTableSize, sizeof(Bucket *), (ht)->persistent); \ + } \ +} while (0) + +static const Bucket *uninitialized_bucket = NULL; - ZEND_API int _zend_hash_init(HashTable *ht, uint nSize, hash_func_t pHashFunction, dtor_func_t pDestructor, zend_bool persistent ZEND_FILE_LINE_DC) { uint i = 3; - Bucket **tmp; SET_INCONSISTENT(HT_OK); @@ -151,9 +157,9 @@ ht->nTableSize = 1 << i; } - ht->nTableMask = ht->nTableSize - 1; + ht->nTableMask = 0; /* 0 means that ht->arBuckets is uninitialized */ ht->pDestructor = pDestructor; - ht->arBuckets = NULL; + ht->arBuckets = (Bucket**)&uninitialized_bucket; ht->pListHead = NULL; ht->pListTail = NULL; ht->nNumOfElements = 0; @@ -162,21 +168,6 @@ ht->persistent = persistent; ht->nApplyCount = 0; ht->bApplyProtection = 1; - - /* Uses ecalloc() so that Bucket* == NULL */ - if (persistent) { - tmp = (Bucket **) calloc(ht->nTableSize, sizeof(Bucket *)); - if (!tmp) { - return FAILURE; - } - ht->arBuckets = tmp; - } else { - tmp = (Bucket **) ecalloc_rel(ht->nTableSize, sizeof(Bucket *)); - if (tmp) { - ht->arBuckets = tmp; - } - } - return SUCCESS; } @@ -212,6 +203,8 @@ return FAILURE; } + CHECK_INIT(ht); + h = zend_inline_hash_func(arKey, nKeyLength); nIndex = h & ht->nTableMask; @@ -278,6 +271,7 @@ return zend_hash_index_update(ht, h, pData, nDataSize, pDest); } + CHECK_INIT(ht); nIndex = h & ht->nTableMask; p = ht->arBuckets[nIndex]; @@ -350,6 +344,7 @@ Bucket *p; IS_CONSISTENT(ht); + CHECK_INIT(ht); if (flag & HASH_NEXT_INSERT) { h = ht->nNextFreeElement; @@ -440,6 +435,9 @@ uint nIndex; IS_CONSISTENT(ht); + if (UNEXPECTED(ht->nNumOfElements == 0)) { + return SUCCESS; + } memset(ht->arBuckets, 0, ht->nTableSize * sizeof(Bucket *)); p = ht->pListHead; @@ -530,7 +528,9 @@ } pefree(q, ht->persistent); } - pefree(ht->arBuckets, ht->persistent); + if (ht->nTableMask) { + pefree(ht->arBuckets, ht->persistent); + } SET_INCONSISTENT(HT_DESTROYED); } @@ -556,7 +556,9 @@ } pefree(q, ht->persistent); } - memset(ht->arBuckets, 0, ht->nTableSize*sizeof(Bucket *)); + if (ht->nTableMask) { + memset(ht->arBuckets, 0, ht->nTableSize*sizeof(Bucket *)); + } ht->pListHead = NULL; ht->pListTail = NULL; ht->nNumOfElements = 0; @@ -630,7 +632,9 @@ while (p != NULL) { p = zend_hash_apply_deleter(ht, p); } - pefree(ht->arBuckets, ht->persistent); + if (ht->nTableMask) { + pefree(ht->arBuckets, ht->persistent); + } SET_INCONSISTENT(HT_DESTROYED); } @@ -647,7 +651,9 @@ p = ht->pListTail; } - pefree(ht->arBuckets, ht->persistent); + if (ht->nTableMask) { + pefree(ht->arBuckets, ht->persistent); + } SET_INCONSISTENT(HT_DESTROYED); } @@ -1177,6 +1183,7 @@ p = pos ? (*pos) : ht->pInternalPointer; IS_CONSISTENT(ht); + CHECK_INIT(ht); if (p) { if (key_type == HASH_KEY_IS_LONG) { @@ -1533,6 +1540,10 @@ Bucket *p; uint i; + if (UNEXPECTED(ht->nNumOfElements == 0)) { + zend_output_debug_string(0, "The hash is empty"); + return; + } for (i = 0; i < ht->nTableSize; i++) { p = ht->arBuckets[i]; while (p != NULL) {
-- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php