2021-12-22 17:39:46 +08:00
|
|
|
package rcmgr
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"sync"
|
|
|
|
|
|
|
|
"github.com/libp2p/go-libp2p-core/network"
|
|
|
|
)
|
|
|
|
|
2021-12-29 23:09:50 +08:00
|
|
|
// resources tracks the current state of resource consumption
|
2021-12-28 22:36:08 +08:00
|
|
|
type resources struct {
|
2021-12-23 21:28:14 +08:00
|
|
|
limit Limit
|
|
|
|
|
|
|
|
nconnsIn, nconnsOut int
|
|
|
|
nstreamsIn, nstreamsOut int
|
|
|
|
nfd int
|
|
|
|
|
2021-12-29 00:18:40 +08:00
|
|
|
memory int64
|
2021-12-23 17:13:12 +08:00
|
|
|
}
|
|
|
|
|
2021-12-28 02:56:23 +08:00
|
|
|
// A ResourceScope can be a DAG, where a downstream node is not allowed to outlive an upstream node
|
|
|
|
// (ie cannot call Done in the upstream node before the downstream node) and account for resources
|
|
|
|
// using a linearized parent set.
|
|
|
|
// A ResourceScope can be a txn scope, where it has a specific owner; txn scopes create a tree rooted
|
|
|
|
// at the owner (which can be a DAG scope) and can outlive their parents -- this is important because
|
2021-12-29 00:18:40 +08:00
|
|
|
// txn scopes are the main *user* interface for memory management, and the user may call
|
2021-12-28 02:56:23 +08:00
|
|
|
// Done in a txn scope after the system has closed the root of the txn tree in some background
|
|
|
|
// goroutine.
|
|
|
|
// If we didn't make this distinction we would have a double release problem in that case.
|
2021-12-22 17:39:46 +08:00
|
|
|
type ResourceScope struct {
|
2021-12-23 19:49:57 +08:00
|
|
|
sync.Mutex
|
2021-12-24 00:39:25 +08:00
|
|
|
done bool
|
|
|
|
refCnt int
|
2021-12-22 17:39:46 +08:00
|
|
|
|
2021-12-28 22:36:08 +08:00
|
|
|
rc *resources
|
2021-12-28 02:32:29 +08:00
|
|
|
owner *ResourceScope // set in transaction scopes, which define trees
|
|
|
|
constraints []*ResourceScope // set in DAG scopes, it's the linearized parent set
|
2021-12-22 17:39:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
var _ network.ResourceScope = (*ResourceScope)(nil)
|
2021-12-23 17:13:12 +08:00
|
|
|
var _ network.TransactionalScope = (*ResourceScope)(nil)
|
2021-12-22 17:39:46 +08:00
|
|
|
|
2021-12-28 22:36:08 +08:00
|
|
|
func newResources(limit Limit) *resources {
|
|
|
|
return &resources{
|
2021-12-23 22:19:01 +08:00
|
|
|
limit: limit,
|
2021-12-23 19:49:57 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewResourceScope(limit Limit, constraints []*ResourceScope) *ResourceScope {
|
2021-12-24 18:01:53 +08:00
|
|
|
for _, cst := range constraints {
|
|
|
|
cst.IncRef()
|
2021-12-23 19:49:57 +08:00
|
|
|
}
|
2021-12-24 17:44:01 +08:00
|
|
|
return &ResourceScope{
|
2021-12-28 22:36:08 +08:00
|
|
|
rc: newResources(limit),
|
2021-12-24 17:44:01 +08:00
|
|
|
constraints: constraints,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-28 02:32:29 +08:00
|
|
|
func NewTxnResourceScope(owner *ResourceScope) *ResourceScope {
|
|
|
|
return &ResourceScope{
|
2021-12-28 22:36:08 +08:00
|
|
|
rc: newResources(owner.rc.limit),
|
2021-12-28 02:32:29 +08:00
|
|
|
owner: owner,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-23 17:15:46 +08:00
|
|
|
// Resources implementation
|
2021-12-28 22:36:08 +08:00
|
|
|
func (rc *resources) checkMemory(rsvp int64) error {
|
2021-12-28 22:33:16 +08:00
|
|
|
// overflow check; this also has the side effect that we cannot reserve negative memory.
|
2021-12-28 22:34:19 +08:00
|
|
|
newmem := rc.memory + rsvp
|
2021-12-22 18:18:08 +08:00
|
|
|
if newmem < rc.memory {
|
|
|
|
return fmt.Errorf("memory reservation overflow: %w", ErrResourceLimitExceeded)
|
|
|
|
}
|
|
|
|
|
|
|
|
// limit check
|
|
|
|
if newmem > rc.limit.GetMemoryLimit() {
|
|
|
|
return fmt.Errorf("cannot reserve memory: %w", ErrResourceLimitExceeded)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-12-28 22:36:08 +08:00
|
|
|
func (rc *resources) reserveMemory(size int64) error {
|
2021-12-22 18:18:08 +08:00
|
|
|
if err := rc.checkMemory(size); err != nil {
|
|
|
|
return err
|
2021-12-22 17:39:46 +08:00
|
|
|
}
|
|
|
|
|
2021-12-28 22:34:19 +08:00
|
|
|
rc.memory += size
|
2021-12-22 17:39:46 +08:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-12-28 22:36:08 +08:00
|
|
|
func (rc *resources) releaseMemory(size int64) {
|
2021-12-23 17:13:12 +08:00
|
|
|
rc.memory -= size
|
2021-12-22 18:59:01 +08:00
|
|
|
|
|
|
|
// sanity check for bugs upstream
|
|
|
|
if rc.memory < 0 {
|
|
|
|
panic("BUG: too much memory released")
|
|
|
|
}
|
2021-12-22 17:39:46 +08:00
|
|
|
}
|
|
|
|
|
2021-12-28 22:36:08 +08:00
|
|
|
func (rc *resources) addStream(dir network.Direction) error {
|
2021-12-28 02:07:28 +08:00
|
|
|
if dir == network.DirInbound {
|
|
|
|
return rc.addStreams(1, 0)
|
|
|
|
}
|
|
|
|
return rc.addStreams(0, 1)
|
|
|
|
}
|
|
|
|
|
2021-12-28 22:36:08 +08:00
|
|
|
func (rc *resources) addStreams(incount, outcount int) error {
|
2021-12-23 21:28:14 +08:00
|
|
|
if incount > 0 && rc.nstreamsIn+incount > rc.limit.GetStreamLimit(network.DirInbound) {
|
|
|
|
return fmt.Errorf("cannot reserve stream: %w", ErrResourceLimitExceeded)
|
|
|
|
}
|
|
|
|
if outcount > 0 && rc.nstreamsOut+outcount > rc.limit.GetStreamLimit(network.DirOutbound) {
|
2021-12-23 17:13:12 +08:00
|
|
|
return fmt.Errorf("cannot reserve stream: %w", ErrResourceLimitExceeded)
|
|
|
|
}
|
|
|
|
|
2021-12-23 21:28:14 +08:00
|
|
|
rc.nstreamsIn += incount
|
|
|
|
rc.nstreamsOut += outcount
|
2021-12-23 17:13:12 +08:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-12-28 22:36:08 +08:00
|
|
|
func (rc *resources) removeStream(dir network.Direction) {
|
2021-12-28 02:07:28 +08:00
|
|
|
if dir == network.DirInbound {
|
|
|
|
rc.removeStreams(1, 0)
|
|
|
|
} else {
|
|
|
|
rc.removeStreams(0, 1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-28 22:36:08 +08:00
|
|
|
func (rc *resources) removeStreams(incount, outcount int) {
|
2021-12-23 21:28:14 +08:00
|
|
|
rc.nstreamsIn -= incount
|
|
|
|
rc.nstreamsOut -= outcount
|
2021-12-23 17:13:12 +08:00
|
|
|
|
2021-12-23 21:28:14 +08:00
|
|
|
if rc.nstreamsIn < 0 || rc.nstreamsOut < 0 {
|
2021-12-23 17:13:12 +08:00
|
|
|
panic("BUG: too many streams released")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-28 22:36:08 +08:00
|
|
|
func (rc *resources) addConn(dir network.Direction) error {
|
2021-12-28 02:07:28 +08:00
|
|
|
if dir == network.DirInbound {
|
|
|
|
return rc.addConns(1, 0)
|
|
|
|
}
|
|
|
|
return rc.addConns(0, 1)
|
|
|
|
}
|
|
|
|
|
2021-12-28 22:36:08 +08:00
|
|
|
func (rc *resources) addConns(incount, outcount int) error {
|
2021-12-23 21:28:14 +08:00
|
|
|
if incount > 0 && rc.nconnsIn+incount > rc.limit.GetConnLimit(network.DirInbound) {
|
|
|
|
return fmt.Errorf("cannot reserve connection: %w", ErrResourceLimitExceeded)
|
|
|
|
}
|
|
|
|
if outcount > 0 && rc.nconnsOut+outcount > rc.limit.GetConnLimit(network.DirOutbound) {
|
2021-12-23 17:13:12 +08:00
|
|
|
return fmt.Errorf("cannot reserve connection: %w", ErrResourceLimitExceeded)
|
|
|
|
}
|
|
|
|
|
2021-12-23 21:28:14 +08:00
|
|
|
rc.nconnsIn += incount
|
|
|
|
rc.nconnsOut += outcount
|
2021-12-23 17:13:12 +08:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-12-28 22:36:08 +08:00
|
|
|
func (rc *resources) removeConn(dir network.Direction) {
|
2021-12-28 02:07:28 +08:00
|
|
|
if dir == network.DirInbound {
|
|
|
|
rc.removeConns(1, 0)
|
|
|
|
} else {
|
|
|
|
rc.removeConns(0, 1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-28 22:36:08 +08:00
|
|
|
func (rc *resources) removeConns(incount, outcount int) {
|
2021-12-23 21:28:14 +08:00
|
|
|
rc.nconnsIn -= incount
|
|
|
|
rc.nconnsOut -= outcount
|
2021-12-23 17:13:12 +08:00
|
|
|
|
2021-12-23 21:28:14 +08:00
|
|
|
if rc.nconnsIn < 0 || rc.nconnsOut < 0 {
|
2021-12-23 17:13:12 +08:00
|
|
|
panic("BUG: too many connections released")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-28 22:36:08 +08:00
|
|
|
func (rc *resources) addFD(count int) error {
|
2021-12-23 21:28:14 +08:00
|
|
|
if rc.nfd+count > rc.limit.GetFDLimit() {
|
|
|
|
return fmt.Errorf("cannot reserve file descriptor: %w", ErrResourceLimitExceeded)
|
|
|
|
}
|
|
|
|
|
|
|
|
rc.nfd += count
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-12-28 22:36:08 +08:00
|
|
|
func (rc *resources) removeFD(count int) {
|
2021-12-23 21:28:14 +08:00
|
|
|
rc.nfd -= count
|
|
|
|
|
|
|
|
if rc.nfd < 0 {
|
|
|
|
panic("BUG: too many file descriptors released")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-28 22:36:08 +08:00
|
|
|
func (rc *resources) stat() network.ScopeStat {
|
2021-12-23 17:13:12 +08:00
|
|
|
return network.ScopeStat{
|
2021-12-23 23:31:51 +08:00
|
|
|
Memory: rc.memory,
|
|
|
|
NumStreamsInbound: rc.nstreamsIn,
|
|
|
|
NumStreamsOutbound: rc.nstreamsOut,
|
|
|
|
NumConnsInbound: rc.nconnsIn,
|
|
|
|
NumConnsOutbound: rc.nconnsOut,
|
|
|
|
NumFD: rc.nfd,
|
2021-12-23 17:13:12 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ResourceScope implementation
|
|
|
|
func (s *ResourceScope) ReserveMemory(size int) error {
|
2021-12-23 19:49:57 +08:00
|
|
|
s.Lock()
|
|
|
|
defer s.Unlock()
|
2021-12-23 17:13:12 +08:00
|
|
|
|
|
|
|
if s.done {
|
|
|
|
return ErrResourceScopeClosed
|
|
|
|
}
|
|
|
|
|
2021-12-23 21:28:14 +08:00
|
|
|
if err := s.rc.reserveMemory(int64(size)); err != nil {
|
2021-12-23 17:13:12 +08:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := s.reserveMemoryForConstraints(size); err != nil {
|
|
|
|
s.rc.releaseMemory(int64(size))
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *ResourceScope) reserveMemoryForConstraints(size int) error {
|
2021-12-28 02:32:29 +08:00
|
|
|
if s.owner != nil {
|
|
|
|
return s.owner.ReserveMemory(size)
|
|
|
|
}
|
|
|
|
|
2021-12-23 17:13:12 +08:00
|
|
|
var reserved int
|
|
|
|
var err error
|
|
|
|
for _, cst := range s.constraints {
|
2021-12-23 21:28:14 +08:00
|
|
|
if err = cst.ReserveMemoryForChild(int64(size)); err != nil {
|
2021-12-23 17:13:12 +08:00
|
|
|
break
|
|
|
|
}
|
|
|
|
reserved++
|
|
|
|
}
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
// we failed because of a constraint; undo memory reservations
|
|
|
|
for _, cst := range s.constraints[:reserved] {
|
|
|
|
cst.ReleaseMemoryForChild(int64(size))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-12-27 21:51:15 +08:00
|
|
|
func (s *ResourceScope) releaseMemoryForConstraints(size int) {
|
2021-12-28 02:32:29 +08:00
|
|
|
if s.owner != nil {
|
|
|
|
s.owner.ReleaseMemory(size)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-12-27 21:51:15 +08:00
|
|
|
for _, cst := range s.constraints {
|
|
|
|
cst.ReleaseMemoryForChild(int64(size))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-23 21:28:14 +08:00
|
|
|
func (s *ResourceScope) ReserveMemoryForChild(size int64) error {
|
2021-12-23 19:49:57 +08:00
|
|
|
s.Lock()
|
|
|
|
defer s.Unlock()
|
2021-12-23 17:13:12 +08:00
|
|
|
|
|
|
|
if s.done {
|
|
|
|
return ErrResourceScopeClosed
|
|
|
|
}
|
|
|
|
|
|
|
|
return s.rc.reserveMemory(size)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *ResourceScope) ReleaseMemory(size int) {
|
2021-12-23 19:49:57 +08:00
|
|
|
s.Lock()
|
|
|
|
defer s.Unlock()
|
2021-12-23 17:13:12 +08:00
|
|
|
|
|
|
|
if s.done {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
s.rc.releaseMemory(int64(size))
|
2021-12-28 06:27:25 +08:00
|
|
|
s.releaseMemoryForConstraints(size)
|
2021-12-23 17:13:12 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *ResourceScope) ReleaseMemoryForChild(size int64) {
|
2021-12-23 19:49:57 +08:00
|
|
|
s.Lock()
|
|
|
|
defer s.Unlock()
|
2021-12-23 17:13:12 +08:00
|
|
|
|
|
|
|
if s.done {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
s.rc.releaseMemory(size)
|
|
|
|
}
|
|
|
|
|
2021-12-23 21:28:14 +08:00
|
|
|
func (s *ResourceScope) AddStream(dir network.Direction) error {
|
2021-12-23 19:49:57 +08:00
|
|
|
s.Lock()
|
|
|
|
defer s.Unlock()
|
2021-12-23 17:13:12 +08:00
|
|
|
|
|
|
|
if s.done {
|
|
|
|
return ErrResourceScopeClosed
|
|
|
|
}
|
|
|
|
|
2021-12-28 02:07:28 +08:00
|
|
|
if err := s.rc.addStream(dir); err != nil {
|
2021-12-23 17:13:12 +08:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-12-28 02:32:29 +08:00
|
|
|
if err := s.addStreamForConstraints(dir); err != nil {
|
|
|
|
s.rc.removeStream(dir)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *ResourceScope) addStreamForConstraints(dir network.Direction) error {
|
|
|
|
if s.owner != nil {
|
|
|
|
return s.owner.AddStream(dir)
|
|
|
|
}
|
|
|
|
|
2021-12-23 17:13:12 +08:00
|
|
|
var err error
|
|
|
|
var reserved int
|
|
|
|
for _, cst := range s.constraints {
|
2021-12-28 02:07:28 +08:00
|
|
|
if err = cst.AddStreamForChild(dir); err != nil {
|
2021-12-23 17:13:12 +08:00
|
|
|
break
|
|
|
|
}
|
|
|
|
reserved++
|
|
|
|
}
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
for _, cst := range s.constraints[:reserved] {
|
2021-12-28 02:07:28 +08:00
|
|
|
cst.RemoveStreamForChild(dir)
|
2021-12-23 17:13:12 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-12-28 02:07:28 +08:00
|
|
|
func (s *ResourceScope) AddStreamForChild(dir network.Direction) error {
|
2021-12-23 19:49:57 +08:00
|
|
|
s.Lock()
|
|
|
|
defer s.Unlock()
|
2021-12-23 17:13:12 +08:00
|
|
|
|
2021-12-24 04:05:04 +08:00
|
|
|
if s.done {
|
|
|
|
return ErrResourceScopeClosed
|
|
|
|
}
|
|
|
|
|
2021-12-28 02:07:28 +08:00
|
|
|
return s.rc.addStream(dir)
|
2021-12-23 17:13:12 +08:00
|
|
|
}
|
|
|
|
|
2021-12-23 21:28:14 +08:00
|
|
|
func (s *ResourceScope) RemoveStream(dir network.Direction) {
|
2021-12-23 19:49:57 +08:00
|
|
|
s.Lock()
|
|
|
|
defer s.Unlock()
|
2021-12-23 17:13:12 +08:00
|
|
|
|
2021-12-24 04:05:04 +08:00
|
|
|
if s.done {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-12-28 02:07:28 +08:00
|
|
|
s.rc.removeStream(dir)
|
2021-12-28 02:32:29 +08:00
|
|
|
s.removeStreamForConstraints(dir)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *ResourceScope) removeStreamForConstraints(dir network.Direction) {
|
|
|
|
if s.owner != nil {
|
|
|
|
s.owner.RemoveStream(dir)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-12-23 17:13:12 +08:00
|
|
|
for _, cst := range s.constraints {
|
2021-12-28 02:07:28 +08:00
|
|
|
cst.RemoveStreamForChild(dir)
|
2021-12-23 17:13:12 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-28 02:07:28 +08:00
|
|
|
func (s *ResourceScope) RemoveStreamForChild(dir network.Direction) {
|
2021-12-23 19:49:57 +08:00
|
|
|
s.Lock()
|
|
|
|
defer s.Unlock()
|
2021-12-24 04:05:04 +08:00
|
|
|
|
|
|
|
if s.done {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-12-28 02:07:28 +08:00
|
|
|
s.rc.removeStream(dir)
|
2021-12-23 17:13:12 +08:00
|
|
|
}
|
|
|
|
|
2021-12-23 21:28:14 +08:00
|
|
|
func (s *ResourceScope) AddConn(dir network.Direction) error {
|
2021-12-23 19:49:57 +08:00
|
|
|
s.Lock()
|
|
|
|
defer s.Unlock()
|
2021-12-23 17:13:12 +08:00
|
|
|
|
|
|
|
if s.done {
|
|
|
|
return ErrResourceScopeClosed
|
|
|
|
}
|
|
|
|
|
2021-12-28 02:07:28 +08:00
|
|
|
if err := s.rc.addConn(dir); err != nil {
|
2021-12-23 17:13:12 +08:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-12-28 02:32:29 +08:00
|
|
|
if err := s.addConnForConstraints(dir); err != nil {
|
|
|
|
s.rc.removeConn(dir)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *ResourceScope) addConnForConstraints(dir network.Direction) error {
|
|
|
|
if s.owner != nil {
|
|
|
|
return s.owner.AddConn(dir)
|
|
|
|
}
|
|
|
|
|
2021-12-23 17:13:12 +08:00
|
|
|
var err error
|
|
|
|
var reserved int
|
|
|
|
for _, cst := range s.constraints {
|
2021-12-28 02:07:28 +08:00
|
|
|
if err = cst.AddConnForChild(dir); err != nil {
|
2021-12-23 17:13:12 +08:00
|
|
|
break
|
|
|
|
}
|
|
|
|
reserved++
|
|
|
|
}
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
for _, cst := range s.constraints[:reserved] {
|
2021-12-28 02:07:28 +08:00
|
|
|
cst.RemoveConnForChild(dir)
|
2021-12-23 17:13:12 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-12-28 02:07:28 +08:00
|
|
|
func (s *ResourceScope) AddConnForChild(dir network.Direction) error {
|
2021-12-23 21:28:14 +08:00
|
|
|
s.Lock()
|
|
|
|
defer s.Unlock()
|
|
|
|
|
2021-12-24 04:05:04 +08:00
|
|
|
if s.done {
|
|
|
|
return ErrResourceScopeClosed
|
|
|
|
}
|
|
|
|
|
2021-12-28 02:07:28 +08:00
|
|
|
return s.rc.addConn(dir)
|
2021-12-23 21:28:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *ResourceScope) RemoveConn(dir network.Direction) {
|
|
|
|
s.Lock()
|
|
|
|
defer s.Unlock()
|
|
|
|
|
2021-12-24 04:05:04 +08:00
|
|
|
if s.done {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-12-28 02:07:28 +08:00
|
|
|
s.rc.removeConn(dir)
|
2021-12-28 02:32:29 +08:00
|
|
|
s.removeConnForConstraints(dir)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *ResourceScope) removeConnForConstraints(dir network.Direction) {
|
|
|
|
if s.owner != nil {
|
|
|
|
s.owner.RemoveConn(dir)
|
|
|
|
}
|
|
|
|
|
2021-12-23 21:28:14 +08:00
|
|
|
for _, cst := range s.constraints {
|
2021-12-28 02:07:28 +08:00
|
|
|
cst.RemoveConnForChild(dir)
|
2021-12-23 21:28:14 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-28 02:07:28 +08:00
|
|
|
func (s *ResourceScope) RemoveConnForChild(dir network.Direction) {
|
2021-12-23 19:49:57 +08:00
|
|
|
s.Lock()
|
|
|
|
defer s.Unlock()
|
2021-12-24 04:05:04 +08:00
|
|
|
|
|
|
|
if s.done {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-12-28 02:07:28 +08:00
|
|
|
s.rc.removeConn(dir)
|
2021-12-23 21:28:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *ResourceScope) AddFD(count int) error {
|
|
|
|
s.Lock()
|
|
|
|
defer s.Unlock()
|
|
|
|
|
2021-12-24 04:05:04 +08:00
|
|
|
if s.done {
|
|
|
|
return ErrResourceScopeClosed
|
|
|
|
}
|
|
|
|
|
2021-12-23 21:28:14 +08:00
|
|
|
if err := s.rc.addFD(count); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-12-28 02:32:29 +08:00
|
|
|
if err := s.addFDForConstraints(count); err != nil {
|
|
|
|
s.rc.removeFD(count)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *ResourceScope) addFDForConstraints(count int) error {
|
|
|
|
if s.owner != nil {
|
|
|
|
return s.owner.AddFD(count)
|
|
|
|
}
|
|
|
|
|
2021-12-23 21:28:14 +08:00
|
|
|
var err error
|
|
|
|
var reserved int
|
|
|
|
for _, cst := range s.constraints {
|
|
|
|
if err = cst.AddFDForChild(count); err != nil {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
reserved++
|
|
|
|
}
|
2021-12-23 17:13:12 +08:00
|
|
|
|
2021-12-23 21:28:14 +08:00
|
|
|
if err != nil {
|
|
|
|
for _, cst := range s.constraints[:reserved] {
|
|
|
|
cst.RemoveFDForChild(count)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *ResourceScope) AddFDForChild(count int) error {
|
|
|
|
s.Lock()
|
|
|
|
defer s.Unlock()
|
2021-12-24 04:05:04 +08:00
|
|
|
|
|
|
|
if s.done {
|
|
|
|
return ErrResourceScopeClosed
|
|
|
|
}
|
|
|
|
|
2021-12-23 21:28:14 +08:00
|
|
|
return s.rc.addFD(count)
|
2021-12-23 17:13:12 +08:00
|
|
|
}
|
|
|
|
|
2021-12-23 21:28:14 +08:00
|
|
|
func (s *ResourceScope) RemoveFD(count int) {
|
2021-12-23 19:49:57 +08:00
|
|
|
s.Lock()
|
|
|
|
defer s.Unlock()
|
2021-12-23 17:13:12 +08:00
|
|
|
|
2021-12-24 04:05:04 +08:00
|
|
|
if s.done {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-12-23 21:28:14 +08:00
|
|
|
s.rc.removeFD(count)
|
2021-12-28 02:32:29 +08:00
|
|
|
s.removeFDForConstraints(count)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *ResourceScope) removeFDForConstraints(count int) {
|
|
|
|
if s.owner != nil {
|
|
|
|
s.owner.RemoveFD(count)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-12-23 17:13:12 +08:00
|
|
|
for _, cst := range s.constraints {
|
2021-12-23 21:28:14 +08:00
|
|
|
cst.RemoveFDForChild(count)
|
2021-12-22 19:27:39 +08:00
|
|
|
}
|
2021-12-23 17:13:12 +08:00
|
|
|
}
|
|
|
|
|
2021-12-23 21:28:14 +08:00
|
|
|
func (s *ResourceScope) RemoveFDForChild(count int) {
|
2021-12-23 19:49:57 +08:00
|
|
|
s.Lock()
|
|
|
|
defer s.Unlock()
|
2021-12-24 04:05:04 +08:00
|
|
|
|
|
|
|
if s.done {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-12-23 21:28:14 +08:00
|
|
|
s.rc.removeFD(count)
|
2021-12-23 17:13:12 +08:00
|
|
|
}
|
|
|
|
|
2021-12-26 19:35:21 +08:00
|
|
|
func (s *ResourceScope) ReserveForChild(st network.ScopeStat) error {
|
|
|
|
s.Lock()
|
|
|
|
defer s.Unlock()
|
|
|
|
|
|
|
|
if s.done {
|
|
|
|
return ErrResourceScopeClosed
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := s.rc.reserveMemory(st.Memory); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-12-28 02:07:28 +08:00
|
|
|
if err := s.rc.addStreams(st.NumStreamsInbound, st.NumStreamsOutbound); err != nil {
|
2021-12-26 19:35:21 +08:00
|
|
|
s.rc.releaseMemory(st.Memory)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-12-28 02:07:28 +08:00
|
|
|
if err := s.rc.addConns(st.NumConnsInbound, st.NumConnsOutbound); err != nil {
|
2021-12-26 19:35:21 +08:00
|
|
|
s.rc.releaseMemory(st.Memory)
|
2021-12-28 02:07:28 +08:00
|
|
|
s.rc.removeStreams(st.NumStreamsInbound, st.NumStreamsOutbound)
|
2021-12-26 19:35:21 +08:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := s.rc.addFD(st.NumFD); err != nil {
|
|
|
|
s.rc.releaseMemory(st.Memory)
|
2021-12-28 02:07:28 +08:00
|
|
|
s.rc.removeStreams(st.NumStreamsInbound, st.NumStreamsOutbound)
|
|
|
|
s.rc.removeConns(st.NumConnsInbound, st.NumConnsOutbound)
|
2021-12-26 19:35:21 +08:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *ResourceScope) ReleaseForChild(st network.ScopeStat) {
|
|
|
|
s.Lock()
|
|
|
|
defer s.Unlock()
|
|
|
|
|
|
|
|
if s.done {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
s.rc.releaseMemory(st.Memory)
|
2021-12-28 02:07:28 +08:00
|
|
|
s.rc.removeStreams(st.NumStreamsInbound, st.NumStreamsOutbound)
|
|
|
|
s.rc.removeConns(st.NumConnsInbound, st.NumConnsOutbound)
|
2021-12-26 19:35:21 +08:00
|
|
|
s.rc.removeFD(st.NumFD)
|
|
|
|
}
|
|
|
|
|
2021-12-28 02:32:29 +08:00
|
|
|
func (s *ResourceScope) ReleaseResources(st network.ScopeStat) {
|
|
|
|
s.Lock()
|
|
|
|
defer s.Unlock()
|
|
|
|
|
|
|
|
if s.done {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
s.rc.releaseMemory(st.Memory)
|
|
|
|
s.rc.removeStreams(st.NumStreamsInbound, st.NumStreamsOutbound)
|
|
|
|
s.rc.removeConns(st.NumConnsInbound, st.NumConnsOutbound)
|
|
|
|
s.rc.removeFD(st.NumFD)
|
|
|
|
|
|
|
|
if s.owner != nil {
|
|
|
|
s.owner.ReleaseResources(st)
|
|
|
|
} else {
|
|
|
|
for _, cst := range s.constraints {
|
|
|
|
cst.ReleaseForChild(st)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-29 00:18:40 +08:00
|
|
|
func (s *ResourceScope) BeginTransaction() (network.TransactionalScope, error) {
|
2021-12-24 17:44:01 +08:00
|
|
|
s.Lock()
|
|
|
|
defer s.Unlock()
|
|
|
|
|
|
|
|
if s.done {
|
|
|
|
return nil, ErrResourceScopeClosed
|
|
|
|
}
|
|
|
|
|
2021-12-28 06:27:25 +08:00
|
|
|
s.refCnt++
|
2021-12-28 02:32:29 +08:00
|
|
|
return NewTxnResourceScope(s), nil
|
2021-12-24 17:44:01 +08:00
|
|
|
}
|
|
|
|
|
2021-12-23 17:13:12 +08:00
|
|
|
func (s *ResourceScope) Done() {
|
2021-12-23 19:49:57 +08:00
|
|
|
s.Lock()
|
|
|
|
defer s.Unlock()
|
2021-12-23 17:13:12 +08:00
|
|
|
|
|
|
|
if s.done {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-12-26 19:35:21 +08:00
|
|
|
stat := s.rc.stat()
|
2021-12-28 02:32:29 +08:00
|
|
|
if s.owner != nil {
|
|
|
|
s.owner.ReleaseResources(stat)
|
|
|
|
s.owner.DecRef()
|
|
|
|
} else {
|
|
|
|
for _, cst := range s.constraints {
|
|
|
|
cst.ReleaseForChild(stat)
|
|
|
|
cst.DecRef()
|
|
|
|
}
|
2021-12-24 17:44:01 +08:00
|
|
|
}
|
|
|
|
|
2021-12-23 21:28:14 +08:00
|
|
|
s.rc.nstreamsIn = 0
|
|
|
|
s.rc.nstreamsOut = 0
|
|
|
|
s.rc.nconnsIn = 0
|
|
|
|
s.rc.nconnsOut = 0
|
|
|
|
s.rc.nfd = 0
|
2021-12-23 17:28:10 +08:00
|
|
|
s.rc.memory = 0
|
2021-12-23 17:13:12 +08:00
|
|
|
|
|
|
|
s.done = true
|
|
|
|
}
|
2021-12-22 19:27:39 +08:00
|
|
|
|
2021-12-23 17:13:12 +08:00
|
|
|
func (s *ResourceScope) Stat() network.ScopeStat {
|
2021-12-23 19:49:57 +08:00
|
|
|
s.Lock()
|
|
|
|
defer s.Unlock()
|
2021-12-22 17:39:46 +08:00
|
|
|
|
2021-12-23 17:13:12 +08:00
|
|
|
return s.rc.stat()
|
2021-12-22 17:39:46 +08:00
|
|
|
}
|
2021-12-24 00:18:02 +08:00
|
|
|
|
2021-12-24 00:39:25 +08:00
|
|
|
func (s *ResourceScope) IncRef() {
|
|
|
|
s.Lock()
|
|
|
|
defer s.Unlock()
|
|
|
|
|
|
|
|
s.refCnt++
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *ResourceScope) DecRef() {
|
|
|
|
s.Lock()
|
|
|
|
defer s.Unlock()
|
|
|
|
|
|
|
|
s.refCnt--
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *ResourceScope) IsUnused() bool {
|
|
|
|
s.Lock()
|
|
|
|
defer s.Unlock()
|
|
|
|
|
|
|
|
if s.done {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
if s.refCnt > 0 {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
st := s.rc.stat()
|
2021-12-24 00:18:02 +08:00
|
|
|
return st.NumStreamsInbound == 0 &&
|
|
|
|
st.NumStreamsOutbound == 0 &&
|
|
|
|
st.NumConnsInbound == 0 &&
|
|
|
|
st.NumConnsOutbound == 0 &&
|
|
|
|
st.NumFD == 0
|
|
|
|
}
|