Платформа ЦРНП "Мирокод" для разработки проектов
https://git.mirocod.ru
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
149 lines
3.5 KiB
149 lines
3.5 KiB
// Copyright 2012, Google Inc. All rights reserved. |
|
// Use of this source code is governed by a BSD-style |
|
// license that can be found in the LICENSE file. |
|
|
|
package pools |
|
|
|
import ( |
|
"fmt" |
|
"sync" |
|
"time" |
|
) |
|
|
|
// Numbered allows you to manage resources by tracking them with numbers. |
|
// There are no interface restrictions on what you can track. |
|
type Numbered struct { |
|
mu sync.Mutex |
|
empty *sync.Cond // Broadcast when pool becomes empty |
|
resources map[int64]*numberedWrapper |
|
} |
|
|
|
type numberedWrapper struct { |
|
val interface{} |
|
inUse bool |
|
purpose string |
|
timeCreated time.Time |
|
timeUsed time.Time |
|
} |
|
|
|
func NewNumbered() *Numbered { |
|
n := &Numbered{resources: make(map[int64]*numberedWrapper)} |
|
n.empty = sync.NewCond(&n.mu) |
|
return n |
|
} |
|
|
|
// Register starts tracking a resource by the supplied id. |
|
// It does not lock the object. |
|
// It returns an error if the id already exists. |
|
func (nu *Numbered) Register(id int64, val interface{}) error { |
|
nu.mu.Lock() |
|
defer nu.mu.Unlock() |
|
if _, ok := nu.resources[id]; ok { |
|
return fmt.Errorf("already present") |
|
} |
|
now := time.Now() |
|
nu.resources[id] = &numberedWrapper{ |
|
val: val, |
|
timeCreated: now, |
|
timeUsed: now, |
|
} |
|
return nil |
|
} |
|
|
|
// Unregiester forgets the specified resource. |
|
// If the resource is not present, it's ignored. |
|
func (nu *Numbered) Unregister(id int64) { |
|
nu.mu.Lock() |
|
defer nu.mu.Unlock() |
|
delete(nu.resources, id) |
|
if len(nu.resources) == 0 { |
|
nu.empty.Broadcast() |
|
} |
|
} |
|
|
|
// Get locks the resource for use. It accepts a purpose as a string. |
|
// If it cannot be found, it returns a "not found" error. If in use, |
|
// it returns a "in use: purpose" error. |
|
func (nu *Numbered) Get(id int64, purpose string) (val interface{}, err error) { |
|
nu.mu.Lock() |
|
defer nu.mu.Unlock() |
|
nw, ok := nu.resources[id] |
|
if !ok { |
|
return nil, fmt.Errorf("not found") |
|
} |
|
if nw.inUse { |
|
return nil, fmt.Errorf("in use: %s", nw.purpose) |
|
} |
|
nw.inUse = true |
|
nw.purpose = purpose |
|
return nw.val, nil |
|
} |
|
|
|
// Put unlocks a resource for someone else to use. |
|
func (nu *Numbered) Put(id int64) { |
|
nu.mu.Lock() |
|
defer nu.mu.Unlock() |
|
if nw, ok := nu.resources[id]; ok { |
|
nw.inUse = false |
|
nw.purpose = "" |
|
nw.timeUsed = time.Now() |
|
} |
|
} |
|
|
|
// GetOutdated returns a list of resources that are older than age, and locks them. |
|
// It does not return any resources that are already locked. |
|
func (nu *Numbered) GetOutdated(age time.Duration, purpose string) (vals []interface{}) { |
|
nu.mu.Lock() |
|
defer nu.mu.Unlock() |
|
now := time.Now() |
|
for _, nw := range nu.resources { |
|
if nw.inUse { |
|
continue |
|
} |
|
if nw.timeCreated.Add(age).Sub(now) <= 0 { |
|
nw.inUse = true |
|
nw.purpose = purpose |
|
vals = append(vals, nw.val) |
|
} |
|
} |
|
return vals |
|
} |
|
|
|
// GetIdle returns a list of resurces that have been idle for longer |
|
// than timeout, and locks them. It does not return any resources that |
|
// are already locked. |
|
func (nu *Numbered) GetIdle(timeout time.Duration, purpose string) (vals []interface{}) { |
|
nu.mu.Lock() |
|
defer nu.mu.Unlock() |
|
now := time.Now() |
|
for _, nw := range nu.resources { |
|
if nw.inUse { |
|
continue |
|
} |
|
if nw.timeUsed.Add(timeout).Sub(now) <= 0 { |
|
nw.inUse = true |
|
nw.purpose = purpose |
|
vals = append(vals, nw.val) |
|
} |
|
} |
|
return vals |
|
} |
|
|
|
// WaitForEmpty returns as soon as the pool becomes empty |
|
func (nu *Numbered) WaitForEmpty() { |
|
nu.mu.Lock() |
|
defer nu.mu.Unlock() |
|
for len(nu.resources) != 0 { |
|
nu.empty.Wait() |
|
} |
|
} |
|
|
|
func (nu *Numbered) StatsJSON() string { |
|
return fmt.Sprintf("{\"Size\": %v}", nu.Size()) |
|
} |
|
|
|
func (nu *Numbered) Size() (size int64) { |
|
nu.mu.Lock() |
|
defer nu.mu.Unlock() |
|
return int64(len(nu.resources)) |
|
}
|
|
|