github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/db/resource_cache_lifecycle.go (about)

     1  package db
     2  
     3  import (
     4  	"strings"
     5  
     6  	"code.cloudfoundry.org/lager"
     7  	sq "github.com/Masterminds/squirrel"
     8  	"github.com/lib/pq"
     9  )
    10  
    11  //go:generate counterfeiter . ResourceCacheLifecycle
    12  
    13  type ResourceCacheLifecycle interface {
    14  	CleanUsesForFinishedBuilds(lager.Logger) error
    15  	CleanBuildImageResourceCaches(lager.Logger) error
    16  	CleanUpInvalidCaches(lager.Logger) error
    17  }
    18  
    19  type resourceCacheLifecycle struct {
    20  	conn Conn
    21  }
    22  
    23  func NewResourceCacheLifecycle(conn Conn) ResourceCacheLifecycle {
    24  	return &resourceCacheLifecycle{
    25  		conn: conn,
    26  	}
    27  }
    28  
    29  func (f *resourceCacheLifecycle) CleanBuildImageResourceCaches(logger lager.Logger) error {
    30  	_, err := sq.Delete("build_image_resource_caches birc USING builds b").
    31  		Where("birc.build_id = b.id").
    32  		Where(sq.Expr("((now() - b.end_time) > '24 HOURS'::INTERVAL)")).
    33  		Where(sq.Eq{"job_id": nil}).
    34  		RunWith(f.conn).
    35  		Exec()
    36  	return err
    37  }
    38  
    39  func (f *resourceCacheLifecycle) CleanUsesForFinishedBuilds(logger lager.Logger) error {
    40  	_, err := psql.Delete("resource_cache_uses rcu USING builds b").
    41  		Where(sq.And{
    42  			sq.Expr("rcu.build_id = b.id"),
    43  			sq.Expr("b.interceptible = false"),
    44  		}).
    45  		RunWith(f.conn).
    46  		Exec()
    47  	return err
    48  }
    49  
    50  func (f *resourceCacheLifecycle) CleanUpInvalidCaches(logger lager.Logger) error {
    51  	stillInUseCacheIds, _, err := sq.
    52  		Select("resource_cache_id").
    53  		From("resource_cache_uses").
    54  		ToSql()
    55  	if err != nil {
    56  		return err
    57  	}
    58  
    59  	resourceConfigCacheIds, _, err := sq.
    60  		Select("resource_cache_id").
    61  		From("resource_configs").
    62  		Where(sq.NotEq{"resource_cache_id": nil}).
    63  		ToSql()
    64  	if err != nil {
    65  		return err
    66  	}
    67  
    68  	buildImageCacheIds, _, err := sq.
    69  		Select("resource_cache_id").
    70  		From("build_image_resource_caches").
    71  		ToSql()
    72  	if err != nil {
    73  		return err
    74  	}
    75  
    76  	nextBuildInputsCacheIds, _, err := sq.
    77  		Select("r_cache.id").
    78  		From("next_build_inputs nbi").
    79  		Join("resources r ON r.id = nbi.resource_id").
    80  		Join("resource_config_versions rcv ON rcv.version_md5 = nbi.version_md5 AND rcv.resource_config_scope_id = r.resource_config_scope_id").
    81  		Join("resource_caches r_cache ON r_cache.resource_config_id = r.resource_config_id AND r_cache.version_md5 = rcv.version_md5").
    82  		Join("jobs j ON nbi.job_id = j.id").
    83  		Join("pipelines p ON j.pipeline_id = p.id").
    84  		Where(sq.Expr("p.paused = false")).
    85  		ToSql()
    86  	if err != nil {
    87  		return err
    88  	}
    89  
    90  	query, args, err := sq.Delete("resource_caches").
    91  		Where("id NOT IN (" + strings.Join([]string{
    92  			stillInUseCacheIds,
    93  			resourceConfigCacheIds,
    94  			buildImageCacheIds,
    95  			nextBuildInputsCacheIds,
    96  		}, " UNION ") + ")").
    97  		Suffix("RETURNING id").
    98  		PlaceholderFormat(sq.Dollar).
    99  		ToSql()
   100  	if err != nil {
   101  		return err
   102  	}
   103  
   104  	rows, err := f.conn.Query(query, args...)
   105  	if err != nil {
   106  		if pqErr, ok := err.(*pq.Error); ok && pqErr.Code.Name() == pqFKeyViolationErrCode {
   107  			// this can happen if a use or resource cache is created referencing the
   108  			// config; as the subqueries above are not atomic
   109  			return nil
   110  		}
   111  
   112  		return err
   113  	}
   114  
   115  	defer Close(rows)
   116  
   117  	var deletedCacheIDs []int
   118  	for rows.Next() {
   119  		var cacheID int
   120  		err = rows.Scan(&cacheID)
   121  		if err != nil {
   122  			return nil
   123  		}
   124  
   125  		deletedCacheIDs = append(deletedCacheIDs, cacheID)
   126  	}
   127  
   128  	if len(deletedCacheIDs) > 0 {
   129  		logger.Debug("deleted-resource-caches", lager.Data{"id": deletedCacheIDs})
   130  	}
   131  
   132  	return nil
   133  }
   134  
   135  func (f *resourceCacheLifecycle) CleanUsesForPausedPipelineResources() error {
   136  	pausedPipelineIds, _, err := sq.
   137  		Select("id").
   138  		Distinct().
   139  		From("pipelines").
   140  		Where(sq.Expr("paused = false")).
   141  		ToSql()
   142  	if err != nil {
   143  		return err
   144  	}
   145  
   146  	_, err = psql.Delete("resource_cache_uses rcu USING resources r").
   147  		Where(sq.And{
   148  			sq.Expr("r.pipeline_id NOT IN (" + pausedPipelineIds + ")"),
   149  			sq.Expr("rcu.resource_id = r.id"),
   150  		}).
   151  		RunWith(f.conn).
   152  		Exec()
   153  
   154  	return err
   155  }