204 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			204 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
/*
 | 
						|
Copyright 2020 The Kubernetes 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 value
 | 
						|
 | 
						|
// Allocator provides a value object allocation strategy.
 | 
						|
// Value objects can be allocated by passing an allocator to the "Using"
 | 
						|
// receiver functions on the value interfaces, e.g. Map.ZipUsing(allocator, ...).
 | 
						|
// Value objects returned from "Using" functions should be given back to the allocator
 | 
						|
// once longer needed by calling Allocator.Free(Value).
 | 
						|
type Allocator interface {
 | 
						|
	// Free gives the allocator back any value objects returned by the "Using"
 | 
						|
	// receiver functions on the value interfaces.
 | 
						|
	// interface{} may be any of: Value, Map, List or Range.
 | 
						|
	Free(interface{})
 | 
						|
 | 
						|
	// The unexported functions are for "Using" receiver functions of the value types
 | 
						|
	// to request what they need from the allocator.
 | 
						|
	allocValueUnstructured() *valueUnstructured
 | 
						|
	allocListUnstructuredRange() *listUnstructuredRange
 | 
						|
	allocValueReflect() *valueReflect
 | 
						|
	allocMapReflect() *mapReflect
 | 
						|
	allocStructReflect() *structReflect
 | 
						|
	allocListReflect() *listReflect
 | 
						|
	allocListReflectRange() *listReflectRange
 | 
						|
}
 | 
						|
 | 
						|
// HeapAllocator simply allocates objects to the heap. It is the default
 | 
						|
// allocator used receiver functions on the value interfaces that do not accept
 | 
						|
// an allocator and should be used whenever allocating objects that will not
 | 
						|
// be given back to an allocator by calling Allocator.Free(Value).
 | 
						|
var HeapAllocator = &heapAllocator{}
 | 
						|
 | 
						|
type heapAllocator struct{}
 | 
						|
 | 
						|
func (p *heapAllocator) allocValueUnstructured() *valueUnstructured {
 | 
						|
	return &valueUnstructured{}
 | 
						|
}
 | 
						|
 | 
						|
func (p *heapAllocator) allocListUnstructuredRange() *listUnstructuredRange {
 | 
						|
	return &listUnstructuredRange{vv: &valueUnstructured{}}
 | 
						|
}
 | 
						|
 | 
						|
func (p *heapAllocator) allocValueReflect() *valueReflect {
 | 
						|
	return &valueReflect{}
 | 
						|
}
 | 
						|
 | 
						|
func (p *heapAllocator) allocStructReflect() *structReflect {
 | 
						|
	return &structReflect{}
 | 
						|
}
 | 
						|
 | 
						|
func (p *heapAllocator) allocMapReflect() *mapReflect {
 | 
						|
	return &mapReflect{}
 | 
						|
}
 | 
						|
 | 
						|
func (p *heapAllocator) allocListReflect() *listReflect {
 | 
						|
	return &listReflect{}
 | 
						|
}
 | 
						|
 | 
						|
func (p *heapAllocator) allocListReflectRange() *listReflectRange {
 | 
						|
	return &listReflectRange{vr: &valueReflect{}}
 | 
						|
}
 | 
						|
 | 
						|
func (p *heapAllocator) Free(_ interface{}) {}
 | 
						|
 | 
						|
// NewFreelistAllocator creates freelist based allocator.
 | 
						|
// This allocator provides fast allocation and freeing of short lived value objects.
 | 
						|
//
 | 
						|
// The freelists are bounded in size by freelistMaxSize. If more than this amount of value objects is
 | 
						|
// allocated at once, the excess will be returned to the heap for garbage collection when freed.
 | 
						|
//
 | 
						|
// This allocator is unsafe and must not be accessed concurrently by goroutines.
 | 
						|
//
 | 
						|
// This allocator works well for traversal of value data trees. Typical usage is to acquire
 | 
						|
// a freelist at the beginning of the traversal and use it through out
 | 
						|
// for all temporary value access.
 | 
						|
func NewFreelistAllocator() Allocator {
 | 
						|
	return &freelistAllocator{
 | 
						|
		valueUnstructured: &freelist{new: func() interface{} {
 | 
						|
			return &valueUnstructured{}
 | 
						|
		}},
 | 
						|
		listUnstructuredRange: &freelist{new: func() interface{} {
 | 
						|
			return &listUnstructuredRange{vv: &valueUnstructured{}}
 | 
						|
		}},
 | 
						|
		valueReflect: &freelist{new: func() interface{} {
 | 
						|
			return &valueReflect{}
 | 
						|
		}},
 | 
						|
		mapReflect: &freelist{new: func() interface{} {
 | 
						|
			return &mapReflect{}
 | 
						|
		}},
 | 
						|
		structReflect: &freelist{new: func() interface{} {
 | 
						|
			return &structReflect{}
 | 
						|
		}},
 | 
						|
		listReflect: &freelist{new: func() interface{} {
 | 
						|
			return &listReflect{}
 | 
						|
		}},
 | 
						|
		listReflectRange: &freelist{new: func() interface{} {
 | 
						|
			return &listReflectRange{vr: &valueReflect{}}
 | 
						|
		}},
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Bound memory usage of freelists. This prevents the processing of very large lists from leaking memory.
 | 
						|
// This limit is large enough for endpoints objects containing 1000 IP address entries. Freed objects
 | 
						|
// that don't fit into the freelist are orphaned on the heap to be garbage collected.
 | 
						|
const freelistMaxSize = 1000
 | 
						|
 | 
						|
type freelistAllocator struct {
 | 
						|
	valueUnstructured     *freelist
 | 
						|
	listUnstructuredRange *freelist
 | 
						|
	valueReflect          *freelist
 | 
						|
	mapReflect            *freelist
 | 
						|
	structReflect         *freelist
 | 
						|
	listReflect           *freelist
 | 
						|
	listReflectRange      *freelist
 | 
						|
}
 | 
						|
 | 
						|
type freelist struct {
 | 
						|
	list []interface{}
 | 
						|
	new  func() interface{}
 | 
						|
}
 | 
						|
 | 
						|
func (f *freelist) allocate() interface{} {
 | 
						|
	var w2 interface{}
 | 
						|
	if n := len(f.list); n > 0 {
 | 
						|
		w2, f.list = f.list[n-1], f.list[:n-1]
 | 
						|
	} else {
 | 
						|
		w2 = f.new()
 | 
						|
	}
 | 
						|
	return w2
 | 
						|
}
 | 
						|
 | 
						|
func (f *freelist) free(v interface{}) {
 | 
						|
	if len(f.list) < freelistMaxSize {
 | 
						|
		f.list = append(f.list, v)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (w *freelistAllocator) Free(value interface{}) {
 | 
						|
	switch v := value.(type) {
 | 
						|
	case *valueUnstructured:
 | 
						|
		v.Value = nil // don't hold references to unstructured objects
 | 
						|
		w.valueUnstructured.free(v)
 | 
						|
	case *listUnstructuredRange:
 | 
						|
		v.vv.Value = nil // don't hold references to unstructured objects
 | 
						|
		w.listUnstructuredRange.free(v)
 | 
						|
	case *valueReflect:
 | 
						|
		v.ParentMapKey = nil
 | 
						|
		v.ParentMap = nil
 | 
						|
		w.valueReflect.free(v)
 | 
						|
	case *mapReflect:
 | 
						|
		w.mapReflect.free(v)
 | 
						|
	case *structReflect:
 | 
						|
		w.structReflect.free(v)
 | 
						|
	case *listReflect:
 | 
						|
		w.listReflect.free(v)
 | 
						|
	case *listReflectRange:
 | 
						|
		v.vr.ParentMapKey = nil
 | 
						|
		v.vr.ParentMap = nil
 | 
						|
		w.listReflectRange.free(v)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (w *freelistAllocator) allocValueUnstructured() *valueUnstructured {
 | 
						|
	return w.valueUnstructured.allocate().(*valueUnstructured)
 | 
						|
}
 | 
						|
 | 
						|
func (w *freelistAllocator) allocListUnstructuredRange() *listUnstructuredRange {
 | 
						|
	return w.listUnstructuredRange.allocate().(*listUnstructuredRange)
 | 
						|
}
 | 
						|
 | 
						|
func (w *freelistAllocator) allocValueReflect() *valueReflect {
 | 
						|
	return w.valueReflect.allocate().(*valueReflect)
 | 
						|
}
 | 
						|
 | 
						|
func (w *freelistAllocator) allocStructReflect() *structReflect {
 | 
						|
	return w.structReflect.allocate().(*structReflect)
 | 
						|
}
 | 
						|
 | 
						|
func (w *freelistAllocator) allocMapReflect() *mapReflect {
 | 
						|
	return w.mapReflect.allocate().(*mapReflect)
 | 
						|
}
 | 
						|
 | 
						|
func (w *freelistAllocator) allocListReflect() *listReflect {
 | 
						|
	return w.listReflect.allocate().(*listReflect)
 | 
						|
}
 | 
						|
 | 
						|
func (w *freelistAllocator) allocListReflectRange() *listReflectRange {
 | 
						|
	return w.listReflectRange.allocate().(*listReflectRange)
 | 
						|
}
 |