@@ -3500,6 +3500,20 @@ func TestTombstoneCompaction(t *testing.T) {
35003500 t .Skip ("If running with no xattrs compact acts as a no-op" )
35013501 }
35023502
3503+ tests := []struct {
3504+ numDocs int
3505+ runAsScheduledBackgroundTask bool
3506+ }{
3507+ // Multiples of Batch Size
3508+ {numDocs : db .QueryTombstoneBatch },
3509+ {numDocs : db .QueryTombstoneBatch * 4 },
3510+ // Smaller Than Batch Size
3511+ {numDocs : 2 },
3512+ {numDocs : db .QueryTombstoneBatch / 4 },
3513+ // Larger than Batch Size
3514+ {numDocs : db .QueryTombstoneBatch + 20 },
3515+ }
3516+
35033517 var rt * rest.RestTester
35043518 numCollections := 1
35053519
@@ -3510,64 +3524,80 @@ func TestTombstoneCompaction(t *testing.T) {
35103524 rt = rest .NewRestTester (t , nil )
35113525 }
35123526 defer rt .Close ()
3513- zero := time .Duration (0 )
3514- rt .GetDatabase ().Options .PurgeInterval = & zero
3515-
3516- compactionTotal := 0
3517- expectedBatches := 0
3527+ rt .GetDatabase ().Options .PurgeInterval = base .Ptr (time .Duration (0 ))
35183528
3519- TestCompact := func (numDocs int ) {
3520-
3521- count := 0
3529+ for _ , test := range tests {
3530+ for _ , runAsScheduledBackgroundTask := range []bool {false , true } {
3531+ t .Run (fmt .Sprintf ("numDocs:%d asBackgroundTask:%v" , test .numDocs , runAsScheduledBackgroundTask ), func (t * testing.T ) {
3532+
3533+ // seed with tombstones
3534+ for count := 0 ; count < test .numDocs ; count ++ {
3535+ for _ , keyspace := range rt .GetKeyspaces () {
3536+ response := rt .SendAdminRequest ("POST" , fmt .Sprintf ("/%s/" , keyspace ), `{"foo":"bar"}` )
3537+ assert .Equal (t , http .StatusOK , response .Code )
3538+ var body db.Body
3539+ err := base .JSONUnmarshal (response .Body .Bytes (), & body )
3540+ assert .NoError (t , err )
3541+ revID := body ["rev" ].(string )
3542+ docID := body ["id" ].(string )
3543+
3544+ response = rt .SendAdminRequest ("DELETE" , fmt .Sprintf ("/%s/%s?rev=%s" , keyspace , docID , revID ), "" )
3545+ assert .Equal (t , http .StatusOK , response .Code )
3546+ }
3547+ }
35223548
3523- for count < numDocs {
3524- count ++
3525- for _ , keyspace := range rt .GetKeyspaces () {
3526- response := rt .SendAdminRequest ("POST" , fmt .Sprintf ("/%s/" , keyspace ), `{"foo":"bar"}` )
3527- assert .Equal (t , 200 , response .Code )
3528- var body db.Body
3529- err := base .JSONUnmarshal (response .Body .Bytes (), & body )
3530- assert .NoError (t , err )
3531- revId := body ["rev" ].(string )
3532- docId := body ["id" ].(string )
3549+ expectedCompactions := (test .numDocs * numCollections )
3550+ expectedBatches := (test .numDocs / db .QueryTombstoneBatch + 1 ) * numCollections
35333551
3534- response = rt .SendAdminRequest ("DELETE" , fmt .Sprintf ("/%s/%s?rev=%s" , keyspace , docId , revId ), "" )
3535- assert .Equal (t , 200 , response .Code )
3536- }
3537- }
3538- resp := rt .SendAdminRequest ("POST" , "/{{.db}}/_compact" , "" )
3539- rest .RequireStatus (t , resp , http .StatusOK )
3552+ numCompactionsBefore := int (rt .GetDatabase ().DbStats .Database ().NumTombstonesCompacted .Value ())
3553+ var numBatchesBefore int
3554+ if base .TestsDisableGSI () {
3555+ numBatchesBefore = int (rt .GetDatabase ().DbStats .Query (fmt .Sprintf (base .StatViewFormat , db .DesignDocSyncHousekeeping (), db .ViewTombstones )).QueryCount .Value ())
3556+ } else {
3557+ numBatchesBefore = int (rt .GetDatabase ().DbStats .Query (db .QueryTypeTombstones ).QueryCount .Value ())
3558+ }
35403559
3541- err := rt .WaitForCondition (func () bool {
3542- time .Sleep (1 * time .Second )
3543- return rt .GetDatabase ().TombstoneCompactionManager .GetRunState () == db .BackgroundProcessStateCompleted
3544- })
3545- assert .NoError (t , err )
3560+ numIdleKvOpsBefore := int (base .SyncGatewayStats .GlobalStats .ResourceUtilizationStats ().NumIdleKvOps .Value ())
3561+ numIdleQueryOpsBefore := int (base .SyncGatewayStats .GlobalStats .ResourceUtilizationStats ().NumIdleQueryOps .Value ())
3562+
3563+ if runAsScheduledBackgroundTask {
3564+ database , err := db .CreateDatabase (rt .GetDatabase ())
3565+ require .NoError (t , err )
3566+ _ , err = database .Compact (base .TestCtx (t ), false , nil , base .NewSafeTerminator (), true )
3567+ require .NoError (t , err )
3568+
3569+ numIdleKvOps := int (base .SyncGatewayStats .GlobalStats .ResourceUtilizationStats ().NumIdleKvOps .Value ()) - numIdleKvOpsBefore
3570+ numIdleQueryOps := int (base .SyncGatewayStats .GlobalStats .ResourceUtilizationStats ().NumIdleQueryOps .Value ()) - numIdleQueryOpsBefore
3571+ assert .Equal (t , expectedCompactions , numIdleKvOps )
3572+ assert .Equal (t , expectedBatches , numIdleQueryOps )
3573+ } else {
3574+ resp := rt .SendAdminRequest ("POST" , "/{{.db}}/_compact" , "" )
3575+ rest .RequireStatus (t , resp , http .StatusOK )
3576+ err := rt .WaitForCondition (func () bool {
3577+ return rt .GetDatabase ().TombstoneCompactionManager .GetRunState () == db .BackgroundProcessStateCompleted
3578+ })
3579+ assert .NoError (t , err )
3580+
3581+ numIdleKvOps := int (base .SyncGatewayStats .GlobalStats .ResourceUtilizationStats ().NumIdleKvOps .Value ()) - numIdleKvOpsBefore
3582+ numIdleQueryOps := int (base .SyncGatewayStats .GlobalStats .ResourceUtilizationStats ().NumIdleQueryOps .Value ()) - numIdleQueryOpsBefore
3583+ // ad-hoc compactions don't invoke idle ops
3584+ assert .Equal (t , 0 , numIdleKvOps )
3585+ assert .Equal (t , 0 , numIdleQueryOps )
3586+ }
35463587
3547- compactionTotal += ( numDocs * numCollections )
3548- require .Equal (t , compactionTotal , int ( rt . GetDatabase (). DbStats . Database (). NumTombstonesCompacted . Value ()) )
3588+ actualCompactions := int ( rt . GetDatabase (). DbStats . Database (). NumTombstonesCompacted . Value ()) - numCompactionsBefore
3589+ require .Equal (t , expectedCompactions , actualCompactions )
35493590
3550- var actualBatches int64
3551- if base .TestsDisableGSI () {
3552- actualBatches = rt .GetDatabase ().DbStats .Query (fmt .Sprintf (base .StatViewFormat , db .DesignDocSyncHousekeeping (), db .ViewTombstones )).QueryCount .Value ()
3553- } else {
3554- actualBatches = rt .GetDatabase ().DbStats .Query (db .QueryTypeTombstones ).QueryCount .Value ()
3591+ var actualBatches int
3592+ if base .TestsDisableGSI () {
3593+ actualBatches = int (rt .GetDatabase ().DbStats .Query (fmt .Sprintf (base .StatViewFormat , db .DesignDocSyncHousekeeping (), db .ViewTombstones )).QueryCount .Value ()) - numBatchesBefore
3594+ } else {
3595+ actualBatches = int (rt .GetDatabase ().DbStats .Query (db .QueryTypeTombstones ).QueryCount .Value ()) - numBatchesBefore
3596+ }
3597+ require .Equal (t , expectedBatches , actualBatches )
3598+ })
35553599 }
3556-
3557- expectedBatches += (numDocs / db .QueryTombstoneBatch + 1 ) * numCollections
3558- require .Equal (t , expectedBatches , int (actualBatches ))
35593600 }
3560-
3561- // Multiples of Batch Size
3562- TestCompact (db .QueryTombstoneBatch )
3563- TestCompact (db .QueryTombstoneBatch * 4 )
3564-
3565- // Smaller Than Batch Size
3566- TestCompact (2 )
3567- TestCompact (db .QueryTombstoneBatch / 4 )
3568-
3569- // Larger than Batch Size
3570- TestCompact (db .QueryTombstoneBatch + 20 )
35713601}
35723602
35733603// TestOneShotGrantTiming simulates a one-shot changes feed returning before a previously issued grant has been
0 commit comments