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

     1  package db
     2  
     3  import (
     4  	"database/sql"
     5  	"encoding/json"
     6  
     7  	sq "github.com/Masterminds/squirrel"
     8  	"github.com/pf-qiu/concourse/v6/atc"
     9  	"github.com/pf-qiu/concourse/v6/atc/db/lock"
    10  )
    11  
    12  //go:generate counterfeiter . ResourceCacheFactory
    13  
    14  type ResourceCacheFactory interface {
    15  	FindOrCreateResourceCache(
    16  		resourceCacheUser ResourceCacheUser,
    17  		resourceTypeName string,
    18  		version atc.Version,
    19  		source atc.Source,
    20  		params atc.Params,
    21  		resourceTypes atc.VersionedResourceTypes,
    22  	) (UsedResourceCache, error)
    23  
    24  	// changing resource cache to interface to allow updates on object is not feasible.
    25  	// Since we need to pass it recursively in ResourceConfig.
    26  	// Also, metadata will be available to us before we create resource cache so this
    27  	// method can be removed at that point. See  https://github.com/pf-qiu/concourse/v6/issues/534
    28  	UpdateResourceCacheMetadata(UsedResourceCache, []atc.MetadataField) error
    29  	ResourceCacheMetadata(UsedResourceCache) (ResourceConfigMetadataFields, error)
    30  
    31  	FindResourceCacheByID(id int) (UsedResourceCache, bool, error)
    32  }
    33  
    34  type resourceCacheFactory struct {
    35  	conn        Conn
    36  	lockFactory lock.LockFactory
    37  }
    38  
    39  func NewResourceCacheFactory(conn Conn, lockFactory lock.LockFactory) ResourceCacheFactory {
    40  	return &resourceCacheFactory{
    41  		conn:        conn,
    42  		lockFactory: lockFactory,
    43  	}
    44  }
    45  
    46  func (f *resourceCacheFactory) FindOrCreateResourceCache(
    47  	resourceCacheUser ResourceCacheUser,
    48  	resourceTypeName string,
    49  	version atc.Version,
    50  	source atc.Source,
    51  	params atc.Params,
    52  	resourceTypes atc.VersionedResourceTypes,
    53  ) (UsedResourceCache, error) {
    54  	resourceConfigDescriptor, err := constructResourceConfigDescriptor(resourceTypeName, source, resourceTypes)
    55  	if err != nil {
    56  		return nil, err
    57  	}
    58  
    59  	resourceCache := ResourceCacheDescriptor{
    60  		ResourceConfigDescriptor: resourceConfigDescriptor,
    61  		Version:                  version,
    62  		Params:                   params,
    63  	}
    64  
    65  	tx, err := f.conn.Begin()
    66  	if err != nil {
    67  		return nil, err
    68  	}
    69  
    70  	defer Rollback(tx)
    71  
    72  	usedResourceCache, err := resourceCache.findOrCreate(tx, f.lockFactory, f.conn)
    73  	if err != nil {
    74  		return nil, err
    75  	}
    76  
    77  	err = resourceCache.use(tx, usedResourceCache, resourceCacheUser)
    78  	if err != nil {
    79  		return nil, err
    80  	}
    81  
    82  	err = tx.Commit()
    83  	if err != nil {
    84  		return nil, err
    85  	}
    86  
    87  	return usedResourceCache, nil
    88  }
    89  
    90  func (f *resourceCacheFactory) UpdateResourceCacheMetadata(resourceCache UsedResourceCache, metadata []atc.MetadataField) error {
    91  	metadataJSON, err := json.Marshal(metadata)
    92  	if err != nil {
    93  		return err
    94  	}
    95  	_, err = psql.Update("resource_caches").
    96  		Set("metadata", metadataJSON).
    97  		Where(sq.Eq{"id": resourceCache.ID()}).
    98  		RunWith(f.conn).
    99  		Exec()
   100  	return err
   101  }
   102  
   103  func (f *resourceCacheFactory) ResourceCacheMetadata(resourceCache UsedResourceCache) (ResourceConfigMetadataFields, error) {
   104  	var metadataJSON sql.NullString
   105  	err := psql.Select("metadata").
   106  		From("resource_caches").
   107  		Where(sq.Eq{"id": resourceCache.ID()}).
   108  		RunWith(f.conn).
   109  		QueryRow().
   110  		Scan(&metadataJSON)
   111  	if err != nil {
   112  		return nil, err
   113  	}
   114  
   115  	var metadata []ResourceConfigMetadataField
   116  	if metadataJSON.Valid {
   117  		err = json.Unmarshal([]byte(metadataJSON.String), &metadata)
   118  		if err != nil {
   119  			return nil, err
   120  		}
   121  	}
   122  
   123  	return metadata, nil
   124  }
   125  
   126  func (f *resourceCacheFactory) FindResourceCacheByID(id int) (UsedResourceCache, bool, error) {
   127  	tx, err := f.conn.Begin()
   128  	if err != nil {
   129  		return nil, false, err
   130  	}
   131  
   132  	defer Rollback(tx)
   133  
   134  	return findResourceCacheByID(tx, id, f.lockFactory, f.conn)
   135  }
   136  
   137  func findResourceCacheByID(tx Tx, resourceCacheID int, lock lock.LockFactory, conn Conn) (UsedResourceCache, bool, error) {
   138  	var rcID int
   139  	var versionBytes string
   140  
   141  	err := psql.Select("resource_config_id", "version").
   142  		From("resource_caches").
   143  		Where(sq.Eq{"id": resourceCacheID}).
   144  		RunWith(tx).
   145  		QueryRow().
   146  		Scan(&rcID, &versionBytes)
   147  
   148  	if err != nil {
   149  		if err == sql.ErrNoRows {
   150  			return nil, false, nil
   151  		}
   152  		return nil, false, err
   153  	}
   154  
   155  	var version atc.Version
   156  	err = json.Unmarshal([]byte(versionBytes), &version)
   157  	if err != nil {
   158  		return nil, false, err
   159  	}
   160  
   161  	rc, found, err := findResourceConfigByID(tx, rcID, lock, conn)
   162  	if err != nil {
   163  		return nil, false, err
   164  	}
   165  
   166  	if !found {
   167  		return nil, false, nil
   168  	}
   169  
   170  	usedResourceCache := &usedResourceCache{
   171  		id:             resourceCacheID,
   172  		version:        version,
   173  		resourceConfig: rc,
   174  		lockFactory:    lock,
   175  		conn:           conn,
   176  	}
   177  
   178  	return usedResourceCache, true, nil
   179  }