Skip to content
Snippets Groups Projects
results.go 2.3 KiB
Newer Older
  • Learn to ignore specific revisions
  • ale's avatar
    ale committed
    package probes
    
    import (
    	"fmt"
    	"sync"
    	"time"
    )
    
    
    // Result of the execution of a probe.
    
    ale's avatar
    ale committed
    type Result struct {
    	ID       string
    	Spec     SpecCommon
    	Ok       bool
    
    ale's avatar
    ale committed
    	Start    time.Time
    	Duration time.Duration
    	Logs     string
    }
    
    // Nice displayable string.
    func (r *Result) String() string {
    	return fmt.Sprintf("%s(%s)", r.Spec.Name, r.ID)
    }
    
    
    // ResultStore keeps the most recent probe results in storage, and
    // allows access to them (mostly for debugging purposes, as this part
    // isn't required by the prober functionality). The results buffer has
    // a fixed size, so older results will be dropped as more recent ones
    // come in. Failures are kept in a separate buffer, with the hope of
    // keeping errors around for longer for inspection purposes, even
    // after they've recovered.
    
    ale's avatar
    ale committed
    type ResultStore interface {
    	Push(*Result)
    
    	Each(func(*Result))
    	EachErrs(func(*Result))
    
    ale's avatar
    ale committed
    	Find(string) *Result
    }
    
    
    // Very simple overwriting circular buffer of results.
    type resultBuffer struct {
    	buf      []*Result
    	sz, head int
    }
    
    func newResultBuffer(sz int) *resultBuffer {
    	return &resultBuffer{
    		buf: make([]*Result, sz),
    		sz:  sz,
    	}
    }
    
    func (b *resultBuffer) Push(result *Result) {
    	b.buf[b.head] = result
    	b.head++
    	if b.head >= b.sz {
    		b.head -= b.sz
    	}
    }
    
    func (b *resultBuffer) Each(f func(*Result)) {
    	for i := 0; i < b.sz; i++ {
    		pos := b.head + i
    		if pos >= b.sz {
    			pos -= b.sz
    		}
    		if b.buf[pos] != nil {
    			f(b.buf[pos])
    		}
    	}
    }
    
    // ResultStore that keeps recent results in memory.
    
    ale's avatar
    ale committed
    type memResultStore struct {
    	mx   sync.Mutex
    
    	last *resultBuffer
    	errs *resultBuffer
    
    ale's avatar
    ale committed
    }
    
    func NewResultStore(numOk, numErrs int) ResultStore {
    	return &memResultStore{
    
    		last: newResultBuffer(numOk),
    		errs: newResultBuffer(numErrs),
    
    ale's avatar
    ale committed
    	}
    }
    
    func (r *memResultStore) Push(result *Result) {
    	r.mx.Lock()
    
    	r.last.Push(result)
    
    ale's avatar
    ale committed
    	if !result.Ok {
    
    		r.errs.Push(result)
    
    ale's avatar
    ale committed
    	}
    	r.mx.Unlock()
    }
    
    
    func (r *memResultStore) Each(f func(*Result)) {
    
    ale's avatar
    ale committed
    	r.mx.Lock()
    
    	r.last.Each(f)
    
    ale's avatar
    ale committed
    	r.mx.Unlock()
    }
    
    
    func (r *memResultStore) EachErrs(f func(*Result)) {
    
    ale's avatar
    ale committed
    	r.mx.Lock()
    
    	r.errs.Each(f)
    
    ale's avatar
    ale committed
    	r.mx.Unlock()
    }
    
    func (r *memResultStore) Find(id string) (out *Result) {
    	r.mx.Lock()
    
    	defer r.mx.Unlock()
    
    	r.last.Each(func(r *Result) {
    		if r.ID == id {
    			out = r
    
    ale's avatar
    ale committed
    		}
    	})
    
    	if out != nil {
    		return
    	}
    	r.errs.Each(func(r *Result) {
    		if r.ID == id {
    			out = r
    		}
    	})
    
    ale's avatar
    ale committed
    	return
    }