v3: Analyze layer content in parallel

This commit is contained in:
Sida Chen 2019-03-20 11:35:20 -04:00
parent 2c7838eac7
commit 88f506918b

View File

@ -15,7 +15,10 @@
package v3 package v3
import ( import (
"sync"
"golang.org/x/net/context" "golang.org/x/net/context"
"golang.org/x/sync/errgroup"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/status" "google.golang.org/grpc/status"
@ -83,7 +86,13 @@ func (s *AncestryServer) PostAncestry(ctx context.Context, req *pb.PostAncestryR
} }
builder := clair.NewAncestryBuilder(clair.EnabledDetectors()) builder := clair.NewAncestryBuilder(clair.EnabledDetectors())
for _, layer := range req.Layers { layerMap := map[string]*database.Layer{}
layerMapLock := sync.RWMutex{}
g, analyzerCtx := errgroup.WithContext(ctx)
for i := range req.Layers {
layer := req.Layers[i]
if _, ok := layerMap[layer.Hash]; !ok {
layerMap[layer.Hash] = nil
if layer == nil { if layer == nil {
err := status.Error(codes.InvalidArgument, "ancestry layer is invalid") err := status.Error(codes.InvalidArgument, "ancestry layer is invalid")
return nil, err return nil, err
@ -97,18 +106,27 @@ func (s *AncestryServer) PostAncestry(ctx context.Context, req *pb.PostAncestryR
return nil, status.Error(codes.InvalidArgument, "ancestry layer path should not be empty") return nil, status.Error(codes.InvalidArgument, "ancestry layer path should not be empty")
} }
// TODO(sidac): make AnalyzeLayer to be async to ensure g.Go(func() error {
// non-blocking downloads. clairLayer, err := clair.AnalyzeLayer(analyzerCtx, s.Store, layer.Hash, req.Format, layer.Path, layer.Headers)
// We'll need to deal with two layers post by the same or different
// requests that may have the same hash. In that case, since every
// layer/feature/namespace is unique in the database, it may introduce
// deadlock.
clairLayer, err := clair.AnalyzeLayer(ctx, s.Store, layer.Hash, req.Format, layer.Path, layer.Headers)
if err != nil { if err != nil {
return err
}
layerMapLock.Lock()
layerMap[layer.Hash] = clairLayer
layerMapLock.Unlock()
return nil
})
}
}
if err = g.Wait(); err != nil {
return nil, newRPCErrorWithClairError(codes.Internal, err) return nil, newRPCErrorWithClairError(codes.Internal, err)
} }
builder.AddLeafLayer(clairLayer) for _, layer := range req.Layers {
builder.AddLeafLayer(layerMap[layer.Hash])
} }
if err := clair.SaveAncestry(s.Store, builder.Ancestry(req.AncestryName)); err != nil { if err := clair.SaveAncestry(s.Store, builder.Ancestry(req.AncestryName)); err != nil {