@@ -4,10 +4,15 @@ import (
4
4
"context"
5
5
"errors"
6
6
"fmt"
7
+ "io"
7
8
"io/fs"
8
9
"os"
9
10
"path/filepath"
11
+ "runtime"
10
12
"strings"
13
+ "sync"
14
+
15
+ "golang.org/x/sync/errgroup"
11
16
12
17
"github.com/operator-framework/operator-registry/alpha/declcfg"
13
18
"github.com/operator-framework/operator-registry/pkg/api"
@@ -208,45 +213,132 @@ func (c *cache) Build(ctx context.Context, fbcFsys fs.FS) error {
208
213
return fmt .Errorf ("init cache: %v" , err )
209
214
}
210
215
211
- fbc , err := declcfg . LoadFS ( ctx , fbcFsys )
216
+ tmpFile , err := os . CreateTemp ( "" , "opm-cache-build-*.json" )
212
217
if err != nil {
213
218
return err
214
219
}
215
- fbcModel , err := declcfg .ConvertToModel (* fbc )
216
- if err != nil {
220
+ defer func () {
221
+ tmpFile .Close ()
222
+ os .Remove (tmpFile .Name ())
223
+ }()
224
+
225
+ var (
226
+ concurrency = runtime .NumCPU ()
227
+ byPackageReaders = map [string ][]io.Reader {}
228
+ walkMu sync.Mutex
229
+ offset int64
230
+ )
231
+ if err := declcfg .WalkMetasFS (ctx , fbcFsys , func (path string , meta * declcfg.Meta , err error ) error {
232
+ if err != nil {
233
+ return err
234
+ }
235
+ packageName := meta .Package
236
+ if meta .Schema == declcfg .SchemaPackage {
237
+ packageName = meta .Name
238
+ }
239
+
240
+ walkMu .Lock ()
241
+ defer walkMu .Unlock ()
242
+ if _ , err := tmpFile .Write (meta .Blob ); err != nil {
243
+ return err
244
+ }
245
+ sr := io .NewSectionReader (tmpFile , offset , int64 (len (meta .Blob )))
246
+ byPackageReaders [packageName ] = append (byPackageReaders [packageName ], sr )
247
+ offset += int64 (len (meta .Blob ))
248
+ return nil
249
+ }, declcfg .WithConcurrency (concurrency )); err != nil {
217
250
return err
218
251
}
219
-
220
- pkgs , err := packagesFromModel (fbcModel )
221
- if err != nil {
252
+ if err := tmpFile .Sync (); err != nil {
222
253
return err
223
254
}
224
255
256
+ eg , egCtx := errgroup .WithContext (ctx )
257
+ pkgNameChan := make (chan string , concurrency )
258
+ eg .Go (func () error {
259
+ defer close (pkgNameChan )
260
+ for pkgName := range byPackageReaders {
261
+ select {
262
+ case <- egCtx .Done ():
263
+ return egCtx .Err ()
264
+ case pkgNameChan <- pkgName :
265
+ }
266
+ }
267
+ return nil
268
+ })
269
+
270
+ var (
271
+ pkgs = packageIndex {}
272
+ pkgsMu sync.Mutex
273
+ )
274
+ for i := 0 ; i < concurrency ; i ++ {
275
+ eg .Go (func () error {
276
+ for {
277
+ select {
278
+ case <- egCtx .Done ():
279
+ return egCtx .Err ()
280
+ case pkgName , ok := <- pkgNameChan :
281
+ if ! ok {
282
+ return nil
283
+ }
284
+ pkgIndex , err := c .processPackage (egCtx , io .MultiReader (byPackageReaders [pkgName ]... ))
285
+ if err != nil {
286
+ return fmt .Errorf ("process package %q: %v" , pkgName , err )
287
+ }
288
+
289
+ pkgsMu .Lock ()
290
+ pkgs [pkgName ] = pkgIndex [pkgName ]
291
+ pkgsMu .Unlock ()
292
+ }
293
+ }
294
+ return nil
295
+ })
296
+ }
297
+ if err := eg .Wait (); err != nil {
298
+ return fmt .Errorf ("build package index: %v" , err )
299
+ }
300
+
225
301
if err := c .backend .PutPackageIndex (ctx , pkgs ); err != nil {
226
302
return fmt .Errorf ("store package index: %v" , err )
227
303
}
228
304
229
- for _ , p := range fbcModel {
305
+ digest , err := c .backend .ComputeDigest (ctx , fbcFsys )
306
+ if err != nil {
307
+ return fmt .Errorf ("compute digest: %v" , err )
308
+ }
309
+ if err := c .backend .PutDigest (ctx , digest ); err != nil {
310
+ return fmt .Errorf ("store digest: %v" , err )
311
+ }
312
+ return nil
313
+ }
314
+
315
+ func (c * cache ) processPackage (ctx context.Context , reader io.Reader ) (packageIndex , error ) {
316
+ pkgFbc , err := declcfg .LoadReader (reader )
317
+ if err != nil {
318
+ return nil , err
319
+ }
320
+ pkgModel , err := declcfg .ConvertToModel (* pkgFbc )
321
+ if err != nil {
322
+ return nil , err
323
+ }
324
+ pkgIndex , err := packagesFromModel (pkgModel )
325
+ if err != nil {
326
+ return nil , err
327
+ }
328
+ for _ , p := range pkgModel {
230
329
for _ , ch := range p .Channels {
231
330
for _ , b := range ch .Bundles {
232
331
apiBundle , err := api .ConvertModelBundleToAPIBundle (* b )
233
332
if err != nil {
234
- return err
333
+ return nil , err
235
334
}
236
335
if err := c .backend .PutBundle (ctx , bundleKey {p .Name , ch .Name , b .Name }, apiBundle ); err != nil {
237
- return fmt .Errorf ("store bundle %q: %v" , b .Name , err )
336
+ return nil , fmt .Errorf ("store bundle %q: %v" , b .Name , err )
238
337
}
239
338
}
240
339
}
241
340
}
242
- digest , err := c .backend .ComputeDigest (ctx , fbcFsys )
243
- if err != nil {
244
- return fmt .Errorf ("compute digest: %v" , err )
245
- }
246
- if err := c .backend .PutDigest (ctx , digest ); err != nil {
247
- return fmt .Errorf ("store digest: %v" , err )
248
- }
249
- return nil
341
+ return pkgIndex , nil
250
342
}
251
343
252
344
func (c * cache ) Load (ctx context.Context ) error {
0 commit comments