@@ -75,12 +75,11 @@ struct rush {
7575static const struct hash_slinger * hash ;
7676static struct objhead * private_oh ;
7777
78- static void hsh_rush1 (const struct worker * , struct objhead * ,
78+ static void hsh_rush1 (const struct worker * , struct objcore * ,
7979 struct rush * , int );
8080static void hsh_rush2 (struct worker * , struct rush * );
8181static int hsh_deref_objhead (struct worker * wrk , struct objhead * * poh );
82- static int hsh_deref_objhead_unlock (struct worker * wrk , struct objhead * * poh ,
83- int );
82+ static int hsh_deref_objhead_unlock (struct worker * wrk , struct objhead * * poh );
8483
8584/*---------------------------------------------------------------------*/
8685
@@ -102,7 +101,6 @@ hsh_newobjhead(void)
102101 XXXAN (oh );
103102 oh -> refcnt = 1 ;
104103 VTAILQ_INIT (& oh -> objcs );
105- VTAILQ_INIT (& oh -> waitinglist );
106104 Lck_New (& oh -> mtx , lck_objhdr );
107105 return (oh );
108106}
@@ -182,7 +180,6 @@ HSH_DeleteObjHead(const struct worker *wrk, struct objhead *oh)
182180
183181 AZ (oh -> refcnt );
184182 assert (VTAILQ_EMPTY (& oh -> objcs ));
185- assert (VTAILQ_EMPTY (& oh -> waitinglist ));
186183 Lck_Delete (& oh -> mtx );
187184 wrk -> stats -> n_objecthead -- ;
188185 FREE_OBJ (oh );
@@ -323,8 +320,8 @@ HSH_Insert(struct worker *wrk, const void *digest, struct objcore *oc,
323320 VTAILQ_REMOVE (& oh -> objcs , oc , hsh_list );
324321 VTAILQ_INSERT_HEAD (& oh -> objcs , oc , hsh_list );
325322 oc -> flags &= ~OC_F_BUSY ;
326- if (!VTAILQ_EMPTY (& oh -> waitinglist ))
327- hsh_rush1 (wrk , oh , & rush , HSH_RUSH_POLICY );
323+ if (!VTAILQ_EMPTY (& oc -> waitinglist ))
324+ hsh_rush1 (wrk , oc , & rush , HSH_RUSH_POLICY );
328325 Lck_Unlock (& oh -> mtx );
329326 hsh_rush2 (wrk , & rush );
330327
@@ -358,16 +355,47 @@ hsh_insert_busyobj(const struct worker *wrk, struct objhead *oh)
358355/*---------------------------------------------------------------------
359356 */
360357
358+ static int
359+ hsh_is_rush_hit (struct req * req )
360+ {
361+ struct objcore * oc ;
362+ const uint8_t * vary ;
363+
364+ oc = req -> hash_oc ;
365+ CHECK_OBJ_ORNULL (oc , OBJCORE_MAGIC );
366+
367+ if (oc == NULL )
368+ return (0 );
369+
370+ AZ (oc -> flags & OC_F_BUSY );
371+ if (oc -> flags != 0 )
372+ return (0 );
373+
374+ /* The objcore was serviceable, all the requests on the waiting list
375+ * were rushed at once.
376+ */
377+ assert (VTAILQ_EMPTY (& oc -> waitinglist ));
378+
379+ if (req -> hash_ignore_vary )
380+ return (1 );
381+ if (!ObjHasAttr (req -> wrk , oc , OA_VARY ))
382+ return (1 );
383+
384+ vary = ObjGetAttr (req -> wrk , oc , OA_VARY , NULL );
385+ AN (vary );
386+ return (VRY_Match (req , vary ));
387+ }
388+
361389enum lookup_e
362390HSH_Lookup (struct req * req , struct objcore * * ocp , struct objcore * * bocp )
363391{
364392 struct worker * wrk ;
365393 struct objhead * oh ;
366394 struct objcore * oc ;
367395 struct objcore * exp_oc ;
396+ struct objcore * busy_oc ;
368397 const struct vcf_return * vr ;
369398 vtim_real exp_t_origin ;
370- int busy_found ;
371399 const uint8_t * vary ;
372400 intmax_t boc_progress ;
373401 unsigned xid = 0 ;
@@ -390,15 +418,30 @@ HSH_Lookup(struct req *req, struct objcore **ocp, struct objcore **bocp)
390418 if (DO_DEBUG (DBG_HASHEDGE ))
391419 hsh_testmagic (req -> digest );
392420
393- if (req -> hash_objhead != NULL ) {
421+ if (hsh_is_rush_hit (req )) {
422+ TAKE_OBJ_NOTNULL (oc , & req -> hash_oc , OBJCORE_MAGIC );
423+ * ocp = oc ;
424+ oc -> hits ++ ;
425+ boc_progress = oc -> boc == NULL ? -1 : oc -> boc -> fetched_so_far ;
426+ Req_LogHit (wrk , req , oc , boc_progress );
427+ /* NB: since this hit comes from the waiting list instead of
428+ * a regular lookup, grace is not considered. The object is
429+ * fresh in the context of the waiting list, even expired: it
430+ * was successfully [re]validated by a fetch task.
431+ */
432+ return (HSH_HIT );
433+ }
434+
435+ if (req -> hash_oc != NULL ) {
394436 /*
395437 * This req came off the waiting list, and brings an
396- * oh refcnt with it.
438+ * incompatible hash_oc refcnt with it.
397439 */
398- CHECK_OBJ_NOTNULL (req -> hash_objhead , OBJHEAD_MAGIC );
399- oh = req -> hash_objhead ;
440+ CHECK_OBJ_NOTNULL (req -> hash_oc -> objhead , OBJHEAD_MAGIC );
441+ oh = req -> hash_oc -> objhead ;
442+ /* XXX: can we avoid grabbing the oh lock twice here? */
443+ (void )HSH_DerefObjCore (wrk , & req -> hash_oc , HSH_RUSH_POLICY );
400444 Lck_Lock (& oh -> mtx );
401- req -> hash_objhead = NULL ;
402445 } else {
403446 AN (wrk -> wpriv -> nobjhead );
404447 oh = hash -> lookup (wrk , req -> digest , & wrk -> wpriv -> nobjhead );
@@ -417,7 +460,7 @@ HSH_Lookup(struct req *req, struct objcore **ocp, struct objcore **bocp)
417460 }
418461
419462 assert (oh -> refcnt > 0 );
420- busy_found = 0 ;
463+ busy_oc = NULL ;
421464 exp_oc = NULL ;
422465 exp_t_origin = 0.0 ;
423466 VTAILQ_FOREACH (oc , & oh -> objcs , hsh_list ) {
@@ -434,17 +477,19 @@ HSH_Lookup(struct req *req, struct objcore **ocp, struct objcore **bocp)
434477
435478 CHECK_OBJ_ORNULL (oc -> boc , BOC_MAGIC );
436479 if (oc -> flags & OC_F_BUSY ) {
480+ if (busy_oc != NULL )
481+ continue ;
437482 if (req -> hash_ignore_busy )
438483 continue ;
439484
440- if (oc -> boc && oc -> boc -> vary != NULL &&
485+ if (oc -> boc != NULL && oc -> boc -> vary != NULL &&
441486 !req -> hash_ignore_vary &&
442487 !VRY_Match (req , oc -> boc -> vary )) {
443488 wrk -> strangelove ++ ;
444489 continue ;
445490 }
446491
447- busy_found = 1 ;
492+ busy_oc = oc ;
448493 continue ;
449494 }
450495
@@ -501,7 +546,7 @@ HSH_Lookup(struct req *req, struct objcore **ocp, struct objcore **bocp)
501546 if (oc != NULL && oc -> flags & OC_F_HFP ) {
502547 xid = VXID (ObjGetXID (wrk , oc ));
503548 dttl = EXP_Dttl (req , oc );
504- AN (hsh_deref_objhead_unlock (wrk , & oh , HSH_RUSH_POLICY ));
549+ AN (hsh_deref_objhead_unlock (wrk , & oh ));
505550 wrk -> stats -> cache_hitpass ++ ;
506551 VSLb (req -> vsl , SLT_HitPass , "%u %.6f" , xid , dttl );
507552 return (HSH_HITPASS );
@@ -521,7 +566,7 @@ HSH_Lookup(struct req *req, struct objcore **ocp, struct objcore **bocp)
521566 }
522567 oc -> hits ++ ;
523568 boc_progress = oc -> boc == NULL ? -1 : oc -> boc -> fetched_so_far ;
524- AN (hsh_deref_objhead_unlock (wrk , & oh , HSH_RUSH_POLICY ));
569+ AN (hsh_deref_objhead_unlock (wrk , & oh ));
525570 Req_LogHit (wrk , req , oc , boc_progress );
526571 return (HSH_HIT );
527572 }
@@ -547,7 +592,7 @@ HSH_Lookup(struct req *req, struct objcore **ocp, struct objcore **bocp)
547592 else
548593 boc_progress = -1 ;
549594
550- if (! busy_found ) {
595+ if (busy_oc == NULL ) {
551596 * bocp = hsh_insert_busyobj (wrk , oh );
552597
553598 if (exp_oc != NULL ) {
@@ -564,33 +609,38 @@ HSH_Lookup(struct req *req, struct objcore **ocp, struct objcore **bocp)
564609 return (HSH_MISS );
565610 }
566611
567- AN (busy_found );
612+ CHECK_OBJ_NOTNULL (busy_oc , OBJCORE_MAGIC );
613+
568614 if (exp_oc != NULL && EXP_Ttl_grace (req , exp_oc ) >= req -> t_req ) {
569615 /* we do not wait on the busy object if in grace */
570616 exp_oc -> refcnt ++ ;
571617 * ocp = exp_oc ;
572618 exp_oc -> hits ++ ;
573- AN (hsh_deref_objhead_unlock (wrk , & oh , 0 ));
619+ AN (hsh_deref_objhead_unlock (wrk , & oh ));
574620 Req_LogHit (wrk , req , exp_oc , boc_progress );
575621 return (HSH_GRACE );
576622 }
577623
578624 /* There are one or more busy objects, wait for them */
579- VTAILQ_INSERT_TAIL (& oh -> waitinglist , req , w_list );
625+ VTAILQ_INSERT_TAIL (& busy_oc -> waitinglist , req , w_list );
580626
581627 AZ (req -> hash_ignore_busy );
582628
583629 /*
584- * The objhead reference transfers to the sess , we get it
585- * back when the sess comes off the waiting list and
586- * calls us again
630+ * The objcore reference transfers to the req , we get it
631+ * back when the req comes off the waiting list and
632+ * calls us again.
587633 */
588- req -> hash_objhead = oh ;
634+ assert (busy_oc -> refcnt > 0 );
635+ busy_oc -> refcnt ++ ;
636+
637+ AZ (req -> hash_oc );
638+ req -> hash_oc = busy_oc ;
589639 req -> wrk = NULL ;
590640 req -> waitinglist = 1 ;
591641
592642 if (DO_DEBUG (DBG_WAITINGLIST ))
593- VSLb (req -> vsl , SLT_Debug , "on waiting list <%p>" , oh );
643+ VSLb (req -> vsl , SLT_Debug , "on waiting list <%p>" , busy_oc );
594644
595645 Lck_Unlock (& oh -> mtx );
596646
@@ -603,30 +653,35 @@ HSH_Lookup(struct req *req, struct objcore **ocp, struct objcore **bocp)
603653 */
604654
605655static void
606- hsh_rush1 (const struct worker * wrk , struct objhead * oh , struct rush * r , int max )
656+ hsh_rush1 (const struct worker * wrk , struct objcore * oc , struct rush * r , int max )
607657{
608658 int i ;
609659 struct req * req ;
610660
611661 if (max == 0 )
612662 return ;
613- if (max == HSH_RUSH_POLICY )
614- max = cache_param -> rush_exponent ;
663+ if (max == HSH_RUSH_POLICY ) {
664+ AZ (oc -> flags & OC_F_BUSY );
665+ if (oc -> flags != 0 )
666+ max = cache_param -> rush_exponent ;
667+ else
668+ max = INT_MAX ;
669+ }
615670 assert (max > 0 );
616671
617672 CHECK_OBJ_NOTNULL (wrk , WORKER_MAGIC );
618- CHECK_OBJ_NOTNULL (oh , OBJHEAD_MAGIC );
673+ CHECK_OBJ_NOTNULL (oc , OBJCORE_MAGIC );
619674 CHECK_OBJ_NOTNULL (r , RUSH_MAGIC );
620675 VTAILQ_INIT (& r -> reqs );
621- Lck_AssertHeld (& oh -> mtx );
676+ Lck_AssertHeld (& oc -> objhead -> mtx );
622677 for (i = 0 ; i < max ; i ++ ) {
623- req = VTAILQ_FIRST (& oh -> waitinglist );
678+ req = VTAILQ_FIRST (& oc -> waitinglist );
624679 if (req == NULL )
625680 break ;
626681 CHECK_OBJ_NOTNULL (req , REQ_MAGIC );
627682 wrk -> stats -> busy_wakeup ++ ;
628683 AZ (req -> wrk );
629- VTAILQ_REMOVE (& oh -> waitinglist , req , w_list );
684+ VTAILQ_REMOVE (& oc -> waitinglist , req , w_list );
630685 VTAILQ_INSERT_TAIL (& r -> reqs , req , w_list );
631686 req -> waitinglist = 0 ;
632687 }
@@ -887,9 +942,9 @@ HSH_Unbusy(struct worker *wrk, struct objcore *oc)
887942 VTAILQ_REMOVE (& oh -> objcs , oc , hsh_list );
888943 VTAILQ_INSERT_HEAD (& oh -> objcs , oc , hsh_list );
889944 oc -> flags &= ~OC_F_BUSY ;
890- if (!VTAILQ_EMPTY (& oh -> waitinglist )) {
891- assert (oh -> refcnt > 1 );
892- hsh_rush1 (wrk , oh , & rush , HSH_RUSH_POLICY );
945+ if (!VTAILQ_EMPTY (& oc -> waitinglist )) {
946+ assert (oc -> refcnt > 1 );
947+ hsh_rush1 (wrk , oc , & rush , HSH_RUSH_POLICY );
893948 }
894949 Lck_Unlock (& oh -> mtx );
895950 EXP_Insert (wrk , oc ); /* Does nothing unless EXP_RefNewObjcore was
@@ -1041,9 +1096,9 @@ HSH_DerefObjCore(struct worker *wrk, struct objcore **ocp, int rushmax)
10411096 r = -- oc -> refcnt ;
10421097 if (!r )
10431098 VTAILQ_REMOVE (& oh -> objcs , oc , hsh_list );
1044- if (!VTAILQ_EMPTY (& oh -> waitinglist )) {
1045- assert (oh -> refcnt > 1 );
1046- hsh_rush1 (wrk , oh , & rush , rushmax );
1099+ if (!VTAILQ_EMPTY (& oc -> waitinglist )) {
1100+ assert (oc -> refcnt > 0 );
1101+ hsh_rush1 (wrk , oc , & rush , rushmax );
10471102 }
10481103 Lck_Unlock (& oh -> mtx );
10491104 hsh_rush2 (wrk , & rush );
@@ -1066,38 +1121,24 @@ HSH_DerefObjCore(struct worker *wrk, struct objcore **ocp, int rushmax)
10661121}
10671122
10681123static int
1069- hsh_deref_objhead_unlock (struct worker * wrk , struct objhead * * poh , int max )
1124+ hsh_deref_objhead_unlock (struct worker * wrk , struct objhead * * poh )
10701125{
10711126 struct objhead * oh ;
1072- struct rush rush ;
1073- int r ;
10741127
10751128 CHECK_OBJ_NOTNULL (wrk , WORKER_MAGIC );
10761129 TAKE_OBJ_NOTNULL (oh , poh , OBJHEAD_MAGIC );
10771130
10781131 Lck_AssertHeld (& oh -> mtx );
10791132
10801133 if (oh == private_oh ) {
1081- assert (VTAILQ_EMPTY (& oh -> waitinglist ));
10821134 assert (oh -> refcnt > 1 );
10831135 oh -> refcnt -- ;
10841136 Lck_Unlock (& oh -> mtx );
10851137 return (1 );
10861138 }
10871139
1088- INIT_OBJ (& rush , RUSH_MAGIC );
1089- if (!VTAILQ_EMPTY (& oh -> waitinglist )) {
1090- assert (oh -> refcnt > 1 );
1091- hsh_rush1 (wrk , oh , & rush , max );
1092- }
1093-
1094- if (oh -> refcnt == 1 )
1095- assert (VTAILQ_EMPTY (& oh -> waitinglist ));
1096-
10971140 assert (oh -> refcnt > 0 );
1098- r = hash -> deref (wrk , oh ); /* Unlocks oh->mtx */
1099- hsh_rush2 (wrk , & rush );
1100- return (r );
1141+ return (hash -> deref (wrk , oh )); /* Unlocks oh->mtx */
11011142}
11021143
11031144static int
@@ -1109,7 +1150,7 @@ hsh_deref_objhead(struct worker *wrk, struct objhead **poh)
11091150 TAKE_OBJ_NOTNULL (oh , poh , OBJHEAD_MAGIC );
11101151
11111152 Lck_Lock (& oh -> mtx );
1112- return (hsh_deref_objhead_unlock (wrk , & oh , 0 ));
1153+ return (hsh_deref_objhead_unlock (wrk , & oh ));
11131154}
11141155
11151156void
0 commit comments