-
Notifications
You must be signed in to change notification settings - Fork 19
/
cachedblob.go
137 lines (108 loc) · 2.83 KB
/
cachedblob.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// SPDX-FileCopyrightText: 2022 SAP SE or an SAP affiliate company and Open Component Model contributors.
//
// SPDX-License-Identifier: Apache-2.0
package accessobj
import (
"fmt"
"io"
"sync"
"github.com/opencontainers/go-digest"
"github.com/open-component-model/ocm/v2/pkg/common/accessio"
"github.com/open-component-model/ocm/v2/pkg/contexts/datacontext"
"github.com/open-component-model/ocm/v2/pkg/contexts/datacontext/attrs/tmpcache"
)
type CachedBlobAccess struct {
lock sync.Mutex
mime string
cache *tmpcache.Attribute
path string
digest digest.Digest
size int64
source accessio.DataWriter
effective accessio.BlobAccess
}
var _ accessio.BlobAccess = (*CachedBlobAccess)(nil)
func CachedBlobAccessForWriter(ctx datacontext.Context, mime string, src accessio.DataWriter) accessio.BlobAccess {
return &CachedBlobAccess{
source: src,
mime: mime,
cache: tmpcache.Get(ctx),
}
}
func CachedBlobAccessForDataAccess(ctx datacontext.Context, mime string, src accessio.DataAccess) accessio.BlobAccess {
return CachedBlobAccessForWriter(ctx, mime, accessio.NewDataAccessWriter(src))
}
func (c *CachedBlobAccess) setup() error {
c.lock.Lock()
defer c.lock.Unlock()
if c.effective != nil {
return nil
}
file, err := c.cache.CreateTempFile("blob*")
if err != nil {
return fmt.Errorf("unable to create temporary file: %w", err)
}
defer file.Close()
c.path = file.Name()
c.size, c.digest, err = c.source.WriteTo(file)
if err != nil {
defer c.cache.Filesystem.Remove(file.Name())
return fmt.Errorf("unable to write source to file '%s': %w", file.Name(), err)
}
c.effective = accessio.BlobAccessForFile(c.mime, c.path, c.cache.Filesystem)
return nil
}
func (c *CachedBlobAccess) Get() ([]byte, error) {
err := c.setup()
if err != nil {
return nil, err
}
return c.effective.Get()
}
func (c *CachedBlobAccess) Reader() (io.ReadCloser, error) {
err := c.setup()
if err != nil {
return nil, err
}
return c.effective.Reader()
}
func (c *CachedBlobAccess) Close() error {
c.lock.Lock()
defer c.lock.Unlock()
var err error
if c.effective != nil {
c.effective.Close()
err = c.cache.Filesystem.Remove(c.path)
}
c.effective = nil
if err != nil {
return fmt.Errorf("failed to close blob access cache: %w", err)
}
return nil
}
func (c *CachedBlobAccess) Digest() digest.Digest {
err := c.setup()
if err != nil {
return accessio.BLOB_UNKNOWN_DIGEST
}
if c.digest == accessio.BLOB_UNKNOWN_DIGEST {
return c.effective.Digest()
}
return c.digest
}
func (c *CachedBlobAccess) MimeType() string {
return c.mime
}
func (c *CachedBlobAccess) DigestKnown() bool {
return c.effective != nil
}
func (c *CachedBlobAccess) Size() int64 {
err := c.setup()
if err != nil {
return accessio.BLOB_UNKNOWN_SIZE
}
if c.size == accessio.BLOB_UNKNOWN_SIZE {
return c.effective.Size()
}
return c.size
}