Skip to content

codegrapple/reaper

Repository files navigation

reaper

reaper implements a deterministic, bounded rewrite loop over a priority structure.

It repeatedly removes a single elment from a heap, allows controlled reinsertion, and enforces a strict upper bound on growth per step.

Motivation

Many systems require repeatedly rewriting or rescheduling items based on partial information. reaper addresses this need while enforcing three invariants:

  1. Only one element is processed at a time
  2. Reinsertion is explicitly bounded
  3. Callbacks run without holding heap locks

Core Concepts

Heap

A Heap is a priority structure protected by explicit locking. Reaper does not assume ownership of synchronization, allowing it to be integrated into exisiting concurrent systems.

Callback

A Callback inspects a popped element and may emit a replacements.

Visit(front T, emit func(...T) error) (stop bool)
  • emit buffers elements for reinsertion. It returns an error if the buffer is full.
  • emission is bounded by the configured degree
  • returning true stops the reaping process and restores front to the heap without reinsertion

Degree

The degree defines the maximum number of elements a callback may emit for reinsertion per visit.

  • degree > 0: bounded rewrite system (DAG)
  • degree == 0: pure consumer

Usage

r := reaper.New[int](2) // degree 2

cb := reaper.CallbackFunc[int](func(front int, emit func(...int) error) bool {
	if front == 1 {
		emit(4, 5)
	}

	retur false
})

res := r.Reap(heap, cb)

Results

Reap returns one of:

  • Exhausted: the heap became empty
  • Stopped: the callback requested termination

Both of which are perfectly normal outcomes.

Guarantees

  • No heap mutation occurs while callbacks exectue, except caused by another goroutine
  • No callback can cause unbounded growth
  • The heap is always in a valid state

Heap Adapter

The heapadapter subpackage provides adapters for using Go’s container/heap with reaper.

h := &MyHeap{} // implements container/heap.Interface of Item
mu := &sync.Mutex{}

heap := heapadapter.New[Item](h, mu)
r := reaper.New(0)
_ = r.Reap(heap, cb)

About

A deterministic, bounded rewrite loop over a priority structure

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages