llbsolver: allow sharing modes for cache mounts

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
docker-18.09
Tonis Tiigi 2018-06-18 13:57:36 -07:00
parent 00140b7992
commit ccbf185006
8 changed files with 341 additions and 116 deletions

10
cache/manager.go vendored
View File

@ -17,7 +17,7 @@ import (
)
var (
errLocked = errors.New("locked")
ErrLocked = errors.New("locked")
errNotFound = errors.New("not found")
errInvalid = errors.New("invalid")
)
@ -122,7 +122,7 @@ func (cm *cacheManager) get(ctx context.Context, id string, fromSnapshotter bool
if rec.mutable {
if len(rec.refs) != 0 {
return nil, errors.Wrapf(errLocked, "%s is locked", id)
return nil, errors.Wrapf(ErrLocked, "%s is locked", id)
}
if rec.equalImmutable != nil {
return rec.equalImmutable.ref(), nil
@ -279,12 +279,12 @@ func (cm *cacheManager) GetMutable(ctx context.Context, id string) (MutableRef,
}
if len(rec.refs) != 0 {
return nil, errors.Wrapf(errLocked, "%s is locked", id)
return nil, errors.Wrapf(ErrLocked, "%s is locked", id)
}
if rec.equalImmutable != nil {
if len(rec.equalImmutable.refs) != 0 {
return nil, errors.Wrapf(errLocked, "%s is locked", id)
return nil, errors.Wrapf(ErrLocked, "%s is locked", id)
}
delete(cm.records, rec.equalImmutable.ID())
if err := rec.equalImmutable.remove(ctx, false); err != nil {
@ -513,7 +513,7 @@ func (cm *cacheManager) DiskUsage(ctx context.Context, opt client.DiskUsageInfo)
}
func IsLocked(err error) bool {
return errors.Cause(err) == errLocked
return errors.Cause(err) == ErrLocked
}
func IsNotFound(err error) bool {

View File

@ -54,7 +54,7 @@ func TestManager(t *testing.T) {
_, err = cm.GetMutable(ctx, active.ID())
require.Error(t, err)
require.Equal(t, errLocked, errors.Cause(err))
require.Equal(t, ErrLocked, errors.Cause(err))
checkDiskUsage(ctx, t, cm, 1, 0)
@ -65,7 +65,7 @@ func TestManager(t *testing.T) {
_, err = cm.GetMutable(ctx, active.ID())
require.Error(t, err)
require.Equal(t, errLocked, errors.Cause(err))
require.Equal(t, ErrLocked, errors.Cause(err))
err = snap.Release(ctx)
require.NoError(t, err)
@ -261,7 +261,7 @@ func TestLazyCommit(t *testing.T) {
_, err = cm.GetMutable(ctx, active.ID())
require.Error(t, err)
require.Equal(t, errLocked, errors.Cause(err))
require.Equal(t, ErrLocked, errors.Cause(err))
// immutable refs still work
snap2, err := cm.Get(ctx, snap.ID())
@ -282,7 +282,7 @@ func TestLazyCommit(t *testing.T) {
// active can't be get while immutable is held
_, err = cm.GetMutable(ctx, active.ID())
require.Error(t, err)
require.Equal(t, errLocked, errors.Cause(err))
require.Equal(t, ErrLocked, errors.Cause(err))
err = snap.Release(ctx)
require.NoError(t, err)

View File

@ -53,6 +53,9 @@ func TestClientIntegration(t *testing.T) {
testProxyEnv,
testLocalSymlinkEscape,
testTmpfsMounts,
testSharedCacheMounts,
testLockedCacheMounts,
testDuplicateCacheMount,
})
}
@ -487,7 +490,7 @@ func testBuildPushAndValidate(t *testing.T, sb integration.Sandbox) {
st = busybox.Run(llb.Shlex(cmd), llb.Dir("/wd")).AddMount("/wd", st)
}
run(`sh -c "mkdir -p foo/sub; echo -n first > foo/sub/bar; chmod 0741 foo;"`)
run(`sh -e -c "mkdir -p foo/sub; echo -n first > foo/sub/bar; chmod 0741 foo;"`)
run(`true`) // this doesn't create a layer
run(`sh -c "echo -n second > foo/sub/baz"`)
@ -748,10 +751,10 @@ func testCachedMounts(t *testing.T, sb integration.Sandbox) {
base := st.AddMount("/wd", llb.Scratch())
st = busybox.Run(llb.Shlex(`sh -c "echo -n first > foo"`), llb.Dir("/wd"))
st.AddMount("/wd", llb.Scratch(), llb.AsPersistentCacheDir("mycache1"))
st.AddMount("/wd", llb.Scratch(), llb.AsPersistentCacheDir("mycache1", llb.CacheMountShared))
st = st.Run(llb.Shlex(`sh -c "cat foo && echo -n second > /wd2/bar"`), llb.Dir("/wd"))
st.AddMount("/wd", llb.Scratch(), llb.AsPersistentCacheDir("mycache1"))
st.AddMount("/wd2", base, llb.AsPersistentCacheDir("mycache2"))
st.AddMount("/wd", llb.Scratch(), llb.AsPersistentCacheDir("mycache1", llb.CacheMountShared))
st.AddMount("/wd2", base, llb.AsPersistentCacheDir("mycache2", llb.CacheMountShared))
def, err := st.Marshal()
require.NoError(t, err)
@ -766,8 +769,8 @@ func testCachedMounts(t *testing.T, sb integration.Sandbox) {
// second build using cache directories
st = busybox.Run(llb.Shlex(`sh -c "cp /src0/foo . && cp /src1/bar . && cp /src1/baz ."`), llb.Dir("/wd"))
out := st.AddMount("/wd", llb.Scratch())
st.AddMount("/src0", llb.Scratch(), llb.AsPersistentCacheDir("mycache1"))
st.AddMount("/src1", base, llb.AsPersistentCacheDir("mycache2"))
st.AddMount("/src0", llb.Scratch(), llb.AsPersistentCacheDir("mycache1", llb.CacheMountShared))
st.AddMount("/src1", base, llb.AsPersistentCacheDir("mycache2", llb.CacheMountShared))
destDir, err := ioutil.TempDir("", "buildkit")
require.NoError(t, err)
@ -797,6 +800,76 @@ func testCachedMounts(t *testing.T, sb integration.Sandbox) {
checkAllReleasable(t, c, sb, true)
}
func testSharedCacheMounts(t *testing.T, sb integration.Sandbox) {
requiresLinux(t)
t.Parallel()
c, err := New(context.TODO(), sb.Address())
require.NoError(t, err)
defer c.Close()
busybox := llb.Image("busybox:latest")
st := busybox.Run(llb.Shlex(`sh -e -c "touch one; while [[ ! -f two ]]; do ls -l; usleep 500000; done"`), llb.Dir("/wd"))
st.AddMount("/wd", llb.Scratch(), llb.AsPersistentCacheDir("mycache1", llb.CacheMountShared))
st2 := busybox.Run(llb.Shlex(`sh -e -c "touch two; while [[ ! -f one ]]; do ls -l; usleep 500000; done"`), llb.Dir("/wd"))
st2.AddMount("/wd", llb.Scratch(), llb.AsPersistentCacheDir("mycache1", llb.CacheMountShared))
out := busybox.Run(llb.Shlex("true"))
out.AddMount("/m1", st.Root())
out.AddMount("/m2", st2.Root())
def, err := out.Marshal()
require.NoError(t, err)
_, err = c.Solve(context.TODO(), def, SolveOpt{}, nil)
require.NoError(t, err)
}
func testLockedCacheMounts(t *testing.T, sb integration.Sandbox) {
requiresLinux(t)
t.Parallel()
c, err := New(context.TODO(), sb.Address())
require.NoError(t, err)
defer c.Close()
busybox := llb.Image("busybox:latest")
st := busybox.Run(llb.Shlex(`sh -e -c "touch one; if [[ -f two ]]; then exit 0; fi; for i in $(seq 10); do if [[ -f two ]]; then exit 1; fi; usleep 200000; done"`), llb.Dir("/wd"))
st.AddMount("/wd", llb.Scratch(), llb.AsPersistentCacheDir("mycache1", llb.CacheMountLocked))
st2 := busybox.Run(llb.Shlex(`sh -e -c "touch two; if [[ -f one ]]; then exit 0; fi; for i in $(seq 10); do if [[ -f one ]]; then exit 1; fi; usleep 200000; done"`), llb.Dir("/wd"))
st2.AddMount("/wd", llb.Scratch(), llb.AsPersistentCacheDir("mycache1", llb.CacheMountLocked))
out := busybox.Run(llb.Shlex("true"))
out.AddMount("/m1", st.Root())
out.AddMount("/m2", st2.Root())
def, err := out.Marshal()
require.NoError(t, err)
_, err = c.Solve(context.TODO(), def, SolveOpt{}, nil)
require.NoError(t, err)
}
func testDuplicateCacheMount(t *testing.T, sb integration.Sandbox) {
requiresLinux(t)
t.Parallel()
c, err := New(context.TODO(), sb.Address())
require.NoError(t, err)
defer c.Close()
busybox := llb.Image("busybox:latest")
out := busybox.Run(llb.Shlex(`sh -e -c "[[ ! -f /m2/foo ]]; touch /m1/foo; [[ -f /m2/foo ]];"`))
out.AddMount("/m1", llb.Scratch(), llb.AsPersistentCacheDir("mycache1", llb.CacheMountLocked))
out.AddMount("/m2", llb.Scratch(), llb.AsPersistentCacheDir("mycache1", llb.CacheMountLocked))
def, err := out.Marshal()
require.NoError(t, err)
_, err = c.Solve(context.TODO(), def, SolveOpt{}, nil)
require.NoError(t, err)
}
// containerd/containerd#2119
func testDuplicateWhiteouts(t *testing.T, sb integration.Sandbox) {
requiresLinux(t)
@ -812,7 +885,7 @@ func testDuplicateWhiteouts(t *testing.T, sb integration.Sandbox) {
st = busybox.Run(llb.Shlex(cmd), llb.Dir("/wd")).AddMount("/wd", st)
}
run(`sh -c "mkdir -p d0 d1; echo -n first > d1/bar;"`)
run(`sh -e -c "mkdir -p d0 d1; echo -n first > d1/bar;"`)
run(`sh -c "rm -rf d0 d1"`)
def, err := st.Marshal()

View File

@ -36,13 +36,14 @@ func NewExecOp(root Output, meta Meta, readOnly bool, md OpMetadata) *ExecOp {
}
type mount struct {
target string
readonly bool
source Output
output Output
selector string
cacheID string
tmpfs bool
target string
readonly bool
source Output
output Output
selector string
cacheID string
tmpfs bool
cacheSharing CacheMountSharingMode
// hasOutput bool
}
@ -190,6 +191,14 @@ func (e *ExecOp) Marshal() (digest.Digest, []byte, *OpMetadata, error) {
pm.CacheOpt = &pb.CacheOpt{
ID: m.cacheID,
}
switch m.cacheSharing {
case CacheMountShared:
pm.CacheOpt.Sharing = pb.CacheSharingOpt_SHARED
case CacheMountPrivate:
pm.CacheOpt.Sharing = pb.CacheSharingOpt_PRIVATE
case CacheMountLocked:
pm.CacheOpt.Sharing = pb.CacheSharingOpt_LOCKED
}
}
if m.tmpfs {
pm.MountType = pb.MountType_TMPFS
@ -273,9 +282,10 @@ func SourcePath(src string) MountOption {
}
}
func AsPersistentCacheDir(id string) MountOption {
func AsPersistentCacheDir(id string, sharing CacheMountSharingMode) MountOption {
return func(m *mount) {
m.cacheID = id
m.cacheSharing = sharing
}
}
@ -385,3 +395,11 @@ type ProxyEnv struct {
FtpProxy string
NoProxy string
}
type CacheMountSharingMode int
const (
CacheMountShared CacheMountSharingMode = iota
CacheMountPrivate
CacheMountLocked
)

View File

@ -61,7 +61,7 @@ func dispatchRunMounts(d *dispatchState, c *instructions.RunCommand, sources []*
mountOpts = append(mountOpts, llb.Readonly)
}
if mount.Type == instructions.MountTypeCache {
mountOpts = append(mountOpts, llb.AsPersistentCacheDir(opt.cacheIDNamespace+"/"+mount.CacheID))
mountOpts = append(mountOpts, llb.AsPersistentCacheDir(opt.cacheIDNamespace+"/"+mount.CacheID, llb.CacheMountShared))
}
if src := path.Join("/", mount.Source); src != "/" {
mountOpts = append(mountOpts, llb.SourcePath(src))

View File

@ -11,9 +11,11 @@ import (
"sort"
"strings"
"sync"
"time"
"github.com/boltdb/bolt"
"github.com/containerd/containerd/mount"
"github.com/docker/docker/pkg/locker"
"github.com/moby/buildkit/cache"
"github.com/moby/buildkit/cache/metadata"
"github.com/moby/buildkit/executor"
@ -37,16 +39,19 @@ type execOp struct {
exec executor.Executor
w worker.Worker
numInputs int
cacheMounts map[string]*cacheRefShare
}
func NewExecOp(v solver.Vertex, op *pb.Op_Exec, cm cache.Manager, md *metadata.Store, exec executor.Executor, w worker.Worker) (solver.Op, error) {
return &execOp{
op: op.Exec,
cm: cm,
md: md,
exec: exec,
numInputs: len(v.Inputs()),
w: w,
op: op.Exec,
cm: cm,
md: md,
exec: exec,
numInputs: len(v.Inputs()),
w: w,
cacheMounts: map[string]*cacheRefShare{},
}, nil
}
@ -165,32 +170,72 @@ func (e *execOp) getMountDeps() ([]dep, error) {
return deps, nil
}
func (e *execOp) getRefCacheDir(ctx context.Context, ref cache.ImmutableRef, id string, m *pb.Mount) (cache.MutableRef, error) {
func (e *execOp) getRefCacheDir(ctx context.Context, ref cache.ImmutableRef, id string, m *pb.Mount, sharing pb.CacheSharingOpt) (mref cache.MutableRef, err error) {
key := "cache-dir:" + id
if ref != nil {
key += ":" + ref.ID()
}
return sharedCacheRefs.get(key, func() (cache.MutableRef, error) {
return e.getRefCacheDirNoCache(ctx, key, ref, id, m)
})
if ref, ok := e.cacheMounts[key]; ok {
return ref.clone(), nil
}
defer func() {
if err == nil {
share := &cacheRefShare{MutableRef: mref, refs: map[*cacheRef]struct{}{}}
e.cacheMounts[key] = share
mref = share.clone()
}
}()
switch sharing {
case pb.CacheSharingOpt_SHARED:
return sharedCacheRefs.get(key, func() (cache.MutableRef, error) {
return e.getRefCacheDirNoCache(ctx, key, ref, id, m, false)
})
case pb.CacheSharingOpt_PRIVATE:
return e.getRefCacheDirNoCache(ctx, key, ref, id, m, false)
case pb.CacheSharingOpt_LOCKED:
return e.getRefCacheDirNoCache(ctx, key, ref, id, m, true)
default:
return nil, errors.Errorf("invalid cache sharing option: %s", sharing.String())
}
}
func (e *execOp) getRefCacheDirNoCache(ctx context.Context, key string, ref cache.ImmutableRef, id string, m *pb.Mount) (cache.MutableRef, error) {
func (e *execOp) getRefCacheDirNoCache(ctx context.Context, key string, ref cache.ImmutableRef, id string, m *pb.Mount, block bool) (cache.MutableRef, error) {
makeMutable := func(cache.ImmutableRef) (cache.MutableRef, error) {
desc := fmt.Sprintf("cached mount %s from exec %s", m.Dest, strings.Join(e.op.Meta.Args, " "))
return e.cm.New(ctx, ref, cache.WithDescription(desc), cache.CachePolicyRetain)
}
sis, err := e.md.Search(key)
if err != nil {
return nil, err
}
for _, si := range sis {
if mRef, err := e.cm.GetMutable(ctx, si.ID()); err == nil {
logrus.Debugf("reusing ref for cache dir: %s", mRef.ID())
return mRef, nil
cacheRefsLocker.Lock(key)
defer cacheRefsLocker.Unlock(key)
for {
sis, err := e.md.Search(key)
if err != nil {
return nil, err
}
locked := false
for _, si := range sis {
if mRef, err := e.cm.GetMutable(ctx, si.ID()); err == nil {
logrus.Debugf("reusing ref for cache dir: %s", mRef.ID())
return mRef, nil
} else if errors.Cause(err) == cache.ErrLocked {
locked = true
}
}
if block && locked {
cacheRefsLocker.Unlock(key)
select {
case <-ctx.Done():
cacheRefsLocker.Lock(key)
return nil, ctx.Err()
case <-time.After(100 * time.Millisecond):
cacheRefsLocker.Lock(key)
}
} else {
break
}
}
mRef, err := makeMutable(ref)
@ -287,7 +332,7 @@ func (e *execOp) Exec(ctx context.Context, inputs []solver.Result) ([]solver.Res
if m.CacheOpt == nil {
return nil, errors.Errorf("missing cache mount options")
}
mRef, err := e.getRefCacheDir(ctx, ref, m.CacheOpt.ID, m)
mRef, err := e.getRefCacheDir(ctx, ref, m.CacheOpt.ID, m, m.CacheOpt.Sharing)
if err != nil {
return nil, err
}
@ -418,6 +463,7 @@ func (m *tmpfsMount) Release() error {
return nil
}
var cacheRefsLocker = locker.New()
var sharedCacheRefs = &cacheRefs{}
type cacheRefs struct {
@ -466,9 +512,11 @@ func (r *cacheRefShare) clone() cache.MutableRef {
}
func (r *cacheRefShare) release(ctx context.Context) error {
r.main.mu.Lock()
defer r.main.mu.Unlock()
delete(r.main.shares, r.key)
if r.main != nil {
r.main.mu.Lock()
defer r.main.mu.Unlock()
delete(r.main.shares, r.key)
}
return r.MutableRef.Release(ctx)
}

View File

@ -50,6 +50,7 @@ var _ = math.Inf
// proto package needs to be updated.
const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
// MountType defines a type of a mount from a supported set
type MountType int32
const (
@ -80,6 +81,34 @@ func (x MountType) String() string {
}
func (MountType) EnumDescriptor() ([]byte, []int) { return fileDescriptorOps, []int{0} }
// CacheSharingOpt defines different sharing modes for cache mount
type CacheSharingOpt int32
const (
// SHARED cache mount can be used concurrently by multiple writers
CacheSharingOpt_SHARED CacheSharingOpt = 0
// PRIVATE creates a new mount if there are multiple writers
CacheSharingOpt_PRIVATE CacheSharingOpt = 1
// LOCKED pauses second writer until first one releases the mount
CacheSharingOpt_LOCKED CacheSharingOpt = 2
)
var CacheSharingOpt_name = map[int32]string{
0: "SHARED",
1: "PRIVATE",
2: "LOCKED",
}
var CacheSharingOpt_value = map[string]int32{
"SHARED": 0,
"PRIVATE": 1,
"LOCKED": 2,
}
func (x CacheSharingOpt) String() string {
return proto.EnumName(CacheSharingOpt_name, int32(x))
}
func (CacheSharingOpt) EnumDescriptor() ([]byte, []int) { return fileDescriptorOps, []int{1} }
// Op represents a vertex of the LLB DAG.
type Op struct {
// inputs is a set of input edges.
@ -415,8 +444,12 @@ func (m *Mount) GetCacheOpt() *CacheOpt {
return nil
}
// CacheOpt defines options specific to cache mounts
type CacheOpt struct {
// ID is an optional namespace for the mount
ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"`
// Sharing is the sharing mode for the mount
Sharing CacheSharingOpt `protobuf:"varint,2,opt,name=sharing,proto3,enum=pb.CacheSharingOpt" json:"sharing,omitempty"`
}
func (m *CacheOpt) Reset() { *m = CacheOpt{} }
@ -431,6 +464,13 @@ func (m *CacheOpt) GetID() string {
return ""
}
func (m *CacheOpt) GetSharing() CacheSharingOpt {
if m != nil {
return m.Sharing
}
return CacheSharingOpt_SHARED
}
// CopyOp copies files across Ops.
type CopyOp struct {
Src []*CopySource `protobuf:"bytes,1,rep,name=src" json:"src,omitempty"`
@ -708,6 +748,7 @@ func init() {
proto.RegisterType((*WorkerConstraint)(nil), "pb.WorkerConstraint")
proto.RegisterType((*Definition)(nil), "pb.Definition")
proto.RegisterEnum("pb.MountType", MountType_name, MountType_value)
proto.RegisterEnum("pb.CacheSharingOpt", CacheSharingOpt_name, CacheSharingOpt_value)
}
func (m *Op) Marshal() (dAtA []byte, err error) {
size := m.Size()
@ -1029,6 +1070,11 @@ func (m *CacheOpt) MarshalTo(dAtA []byte) (int, error) {
i = encodeVarintOps(dAtA, i, uint64(len(m.ID)))
i += copy(dAtA[i:], m.ID)
}
if m.Sharing != 0 {
dAtA[i] = 0x10
i++
i = encodeVarintOps(dAtA, i, uint64(m.Sharing))
}
return i, nil
}
@ -1615,6 +1661,9 @@ func (m *CacheOpt) Size() (n int) {
if l > 0 {
n += 1 + l + sovOps(uint64(l))
}
if m.Sharing != 0 {
n += 1 + sovOps(uint64(m.Sharing))
}
return n
}
@ -2706,6 +2755,25 @@ func (m *CacheOpt) Unmarshal(dAtA []byte) error {
}
m.ID = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Sharing", wireType)
}
m.Sharing = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowOps
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Sharing |= (CacheSharingOpt(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
default:
iNdEx = preIndex
skippy, err := skipOps(dAtA[iNdEx:])
@ -4423,72 +4491,75 @@ var (
func init() { proto.RegisterFile("ops.proto", fileDescriptorOps) }
var fileDescriptorOps = []byte{
// 1062 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0xdd, 0x6e, 0x1b, 0xc5,
0x17, 0xcf, 0xae, 0x3f, 0xb2, 0x7b, 0x36, 0xed, 0xdf, 0xff, 0x21, 0x2a, 0xc6, 0x94, 0xc4, 0x6c,
0x11, 0x72, 0xd3, 0xc6, 0x91, 0x8c, 0x84, 0x2a, 0x2e, 0x2a, 0xe2, 0x0f, 0x14, 0x83, 0x42, 0xaa,
0x49, 0x04, 0x97, 0x91, 0xbd, 0x1e, 0x3b, 0xab, 0x3a, 0x3b, 0xab, 0xdd, 0xd9, 0x24, 0xbe, 0x00,
0x89, 0x3e, 0x01, 0x12, 0x4f, 0xc1, 0x43, 0xc0, 0x75, 0x2f, 0xb9, 0x85, 0x8b, 0x82, 0xc2, 0x8b,
0xa0, 0x73, 0x66, 0xbc, 0xeb, 0x86, 0x22, 0xb5, 0x82, 0x2b, 0xcf, 0x9c, 0xf3, 0x3b, 0x67, 0xce,
0xf9, 0x9d, 0x8f, 0x35, 0xb8, 0x32, 0x4e, 0xdb, 0x71, 0x22, 0x95, 0x64, 0x76, 0x3c, 0x6e, 0xec,
0xce, 0x42, 0x75, 0x96, 0x8d, 0xdb, 0x81, 0x3c, 0xdf, 0x9b, 0xc9, 0x99, 0xdc, 0x23, 0xd5, 0x38,
0x9b, 0xd2, 0x8d, 0x2e, 0x74, 0xd2, 0x26, 0xfe, 0xcf, 0x16, 0xd8, 0x47, 0x31, 0x7b, 0x1f, 0xaa,
0x61, 0x14, 0x67, 0x2a, 0xad, 0x5b, 0xcd, 0x52, 0xcb, 0xeb, 0xb8, 0xed, 0x78, 0xdc, 0x1e, 0xa2,
0x84, 0x1b, 0x05, 0x6b, 0x42, 0x59, 0x5c, 0x89, 0xa0, 0x6e, 0x37, 0xad, 0x96, 0xd7, 0x01, 0x04,
0x0c, 0xae, 0x44, 0x70, 0x14, 0x1f, 0xac, 0x71, 0xd2, 0xb0, 0x0f, 0xa1, 0x9a, 0xca, 0x2c, 0x09,
0x44, 0xbd, 0x44, 0x98, 0x0d, 0xc4, 0x1c, 0x93, 0x84, 0x50, 0x46, 0x8b, 0x9e, 0x02, 0x19, 0x2f,
0xea, 0xe5, 0xc2, 0x53, 0x4f, 0xc6, 0x0b, 0xed, 0x09, 0x35, 0xec, 0x1e, 0x54, 0xc6, 0x59, 0x38,
0x9f, 0xd4, 0x2b, 0x04, 0xf1, 0x10, 0xd2, 0x45, 0x01, 0x61, 0xb4, 0xae, 0x5b, 0x06, 0x5b, 0xc6,
0xfe, 0xb7, 0x50, 0xa1, 0x38, 0xd9, 0xe7, 0x50, 0x9d, 0x84, 0x33, 0x91, 0xaa, 0xba, 0xd5, 0xb4,
0x5a, 0x6e, 0xb7, 0xf3, 0xfc, 0xc5, 0xf6, 0xda, 0x6f, 0x2f, 0xb6, 0x77, 0x56, 0x08, 0x91, 0xb1,
0x88, 0x02, 0x19, 0xa9, 0x51, 0x18, 0x89, 0x24, 0xdd, 0x9b, 0xc9, 0x5d, 0x6d, 0xd2, 0xee, 0xd3,
0x0f, 0x37, 0x1e, 0xd8, 0x7d, 0xa8, 0x84, 0xd1, 0x44, 0x5c, 0x51, 0xb2, 0xa5, 0xee, 0x5b, 0xc6,
0x95, 0x77, 0x94, 0xa9, 0x38, 0x53, 0x43, 0x54, 0x71, 0x8d, 0xf0, 0x87, 0x50, 0xd5, 0x34, 0xb0,
0xbb, 0x50, 0x3e, 0x17, 0x6a, 0x44, 0xcf, 0x7b, 0x1d, 0x07, 0x63, 0x3e, 0x14, 0x6a, 0xc4, 0x49,
0x8a, 0x0c, 0x9f, 0xcb, 0x2c, 0x52, 0x69, 0xdd, 0x2e, 0x18, 0x3e, 0x44, 0x09, 0x37, 0x0a, 0xff,
0x1b, 0x28, 0xa3, 0x01, 0x63, 0x50, 0x1e, 0x25, 0x33, 0x5d, 0x0a, 0x97, 0xd3, 0x99, 0xd5, 0xa0,
0x24, 0xa2, 0x0b, 0xb2, 0x75, 0x39, 0x1e, 0x51, 0x12, 0x5c, 0x4e, 0x88, 0x6a, 0x97, 0xe3, 0x11,
0xed, 0xb2, 0x54, 0x24, 0xc4, 0xab, 0xcb, 0xe9, 0xcc, 0xee, 0x83, 0x1b, 0x27, 0xf2, 0x6a, 0x71,
0x8a, 0xd6, 0x95, 0xa2, 0x2c, 0x4f, 0x50, 0x38, 0x88, 0x2e, 0xb8, 0x13, 0x9b, 0x93, 0xff, 0x9d,
0x0d, 0x15, 0x0a, 0x88, 0xb5, 0x30, 0xfd, 0x38, 0xd3, 0x4c, 0x96, 0xba, 0xcc, 0xa4, 0x0f, 0x44,
0x74, 0x9e, 0x3d, 0x92, 0xde, 0x00, 0x27, 0x15, 0x73, 0x11, 0x28, 0x99, 0x10, 0x57, 0x2e, 0xcf,
0xef, 0x18, 0xce, 0x04, 0xcb, 0xa1, 0x23, 0xa4, 0x33, 0x7b, 0x00, 0x55, 0x49, 0x1c, 0x52, 0x90,
0xff, 0xc0, 0xac, 0x81, 0xa0, 0xf3, 0x44, 0x8c, 0x26, 0x32, 0x9a, 0x2f, 0x28, 0x74, 0x87, 0xe7,
0x77, 0xf6, 0x00, 0x5c, 0x62, 0xed, 0x64, 0x11, 0x8b, 0x7a, 0xb5, 0x69, 0xb5, 0x6e, 0x77, 0x6e,
0xe5, 0x8c, 0xa2, 0x90, 0x17, 0x7a, 0xd6, 0x02, 0x27, 0x18, 0x05, 0x67, 0xe2, 0x28, 0x56, 0xf5,
0xcd, 0x82, 0x83, 0x9e, 0x91, 0xf1, 0x5c, 0xeb, 0x37, 0xc0, 0x59, 0x4a, 0xd9, 0x6d, 0xb0, 0x87,
0x7d, 0xdd, 0x4c, 0xdc, 0x1e, 0xf6, 0xfd, 0xc7, 0x50, 0xd5, 0x6d, 0xca, 0x9a, 0x50, 0x4a, 0x93,
0xc0, 0x8c, 0xca, 0xed, 0x65, 0xff, 0xea, 0x4e, 0xe7, 0xa8, 0xca, 0x73, 0xb7, 0x8b, 0xdc, 0x7d,
0x0e, 0x50, 0xc0, 0xfe, 0x1b, 0x8e, 0xfd, 0x1f, 0x2c, 0x70, 0x96, 0x13, 0xc6, 0xb6, 0x00, 0xc2,
0x89, 0x88, 0x54, 0x38, 0x0d, 0x45, 0x62, 0x02, 0x5f, 0x91, 0xb0, 0x5d, 0xa8, 0x8c, 0x94, 0x4a,
0x96, 0x1d, 0xf8, 0xf6, 0xea, 0x78, 0xb6, 0xf7, 0x51, 0x33, 0x88, 0x54, 0xb2, 0xe0, 0x1a, 0xd5,
0x78, 0x04, 0x50, 0x08, 0xb1, 0xdd, 0x9e, 0x8a, 0x85, 0xf1, 0x8a, 0x47, 0xb6, 0x09, 0x95, 0x8b,
0xd1, 0x3c, 0x13, 0x26, 0x28, 0x7d, 0xf9, 0xc4, 0x7e, 0x64, 0xf9, 0x3f, 0xd9, 0xb0, 0x6e, 0xc6,
0x95, 0x3d, 0x84, 0x75, 0x1a, 0x57, 0x13, 0xd1, 0xab, 0x33, 0x5d, 0x42, 0xd8, 0x5e, 0xbe, 0x87,
0x56, 0x62, 0x34, 0xae, 0xf4, 0x3e, 0x32, 0x31, 0x16, 0x5b, 0xa9, 0x34, 0x11, 0x53, 0xb3, 0x70,
0xa8, 0x14, 0x7d, 0x31, 0x0d, 0xa3, 0x50, 0x85, 0x32, 0xe2, 0xa8, 0x62, 0x0f, 0x97, 0x59, 0x97,
0xc9, 0xe3, 0x9d, 0x55, 0x8f, 0x7f, 0x4f, 0x7a, 0x08, 0xde, 0xca, 0x33, 0xaf, 0xc8, 0xfa, 0x83,
0xd5, 0xac, 0xcd, 0x93, 0xe4, 0x4e, 0x6f, 0xcb, 0x82, 0x85, 0x7f, 0xc1, 0xdf, 0xc7, 0x00, 0x85,
0xcb, 0xd7, 0xef, 0x14, 0xff, 0x47, 0x1b, 0xe0, 0x28, 0xc6, 0x1d, 0x32, 0x19, 0xd1, 0xca, 0xd9,
0x08, 0x67, 0x91, 0x4c, 0xc4, 0x29, 0xf5, 0x37, 0xd9, 0x3b, 0xdc, 0xd3, 0x32, 0x6a, 0x73, 0xb6,
0x0f, 0xde, 0x44, 0xa4, 0x41, 0x12, 0xc6, 0x48, 0x98, 0x21, 0x7d, 0x1b, 0x73, 0x2a, 0xfc, 0xb4,
0xfb, 0x05, 0x42, 0x73, 0xb5, 0x6a, 0xc3, 0xf6, 0xe1, 0xff, 0x97, 0x32, 0x79, 0x2a, 0x92, 0xd3,
0x40, 0x46, 0xa9, 0x4a, 0x46, 0x61, 0xa4, 0x4c, 0x3d, 0x36, 0xd1, 0xd1, 0xd7, 0xa4, 0xec, 0xe5,
0x3a, 0x5e, 0xbb, 0xbc, 0x21, 0x61, 0x1d, 0xd8, 0x10, 0x57, 0xb1, 0x4c, 0x94, 0x09, 0x54, 0x7f,
0x18, 0xfe, 0xa7, 0x3f, 0x31, 0x28, 0xa7, 0x60, 0xb9, 0x27, 0x8a, 0x4b, 0xe3, 0x31, 0xd4, 0x6e,
0xc6, 0xf5, 0x46, 0x1c, 0xdf, 0x03, 0x6f, 0xc5, 0x37, 0x02, 0xbf, 0x22, 0xa0, 0x26, 0x49, 0x5f,
0xfc, 0x67, 0x16, 0x38, 0xcb, 0x4d, 0xc9, 0xde, 0x03, 0x38, 0x53, 0x2a, 0x3e, 0xa5, 0x85, 0x69,
0x1e, 0x71, 0x51, 0x42, 0x08, 0xb6, 0x0d, 0x1e, 0x5e, 0x52, 0xa3, 0xd7, 0x0f, 0x92, 0x45, 0xaa,
0x01, 0xef, 0x82, 0x3b, 0xcd, 0xcd, 0xf5, 0x52, 0x74, 0xa6, 0x4b, 0xeb, 0x77, 0xc0, 0x89, 0xa4,
0xd1, 0xe9, 0xfd, 0xbd, 0x1e, 0x49, 0x52, 0xf9, 0x3b, 0x50, 0xbb, 0xc9, 0x21, 0xbb, 0x03, 0xd5,
0x69, 0x38, 0x57, 0x34, 0x54, 0xf8, 0x45, 0x30, 0x37, 0xff, 0x57, 0x0b, 0xa0, 0x18, 0x00, 0x24,
0x04, 0xa7, 0x03, 0x31, 0x1b, 0x7a, 0x1a, 0xe6, 0xe0, 0x9c, 0x9b, 0xba, 0x9a, 0x6a, 0xdf, 0x7d,
0x79, 0x68, 0xda, 0xcb, 0xb2, 0x13, 0xa5, 0xfa, 0x2b, 0xfa, 0xec, 0xf7, 0x37, 0xfa, 0x8a, 0xe6,
0x2f, 0x34, 0xbe, 0x80, 0x5b, 0x2f, 0xb9, 0x7b, 0xcd, 0x79, 0x2a, 0x7a, 0x6f, 0xa5, 0x62, 0x3b,
0x9f, 0x82, 0x9b, 0x6f, 0x77, 0xe6, 0x40, 0xb9, 0x3b, 0xfc, 0xb2, 0x5f, 0x5b, 0x63, 0x00, 0xd5,
0xe3, 0x41, 0x8f, 0x0f, 0x4e, 0x6a, 0x16, 0x5b, 0x87, 0xd2, 0xf1, 0xf1, 0x41, 0xcd, 0x66, 0x2e,
0x54, 0x7a, 0xfb, 0xbd, 0x83, 0x41, 0xad, 0x84, 0xc7, 0x93, 0xc3, 0x27, 0x9f, 0x1d, 0xd7, 0xca,
0xdd, 0xda, 0xf3, 0xeb, 0x2d, 0xeb, 0x97, 0xeb, 0x2d, 0xeb, 0x8f, 0xeb, 0x2d, 0xeb, 0xfb, 0x3f,
0xb7, 0xd6, 0xc6, 0x55, 0xfa, 0x17, 0xf4, 0xd1, 0x5f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xa8, 0x76,
0x25, 0x54, 0x45, 0x09, 0x00, 0x00,
// 1115 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0x5f, 0x6f, 0x1b, 0x45,
0x10, 0xcf, 0x9d, 0xff, 0xdd, 0xcd, 0xa5, 0xe9, 0xb1, 0x8d, 0x8a, 0x09, 0x25, 0x31, 0x57, 0x84,
0xdc, 0xb4, 0x71, 0x24, 0x23, 0x55, 0x15, 0x0f, 0x15, 0xfe, 0x87, 0x62, 0x4a, 0x70, 0xb4, 0x8e,
0xca, 0x63, 0x64, 0x9f, 0xd7, 0xce, 0xa9, 0xce, 0xed, 0xe9, 0x6e, 0x2f, 0x89, 0x1f, 0x40, 0xa2,
0x9f, 0x00, 0x89, 0x4f, 0xc1, 0x87, 0x80, 0xe7, 0x3e, 0xf2, 0x0a, 0x0f, 0x05, 0x85, 0x2f, 0x82,
0x76, 0x76, 0x7d, 0xe7, 0x86, 0x22, 0xb5, 0xa2, 0x4f, 0xde, 0x9d, 0xf9, 0xcd, 0xef, 0x66, 0x7e,
0xbb, 0x33, 0x6b, 0xb0, 0x79, 0x94, 0x34, 0xa2, 0x98, 0x0b, 0x4e, 0xcc, 0x68, 0xbc, 0xb5, 0x37,
0x0b, 0xc4, 0x69, 0x3a, 0x6e, 0xf8, 0xfc, 0x6c, 0x7f, 0xc6, 0x67, 0x7c, 0x1f, 0x5d, 0xe3, 0x74,
0x8a, 0x3b, 0xdc, 0xe0, 0x4a, 0x85, 0x78, 0xbf, 0x1a, 0x60, 0x0e, 0x22, 0xf2, 0x31, 0x94, 0x83,
0x30, 0x4a, 0x45, 0x52, 0x35, 0x6a, 0x85, 0xba, 0xd3, 0xb4, 0x1b, 0xd1, 0xb8, 0xd1, 0x97, 0x16,
0xaa, 0x1d, 0xa4, 0x06, 0x45, 0x76, 0xc9, 0xfc, 0xaa, 0x59, 0x33, 0xea, 0x4e, 0x13, 0x24, 0xa0,
0x77, 0xc9, 0xfc, 0x41, 0x74, 0xb0, 0x46, 0xd1, 0x43, 0x3e, 0x85, 0x72, 0xc2, 0xd3, 0xd8, 0x67,
0xd5, 0x02, 0x62, 0xd6, 0x25, 0x66, 0x88, 0x16, 0x44, 0x69, 0xaf, 0x64, 0xf2, 0x79, 0xb4, 0xa8,
0x16, 0x73, 0xa6, 0x0e, 0x8f, 0x16, 0x8a, 0x49, 0x7a, 0xc8, 0x5d, 0x28, 0x8d, 0xd3, 0x60, 0x3e,
0xa9, 0x96, 0x10, 0xe2, 0x48, 0x48, 0x5b, 0x1a, 0x10, 0xa3, 0x7c, 0xed, 0x22, 0x98, 0x3c, 0xf2,
0xbe, 0x87, 0x12, 0xe6, 0x49, 0xbe, 0x82, 0xf2, 0x24, 0x98, 0xb1, 0x44, 0x54, 0x8d, 0x9a, 0x51,
0xb7, 0xdb, 0xcd, 0x17, 0x2f, 0x77, 0xd6, 0xfe, 0x78, 0xb9, 0xb3, 0xbb, 0x22, 0x08, 0x8f, 0x58,
0xe8, 0xf3, 0x50, 0x8c, 0x82, 0x90, 0xc5, 0xc9, 0xfe, 0x8c, 0xef, 0xa9, 0x90, 0x46, 0x17, 0x7f,
0xa8, 0x66, 0x20, 0xf7, 0xa0, 0x14, 0x84, 0x13, 0x76, 0x89, 0xc5, 0x16, 0xda, 0xb7, 0x34, 0x95,
0x33, 0x48, 0x45, 0x94, 0x8a, 0xbe, 0x74, 0x51, 0x85, 0xf0, 0xfa, 0x50, 0x56, 0x32, 0x90, 0x3b,
0x50, 0x3c, 0x63, 0x62, 0x84, 0x9f, 0x77, 0x9a, 0x96, 0xcc, 0xf9, 0x90, 0x89, 0x11, 0x45, 0xab,
0x54, 0xf8, 0x8c, 0xa7, 0xa1, 0x48, 0xaa, 0x66, 0xae, 0xf0, 0xa1, 0xb4, 0x50, 0xed, 0xf0, 0xbe,
0x83, 0xa2, 0x0c, 0x20, 0x04, 0x8a, 0xa3, 0x78, 0xa6, 0x8e, 0xc2, 0xa6, 0xb8, 0x26, 0x2e, 0x14,
0x58, 0x78, 0x8e, 0xb1, 0x36, 0x95, 0x4b, 0x69, 0xf1, 0x2f, 0x26, 0x28, 0xb5, 0x4d, 0xe5, 0x52,
0xc6, 0xa5, 0x09, 0x8b, 0x51, 0x57, 0x9b, 0xe2, 0x9a, 0xdc, 0x03, 0x3b, 0x8a, 0xf9, 0xe5, 0xe2,
0x44, 0x46, 0x97, 0xf2, 0x63, 0x39, 0x92, 0xc6, 0x5e, 0x78, 0x4e, 0xad, 0x48, 0xaf, 0xbc, 0x1f,
0x4c, 0x28, 0x61, 0x42, 0xa4, 0x2e, 0xcb, 0x8f, 0x52, 0xa5, 0x64, 0xa1, 0x4d, 0x74, 0xf9, 0x80,
0x42, 0x67, 0xd5, 0x4b, 0xd1, 0xb7, 0xc0, 0x4a, 0xd8, 0x9c, 0xf9, 0x82, 0xc7, 0xa8, 0x95, 0x4d,
0xb3, 0xbd, 0x4c, 0x67, 0x22, 0x8f, 0x43, 0x65, 0x88, 0x6b, 0x72, 0x1f, 0xca, 0x1c, 0x35, 0xc4,
0x24, 0xff, 0x43, 0x59, 0x0d, 0x91, 0xe4, 0x31, 0x1b, 0x4d, 0x78, 0x38, 0x5f, 0x60, 0xea, 0x16,
0xcd, 0xf6, 0xe4, 0x3e, 0xd8, 0xa8, 0xda, 0xf1, 0x22, 0x62, 0xd5, 0x72, 0xcd, 0xa8, 0x6f, 0x34,
0x6f, 0x64, 0x8a, 0x4a, 0x23, 0xcd, 0xfd, 0xa4, 0x0e, 0x96, 0x3f, 0xf2, 0x4f, 0xd9, 0x20, 0x12,
0xd5, 0xcd, 0x5c, 0x83, 0x8e, 0xb6, 0xd1, 0xcc, 0xeb, 0xf5, 0xc1, 0x5a, 0x5a, 0xc9, 0x06, 0x98,
0xfd, 0xae, 0xba, 0x4c, 0xd4, 0xec, 0x77, 0xc9, 0x1e, 0x54, 0x92, 0xd3, 0x51, 0x1c, 0x84, 0x33,
0x2c, 0x75, 0xa3, 0x79, 0x2b, 0x23, 0x19, 0x2a, 0xbb, 0xe4, 0x5a, 0x62, 0xbc, 0xc7, 0x50, 0x56,
0xb7, 0x9a, 0xd4, 0xa0, 0x90, 0xc4, 0xbe, 0xee, 0xac, 0x8d, 0xe5, 0x75, 0x57, 0x8d, 0x41, 0xa5,
0x2b, 0x93, 0xca, 0xcc, 0xa5, 0xf2, 0x28, 0x40, 0x0e, 0x7b, 0x37, 0x47, 0xe2, 0xfd, 0x64, 0x80,
0xb5, 0x6c, 0x48, 0xb2, 0x0d, 0x10, 0x4c, 0x58, 0x28, 0x82, 0x69, 0xc0, 0x62, 0x5d, 0xe7, 0x8a,
0x85, 0xec, 0x41, 0x69, 0x24, 0x44, 0xbc, 0xbc, 0xb0, 0xef, 0xaf, 0x76, 0x73, 0xa3, 0x25, 0x3d,
0xbd, 0x50, 0xc4, 0x0b, 0xaa, 0x50, 0x5b, 0x8f, 0x00, 0x72, 0xa3, 0xbc, 0x9d, 0xcf, 0xd8, 0x42,
0xb3, 0xca, 0x25, 0xd9, 0x84, 0xd2, 0xf9, 0x68, 0x9e, 0x32, 0x9d, 0x94, 0xda, 0x7c, 0x6e, 0x3e,
0x32, 0xbc, 0x5f, 0x4c, 0xa8, 0xe8, 0xee, 0x26, 0x0f, 0xa0, 0x82, 0xdd, 0xad, 0x33, 0x7a, 0x7d,
0xa5, 0x4b, 0x08, 0xd9, 0xcf, 0xc6, 0xd6, 0x4a, 0x8e, 0x9a, 0x4a, 0x8d, 0x2f, 0x9d, 0x63, 0x3e,
0xc4, 0x0a, 0x13, 0x36, 0xd5, 0xf3, 0x09, 0x8f, 0xa2, 0xcb, 0xa6, 0x41, 0x18, 0x88, 0x80, 0x87,
0x54, 0xba, 0xc8, 0x83, 0x65, 0xd5, 0x45, 0x64, 0xbc, 0xbd, 0xca, 0xf8, 0xef, 0xa2, 0xfb, 0xe0,
0xac, 0x7c, 0xe6, 0x35, 0x55, 0x7f, 0xb2, 0x5a, 0xb5, 0xfe, 0x24, 0xd2, 0xa9, 0xe1, 0x9a, 0xab,
0xf0, 0x3f, 0xf4, 0x7b, 0x08, 0x90, 0x53, 0xbe, 0xf9, 0x4d, 0xf1, 0x7e, 0x36, 0x01, 0x06, 0x91,
0x1c, 0x39, 0x93, 0x11, 0x4e, 0xa8, 0xf5, 0x60, 0x16, 0xf2, 0x98, 0x9d, 0x60, 0x3b, 0x60, 0xbc,
0x45, 0x1d, 0x65, 0xc3, 0x6b, 0x4e, 0x5a, 0xe0, 0x4c, 0x58, 0xe2, 0xc7, 0x41, 0x24, 0x05, 0xd3,
0xa2, 0xef, 0xc8, 0x9a, 0x72, 0x9e, 0x46, 0x37, 0x47, 0x28, 0xad, 0x56, 0x63, 0x48, 0x0b, 0xde,
0xbb, 0xe0, 0xf1, 0x33, 0x16, 0x9f, 0xf8, 0x3c, 0x4c, 0x44, 0x3c, 0x0a, 0x42, 0xa1, 0xcf, 0x63,
0x53, 0x12, 0x7d, 0x8b, 0xce, 0x4e, 0xe6, 0xa3, 0xee, 0xc5, 0x35, 0x0b, 0x69, 0xc2, 0x3a, 0xbb,
0x8c, 0x78, 0x2c, 0x74, 0xa2, 0xea, 0x1d, 0xb9, 0xa9, 0x5e, 0x24, 0x69, 0xc7, 0x64, 0xa9, 0xc3,
0xf2, 0xcd, 0xd6, 0x63, 0x70, 0xaf, 0xe7, 0xf5, 0x56, 0x1a, 0xdf, 0x05, 0x67, 0x85, 0x5b, 0x02,
0x9f, 0x22, 0x50, 0x89, 0xa4, 0x36, 0xde, 0x73, 0x03, 0xac, 0xe5, 0x60, 0x25, 0x1f, 0x01, 0x9c,
0x0a, 0x11, 0x9d, 0xe0, 0x7c, 0xd5, 0x1f, 0xb1, 0xa5, 0x05, 0x11, 0x64, 0x07, 0x1c, 0xb9, 0x49,
0xb4, 0x5f, 0x7d, 0x10, 0x23, 0x12, 0x05, 0xf8, 0x10, 0xec, 0x69, 0x16, 0xae, 0x66, 0xa8, 0x35,
0x5d, 0x46, 0x7f, 0x00, 0x56, 0xc8, 0xb5, 0x4f, 0x8d, 0xfb, 0x4a, 0xc8, 0xd1, 0xe5, 0xed, 0x82,
0x7b, 0x5d, 0x43, 0x72, 0x1b, 0xca, 0xd3, 0x60, 0x2e, 0xb0, 0xa9, 0xe4, 0x03, 0xa2, 0x77, 0xde,
0xef, 0x06, 0x40, 0xde, 0x00, 0x52, 0x10, 0xd9, 0x1d, 0x12, 0xb3, 0xae, 0xba, 0x61, 0x0e, 0xd6,
0x99, 0x3e, 0x57, 0x7d, 0xda, 0x77, 0x5e, 0x6d, 0x9a, 0xc6, 0xf2, 0xd8, 0x51, 0x52, 0xf5, 0xe8,
0x3e, 0xff, 0xf3, 0xad, 0x1e, 0xdd, 0xec, 0x0b, 0x5b, 0x4f, 0xe0, 0xc6, 0x2b, 0x74, 0x6f, 0xd8,
0x4f, 0xf9, 0xdd, 0x5b, 0x39, 0xb1, 0xdd, 0x2f, 0xc0, 0xce, 0x1e, 0x03, 0x62, 0x41, 0xb1, 0xdd,
0xff, 0xa6, 0xeb, 0xae, 0x11, 0x80, 0xf2, 0xb0, 0xd7, 0xa1, 0xbd, 0x63, 0xd7, 0x20, 0x15, 0x28,
0x0c, 0x87, 0x07, 0xae, 0x49, 0x6c, 0x28, 0x75, 0x5a, 0x9d, 0x83, 0x9e, 0x5b, 0x90, 0xcb, 0xe3,
0xc3, 0xa3, 0x2f, 0x87, 0x6e, 0x71, 0xf7, 0x21, 0xdc, 0xbc, 0x36, 0xdd, 0x31, 0xfa, 0xa0, 0x45,
0x7b, 0x92, 0xc9, 0x81, 0xca, 0x11, 0xed, 0x3f, 0x6d, 0x1d, 0xf7, 0x5c, 0x43, 0x3a, 0xbe, 0x1e,
0x74, 0x9e, 0xf4, 0xba, 0xae, 0xd9, 0x76, 0x5f, 0x5c, 0x6d, 0x1b, 0xbf, 0x5d, 0x6d, 0x1b, 0x7f,
0x5d, 0x6d, 0x1b, 0x3f, 0xfe, 0xbd, 0xbd, 0x36, 0x2e, 0xe3, 0x9f, 0xad, 0xcf, 0xfe, 0x09, 0x00,
0x00, 0xff, 0xff, 0xa6, 0x74, 0xdc, 0xa3, 0xac, 0x09, 0x00, 0x00,
}

View File

@ -54,6 +54,7 @@ message Mount {
CacheOpt cacheOpt = 20;
}
// MountType defines a type of a mount from a supported set
enum MountType {
BIND = 0;
SECRET = 1;
@ -62,8 +63,22 @@ enum MountType {
TMPFS = 4;
}
// CacheOpt defines options specific to cache mounts
message CacheOpt {
// ID is an optional namespace for the mount
string ID = 1;
// Sharing is the sharing mode for the mount
CacheSharingOpt sharing = 2;
}
// CacheSharingOpt defines different sharing modes for cache mount
enum CacheSharingOpt {
// SHARED cache mount can be used concurrently by multiple writers
SHARED = 0;
// PRIVATE creates a new mount if there are multiple writers
PRIVATE = 1;
// LOCKED pauses second writer until first one releases the mount
LOCKED = 2;
}
// CopyOp copies files across Ops.