예제 #1
0
static zend_always_inline zval *_zend_hash_add_or_update_i(HashTable *ht, zend_string *key, zval *pData, uint32_t flag ZEND_FILE_LINE_DC)
{
	zend_ulong h;
	uint32_t nIndex;
	uint32_t idx;
	Bucket *p;

	IS_CONSISTENT(ht);

	if (UNEXPECTED(ht->nTableMask == 0)) {
		CHECK_INIT(ht, 0);
		goto add_to_hash; 
	} else if (ht->u.flags & HASH_FLAG_PACKED) {
		zend_hash_packed_to_hash(ht);
	} else if ((flag & HASH_ADD_NEW) == 0) {
		p = zend_hash_find_bucket(ht, key);

		if (p) {
			zval *data;

			if (flag & HASH_ADD) {
				return NULL;
			}
			ZEND_ASSERT(&p->val != pData);
			data = &p->val;
			if ((flag & HASH_UPDATE_INDIRECT) && Z_TYPE_P(data) == IS_INDIRECT) {
				data = Z_INDIRECT_P(data);
			}
			HANDLE_BLOCK_INTERRUPTIONS();
			if (ht->pDestructor) {
				ht->pDestructor(data);
			}
			ZVAL_COPY_VALUE(data, pData);
			HANDLE_UNBLOCK_INTERRUPTIONS();
			return data;
		}
	}
	
	ZEND_HASH_IF_FULL_DO_RESIZE(ht);		/* If the Hash table is full, resize it */

add_to_hash:
	HANDLE_BLOCK_INTERRUPTIONS();
	idx = ht->nNumUsed++;
	ht->nNumOfElements++;
	if (ht->nInternalPointer == INVALID_IDX) {
		ht->nInternalPointer = idx;
	}
	p = ht->arData + idx; 
	p->h = h = zend_string_hash_val(key);
	p->key = key;
	zend_string_addref(key);
	ZVAL_COPY_VALUE(&p->val, pData);
	nIndex = h & ht->nTableMask;
	Z_NEXT(p->val) = ht->arHash[nIndex];
	ht->arHash[nIndex] = idx;
	HANDLE_UNBLOCK_INTERRUPTIONS();

	return &p->val;
}
예제 #2
0
ZEND_API int _zend_hash_index_update_or_next_insert(HashTable *ht, ulong h, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC)
{
	uint nIndex;
	Bucket *p;
#ifdef ZEND_SIGNALS
	TSRMLS_FETCH();
#endif

	IS_CONSISTENT(ht);
	CHECK_INIT(ht);

	if (flag & HASH_NEXT_INSERT) {
		h = ht->nNextFreeElement;
	}
	nIndex = h & ht->nTableMask;

	p = ht->arBuckets[nIndex];
	while (p != NULL) {
		if ((p->nKeyLength == 0) && (p->h == h)) {
			if (flag & HASH_NEXT_INSERT || flag & HASH_ADD) {
				return FAILURE;
			}
			ZEND_ASSERT(p->pData != pData);
			HANDLE_BLOCK_INTERRUPTIONS();
			if (ht->pDestructor) {
				ht->pDestructor(p->pData);
			}
			UPDATE_DATA(ht, p, pData, nDataSize);
			HANDLE_UNBLOCK_INTERRUPTIONS();
			if (pDest) {
				*pDest = p->pData;
			}
			return SUCCESS;
		}
		p = p->pNext;
	}
	p = (Bucket *) pemalloc_rel(sizeof(Bucket), ht->persistent);
	p->arKey = NULL;
	p->nKeyLength = 0; /* Numeric indices are marked by making the nKeyLength == 0 */
	p->h = h;
	INIT_DATA(ht, p, pData, nDataSize);
	if (pDest) {
		*pDest = p->pData;
	}

	CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[nIndex]);

	HANDLE_BLOCK_INTERRUPTIONS();
	ht->arBuckets[nIndex] = p;
	CONNECT_TO_GLOBAL_DLLIST(p, ht);
	HANDLE_UNBLOCK_INTERRUPTIONS();

	if ((long)h >= (long)ht->nNextFreeElement) {
		ht->nNextFreeElement = h < LONG_MAX ? h + 1 : LONG_MAX;
	}
	ht->nNumOfElements++;
	ZEND_HASH_IF_FULL_DO_RESIZE(ht);
	return SUCCESS;
}
예제 #3
0
/* HashTable容量满了的时候重新分配大小 */
static int zend_hash_do_resize(HashTable *ht)
{
	Bucket **t;
#ifdef ZEND_SIGNALS
	TSRMLS_FETCH();
#endif

	IS_CONSISTENT(ht);

	if ((ht->nTableSize << 1) > 0) { /* Let's double the table size */
		/* 重新分配大小 */
		t = (Bucket **)perealloc_recoverable(
		    ht->arBuckets, (ht->nTableSize << 1) * sizeof(Bucket *),
		    ht->persistent);
		if (t) {
			HANDLE_BLOCK_INTERRUPTIONS();
			ht->arBuckets = t;
			/* 设置nTableSize */
			ht->nTableSize = (ht->nTableSize << 1);
			/* nTableMask随着nTableSize改变,永远是nTableSize-1 */
			ht->nTableMask = ht->nTableSize - 1;
			/* 修改HashTable大小之后需要重新哈希 */
			zend_hash_rehash(ht);
			HANDLE_UNBLOCK_INTERRUPTIONS();
			return SUCCESS;
		}
		return FAILURE;
	}
	return SUCCESS;
}
예제 #4
0
static int zend_hash_do_resize(HashTable *ht)
{
	Bucket **t;

	IS_CONSISTENT(ht);

	if ((ht->nTableSize << 1) > 0) {	/* Let's double the table size */
		t = (Bucket **) perealloc_recoverable(ht->arBuckets, (ht->nTableSize << 1) * sizeof(Bucket *), ht->persistent);
		if (t) {
			HANDLE_BLOCK_INTERRUPTIONS();
			ht->arBuckets = t;
			ht->nTableSize = (ht->nTableSize << 1);
			ht->nTableMask = ht->nTableSize - 1;
			zend_hash_rehash(ht);
			HANDLE_UNBLOCK_INTERRUPTIONS();
#if DEBUG_RESIZE
			asm("int3");
			printf("#%d resized %d\n", ++resizes, ht->nTableSize);
#endif
			return SUCCESS;
		}
		return FAILURE;
	}
	return SUCCESS;
}
예제 #5
0
파일: zend_hash.c 프로젝트: rogerhu/dd-wrt
ZEND_API int zend_hash_del_key_or_index(HashTable *ht, const char *arKey, uint nKeyLength, ulong h, int flag)
{
    uint nIndex;
    Bucket *p;
#ifdef ZEND_SIGNALS
    TSRMLS_FETCH();
#endif

    IS_CONSISTENT(ht);

    if (flag == HASH_DEL_KEY) {
        h = zend_inline_hash_func(arKey, nKeyLength);
    }
    nIndex = h & ht->nTableMask;

    p = ht->arBuckets[nIndex];
    while (p != NULL) {
        if ((p->h == h)
                && (p->nKeyLength == nKeyLength)
                && ((p->nKeyLength == 0) /* Numeric index (short circuits the memcmp() check) */
                    || !memcmp(p->arKey, arKey, nKeyLength))) { /* String index */
            HANDLE_BLOCK_INTERRUPTIONS();
            if (p == ht->arBuckets[nIndex]) {
                ht->arBuckets[nIndex] = p->pNext;
            } else {
                p->pLast->pNext = p->pNext;
            }
            if (p->pNext) {
                p->pNext->pLast = p->pLast;
            }
            if (p->pListLast != NULL) {
                p->pListLast->pListNext = p->pListNext;
            } else {
                /* Deleting the head of the list */
                ht->pListHead = p->pListNext;
            }
            if (p->pListNext != NULL) {
                p->pListNext->pListLast = p->pListLast;
            } else {
                ht->pListTail = p->pListLast;
            }
            if (ht->pInternalPointer == p) {
                ht->pInternalPointer = p->pListNext;
            }
            ht->nNumOfElements--;
            if (ht->pDestructor) {
                ht->pDestructor(p->pData);
            }
            if (p->pData != &p->pDataPtr) {
                pefree(p->pData, ht->persistent);
            }
            pefree(p, ht->persistent);
            HANDLE_UNBLOCK_INTERRUPTIONS();
            return SUCCESS;
        }
        p = p->pNext;
    }
    return FAILURE;
}
예제 #6
0
ZEND_API void zend_hash_to_packed(HashTable *ht)
{
	HANDLE_BLOCK_INTERRUPTIONS();
	ht->u.flags |= HASH_FLAG_PACKED;
	ht->arData = erealloc(ht->arData, ht->nTableSize * sizeof(Bucket));
	ht->arHash = (zend_uint*)&uninitialized_bucket;
	HANDLE_UNBLOCK_INTERRUPTIONS();
}
예제 #7
0
static void zend_hash_packed_grow(HashTable *ht)
{
	HANDLE_BLOCK_INTERRUPTIONS();
	ht->arData = (Bucket *) safe_perealloc(ht->arData, (ht->nTableSize << 1), sizeof(Bucket), 0, ht->u.flags & HASH_FLAG_PERSISTENT);
	ht->nTableSize = (ht->nTableSize << 1);
	ht->nTableMask = ht->nTableSize - 1;
	HANDLE_UNBLOCK_INTERRUPTIONS();
}
예제 #8
0
ZEND_API void zend_hash_packed_to_hash(HashTable *ht)
{
	HANDLE_BLOCK_INTERRUPTIONS();
	ht->u.flags &= ~HASH_FLAG_PACKED;
	ht->arData = (Bucket *) safe_perealloc(ht->arData, ht->nTableSize, sizeof(Bucket) + sizeof(zend_uint), 0, ht->u.flags & HASH_FLAG_PERSISTENT);
	ht->arHash = (zend_uint*)(ht->arData + ht->nTableSize);
	zend_hash_rehash(ht);
	HANDLE_UNBLOCK_INTERRUPTIONS();
}
예제 #9
0
파일: zend_hash.c 프로젝트: rogerhu/dd-wrt
/* This function is used by the various apply() functions.
 * It deletes the passed bucket, and returns the address of the
 * next bucket.  The hash *may* be altered during that time, the
 * returned value will still be valid.
 */
static Bucket *zend_hash_apply_deleter(HashTable *ht, Bucket *p)
{
    Bucket *retval;
#ifdef ZEND_SIGNALS
    TSRMLS_FETCH();
#endif

    HANDLE_BLOCK_INTERRUPTIONS();
    if (p->pLast) {
        p->pLast->pNext = p->pNext;
    } else {
        uint nIndex;

        nIndex = p->h & ht->nTableMask;
        ht->arBuckets[nIndex] = p->pNext;
    }
    if (p->pNext) {
        p->pNext->pLast = p->pLast;
    } else {
        /* Nothing to do as this list doesn't have a tail */
    }

    if (p->pListLast != NULL) {
        p->pListLast->pListNext = p->pListNext;
    } else {
        /* Deleting the head of the list */
        ht->pListHead = p->pListNext;
    }
    if (p->pListNext != NULL) {
        p->pListNext->pListLast = p->pListLast;
    } else {
        ht->pListTail = p->pListLast;
    }
    if (ht->pInternalPointer == p) {
        ht->pInternalPointer = p->pListNext;
    }
    ht->nNumOfElements--;
    HANDLE_UNBLOCK_INTERRUPTIONS();

    if (ht->pDestructor) {
        ht->pDestructor(p->pData);
    }
    if (p->pData != &p->pDataPtr) {
        pefree(p->pData, ht->persistent);
    }
    retval = p->pListNext;
    pefree(p, ht->persistent);

    return retval;
}
예제 #10
0
static void zend_hash_do_resize(HashTable *ht)
{
	Bucket **t;
#ifdef ZEND_SIGNALS
	TSRMLS_FETCH();
#endif

	IS_CONSISTENT(ht);

	if ((ht->nTableSize << 1) > 0) {	/* Let's double the table size */
		t = (Bucket **) perealloc(ht->arBuckets, (ht->nTableSize << 1) * sizeof(Bucket *), ht->persistent);
		HANDLE_BLOCK_INTERRUPTIONS();
		ht->arBuckets = t;
		ht->nTableSize = (ht->nTableSize << 1);
		ht->nTableMask = ht->nTableSize - 1;
		zend_hash_rehash(ht);
		HANDLE_UNBLOCK_INTERRUPTIONS();
	}
}
예제 #11
0
static zend_always_inline void i_zend_hash_bucket_delete(HashTable *ht, Bucket *p)
{
#ifdef ZEND_SIGNALS
	TSRMLS_FETCH();
#endif

	HANDLE_BLOCK_INTERRUPTIONS();
	if (p->pLast) {
		p->pLast->pNext = p->pNext;
	} else {
		ht->arBuckets[p->h & ht->nTableMask] = p->pNext;
	}
	if (p->pNext) {
		p->pNext->pLast = p->pLast;
	}
	if (p->pListLast != NULL) {
		p->pListLast->pListNext = p->pListNext;
	} else { 
		/* Deleting the head of the list */
		ht->pListHead = p->pListNext;
	}
	if (p->pListNext != NULL) {
		p->pListNext->pListLast = p->pListLast;
	} else {
		/* Deleting the tail of the list */
		ht->pListTail = p->pListLast;
	}
	if (ht->pInternalPointer == p) {
		ht->pInternalPointer = p->pListNext;
	}
	ht->nNumOfElements--;
	if (ht->pDestructor) {
		ht->pDestructor(p->pData);
	}
	if (p->pData != &p->pDataPtr) {
		pefree(p->pData, ht->persistent);
	}
	pefree(p, ht->persistent);
	HANDLE_UNBLOCK_INTERRUPTIONS();
}
예제 #12
0
ZEND_API int _zend_hash_add_or_update(HashTable *ht, const char *arKey, uint nKeyLength, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC)
{
	ulong h;
	uint nIndex;
	Bucket *p;

	IS_CONSISTENT(ht);

	if (nKeyLength <= 0) {
#if ZEND_DEBUG
		ZEND_PUTS("zend_hash_update: Can't put in empty key\n");
#endif
		return FAILURE;
	}

	h = zend_inline_hash_func(arKey, nKeyLength);
	nIndex = h & ht->nTableMask;

	p = ht->arBuckets[nIndex];
	while (p != NULL) {
		if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
			if (!memcmp(p->arKey, arKey, nKeyLength)) {
				if (flag & HASH_ADD) {
					return FAILURE;
				}
				HANDLE_BLOCK_INTERRUPTIONS();
#if ZEND_DEBUG
				if (p->pData == pData) {
					ZEND_PUTS("Fatal error in zend_hash_update: p->pData == pData\n");
					HANDLE_UNBLOCK_INTERRUPTIONS();
					return FAILURE;
				}
#endif
				if (ht->pDestructor) {
					ht->pDestructor(p->pData);
				}
				UPDATE_DATA(ht, p, pData, nDataSize);
				if (pDest) {
					*pDest = p->pData;
				}
				HANDLE_UNBLOCK_INTERRUPTIONS();
				return SUCCESS;
			}
		}
		p = p->pNext;
	}
	
	p = (Bucket *) pemalloc(sizeof(Bucket) - 1 + nKeyLength, ht->persistent);
	if (!p) {
		return FAILURE;
	}
	memcpy(p->arKey, arKey, nKeyLength);
	p->nKeyLength = nKeyLength;
	INIT_DATA(ht, p, pData, nDataSize);
	p->h = h;
	CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[nIndex]);
	if (pDest) {
		*pDest = p->pData;
	}

	HANDLE_BLOCK_INTERRUPTIONS();
	CONNECT_TO_GLOBAL_DLLIST(p, ht);
	ht->arBuckets[nIndex] = p;
	HANDLE_UNBLOCK_INTERRUPTIONS();

	ht->nNumOfElements++;
	ZEND_HASH_IF_FULL_DO_RESIZE(ht);		/* If the Hash table is full, resize it */
	return SUCCESS;
}
예제 #13
0
파일: zend_hash.c 프로젝트: rogerhu/dd-wrt
ZEND_API int _zend_hash_quick_add_or_update(HashTable *ht, const char *arKey, uint nKeyLength, ulong h, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC)
{
    uint nIndex;
    Bucket *p;
#ifdef ZEND_SIGNALS
    TSRMLS_FETCH();
#endif

    IS_CONSISTENT(ht);

    if (nKeyLength == 0) {
        return zend_hash_index_update(ht, h, pData, nDataSize, pDest);
    }

    CHECK_INIT(ht);
    nIndex = h & ht->nTableMask;

    p = ht->arBuckets[nIndex];
    while (p != NULL) {
        if (p->arKey == arKey ||
                ((p->h == h) && (p->nKeyLength == nKeyLength) && !memcmp(p->arKey, arKey, nKeyLength))) {
            if (flag & HASH_ADD) {
                return FAILURE;
            }
            HANDLE_BLOCK_INTERRUPTIONS();
#if ZEND_DEBUG
            if (p->pData == pData) {
                ZEND_PUTS("Fatal error in zend_hash_update: p->pData == pData\n");
                HANDLE_UNBLOCK_INTERRUPTIONS();
                return FAILURE;
            }
#endif
            if (ht->pDestructor) {
                ht->pDestructor(p->pData);
            }
            UPDATE_DATA(ht, p, pData, nDataSize);
            if (pDest) {
                *pDest = p->pData;
            }
            HANDLE_UNBLOCK_INTERRUPTIONS();
            return SUCCESS;
        }
        p = p->pNext;
    }

    if (IS_INTERNED(arKey)) {
        p = (Bucket *) pemalloc(sizeof(Bucket), ht->persistent);
        if (!p) {
            return FAILURE;
        }
        p->arKey = arKey;
    } else {
        p = (Bucket *) pemalloc(sizeof(Bucket) + nKeyLength, ht->persistent);
        if (!p) {
            return FAILURE;
        }
        p->arKey = (const char*)(p + 1);
        memcpy((char*)p->arKey, arKey, nKeyLength);
    }

    p->nKeyLength = nKeyLength;
    INIT_DATA(ht, p, pData, nDataSize);
    p->h = h;

    CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[nIndex]);

    if (pDest) {
        *pDest = p->pData;
    }

    HANDLE_BLOCK_INTERRUPTIONS();
    ht->arBuckets[nIndex] = p;
    CONNECT_TO_GLOBAL_DLLIST(p, ht);
    HANDLE_UNBLOCK_INTERRUPTIONS();

    ht->nNumOfElements++;
    ZEND_HASH_IF_FULL_DO_RESIZE(ht);		/* If the Hash table is full, resize it */
    return SUCCESS;
}
예제 #14
0
/* 插入新值到哈希表中 */
ZEND_API int _zend_hash_add_or_update(HashTable *ht, const char *arKey,
				      uint nKeyLength, void *pData,
				      uint nDataSize, void **pDest,
				      int flag ZEND_FILE_LINE_DC)
{
	ulong h;
	uint nIndex;
	Bucket *p;
#ifdef ZEND_SIGNALS
	TSRMLS_FETCH();
#endif

	IS_CONSISTENT(ht);

	/* 键值不能为空字符串 */
	if (nKeyLength <= 0) {
#if ZEND_DEBUG
		ZEND_PUTS("zend_hash_update: Can't put in empty key\n");
#endif
		return FAILURE;
	}

	/* 检查哈希表是否以及初始化,如果没有初始化则进行初始化 */
	CHECK_INIT(ht);

	/* 计算key代表的哈希值以及获取其在arBuckets数组中的下标 */
	h = zend_inline_hash_func(arKey, nKeyLength);
	nIndex = h & ht->nTableMask;

	p = ht->arBuckets[nIndex];
	while (p != NULL) {
		if (p->arKey == arKey ||
		    ((p->h == h) && (p->nKeyLength == nKeyLength) &&
		     !memcmp(p->arKey, arKey, nKeyLength))) { /* 需要更新 */
			if (flag &
			    HASH_ADD) { /* 如果是插入的话就返回,不能插入具有相同键值的元素
					   */
				return FAILURE;
			}
			HANDLE_BLOCK_INTERRUPTIONS();
#if ZEND_DEBUG
			if (p->pData == pData) {
				ZEND_PUTS("Fatal error in zend_hash_update: "
					  "p->pData == pData\n");
				HANDLE_UNBLOCK_INTERRUPTIONS();
				return FAILURE;
			}
#endif
			if (ht->pDestructor) { /* 如果有析构函数,则将指向数据的指针释放掉
						  */
				ht->pDestructor(p->pData);
			}

			/* 更新数据 */
			UPDATE_DATA(ht, p, pData, nDataSize);
			if (pDest) {
				*pDest = p->pData;
			}
			HANDLE_UNBLOCK_INTERRUPTIONS();
			return SUCCESS;
		}
		/* 移动到具有相同hash值的bucket链表中的下一个bucket */
		p = p->pNext;
	}

	if (IS_INTERNED(arKey)) {
		p = (Bucket *)pemalloc(sizeof(Bucket), ht->persistent);
		if (!p) {
			return FAILURE;
		}
		p->arKey = arKey;
	} else {
		p = (Bucket *)pemalloc(sizeof(Bucket) + nKeyLength,
				       ht->persistent);
		if (!p) {
			return FAILURE;
		}
		p->arKey = (const char *)(p + 1);
		memcpy((char *)p->arKey, arKey, nKeyLength);
	}

	/* 设置新的bucket的属性值及添加到哈希表中 */
	p->nKeyLength = nKeyLength;
	INIT_DATA(ht, p, pData, nDataSize);
	p->h = h;
	CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[nIndex]);
	if (pDest) {
		*pDest = p->pData;
	}

	HANDLE_BLOCK_INTERRUPTIONS();
	CONNECT_TO_GLOBAL_DLLIST(p, ht);
	ht->arBuckets[nIndex] = p;
	HANDLE_UNBLOCK_INTERRUPTIONS();

	ht->nNumOfElements++;
	ZEND_HASH_IF_FULL_DO_RESIZE(
	    ht); /* If the Hash table is full, resize it */
	return SUCCESS;
}
예제 #15
0
// flag参数: HASH_UPDATE HASH_NEXT_INSERT
ZEND_API int _zend_hash_index_update_or_next_insert(HashTable *ht, ulong h, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC)
{
	uint nIndex;
	Bucket *p;

	IS_CONSISTENT(ht);

	if (flag & HASH_NEXT_INSERT) {
		h = ht->nNextFreeElement;
	}
	nIndex = h & ht->nTableMask;

	p = ht->arBuckets[nIndex];
	while (p != NULL) {
		if ((p->nKeyLength == 0) && (p->h == h)) {
			// 没看到有针对HAHS_ADD的宏
			// 这个case什么时候会触发?
			if (flag & HASH_NEXT_INSERT || flag & HASH_ADD) {
				return FAILURE;
			}
			HANDLE_BLOCK_INTERRUPTIONS();
#if ZEND_DEBUG
			if (p->pData == pData) {
				ZEND_PUTS("Fatal error in zend_hash_index_update: p->pData == pData\n");
				HANDLE_UNBLOCK_INTERRUPTIONS();
				return FAILURE;
			}
#endif
			if (ht->pDestructor) {
				ht->pDestructor(p->pData);
			}
			UPDATE_DATA(ht, p, pData, nDataSize);
			HANDLE_UNBLOCK_INTERRUPTIONS();
			if ((long)h >= (long)ht->nNextFreeElement) {
				ht->nNextFreeElement = h < LONG_MAX ? h + 1 : LONG_MAX;
			}
			if (pDest) {
				*pDest = p->pData;
			}
			return SUCCESS;
		}
		p = p->pNext;
	}
	p = (Bucket *) pemalloc_rel(sizeof(Bucket) - 1, ht->persistent);
	if (!p) {
		return FAILURE;
	}
	p->nKeyLength = 0; /* Numeric indices are marked by making the nKeyLength == 0 */
	p->h = h;
	INIT_DATA(ht, p, pData, nDataSize);
	if (pDest) {
		*pDest = p->pData;
	}

	CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[nIndex]);

	HANDLE_BLOCK_INTERRUPTIONS();
	ht->arBuckets[nIndex] = p;
	CONNECT_TO_GLOBAL_DLLIST(p, ht);
	HANDLE_UNBLOCK_INTERRUPTIONS();

	// 上线就是LONG_MAX
	// max(h+1, nNextFreeElement)
	if ((long)h >= (long)ht->nNextFreeElement) {
		ht->nNextFreeElement = h < LONG_MAX ? h + 1 : LONG_MAX;
	}
	ht->nNumOfElements++;
	ZEND_HASH_IF_FULL_DO_RESIZE(ht);
	return SUCCESS;
}
예제 #16
0
static const char *zend_new_interned_string_int(const char *arKey, int nKeyLength, int free_src TSRMLS_DC)
{
#ifndef ZTS
	ulong h;
	uint nIndex;
	Bucket *p;

	if (IS_INTERNED(arKey)) {
		return arKey;
	}

	h = zend_inline_hash_func(arKey, nKeyLength);
	nIndex = h & CG(interned_strings).nTableMask;
	p = CG(interned_strings).arBuckets[nIndex];
	while (p != NULL) {
		if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
			if (!memcmp(p->arKey, arKey, nKeyLength)) {
				if (free_src) {
					efree((void *)arKey);
				}
				return p->arKey;
			}
		}
		p = p->pNext;
	}
	
	if (CG(interned_strings_top) + ZEND_MM_ALIGNED_SIZE(sizeof(Bucket) + nKeyLength) >=
	    CG(interned_strings_end)) {
	    /* no memory */
		return arKey;
	}

	p = (Bucket *) CG(interned_strings_top);
	CG(interned_strings_top) += ZEND_MM_ALIGNED_SIZE(sizeof(Bucket) + nKeyLength);

#if ZEND_DEBUG_INTERNED_STRINGS
	mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_READ | PROT_WRITE);
#endif
	
	p->arKey = (char*)(p+1);
	memcpy((char*)p->arKey, arKey, nKeyLength);
	if (free_src) {
		efree((void *)arKey);
	}
	p->nKeyLength = nKeyLength;
	p->h = h;
	p->pData = &p->pDataPtr;
	p->pDataPtr = p;
	
	p->pNext = CG(interned_strings).arBuckets[nIndex];
	p->pLast = NULL;
	if (p->pNext) {
		p->pNext->pLast = p;
	}

	HANDLE_BLOCK_INTERRUPTIONS();
	
	p->pListLast = CG(interned_strings).pListTail;
	CG(interned_strings).pListTail = p;
	p->pListNext = NULL;
	if (p->pListLast != NULL) {
		p->pListLast->pListNext = p;
	}
	if (!CG(interned_strings).pListHead) {
		CG(interned_strings).pListHead = p;
	}

	CG(interned_strings).arBuckets[nIndex] = p;

	HANDLE_UNBLOCK_INTERRUPTIONS();

	CG(interned_strings).nNumOfElements++;

	if (CG(interned_strings).nNumOfElements > CG(interned_strings).nTableSize) {
		if ((CG(interned_strings).nTableSize << 1) > 0) {	/* Let's double the table size */
			Bucket **t = (Bucket **) perealloc_recoverable(CG(interned_strings).arBuckets, (CG(interned_strings).nTableSize << 1) * sizeof(Bucket *), CG(interned_strings).persistent);

			if (t) {
				HANDLE_BLOCK_INTERRUPTIONS();
				CG(interned_strings).arBuckets = t;
				CG(interned_strings).nTableSize = (CG(interned_strings).nTableSize << 1);
				CG(interned_strings).nTableMask = CG(interned_strings).nTableSize - 1;
				zend_hash_rehash(&CG(interned_strings));
				HANDLE_UNBLOCK_INTERRUPTIONS();
			}
		}
	}

