@@ -41,6 +41,8 @@ void pmmpthread_store_init(pmmpthread_store_t* store) {
4141 zend_hash_init (
4242 & store -> hash , 8 , NULL ,
4343 (dtor_func_t )pmmpthread_store_storage_dtor , 1 );
44+ store -> first = HT_INVALID_IDX ;
45+ store -> last = HT_INVALID_IDX ;
4446} /* }}} */
4547
4648/* {{{ */
@@ -286,6 +288,10 @@ int pmmpthread_store_delete(zend_object *object, zval *key) {
286288 if (result == SUCCESS && was_pmmpthread_object ) {
287289 _pmmpthread_store_bump_modcount_nolock (threaded );
288290 }
291+ //TODO: it would be better if we can update this, if we deleted the first element
292+ ts_obj -> props .first = HT_INVALID_IDX ;
293+ ts_obj -> props .last = HT_INVALID_IDX ;
294+
289295 //TODO: sync local properties?
290296 pmmpthread_monitor_unlock (& ts_obj -> monitor );
291297 } else result = FAILURE ;
@@ -414,6 +420,8 @@ static inline zend_bool pmmpthread_store_update_shared_property(pmmpthread_objec
414420 }
415421 }
416422 }
423+ ts_obj -> props .first = HT_INVALID_IDX ;
424+ ts_obj -> props .last = HT_INVALID_IDX ;
417425
418426 return result ;
419427}
@@ -538,6 +546,12 @@ int pmmpthread_store_write(zend_object *object, zval *key, zval *write, zend_boo
538546 if (result == SUCCESS && was_pmmpthread_object ) {
539547 _pmmpthread_store_bump_modcount_nolock (threaded );
540548 }
549+ if (key ) {
550+ //only invalidate position if an arbitrary key was used
551+ //if the item was appended, the first element was either unchanged or the position was invalid anyway
552+ ts_obj -> props .first = HT_INVALID_IDX ;
553+ ts_obj -> props .last = HT_INVALID_IDX ;
554+ }
541555 //this isn't necessary for any specific property write, but since we don't have any other way to clean up local
542556 //cached ThreadSafe references that are dead, we have to take the opportunity
543557 pmmpthread_store_sync_local_properties (object );
@@ -576,12 +590,20 @@ int pmmpthread_store_shift(zend_object *object, zval *member) {
576590
577591 if (pmmpthread_monitor_lock (& ts_obj -> monitor )) {
578592 zval key ;
579- HashPosition position ;
580593 zval * zstorage ;
581594
582- zend_hash_internal_pointer_reset_ex (& ts_obj -> props .hash , & position );
583- if ((zstorage = zend_hash_get_current_data_ex (& ts_obj -> props .hash , & position ))) {
584- zend_hash_get_current_key_zval_ex (& ts_obj -> props .hash , & key , & position );
595+ if (ts_obj -> props .first == HT_INVALID_IDX ) {
596+ zend_hash_internal_pointer_reset_ex (& ts_obj -> props .hash , & ts_obj -> props .first );
597+ }
598+ if ((zstorage = zend_hash_get_current_data_ex (& ts_obj -> props .hash , & ts_obj -> props .first ))) {
599+ zend_hash_get_current_key_zval_ex (& ts_obj -> props .hash , & key , & ts_obj -> props .first );
600+
601+ //the new first element will now be the next item, if there is one
602+ if (zend_hash_move_forward_ex (& ts_obj -> props .hash , & ts_obj -> props .first ) == FAILURE ) {
603+ ts_obj -> props .first = HT_INVALID_IDX ;
604+ ts_obj -> props .last = HT_INVALID_IDX ;
605+ }
606+
585607 zend_bool may_be_locally_cached ;
586608
587609 pmmpthread_store_restore_zval_ex (member , zstorage , & may_be_locally_cached );
@@ -617,17 +639,22 @@ int pmmpthread_store_chunk(zend_object *object, zend_long size, zend_bool preser
617639 pmmpthread_object_t * ts_obj = threaded -> ts_obj ;
618640
619641 if (pmmpthread_monitor_lock (& ts_obj -> monitor )) {
620- HashPosition position ;
621642 zval * zstorage ;
622643
623644 array_init (chunk );
624- zend_hash_internal_pointer_reset_ex (& ts_obj -> props .hash , & position );
645+ if (ts_obj -> props .first == HT_INVALID_IDX ) {
646+ zend_hash_internal_pointer_reset_ex (& ts_obj -> props .hash , & ts_obj -> props .first );
647+ }
625648 zend_bool stale_local_cache = 0 ;
626649 while ((zend_hash_num_elements (Z_ARRVAL_P (chunk )) < size ) &&
627- (zstorage = zend_hash_get_current_data_ex (& ts_obj -> props .hash , & position ))) {
650+ (zstorage = zend_hash_get_current_data_ex (& ts_obj -> props .hash , & ts_obj -> props . first ))) {
628651 zval key , zv ;
629652
630- zend_hash_get_current_key_zval_ex (& ts_obj -> props .hash , & key , & position );
653+ zend_hash_get_current_key_zval_ex (& ts_obj -> props .hash , & key , & ts_obj -> props .first );
654+ if (zend_hash_move_forward_ex (& ts_obj -> props .hash , & ts_obj -> props .first ) == FAILURE ) {
655+ ts_obj -> props .first = HT_INVALID_IDX ;
656+ ts_obj -> props .last = HT_INVALID_IDX ;
657+ }
631658
632659 zend_bool may_be_locally_cached ;
633660 pmmpthread_store_restore_zval_ex (& zv , zstorage , & may_be_locally_cached );
@@ -651,8 +678,6 @@ int pmmpthread_store_chunk(zend_object *object, zend_long size, zend_bool preser
651678 }
652679 zend_string_release (Z_STR (key ));
653680 }
654-
655- zend_hash_internal_pointer_reset_ex (& ts_obj -> props .hash , & position );
656681 }
657682 if (stale_local_cache ) {
658683 _pmmpthread_store_bump_modcount_nolock (threaded );
@@ -673,12 +698,18 @@ int pmmpthread_store_pop(zend_object *object, zval *member) {
673698
674699 if (pmmpthread_monitor_lock (& ts_obj -> monitor )) {
675700 zval key ;
676- HashPosition position ;
677701 zval * zstorage ;
678702
679- zend_hash_internal_pointer_end_ex (& ts_obj -> props .hash , & position );
680- if ((zstorage = zend_hash_get_current_data_ex (& ts_obj -> props .hash , & position ))) {
681- zend_hash_get_current_key_zval_ex (& ts_obj -> props .hash , & key , & position );
703+ if (ts_obj -> props .last == HT_INVALID_IDX ) {
704+ zend_hash_internal_pointer_end_ex (& ts_obj -> props .hash , & ts_obj -> props .last );
705+ }
706+ if ((zstorage = zend_hash_get_current_data_ex (& ts_obj -> props .hash , & ts_obj -> props .last ))) {
707+ zend_hash_get_current_key_zval_ex (& ts_obj -> props .hash , & key , & ts_obj -> props .last );
708+
709+ if (zend_hash_move_backwards_ex (& ts_obj -> props .hash , & ts_obj -> props .last ) == FAILURE ) {
710+ ts_obj -> props .first = HT_INVALID_IDX ;
711+ ts_obj -> props .last = HT_INVALID_IDX ;
712+ }
682713
683714 zend_bool may_be_locally_cached ;
684715 pmmpthread_store_restore_zval_ex (member , zstorage , & may_be_locally_cached );
@@ -1313,9 +1344,15 @@ void pmmpthread_store_reset(zend_object *object, HashPosition *position) {
13131344 pmmpthread_object_t * ts_obj = PMMPTHREAD_FETCH_TS_FROM (object );
13141345
13151346 if (pmmpthread_monitor_lock (& ts_obj -> monitor )) {
1316- zend_hash_internal_pointer_reset_ex (& ts_obj -> props .hash , position );
1317- if (zend_hash_has_more_elements_ex (& ts_obj -> props .hash , position ) == FAILURE ) { //empty
1318- * position = HT_INVALID_IDX ;
1347+ if (ts_obj -> props .first == HT_INVALID_IDX ) {
1348+ zend_hash_internal_pointer_reset_ex (& ts_obj -> props .hash , position );
1349+ if (zend_hash_has_more_elements_ex (& ts_obj -> props .hash , position ) == FAILURE ) { //empty
1350+ * position = HT_INVALID_IDX ;
1351+ } else {
1352+ ts_obj -> props .first = * position ;
1353+ }
1354+ } else {
1355+ * position = ts_obj -> props .first ;
13191356 }
13201357 pmmpthread_monitor_unlock (& ts_obj -> monitor );
13211358 }
0 commit comments