github.com/uriddle/docker@v0.0.0-20210926094723-4072e6aeb013/distribution/metadata/v2_metadata_service.go (about)

     1  package metadata
     2  
     3  import (
     4  	"encoding/json"
     5  
     6  	"github.com/docker/distribution/digest"
     7  	"github.com/docker/docker/layer"
     8  )
     9  
    10  // V2MetadataService maps layer IDs to a set of known metadata for
    11  // the layer.
    12  type V2MetadataService struct {
    13  	store Store
    14  }
    15  
    16  // V2Metadata contains the digest and source repository information for a layer.
    17  type V2Metadata struct {
    18  	Digest           digest.Digest
    19  	SourceRepository string
    20  }
    21  
    22  // maxMetadata is the number of metadata entries to keep per layer DiffID.
    23  const maxMetadata = 50
    24  
    25  // NewV2MetadataService creates a new diff ID to v2 metadata mapping service.
    26  func NewV2MetadataService(store Store) *V2MetadataService {
    27  	return &V2MetadataService{
    28  		store: store,
    29  	}
    30  }
    31  
    32  func (serv *V2MetadataService) diffIDNamespace() string {
    33  	return "v2metadata-by-diffid"
    34  }
    35  
    36  func (serv *V2MetadataService) digestNamespace() string {
    37  	return "diffid-by-digest"
    38  }
    39  
    40  func (serv *V2MetadataService) diffIDKey(diffID layer.DiffID) string {
    41  	return string(digest.Digest(diffID).Algorithm()) + "/" + digest.Digest(diffID).Hex()
    42  }
    43  
    44  func (serv *V2MetadataService) digestKey(dgst digest.Digest) string {
    45  	return string(dgst.Algorithm()) + "/" + dgst.Hex()
    46  }
    47  
    48  // GetMetadata finds the metadata associated with a layer DiffID.
    49  func (serv *V2MetadataService) GetMetadata(diffID layer.DiffID) ([]V2Metadata, error) {
    50  	jsonBytes, err := serv.store.Get(serv.diffIDNamespace(), serv.diffIDKey(diffID))
    51  	if err != nil {
    52  		return nil, err
    53  	}
    54  
    55  	var metadata []V2Metadata
    56  	if err := json.Unmarshal(jsonBytes, &metadata); err != nil {
    57  		return nil, err
    58  	}
    59  
    60  	return metadata, nil
    61  }
    62  
    63  // GetDiffID finds a layer DiffID from a digest.
    64  func (serv *V2MetadataService) GetDiffID(dgst digest.Digest) (layer.DiffID, error) {
    65  	diffIDBytes, err := serv.store.Get(serv.digestNamespace(), serv.digestKey(dgst))
    66  	if err != nil {
    67  		return layer.DiffID(""), err
    68  	}
    69  
    70  	return layer.DiffID(diffIDBytes), nil
    71  }
    72  
    73  // Add associates metadata with a layer DiffID. If too many metadata entries are
    74  // present, the oldest one is dropped.
    75  func (serv *V2MetadataService) Add(diffID layer.DiffID, metadata V2Metadata) error {
    76  	oldMetadata, err := serv.GetMetadata(diffID)
    77  	if err != nil {
    78  		oldMetadata = nil
    79  	}
    80  	newMetadata := make([]V2Metadata, 0, len(oldMetadata)+1)
    81  
    82  	// Copy all other metadata to new slice
    83  	for _, oldMeta := range oldMetadata {
    84  		if oldMeta != metadata {
    85  			newMetadata = append(newMetadata, oldMeta)
    86  		}
    87  	}
    88  
    89  	newMetadata = append(newMetadata, metadata)
    90  
    91  	if len(newMetadata) > maxMetadata {
    92  		newMetadata = newMetadata[len(newMetadata)-maxMetadata:]
    93  	}
    94  
    95  	jsonBytes, err := json.Marshal(newMetadata)
    96  	if err != nil {
    97  		return err
    98  	}
    99  
   100  	err = serv.store.Set(serv.diffIDNamespace(), serv.diffIDKey(diffID), jsonBytes)
   101  	if err != nil {
   102  		return err
   103  	}
   104  
   105  	return serv.store.Set(serv.digestNamespace(), serv.digestKey(metadata.Digest), []byte(diffID))
   106  }
   107  
   108  // Remove unassociates a metadata entry from a layer DiffID.
   109  func (serv *V2MetadataService) Remove(metadata V2Metadata) error {
   110  	diffID, err := serv.GetDiffID(metadata.Digest)
   111  	if err != nil {
   112  		return err
   113  	}
   114  	oldMetadata, err := serv.GetMetadata(diffID)
   115  	if err != nil {
   116  		oldMetadata = nil
   117  	}
   118  	newMetadata := make([]V2Metadata, 0, len(oldMetadata))
   119  
   120  	// Copy all other metadata to new slice
   121  	for _, oldMeta := range oldMetadata {
   122  		if oldMeta != metadata {
   123  			newMetadata = append(newMetadata, oldMeta)
   124  		}
   125  	}
   126  
   127  	if len(newMetadata) == 0 {
   128  		return serv.store.Delete(serv.diffIDNamespace(), serv.diffIDKey(diffID))
   129  	}
   130  
   131  	jsonBytes, err := json.Marshal(newMetadata)
   132  	if err != nil {
   133  		return err
   134  	}
   135  
   136  	return serv.store.Set(serv.diffIDNamespace(), serv.diffIDKey(diffID), jsonBytes)
   137  }