@@ -35,12 +35,19 @@ static void pmmpthread_store_restore_zval_ex(zval* unstore, zval* zstorage, zend
35
35
static void pmmpthread_store_restore_zval (zval * unstore , zval * zstorage ); /* }}} */
36
36
static void pmmpthread_store_storage_dtor (zval * element );
37
37
38
+ /* {{{ */
39
+ static inline void pmmpthread_store_invalidate_bounds (pmmpthread_store_t * store ) {
40
+ store -> first = HT_INVALID_IDX ;
41
+ store -> last = HT_INVALID_IDX ;
42
+ } /* }}} */
43
+
38
44
/* {{{ */
39
45
void pmmpthread_store_init (pmmpthread_store_t * store ) {
40
46
store -> modcount = 0 ;
41
47
zend_hash_init (
42
48
& store -> hash , 8 , NULL ,
43
49
(dtor_func_t )pmmpthread_store_storage_dtor , 1 );
50
+ pmmpthread_store_invalidate_bounds (store );
44
51
} /* }}} */
45
52
46
53
/* {{{ */
@@ -286,6 +293,9 @@ int pmmpthread_store_delete(zend_object *object, zval *key) {
286
293
if (result == SUCCESS && was_pmmpthread_object ) {
287
294
_pmmpthread_store_bump_modcount_nolock (threaded );
288
295
}
296
+ //TODO: it would be better if we can update this, if we deleted the first element
297
+ pmmpthread_store_invalidate_bounds (& ts_obj -> props );
298
+
289
299
//TODO: sync local properties?
290
300
pmmpthread_monitor_unlock (& ts_obj -> monitor );
291
301
} else result = FAILURE ;
@@ -538,6 +548,24 @@ int pmmpthread_store_write(zend_object *object, zval *key, zval *write, zend_boo
538
548
if (result == SUCCESS && was_pmmpthread_object ) {
539
549
_pmmpthread_store_bump_modcount_nolock (threaded );
540
550
}
551
+ if (ts_obj -> props .first != HT_INVALID_IDX && ts_obj -> props .first != 0 ) {
552
+ HashPosition start = 0 ;
553
+ if (zend_hash_get_current_data_ex (& ts_obj -> props .hash , & start ) != NULL ) {
554
+ //a table rehash may have occurred, moving all elements to the start of the table
555
+ //this is usually because the table size was increased to accommodate the new element
556
+ pmmpthread_store_invalidate_bounds (& ts_obj -> props );
557
+ }
558
+ }
559
+ if (key ) {
560
+ //only invalidate position if an arbitrary key was used
561
+ //if the item was appended, the first element was either unchanged or the position was invalid anyway
562
+ pmmpthread_store_invalidate_bounds (& ts_obj -> props );
563
+ } else if (ts_obj -> props .last != HT_INVALID_IDX ) {
564
+ //if we appended, the last element is now the new item
565
+ if (zend_hash_move_forward_ex (& ts_obj -> props .hash , & ts_obj -> props .last ) == FAILURE ) {
566
+ ZEND_ASSERT (0 );
567
+ }
568
+ }
541
569
//this isn't necessary for any specific property write, but since we don't have any other way to clean up local
542
570
//cached ThreadSafe references that are dead, we have to take the opportunity
543
571
pmmpthread_store_sync_local_properties (object );
@@ -576,12 +604,22 @@ int pmmpthread_store_shift(zend_object *object, zval *member) {
576
604
577
605
if (pmmpthread_monitor_lock (& ts_obj -> monitor )) {
578
606
zval key ;
579
- HashPosition position ;
580
607
zval * zstorage ;
608
+ HashPosition position = ts_obj -> props .first ;
581
609
582
- zend_hash_internal_pointer_reset_ex (& ts_obj -> props .hash , & position );
610
+ if (position == HT_INVALID_IDX ) {
611
+ zend_hash_internal_pointer_reset_ex (& ts_obj -> props .hash , & position );
612
+ }
583
613
if ((zstorage = zend_hash_get_current_data_ex (& ts_obj -> props .hash , & position ))) {
584
614
zend_hash_get_current_key_zval_ex (& ts_obj -> props .hash , & key , & position );
615
+
616
+ if (zend_hash_num_elements (& ts_obj -> props .hash ) == 1 ) { //we're about to delete the last element
617
+ pmmpthread_store_invalidate_bounds (& ts_obj -> props );
618
+ } else {
619
+ zend_hash_move_forward_ex (& ts_obj -> props .hash , & position );
620
+ ts_obj -> props .first = position ;
621
+ }
622
+
585
623
zend_bool may_be_locally_cached ;
586
624
587
625
pmmpthread_store_restore_zval_ex (member , zstorage , & may_be_locally_cached );
@@ -617,18 +655,28 @@ int pmmpthread_store_chunk(zend_object *object, zend_long size, zend_bool preser
617
655
pmmpthread_object_t * ts_obj = threaded -> ts_obj ;
618
656
619
657
if (pmmpthread_monitor_lock (& ts_obj -> monitor )) {
620
- HashPosition position ;
621
658
zval * zstorage ;
622
659
660
+ HashPosition position = ts_obj -> props .first ;
661
+ if (position == HT_INVALID_IDX ) {
662
+ zend_hash_internal_pointer_reset_ex (& ts_obj -> props .hash , & position );
663
+ }
623
664
array_init (chunk );
624
- zend_hash_internal_pointer_reset_ex (& ts_obj -> props .hash , & position );
625
665
zend_bool stale_local_cache = 0 ;
626
666
while ((zend_hash_num_elements (Z_ARRVAL_P (chunk )) < size ) &&
627
667
(zstorage = zend_hash_get_current_data_ex (& ts_obj -> props .hash , & position ))) {
668
+
628
669
zval key , zv ;
629
670
630
671
zend_hash_get_current_key_zval_ex (& ts_obj -> props .hash , & key , & position );
631
672
673
+ if (zend_hash_num_elements (& ts_obj -> props .hash ) == 1 ) { //we're about to delete the last element
674
+ pmmpthread_store_invalidate_bounds (& ts_obj -> props );
675
+ } else {
676
+ zend_hash_move_forward_ex (& ts_obj -> props .hash , & position );
677
+ ts_obj -> props .first = position ;
678
+ }
679
+
632
680
zend_bool may_be_locally_cached ;
633
681
pmmpthread_store_restore_zval_ex (& zv , zstorage , & may_be_locally_cached );
634
682
if (!stale_local_cache ) {
@@ -651,8 +699,6 @@ int pmmpthread_store_chunk(zend_object *object, zend_long size, zend_bool preser
651
699
}
652
700
zend_string_release (Z_STR (key ));
653
701
}
654
-
655
- zend_hash_internal_pointer_reset_ex (& ts_obj -> props .hash , & position );
656
702
}
657
703
if (stale_local_cache ) {
658
704
_pmmpthread_store_bump_modcount_nolock (threaded );
@@ -673,13 +719,22 @@ int pmmpthread_store_pop(zend_object *object, zval *member) {
673
719
674
720
if (pmmpthread_monitor_lock (& ts_obj -> monitor )) {
675
721
zval key ;
676
- HashPosition position ;
677
722
zval * zstorage ;
723
+ HashPosition position = ts_obj -> props .last ;
678
724
679
- zend_hash_internal_pointer_end_ex (& ts_obj -> props .hash , & position );
725
+ if (position == HT_INVALID_IDX ) {
726
+ zend_hash_internal_pointer_end_ex (& ts_obj -> props .hash , & position );
727
+ }
680
728
if ((zstorage = zend_hash_get_current_data_ex (& ts_obj -> props .hash , & position ))) {
681
729
zend_hash_get_current_key_zval_ex (& ts_obj -> props .hash , & key , & position );
682
730
731
+ if (zend_hash_num_elements (& ts_obj -> props .hash ) == 1 ) { //we're about to delete the last element
732
+ pmmpthread_store_invalidate_bounds (& ts_obj -> props );
733
+ } else {
734
+ zend_hash_move_backwards_ex (& ts_obj -> props .hash , & position );
735
+ ts_obj -> props .last = position ;
736
+ }
737
+
683
738
zend_bool may_be_locally_cached ;
684
739
pmmpthread_store_restore_zval_ex (member , zstorage , & may_be_locally_cached );
685
740
@@ -1195,6 +1250,8 @@ int pmmpthread_store_merge(zend_object *destination, zval *from, zend_bool overw
1195
1250
if (overwrote_pmmpthread_object ) {
1196
1251
_pmmpthread_store_bump_modcount_nolock (PMMPTHREAD_FETCH_FROM (destination ));
1197
1252
}
1253
+ pmmpthread_store_invalidate_bounds (& threaded [0 ]-> props );
1254
+
1198
1255
//TODO: sync local properties?
1199
1256
1200
1257
pmmpthread_monitor_unlock (& threaded [1 ]-> monitor );
@@ -1313,9 +1370,15 @@ void pmmpthread_store_reset(zend_object *object, HashPosition *position) {
1313
1370
pmmpthread_object_t * ts_obj = PMMPTHREAD_FETCH_TS_FROM (object );
1314
1371
1315
1372
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 ;
1373
+ if (ts_obj -> props .first == HT_INVALID_IDX ) {
1374
+ zend_hash_internal_pointer_reset_ex (& ts_obj -> props .hash , position );
1375
+ if (zend_hash_has_more_elements_ex (& ts_obj -> props .hash , position ) == FAILURE ) { //empty
1376
+ * position = HT_INVALID_IDX ;
1377
+ } else {
1378
+ ts_obj -> props .first = * position ;
1379
+ }
1380
+ } else {
1381
+ * position = ts_obj -> props .first ;
1319
1382
}
1320
1383
pmmpthread_monitor_unlock (& ts_obj -> monitor );
1321
1384
}
0 commit comments