v2_metadata_service.go 3.5 KB

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