feat: load model from oci image

This commit is contained in:
2023-05-05 17:07:29 +02:00
parent b57698380e
commit 9fb01f7be9
441 changed files with 61395 additions and 15356 deletions

View File

@@ -0,0 +1,84 @@
/*
Copyright The ORAS Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package syncutil
import (
"context"
"golang.org/x/sync/errgroup"
"golang.org/x/sync/semaphore"
)
// LimitedRegion provides a way to bound concurrent access to a code block.
type LimitedRegion struct {
ctx context.Context
limiter *semaphore.Weighted
ended bool
}
// LimitRegion creates a new LimitedRegion.
func LimitRegion(ctx context.Context, limiter *semaphore.Weighted) *LimitedRegion {
if limiter == nil {
return nil
}
return &LimitedRegion{
ctx: ctx,
limiter: limiter,
ended: true,
}
}
// Start starts the region with concurrency limit.
func (lr *LimitedRegion) Start() error {
if lr == nil || !lr.ended {
return nil
}
if err := lr.limiter.Acquire(lr.ctx, 1); err != nil {
return err
}
lr.ended = false
return nil
}
// End ends the region with concurrency limit.
func (lr *LimitedRegion) End() {
if lr == nil || lr.ended {
return
}
lr.limiter.Release(1)
lr.ended = true
}
// GoFunc represents a function that can be invoked by Go.
type GoFunc[T any] func(ctx context.Context, region *LimitedRegion, t T) error
// Go concurrently invokes fn on items.
func Go[T any](ctx context.Context, limiter *semaphore.Weighted, fn GoFunc[T], items ...T) error {
eg, egCtx := errgroup.WithContext(ctx)
for _, item := range items {
region := LimitRegion(ctx, limiter)
if err := region.Start(); err != nil {
return err
}
eg.Go(func(t T) func() error {
return func() error {
defer region.End()
return fn(egCtx, region, t)
}
}(item))
}
return eg.Wait()
}

View File

@@ -0,0 +1,67 @@
/*
Copyright The ORAS Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package syncutil
import (
"context"
"golang.org/x/sync/errgroup"
)
// A LimitedGroup is a collection of goroutines working on subtasks that are part of
// the same overall task.
type LimitedGroup struct {
grp *errgroup.Group
ctx context.Context
}
// LimitGroup returns a new LimitedGroup and an associated Context derived from ctx.
//
// The number of active goroutines in this group is limited to the given limit.
// A negative value indicates no limit.
//
// The derived Context is canceled the first time a function passed to Go
// returns a non-nil error or the first time Wait returns, whichever occurs
// first.
func LimitGroup(ctx context.Context, limit int) (*LimitedGroup, context.Context) {
grp, ctx := errgroup.WithContext(ctx)
grp.SetLimit(limit)
return &LimitedGroup{grp: grp, ctx: ctx}, ctx
}
// Go calls the given function in a new goroutine.
// It blocks until the new goroutine can be added without the number of
// active goroutines in the group exceeding the configured limit.
//
// The first call to return a non-nil error cancels the group's context.
// After which, any subsequent calls to Go will not execute their given function.
// The error will be returned by Wait.
func (g *LimitedGroup) Go(f func() error) {
g.grp.Go(func() error {
select {
case <-g.ctx.Done():
return g.ctx.Err()
default:
return f()
}
})
}
// Wait blocks until all function calls from the Go method have returned, then
// returns the first non-nil error (if any) from them.
func (g *LimitedGroup) Wait() error {
return g.grp.Wait()
}

View File

@@ -0,0 +1,140 @@
/*
Copyright The ORAS Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package syncutil
import "sync"
// mergeStatus represents the merge status of an item.
type mergeStatus struct {
// main indicates if items are being merged by the current go-routine.
main bool
// err represents the error of the merge operation.
err error
}
// Merge represents merge operations on items.
// The state transfer is shown as below:
//
// +----------+
// | Start +--------+-------------+
// +----+-----+ | |
// | | |
// v v v
// +----+-----+ +----+----+ +----+----+
// +-------+ Prepare +<--+ Pending +-->+ Waiting |
// | +----+-----+ +---------+ +----+----+
// | | |
// | v |
// | + ---+---- + |
// On Error | Resolve | |
// | + ---+---- + |
// | | |
// | v |
// | +----+-----+ |
// +------>+ Complete +<---------------------+
// +----+-----+
// |
// v
// +----+-----+
// | End |
// +----------+
type Merge[T any] struct {
lock sync.Mutex
committed bool
items []T
status chan mergeStatus
pending []T
pendingStatus chan mergeStatus
}
// Do merges concurrent operations of items into a single call of prepare and
// resolve.
// If Do is called multiple times concurrently, only one of the calls will be
// selected to invoke prepare and resolve.
func (m *Merge[T]) Do(item T, prepare func() error, resolve func(items []T) error) error {
status := <-m.assign(item)
if status.main {
err := prepare()
items := m.commit()
if err == nil {
err = resolve(items)
}
m.complete(err)
return err
}
return status.err
}
// assign adds a new item into the item list.
func (m *Merge[T]) assign(item T) <-chan mergeStatus {
m.lock.Lock()
defer m.lock.Unlock()
if m.committed {
if m.pendingStatus == nil {
m.pendingStatus = make(chan mergeStatus, 1)
}
m.pending = append(m.pending, item)
return m.pendingStatus
}
if m.status == nil {
m.status = make(chan mergeStatus, 1)
m.status <- mergeStatus{main: true}
}
m.items = append(m.items, item)
return m.status
}
// commit closes the assignment window, and the assigned items will be ready
// for resolve.
func (m *Merge[T]) commit() []T {
m.lock.Lock()
defer m.lock.Unlock()
m.committed = true
return m.items
}
// complete completes the previous merge, and moves the pending items to the
// stage for the next merge.
func (m *Merge[T]) complete(err error) {
// notify results
if err == nil {
close(m.status)
} else {
remaining := len(m.items) - 1
status := m.status
for remaining > 0 {
status <- mergeStatus{err: err}
remaining--
}
}
// move pending items to the stage
m.lock.Lock()
defer m.lock.Unlock()
m.committed = false
m.items = m.pending
m.status = m.pendingStatus
m.pending = nil
m.pendingStatus = nil
if m.status != nil {
m.status <- mergeStatus{main: true}
}
}

View File

@@ -0,0 +1,70 @@
/*
Copyright The ORAS Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package syncutil
import "context"
// Once is an object that will perform exactly one action.
// Unlike sync.Once, this Once allowes the action to have return values.
type Once struct {
result interface{}
err error
status chan bool
}
// NewOnce creates a new Once instance.
func NewOnce() *Once {
status := make(chan bool, 1)
status <- true
return &Once{
status: status,
}
}
// Do calls the function f if and only if Do is being called first time or all
// previous function calls are cancelled, deadline exceeded, or panicking.
// When `once.Do(ctx, f)` is called multiple times, the return value of the
// first call of the function f is stored, and is directly returned for other
// calls.
// Besides the return value of the function f, including the error, Do returns
// true if the function f passed is called first and is not cancelled, deadline
// exceeded, or panicking. Otherwise, returns false.
func (o *Once) Do(ctx context.Context, f func() (interface{}, error)) (bool, interface{}, error) {
defer func() {
if r := recover(); r != nil {
o.status <- true
panic(r)
}
}()
for {
select {
case inProgress := <-o.status:
if !inProgress {
return false, o.result, o.err
}
result, err := f()
if err == context.Canceled || err == context.DeadlineExceeded {
o.status <- true
return false, nil, err
}
o.result, o.err = result, err
close(o.status)
return true, result, err
case <-ctx.Done():
return false, nil, ctx.Err()
}
}
}

View File

@@ -0,0 +1,64 @@
/*
Copyright The ORAS Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package syncutil
import "sync"
// poolItem represents an item in Pool.
type poolItem[T any] struct {
value T
refCount int
}
// Pool is a scalable pool with items identified by keys.
type Pool[T any] struct {
// New optionally specifies a function to generate a value when Get would
// otherwise return nil.
// It may not be changed concurrently with calls to Get.
New func() T
lock sync.Mutex
items map[any]*poolItem[T]
}
// Get gets the value identified by key.
// The caller should invoke the returned function after using the returned item.
func (p *Pool[T]) Get(key any) (*T, func()) {
p.lock.Lock()
defer p.lock.Unlock()
item, ok := p.items[key]
if !ok {
if p.items == nil {
p.items = make(map[any]*poolItem[T])
}
item = &poolItem[T]{}
if p.New != nil {
item.value = p.New()
}
p.items[key] = item
}
item.refCount++
return &item.value, func() {
p.lock.Lock()
defer p.lock.Unlock()
item.refCount--
if item.refCount <= 0 {
delete(p.items, key)
}
}
}