#if ZEND_DEBUG_INTERNED_STRINGS
	mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_READ);
#endif

	return p->arKey;
#else
	return arKey;
#endif
}
예제 #17
0
/* 数字键值的插入修改 */
ZEND_API int _zend_hash_index_update_or_next_insert(HashTable *ht, ulong h,
						    void *pData, uint nDataSize,
						    void **pDest,
						    int flag ZEND_FILE_LINE_DC)
{
	uint nIndex;
	Bucket *p;
#ifdef ZEND_SIGNALS
	TSRMLS_FETCH();
#endif

	IS_CONSISTENT(ht); // 调试信息
	CHECK_INIT(ht);

	// 如果是新增元素,则h等于下一个数字索引的位置
	if (flag & HASH_NEXT_INSERT) {
		h = ht->nNextFreeElement;
	}
	// 计算键值在HashTable中的存储位置为nIndex
	nIndex = h & ht->nTableMask;

	p = ht->arBuckets[nIndex]; /* 取得索引对应的Bucket的指针 */
	// 循环Bucket中含有nIndex键值的链表
	while (p != NULL) {
		// p 不为NULL说明Bucket中存在键值为nIndex的元素
		if ((p->nKeyLength == 0) &&
		    (p->h == h)) { // 如果是数字键值且键值相同
			if (flag & HASH_NEXT_INSERT ||
			    flag & HASH_ADD) { // 如果是新增元素,则插入失败
				return FAILURE;
			}
			HANDLE_BLOCK_INTERRUPTIONS();
#if ZEND_DEBUG
			if (p->pData == pData) {
				ZEND_PUTS("Fatal error in "
					  "zend_hash_index_update: p->pData == "
					  "pData\n");
				HANDLE_UNBLOCK_INTERRUPTIONS();
				return FAILURE;
			}
#endif
			// 上面的代码return ,说明是更新Bucket中已有键值元素值
			if (ht->pDestructor) { // 如果数据元素存在,则将原来的数据销毁
				ht->pDestructor(p->pData);
			}
			UPDATE_DATA(ht, p, pData, nDataSize); // 更新数据值
			HANDLE_UNBLOCK_INTERRUPTIONS();
			if ((long)h >= (long)ht->nNextFreeElement) {
				ht->nNextFreeElement =
				    h < LONG_MAX ? h + 1 : LONG_MAX;
			}
			// 如果需要返回更新值,则将返回值赋值给pDest
			if (pDest) {
				*pDest = p->pData;
			}
			return SUCCESS;
		}
		// 移动到链表的下一个元素
		p = p->pNext;
	}
	// 如果是新增,为新增元素分配一个Bucket空间
	p = (Bucket *)pemalloc_rel(sizeof(Bucket), ht->persistent);
	if (!p) {
		return FAILURE;
	}
	// 赋值
	p->arKey = NULL;
	p->nKeyLength =
	    0; /* Numeric indices are marked by making the nKeyLength == 0 */
	p->h = h;
	INIT_DATA(ht, p, pData, nDataSize);
	// 如果需要返回更新值,则将返回值赋值给pDest
	if (pDest) {
		*pDest = p->pData;
	}

	CONNECT_TO_BUCKET_DLLIST(
	    p, ht->arBuckets[nIndex]); // 将Bucket加入到对应的桶双向链表中

	HANDLE_BLOCK_INTERRUPTIONS();
	ht->arBuckets[nIndex] = p;
	CONNECT_TO_GLOBAL_DLLIST(
	    p, ht); // 将新的Bucket元素添加到哈希表的双向链表中
	HANDLE_UNBLOCK_INTERRUPTIONS();

	if ((long)h >= (long)ht->nNextFreeElement) {
		ht->nNextFreeElement = h < LONG_MAX ? h + 1 : LONG_MAX;
	}
	ht->nNumOfElements++;
	ZEND_HASH_IF_FULL_DO_RESIZE(
	    ht); /* 如果此时数组的容量满了,则重新分配空间。*/
	return SUCCESS;
}