<commit_before>// Copyright 2013 Sean Treadway, SoundCloud Ltd. All rights reserved.  Use of
// this source code is governed by a BSD-style license that can be found in the
// LICENSE file.

/*
Package quantile implements a streaming quantile estimator. The implementation
is based on "Effective Computation of Biased Quantiles over Data Streams"
(Cormode, Korn, Muthukrishnan, Srivastava) to provide a space and time
efficient estimator for online quantile estimation.

For the normal distribution of 10^9 elements, a tolerance for 0.99th percentile
at 0.001 uses under 1000 bins at 32 bytes per bin.
*/
package quantile

import (
	"math"
	"sort"
)

type Estimate interface {
	// Delta calculates the acceptable difference in ranks between two values.
	// It is used to remove redundant values during compression.
	Delta(rank, observations float64) float64
}

type bias struct {
	tolerance float64
}

func (b bias) Delta(rank, observations float64) float64 {
	return 2 * b.tolerance * rank
}

// Unknown produces estimations for all possible quantiles at this error tolerance.
// It uses significantly more space and time than when you know the quantiles
// you wish to estimate.
//
// The Known estimation should be used when you know which quantiles you will be
// querying.
func Unknown(tolerance float64) Estimate {
	return bias{tolerance: tolerance}
}

type target struct {
	q  float64 // targeted quantile
	f1 float64 // cached coefficient for fi  q*n <= rank <= n
	f2 float64 // cached coefficient for fii 0 <= rank <= q*n
}

func (t target) Delta(rank, observations float64) float64 {
	if rank <= math.Floor(t.q*observations) {
		return t.f2 * (observations - rank)
	}
	return t.f1 * rank
}

// Known produces a optimal space usage for estimations at the given quantile and error tolerance.
//
// Quantiles not known ahead of time can also be queried, but at a lower accuracy.
func Known(quantile, tolerance float64) Estimate {
	return target{
		q:  quantile,
		f1: 2 * tolerance / quantile,
		f2: 2 * tolerance / (1 - quantile),
	}
}

// the tuple and list element
type item struct {
	v     float64
	rank  float64
	delta float64
	next  *item
}

type Estimator struct {
	// linked list data structure "S", bookeeping in observe/recycle
	head  *item
	items int

	// float64 avoids conversion during invariant checks
	observations float64

	// used to calculate ƒ(r,n)
	invariants []Estimate

	// batching of updates
	buffer []float64

	// free list
	pool chan *item
}

// New allocates a new estimator tolerating the minimum of the invariants provided.
//
// When you know how much error you can tolerate in the quantiles you will
// query, use a Known estimation for each quantile you will query.  For
// example:
//
//    quantile.New(quantile.Known(0.50, 0.01), quantile.Known(0.95, 0.001), quantile.Known(0.99, 0.0005))
//
// When you will query for multiple different quantiles, and know the error
// tolerance, use the Bias invariant.  For example:
//
//    quantile.New(quantile.Unknown(0.01))
//
// Targeted estimators consume significantly less resources than Biased estimators.
//
// Estimators are not safe to use from multiple goroutines.
func New(invariants ...Estimate) *Estimator {
	return &Estimator{
		invariants: invariants,
		buffer:     make([]float64, 0, 512),
		pool:       make(chan *item, 1024),
	}
}

// Add buffers a new sample, committing and compressing the data structure
// when the buffer is full.
func (est *Estimator) Add(value float64) {
	est.buffer = append(est.buffer, value)
	if len(est.buffer) == cap(est.buffer) {
		est.flush()
	}
}

// Get finds a value within (quantile - tolerance) * n <= value <= (quantile + tolerance) * n
func (est *Estimator) Get(quantile float64) float64 {
	est.flush()

	cur := est.head
	if cur == nil {
		return 0
	}

	midrank := math.Floor(quantile * est.observations)
	maxrank := midrank + math.Floor(est.invariant(midrank, est.observations)/2)

	rank := 0.0
	for cur.next != nil {
		rank += cur.rank
		if rank+cur.next.rank+cur.next.delta > maxrank {
			return cur.v
		}
		cur = cur.next
	}
	return cur.v
}

// ƒ(r,n) = minⁱ(ƒⁱ(r,n))
func (est *Estimator) invariant(rank float64, n float64) float64 {
	min := (n + 1)
	for _, f := range est.invariants {
		if delta := f.Delta(rank, n); delta < min {
			min = delta
		}
	}
	return math.Floor(min)
}

func (est *Estimator) observe(v float64, rank, delta float64, next *item) *item {
	est.observations++
	est.items++

	// reuse or allocate
	select {
	case old := <-est.pool:
		old.v = v
		old.rank = rank
		old.delta = delta
		old.next = next
		return old
	default:
		return &item{
			v:     v,
			rank:  rank,
			delta: delta,
			next:  next,
		}
	}

	panic("unreachable")
}

func (est *Estimator) recycle(old *item) {
	est.items--
	select {
	case est.pool <- old:
	default:
	}
}

// merges the batch
func (est *Estimator) update(batch []float64) {
	// initial data
	if est.head == nil {
		est.head = est.observe(batch[0], 1, 0, nil)
		batch = batch[1:]
	}

	rank := 0.0
	cur := est.head
	for _, v := range batch {
		// min
		if v < est.head.v {
			est.head = est.observe(v, 1, 0, est.head)
			cur = est.head
			continue
		}

		// cursor
		for cur.next != nil && cur.next.v < v {
			rank += cur.rank
			cur = cur.next
		}

		// max
		if cur.next == nil {
			cur.next = est.observe(v, 1, 0, nil)
			continue
		}

		cur.next = est.observe(v, 1, est.invariant(rank, est.observations)-1, cur.next)
	}
}

func (est *Estimator) compress() {
	rank := 0.0
	cur := est.head
	for cur != nil && cur.next != nil {
		if cur.rank+cur.next.rank+cur.next.delta <= est.invariant(rank, est.observations) {
			// merge with previous/head
			removed := cur.next

			cur.v = removed.v
			cur.rank += removed.rank
			cur.delta = removed.delta
			cur.next = removed.next

			est.recycle(removed)
		}
		rank += cur.rank
		cur = cur.next
	}
}

func (est *Estimator) flush() {
	sort.Float64Slice(est.buffer).Sort()
	est.update(est.buffer)
	est.buffer = est.buffer[0:0]
	est.compress()
}
<commit_msg>Support default construction tolerating 1% error<commit_after>// Copyright 2013 Sean Treadway, SoundCloud Ltd. All rights reserved.  Use of
// this source code is governed by a BSD-style license that can be found in the
// LICENSE file.

/*
Package quantile implements a streaming quantile estimator. The implementation
is based on "Effective Computation of Biased Quantiles over Data Streams"
(Cormode, Korn, Muthukrishnan, Srivastava) to provide a space and time
efficient estimator for online quantile estimation.

For the normal distribution of 10^9 elements, a tolerance for 0.99th percentile
at 0.001 uses under 1000 bins at 32 bytes per bin.
*/
package quantile

import (
	"math"
	"sort"
)

type Estimate interface {
	// Delta calculates the acceptable difference in ranks between two values.
	// It is used to remove redundant values during compression.
	Delta(rank, observations float64) float64
}

type bias struct {
	tolerance float64
}

func (b bias) Delta(rank, observations float64) float64 {
	return 2 * b.tolerance * rank
}

// Unknown produces estimations for all possible quantiles at this error tolerance.
// It uses significantly more space and time than when you know the quantiles
// you wish to estimate.
//
// The Known estimation should be used when you know which quantiles you will be
// querying.
func Unknown(tolerance float64) Estimate {
	return bias{tolerance: tolerance}
}

type target struct {
	q  float64 // targeted quantile
	f1 float64 // cached coefficient for fi  q*n <= rank <= n
	f2 float64 // cached coefficient for fii 0 <= rank <= q*n
}

func (t target) Delta(rank, observations float64) float64 {
	if rank <= math.Floor(t.q*observations) {
		return t.f2 * (observations - rank)
	}
	return t.f1 * rank
}

// Known produces a optimal space usage for estimations at the given quantile and error tolerance.
//
// Quantiles not known ahead of time can also be queried, but at a lower accuracy.
func Known(quantile, tolerance float64) Estimate {
	return target{
		q:  quantile,
		f1: 2 * tolerance / quantile,
		f2: 2 * tolerance / (1 - quantile),
	}
}

// the tuple and list element
type item struct {
	v     float64
	rank  float64
	delta float64
	next  *item
}

type Estimator struct {
	// linked list data structure "S", bookeeping in observe/recycle
	head  *item
	items int

	// float64 avoids conversion during invariant checks
	observations float64

	// used to calculate ƒ(r,n)
	invariants []Estimate

	// batching of updates
	buffer []float64

	// free list
	pool chan *item
}

// New allocates a new estimator tolerating the minimum of the invariants provided.
//
// When you know how much error you can tolerate in the quantiles you will
// query, use a Known estimation for each quantile you will query.  For
// example:
//
//    quantile.New(quantile.Known(0.50, 0.01), quantile.Known(0.95, 0.001), quantile.Known(0.99, 0.0005))
//
// When you will query for multiple different quantiles, and know the error
// tolerance, use the Bias invariant.  For example:
//
//    quantile.New(quantile.Unknown(0.01))
//
// Targeted estimators consume significantly less resources than Biased estimators.
//
// Passing no parameters will create an estimator that has a tolerance of 0.1, equivalent to:
//
//   quantile.New(quantile.Unknown(0.1))
//
// Estimators are not safe to use from multiple goroutines.
func New(invariants ...Estimate) *Estimator {
	if len(invariants) == 0 {
		invariants = append(invariants, Unknown(0.1))
	}

	return &Estimator{
		invariants: invariants,
		buffer:     make([]float64, 0, 512),
		pool:       make(chan *item, 1024),
	}
}

// Add buffers a new sample, committing and compressing the data structure
// when the buffer is full.
func (est *Estimator) Add(value float64) {
	est.buffer = append(est.buffer, value)
	if len(est.buffer) == cap(est.buffer) {
		est.flush()
	}
}

// Get finds a value within (quantile - tolerance) * n <= value <= (quantile + tolerance) * n
func (est *Estimator) Get(quantile float64) float64 {
	est.flush()

	cur := est.head
	if cur == nil {
		return 0
	}

	midrank := math.Floor(quantile * est.observations)
	maxrank := midrank + math.Floor(est.invariant(midrank, est.observations)/2)

	rank := 0.0
	for cur.next != nil {
		rank += cur.rank
		if rank+cur.next.rank+cur.next.delta > maxrank {
			return cur.v
		}
		cur = cur.next
	}
	return cur.v
}

// ƒ(r,n) = minⁱ(ƒⁱ(r,n))
func (est *Estimator) invariant(rank float64, n float64) float64 {
	min := (n + 1)
	for _, f := range est.invariants {
		if delta := f.Delta(rank, n); delta < min {
			min = delta
		}
	}
	return math.Floor(min)
}

func (est *Estimator) observe(v float64, rank, delta float64, next *item) *item {
	est.observations++
	est.items++

	// reuse or allocate
	select {
	case old := <-est.pool:
		old.v = v
		old.rank = rank
		old.delta = delta
		old.next = next
		return old
	default:
		return &item{
			v:     v,
			rank:  rank,
			delta: delta,
			next:  next,
		}
	}

	panic("unreachable")
}

func (est *Estimator) recycle(old *item) {
	est.items--
	select {
	case est.pool <- old:
	default:
	}
}

// merges the batch
func (est *Estimator) update(batch []float64) {
	// initial data
	if est.head == nil {
		est.head = est.observe(batch[0], 1, 0, nil)
		batch = batch[1:]
	}

	rank := 0.0
	cur := est.head
	for _, v := range batch {
		// min
		if v < est.head.v {
			est.head = est.observe(v, 1, 0, est.head)
			cur = est.head
			continue
		}

		// cursor
		for cur.next != nil && cur.next.v < v {
			rank += cur.rank
			cur = cur.next
		}

		// max
		if cur.next == nil {
			cur.next = est.observe(v, 1, 0, nil)
			continue
		}

		cur.next = est.observe(v, 1, est.invariant(rank, est.observations)-1, cur.next)
	}
}

func (est *Estimator) compress() {
	rank := 0.0
	cur := est.head
	for cur != nil && cur.next != nil {
		if cur.rank+cur.next.rank+cur.next.delta <= est.invariant(rank, est.observations) {
			// merge with previous/head
			removed := cur.next

			cur.v = removed.v
			cur.rank += removed.rank
			cur.delta = removed.delta
			cur.next = removed.next

			est.recycle(removed)
		}
		rank += cur.rank
		cur = cur.next
	}
}

func (est *Estimator) flush() {
	sort.Float64Slice(est.buffer).Sort()
	est.update(est.buffer)
	est.buffer = est.buffer[0:0]
	est.compress()
}
<|endoftext|>


<commit_before>package api

import (
	"log"
	"net/http"

	"github.com/mdlayher/wavepipe/data"

	"github.com/gorilla/context"
	"github.com/gorilla/mux"
	"github.com/unrolled/render"
)

// PostLogout destroys an existing session from the wavepipe API, and returns a HTTP status and JSON
func PostLogout(res http.ResponseWriter, req *http.Request) {
	// Retrieve render
	r := context.Get(req, CtxRender).(*render.Render)

	// Attempt to retrieve session from context
	session := new(data.Session)
	if tempSession := context.Get(req, CtxSession); tempSession != nil {
		session = tempSession.(*data.Session)
	} else {
		// No session stored in context
		log.Println("api: no session stored in request context!")
		r.JSON(res, 500, serverErr)
		return
	}

	// Output struct for logout request
	out := ErrorResponse{}

	// Check API version
	if version, ok := mux.Vars(req)["version"]; ok {
		// Check if this API call is supported in the advertised version
		if !apiVersionSet.Has(version) {
			r.JSON(res, 400, errRes(400, "unsupported API version: "+version))
			return
		}
	}

	// Destroy the current API session
	if session != nil {
		if err := session.Delete(); err != nil {
			log.Println(err)
			r.JSON(res, 500, serverErr)
			return
		}
	}

	// No errors
	out.Error = nil

	// HTTP 200 OK with JSON
	r.JSON(res, 200, out)
	return
}
<commit_msg>api/logout: cleanup<commit_after>package api

import (
	"log"
	"net/http"

	"github.com/mdlayher/wavepipe/data"

	"github.com/gorilla/context"
	"github.com/gorilla/mux"
	"github.com/unrolled/render"
)

// PostLogout destroys an existing session from the wavepipe API,
// and returns a HTTP status and JSON.
func PostLogout(w http.ResponseWriter, r *http.Request) {
	// Retrieve render
	ren := context.Get(r, CtxRender).(*render.Render)

	// Attempt to retrieve session from context
	session := new(data.Session)
	if tempSession := context.Get(r, CtxSession); tempSession != nil {
		session = tempSession.(*data.Session)
	} else {
		// No session stored in context
		log.Println("api: no session stored in request context!")
		ren.JSON(w, 500, serverErr)
		return
	}

	// Check API version
	if version, ok := mux.Vars(r)["version"]; ok {
		// Check if this API call is supported in the advertised version
		if !apiVersionSet.Has(version) {
			ren.JSON(w, 400, errRes(400, "unsupported API version: "+version))
			return
		}
	}

	// Destroy the current API session
	if session != nil {
		if err := session.Delete(); err != nil {
			log.Println(err)
			ren.JSON(w, 500, serverErr)
			return
		}
	}

	// HTTP 200 OK with JSON
	ren.JSON(w, 200, ErrorResponse{})
	return
}
<|endoftext|>


<commit_before>package api

import "fmt"

type SwitchAPI struct {
	*baseAPI
}

func NewSwitchAPI(client *Client) *SwitchAPI {
	return &SwitchAPI{
		&baseAPI{
			client: client,
			FuncGetResourceURL: func() string {
				return "switch"
			},
		},
	}
}

func (api *SwitchAPI) DisconnectFromBridge(switchID string) (bool, error) {
	var (
		method = "DELETE"
		uri    = fmt.Sprintf("%s/%s/to/bridge", api.getResourceURL(), switchID)
	)
	return api.modify(method, uri, nil)
}

func (api *SwitchAPI) ConnectToBridge(switchID string, bridgeID string) (bool, error) {
	var (
		method = "PUT"
		uri    = fmt.Sprintf("%s/%s/to/bridge/%s", api.getResourceURL(), switchID, bridgeID)
	)
	return api.modify(method, uri, nil)
}
<commit_msg>Add switch API func : GetServers<commit_after>package api

import (
	"fmt"
	"github.com/yamamoto-febc/libsacloud/sacloud"
)

type SwitchAPI struct {
	*baseAPI
}

func NewSwitchAPI(client *Client) *SwitchAPI {
	return &SwitchAPI{
		&baseAPI{
			client: client,
			FuncGetResourceURL: func() string {
				return "switch"
			},
		},
	}
}

func (api *SwitchAPI) DisconnectFromBridge(switchID string) (bool, error) {
	var (
		method = "DELETE"
		uri    = fmt.Sprintf("%s/%s/to/bridge", api.getResourceURL(), switchID)
	)
	return api.modify(method, uri, nil)
}

func (api *SwitchAPI) ConnectToBridge(switchID string, bridgeID string) (bool, error) {
	var (
		method = "PUT"
		uri    = fmt.Sprintf("%s/%s/to/bridge/%s", api.getResourceURL(), switchID, bridgeID)
	)
	return api.modify(method, uri, nil)
}

func (api *SwitchAPI) GetServers(switchID string) ([]sacloud.Server, error) {
	var (
		method = "GET"
		uri    = fmt.Sprintf("%s/%s/server", api.getResourceURL(), switchID)
		res    = &sacloud.SearchResponse{}
	)
	err := api.baseAPI.request(method, uri, nil, res)
	if err != nil {
		return nil, err
	}
	return res.Servers, nil
}
<|endoftext|>


<commit_before>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Pipe adapter to connect code expecting an io.Reader
// with code expecting an io.Writer.

package io

import (
	"os"
	"runtime"
	"sync"
)

type pipeResult struct {
	n   int
	err os.Error
}

// Shared pipe structure.
type pipe struct {
	// Reader sends on cr1, receives on cr2.
	// Writer does the same on cw1, cw2.
	r1, w1 chan []byte
	r2, w2 chan pipeResult

	rclose chan os.Error // read close; error to return to writers
	wclose chan os.Error // write close; error to return to readers

	done chan int // read or write half is done
}

func (p *pipe) run() {
	var (
		rb    []byte      // pending Read
		wb    []byte      // pending Write
		wn    int         // amount written so far from wb
		rerr  os.Error    // if read end is closed, error to send to writers
		werr  os.Error    // if write end is closed, error to send to readers
		r1    chan []byte // p.cr1 or nil depending on whether Read is ok
		w1    chan []byte // p.cw1 or nil depending on whether Write is ok
		ndone int
	)

	// Read and Write are enabled at the start.
	r1 = p.r1
	w1 = p.w1

	for {
		select {
		case <-p.done:
			if ndone++; ndone == 2 {
				// both reader and writer are gone
				return
			}
			continue
		case rerr = <-p.rclose:
			if w1 == nil {
				// finish pending Write
				p.w2 <- pipeResult{wn, rerr}
				wn = 0
				w1 = p.w1 // allow another Write
			}
			if r1 == nil {
				// Close of read side during Read.
				// finish pending Read with os.EINVAL.
				p.r2 <- pipeResult{0, os.EINVAL}
				r1 = p.r1 // allow another Read
			}
			continue
		case werr = <-p.wclose:
			if r1 == nil {
				// finish pending Read
				p.r2 <- pipeResult{0, werr}
				r1 = p.r1 // allow another Read
			}
			if w1 == nil {
				// Close of write side during Write.
				// finish pending Write with os.EINVAL.
				p.w2 <- pipeResult{wn, os.EINVAL}
				wn = 0
				w1 = p.w1 // allow another Write
			}
			continue
		case rb = <-r1:
			if werr != nil {
				// write end is closed
				p.r2 <- pipeResult{0, werr}
				continue
			}
			r1 = nil // disable Read until this one is done
		case wb = <-w1:
			if rerr != nil {
				// read end is closed
				p.w2 <- pipeResult{0, rerr}
				continue
			}
			w1 = nil // disable Write until this one is done
		}

		if r1 == nil && w1 == nil {
			// Have rb and wb.  Execute.
			n := copy(rb, wb)
			wn += n
			wb = wb[n:]

			// Finish Read.
			p.r2 <- pipeResult{n, nil}
			r1 = p.r1 // allow another Read

			// Maybe finish Write.
			if len(wb) == 0 {
				p.w2 <- pipeResult{wn, nil}
				wn = 0
				w1 = p.w1 // allow another Write
			}
		}
	}
}

// Read/write halves of the pipe.
// They are separate structures for two reasons:
//  1.  If one end becomes garbage without being Closed,
//      its finalizer can Close so that the other end
//      does not hang indefinitely.
//  2.  Clients cannot use interface conversions on the
//      read end to find the Write method, and vice versa.

type pipeHalf struct {
	c1     chan []byte
	c2     chan pipeResult
	cclose chan os.Error
	done   chan int

	lock   sync.Mutex
	closed bool

	io       sync.Mutex
	ioclosed bool
}

func (p *pipeHalf) rw(data []byte) (n int, err os.Error) {
	// Run i/o operation.
	// Check ioclosed flag under lock to make sure we're still allowed to do i/o.
	p.io.Lock()
	defer p.io.Unlock()
	if p.ioclosed {
		return 0, os.EINVAL
	}
	p.c1 <- data
	res := <-p.c2
	return res.n, res.err
}

func (p *pipeHalf) close(err os.Error) os.Error {
	// Close pipe half.
	// Only first call to close does anything.
	p.lock.Lock()
	if p.closed {
		p.lock.Unlock()
		return os.EINVAL
	}
	p.closed = true
	p.lock.Unlock()

	// First, send the close notification.
	p.cclose <- err

	// Runner is now responding to rw operations
	// with os.EINVAL.  Cut off future rw operations
	// by setting ioclosed flag.
	p.io.Lock()
	p.ioclosed = true
	p.io.Unlock()

	// With ioclosed set, there will be no more rw operations
	// working on the channels.
	// Tell the runner we won't be bothering it anymore.
	p.done <- 1

	// Successfully torn down; can disable finalizer.
	runtime.SetFinalizer(p, nil)

	return nil
}

func (p *pipeHalf) finalizer() {
	p.close(os.EINVAL)
}

// A PipeReader is the read half of a pipe.
type PipeReader struct {
	pipeHalf
}

// Read implements the standard Read interface:
// it reads data from the pipe, blocking until a writer
// arrives or the write end is closed.
// If the write end is closed with an error, that error is
// returned as err; otherwise err is nil.
func (r *PipeReader) Read(data []byte) (n int, err os.Error) {
	return r.rw(data)
}

// Close closes the reader; subsequent writes to the
// write half of the pipe will return the error os.EPIPE.
func (r *PipeReader) Close() os.Error {
	return r.CloseWithError(nil)
}

// CloseWithError closes the reader; subsequent writes
// to the write half of the pipe will return the error err.
func (r *PipeReader) CloseWithError(err os.Error) os.Error {
	if err == nil {
		err = os.EPIPE
	}
	return r.close(err)
}

// A PipeWriter is the write half of a pipe.
type PipeWriter struct {
	pipeHalf
}

// Write implements the standard Write interface:
// it writes data to the pipe, blocking until readers
// have consumed all the data or the read end is closed.
// If the read end is closed with an error, that err is
// returned as err; otherwise err is os.EPIPE.
func (w *PipeWriter) Write(data []byte) (n int, err os.Error) {
	return w.rw(data)
}

// Close closes the writer; subsequent reads from the
// read half of the pipe will return no bytes and os.EOF.
func (w *PipeWriter) Close() os.Error {
	return w.CloseWithError(nil)
}

// CloseWithError closes the writer; subsequent reads from the
// read half of the pipe will return no bytes and the error err.
func (w *PipeWriter) CloseWithError(err os.Error) os.Error {
	if err == nil {
		err = os.EOF
	}
	return w.close(err)
}

// Pipe creates a synchronous in-memory pipe.
// It can be used to connect code expecting an io.Reader
// with code expecting an io.Writer.
// Reads on one end are matched with writes on the other,
// copying data directly between the two; there is no internal buffering.
func Pipe() (*PipeReader, *PipeWriter) {
	p := &pipe{
		r1:     make(chan []byte),
		r2:     make(chan pipeResult),
		w1:     make(chan []byte),
		w2:     make(chan pipeResult),
		rclose: make(chan os.Error),
		wclose: make(chan os.Error),
		done:   make(chan int),
	}
	go p.run()

	// NOTE: Cannot use composite literal here:
	//	pipeHalf{c1: p.cr1, c2: p.cr2, cclose: p.crclose, cdone: p.cdone}
	// because this implicitly copies the pipeHalf, which copies the inner mutex.

	r := new(PipeReader)
	r.c1 = p.r1
	r.c2 = p.r2
	r.cclose = p.rclose
	r.done = p.done
	// TODO(rsc): Should be able to write
	//	runtime.SetFinalizer(r, (*PipeReader).finalizer)
	// but 6g doesn't see the finalizer method.
	runtime.SetFinalizer(&r.pipeHalf, (*pipeHalf).finalizer)

	w := new(PipeWriter)
	w.c1 = p.w1
	w.c2 = p.w2
	w.cclose = p.wclose
	w.done = p.done
	// TODO(rsc): Should be able to write
	//	runtime.SetFinalizer(w, (*PipeWriter).finalizer)
	// but 6g doesn't see the finalizer method.
	runtime.SetFinalizer(&w.pipeHalf, (*pipeHalf).finalizer)

	return r, w
}
<commit_msg>io: Avoid race condition in pipe.<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Pipe adapter to connect code expecting an io.Reader
// with code expecting an io.Writer.

package io

import (
	"os"
	"runtime"
	"sync"
)

type pipeResult struct {
	n   int
	err os.Error
}

// Shared pipe structure.
type pipe struct {
	// Reader sends on cr1, receives on cr2.
	// Writer does the same on cw1, cw2.
	r1, w1 chan []byte
	r2, w2 chan pipeResult

	rclose chan os.Error // read close; error to return to writers
	wclose chan os.Error // write close; error to return to readers

	done chan int // read or write half is done
}

func (p *pipe) run() {
	var (
		rb    []byte      // pending Read
		wb    []byte      // pending Write
		wn    int         // amount written so far from wb
		rerr  os.Error    // if read end is closed, error to send to writers
		werr  os.Error    // if write end is closed, error to send to readers
		r1    chan []byte // p.cr1 or nil depending on whether Read is ok
		w1    chan []byte // p.cw1 or nil depending on whether Write is ok
		ndone int
	)

	// Read and Write are enabled at the start.
	r1 = p.r1
	w1 = p.w1

	for {
		select {
		case <-p.done:
			if ndone++; ndone == 2 {
				// both reader and writer are gone
				return
			}
			continue
		case rerr = <-p.rclose:
			if w1 == nil {
				// finish pending Write
				p.w2 <- pipeResult{wn, rerr}
				wn = 0
				w1 = p.w1 // allow another Write
			}
			if r1 == nil {
				// Close of read side during Read.
				// finish pending Read with os.EINVAL.
				p.r2 <- pipeResult{0, os.EINVAL}
				r1 = p.r1 // allow another Read
			}
			continue
		case werr = <-p.wclose:
			if r1 == nil {
				// finish pending Read
				p.r2 <- pipeResult{0, werr}
				r1 = p.r1 // allow another Read
			}
			if w1 == nil {
				// Close of write side during Write.
				// finish pending Write with os.EINVAL.
				p.w2 <- pipeResult{wn, os.EINVAL}
				wn = 0
				w1 = p.w1 // allow another Write
			}
			continue
		case rb = <-r1:
			if werr != nil {
				// write end is closed
				p.r2 <- pipeResult{0, werr}
				continue
			}
			r1 = nil // disable Read until this one is done
		case wb = <-w1:
			if rerr != nil {
				// read end is closed
				p.w2 <- pipeResult{0, rerr}
				continue
			}
			w1 = nil // disable Write until this one is done
		}

		if r1 == nil && w1 == nil {
			// Have rb and wb.  Execute.
			n := copy(rb, wb)
			wn += n
			wb = wb[n:]

			// Finish Read.
			p.r2 <- pipeResult{n, nil}
			r1 = p.r1 // allow another Read

			// Maybe finish Write.
			if len(wb) == 0 {
				p.w2 <- pipeResult{wn, nil}
				wn = 0
				w1 = p.w1 // allow another Write
			}
		}
	}
}

// Read/write halves of the pipe.
// They are separate structures for two reasons:
//  1.  If one end becomes garbage without being Closed,
//      its finalizer can Close so that the other end
//      does not hang indefinitely.
//  2.  Clients cannot use interface conversions on the
//      read end to find the Write method, and vice versa.

type pipeHalf struct {
	c1     chan []byte
	c2     chan pipeResult
	cclose chan os.Error
	done   chan int

	lock   sync.Mutex
	closed bool

	io       sync.Mutex
	ioclosed bool
}

func (p *pipeHalf) rw(data []byte) (n int, err os.Error) {
	// Run i/o operation.
	// Check ioclosed flag under lock to make sure we're still allowed to do i/o.
	p.io.Lock()
	if p.ioclosed {
		p.io.Unlock()
		return 0, os.EINVAL
	}
	p.io.Unlock()
	p.c1 <- data
	res := <-p.c2
	return res.n, res.err
}

func (p *pipeHalf) close(err os.Error) os.Error {
	// Close pipe half.
	// Only first call to close does anything.
	p.lock.Lock()
	if p.closed {
		p.lock.Unlock()
		return os.EINVAL
	}
	p.closed = true
	p.lock.Unlock()

	// First, send the close notification.
	p.cclose <- err

	// Runner is now responding to rw operations
	// with os.EINVAL.  Cut off future rw operations
	// by setting ioclosed flag.
	p.io.Lock()
	p.ioclosed = true
	p.io.Unlock()

	// With ioclosed set, there will be no more rw operations
	// working on the channels.
	// Tell the runner we won't be bothering it anymore.
	p.done <- 1

	// Successfully torn down; can disable finalizer.
	runtime.SetFinalizer(p, nil)

	return nil
}

func (p *pipeHalf) finalizer() {
	p.close(os.EINVAL)
}

// A PipeReader is the read half of a pipe.
type PipeReader struct {
	pipeHalf
}

// Read implements the standard Read interface:
// it reads data from the pipe, blocking until a writer
// arrives or the write end is closed.
// If the write end is closed with an error, that error is
// returned as err; otherwise err is nil.
func (r *PipeReader) Read(data []byte) (n int, err os.Error) {
	return r.rw(data)
}

// Close closes the reader; subsequent writes to the
// write half of the pipe will return the error os.EPIPE.
func (r *PipeReader) Close() os.Error {
	return r.CloseWithError(nil)
}

// CloseWithError closes the reader; subsequent writes
// to the write half of the pipe will return the error err.
func (r *PipeReader) CloseWithError(err os.Error) os.Error {
	if err == nil {
		err = os.EPIPE
	}
	return r.close(err)
}

// A PipeWriter is the write half of a pipe.
type PipeWriter struct {
	pipeHalf
}

// Write implements the standard Write interface:
// it writes data to the pipe, blocking until readers
// have consumed all the data or the read end is closed.
// If the read end is closed with an error, that err is
// returned as err; otherwise err is os.EPIPE.
func (w *PipeWriter) Write(data []byte) (n int, err os.Error) {
	return w.rw(data)
}

// Close closes the writer; subsequent reads from the
// read half of the pipe will return no bytes and os.EOF.
func (w *PipeWriter) Close() os.Error {
	return w.CloseWithError(nil)
}

// CloseWithError closes the writer; subsequent reads from the
// read half of the pipe will return no bytes and the error err.
func (w *PipeWriter) CloseWithError(err os.Error) os.Error {
	if err == nil {
		err = os.EOF
	}
	return w.close(err)
}

// Pipe creates a synchronous in-memory pipe.
// It can be used to connect code expecting an io.Reader
// with code expecting an io.Writer.
// Reads on one end are matched with writes on the other,
// copying data directly between the two; there is no internal buffering.
func Pipe() (*PipeReader, *PipeWriter) {
	p := &pipe{
		r1:     make(chan []byte),
		r2:     make(chan pipeResult),
		w1:     make(chan []byte),
		w2:     make(chan pipeResult),
		rclose: make(chan os.Error),
		wclose: make(chan os.Error),
		done:   make(chan int),
	}
	go p.run()

	// NOTE: Cannot use composite literal here:
	//	pipeHalf{c1: p.cr1, c2: p.cr2, cclose: p.crclose, cdone: p.cdone}
	// because this implicitly copies the pipeHalf, which copies the inner mutex.

	r := new(PipeReader)
	r.c1 = p.r1
	r.c2 = p.r2
	r.cclose = p.rclose
	r.done = p.done
	// TODO(rsc): Should be able to write
	//	runtime.SetFinalizer(r, (*PipeReader).finalizer)
	// but 6g doesn't see the finalizer method.
	runtime.SetFinalizer(&r.pipeHalf, (*pipeHalf).finalizer)

	w := new(PipeWriter)
	w.c1 = p.w1
	w.c2 = p.w2
	w.cclose = p.wclose
	w.done = p.done
	// TODO(rsc): Should be able to write
	//	runtime.SetFinalizer(w, (*PipeWriter).finalizer)
	// but 6g doesn't see the finalizer method.
	runtime.SetFinalizer(&w.pipeHalf, (*pipeHalf).finalizer)

	return r, w
}
<|endoftext|>


<commit_before>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
Package net provides a portable interface for network I/O, including
TCP/IP, UDP, domain name resolution, and Unix domain sockets.

Although the package provides access to low-level networking
primitives, most clients will need only the basic interface provided
by the Dial, Listen, and Accept functions and the associated
Conn and Listener interfaces. The crypto/tls package uses
the same interfaces and similar Dial and Listen functions.

The Dial function connects to a server:

	conn, err := net.Dial("tcp", "google.com:80")
	if err != nil {
		// handle error
	}
	fmt.Fprintf(conn, "GET / HTTP/1.0\r\n\r\n")
	status, err := bufio.NewReader(conn).ReadString('\n')
	// ...

The Listen function creates servers:

	ln, err := net.Listen("tcp", ":8080")
	if err != nil {
		// handle error
	}
	for {
		conn, err := ln.Accept()
		if err != nil {
			// handle error
			continue
		}
		go handleConnection(conn)
	}
*/
package net

// TODO(rsc):
//	support for raw ethernet sockets

import (
	"errors"
	"io"
	"os"
	"sync"
	"syscall"
	"time"
)

// Addr represents a network end point address.
type Addr interface {
	Network() string // name of the network
	String() string  // string form of address
}

// Conn is a generic stream-oriented network connection.
//
// Multiple goroutines may invoke methods on a Conn simultaneously.
type Conn interface {
	// Read reads data from the connection.
	// Read can be made to time out and return a Error with Timeout() == true
	// after a fixed time limit; see SetDeadline and SetReadDeadline.
	Read(b []byte) (n int, err error)

	// Write writes data to the connection.
	// Write can be made to time out and return a Error with Timeout() == true
	// after a fixed time limit; see SetDeadline and SetWriteDeadline.
	Write(b []byte) (n int, err error)

	// Close closes the connection.
	// Any blocked Read or Write operations will be unblocked and return errors.
	Close() error

	// LocalAddr returns the local network address.
	LocalAddr() Addr

	// RemoteAddr returns the remote network address.
	RemoteAddr() Addr

	// SetDeadline sets the read and write deadlines associated
	// with the connection. It is equivalent to calling both
	// SetReadDeadline and SetWriteDeadline.
	//
	// A deadline is an absolute time after which I/O operations
	// fail with a timeout (see type Error) instead of
	// blocking. The deadline applies to all future I/O, not just
	// the immediately following call to Read or Write.
	//
	// An idle timeout can be implemented by repeatedly extending
	// the deadline after successful Read or Write calls.
	//
	// A zero value for t means I/O operations will not time out.
	SetDeadline(t time.Time) error

	// SetReadDeadline sets the deadline for future Read calls.
	// A zero value for t means Read will not time out.
	SetReadDeadline(t time.Time) error

	// SetWriteDeadline sets the deadline for future Write calls.
	// Even if write times out, it may return n > 0, indicating that
	// some of the data was successfully written.
	// A zero value for t means Write will not time out.
	SetWriteDeadline(t time.Time) error
}

type conn struct {
	fd *netFD
}

func (c *conn) ok() bool { return c != nil && c.fd != nil }

// Implementation of the Conn interface.

// Read implements the Conn Read method.
func (c *conn) Read(b []byte) (int, error) {
	if !c.ok() {
		return 0, syscall.EINVAL
	}
	return c.fd.Read(b)
}

// Write implements the Conn Write method.
func (c *conn) Write(b []byte) (int, error) {
	if !c.ok() {
		return 0, syscall.EINVAL
	}
	return c.fd.Write(b)
}

// Close closes the connection.
func (c *conn) Close() error {
	if !c.ok() {
		return syscall.EINVAL
	}
	return c.fd.Close()
}

// LocalAddr returns the local network address.
func (c *conn) LocalAddr() Addr {
	if !c.ok() {
		return nil
	}
	return c.fd.laddr
}

// RemoteAddr returns the remote network address.
func (c *conn) RemoteAddr() Addr {
	if !c.ok() {
		return nil
	}
	return c.fd.raddr
}

// SetDeadline implements the Conn SetDeadline method.
func (c *conn) SetDeadline(t time.Time) error {
	if !c.ok() {
		return syscall.EINVAL
	}
	return setDeadline(c.fd, t)
}

// SetReadDeadline implements the Conn SetReadDeadline method.
func (c *conn) SetReadDeadline(t time.Time) error {
	if !c.ok() {
		return syscall.EINVAL
	}
	return setReadDeadline(c.fd, t)
}

// SetWriteDeadline implements the Conn SetWriteDeadline method.
func (c *conn) SetWriteDeadline(t time.Time) error {
	if !c.ok() {
		return syscall.EINVAL
	}
	return setWriteDeadline(c.fd, t)
}

// SetReadBuffer sets the size of the operating system's
// receive buffer associated with the connection.
func (c *conn) SetReadBuffer(bytes int) error {
	if !c.ok() {
		return syscall.EINVAL
	}
	return setReadBuffer(c.fd, bytes)
}

// SetWriteBuffer sets the size of the operating system's
// transmit buffer associated with the connection.
func (c *conn) SetWriteBuffer(bytes int) error {
	if !c.ok() {
		return syscall.EINVAL
	}
	return setWriteBuffer(c.fd, bytes)
}

// File returns a copy of the underlying os.File, set to blocking mode.
// It is the caller's responsibility to close f when finished.
// Closing c does not affect f, and closing f does not affect c.
func (c *conn) File() (f *os.File, err error) { return c.fd.dup() }

// An Error represents a network error.
type Error interface {
	error
	Timeout() bool   // Is the error a timeout?
	Temporary() bool // Is the error temporary?
}

// PacketConn is a generic packet-oriented network connection.
//
// Multiple goroutines may invoke methods on a PacketConn simultaneously.
type PacketConn interface {
	// ReadFrom reads a packet from the connection,
	// copying the payload into b.  It returns the number of
	// bytes copied into b and the return address that
	// was on the packet.
	// ReadFrom can be made to time out and return
	// an error with Timeout() == true after a fixed time limit;
	// see SetDeadline and SetReadDeadline.
	ReadFrom(b []byte) (n int, addr Addr, err error)

	// WriteTo writes a packet with payload b to addr.
	// WriteTo can be made to time out and return
	// an error with Timeout() == true after a fixed time limit;
	// see SetDeadline and SetWriteDeadline.
	// On packet-oriented connections, write timeouts are rare.
	WriteTo(b []byte, addr Addr) (n int, err error)

	// Close closes the connection.
	// Any blocked ReadFrom or WriteTo operations will be unblocked and return errors.
	Close() error

	// LocalAddr returns the local network address.
	LocalAddr() Addr

	// SetDeadline sets the read and write deadlines associated
	// with the connection.
	SetDeadline(t time.Time) error

	// SetReadDeadline sets the deadline for future Read calls.
	// If the deadline is reached, Read will fail with a timeout
	// (see type Error) instead of blocking.
	// A zero value for t means Read will not time out.
	SetReadDeadline(t time.Time) error

	// SetWriteDeadline sets the deadline for future Write calls.
	// If the deadline is reached, Write will fail with a timeout
	// (see type Error) instead of blocking.
	// A zero value for t means Write will not time out.
	// Even if write times out, it may return n > 0, indicating that
	// some of the data was successfully written.
	SetWriteDeadline(t time.Time) error
}

// A Listener is a generic network listener for stream-oriented protocols.
//
// Multiple goroutines may invoke methods on a Listener simultaneously.
type Listener interface {
	// Accept waits for and returns the next connection to the listener.
	Accept() (c Conn, err error)

	// Close closes the listener.
	// Any blocked Accept operations will be unblocked and return errors.
	Close() error

	// Addr returns the listener's network address.
	Addr() Addr
}

var errMissingAddress = errors.New("missing address")

type OpError struct {
	Op   string
	Net  string
	Addr Addr
	Err  error
}

func (e *OpError) Error() string {
	if e == nil {
		return "<nil>"
	}
	s := e.Op
	if e.Net != "" {
		s += " " + e.Net
	}
	if e.Addr != nil {
		s += " " + e.Addr.String()
	}
	s += ": " + e.Err.Error()
	return s
}

type temporary interface {
	Temporary() bool
}

func (e *OpError) Temporary() bool {
	t, ok := e.Err.(temporary)
	return ok && t.Temporary()
}

var noDeadline = time.Time{}

type timeout interface {
	Timeout() bool
}

func (e *OpError) Timeout() bool {
	t, ok := e.Err.(timeout)
	return ok && t.Timeout()
}

type timeoutError struct{}

func (e *timeoutError) Error() string   { return "i/o timeout" }
func (e *timeoutError) Timeout() bool   { return true }
func (e *timeoutError) Temporary() bool { return true }

var errTimeout error = &timeoutError{}

var errClosing = errors.New("use of closed network connection")

type AddrError struct {
	Err  string
	Addr string
}

func (e *AddrError) Error() string {
	if e == nil {
		return "<nil>"
	}
	s := e.Err
	if e.Addr != "" {
		s += " " + e.Addr
	}
	return s
}

func (e *AddrError) Temporary() bool {
	return false
}

func (e *AddrError) Timeout() bool {
	return false
}

type UnknownNetworkError string

func (e UnknownNetworkError) Error() string   { return "unknown network " + string(e) }
func (e UnknownNetworkError) Temporary() bool { return false }
func (e UnknownNetworkError) Timeout() bool   { return false }

// DNSConfigError represents an error reading the machine's DNS configuration.
type DNSConfigError struct {
	Err error
}

func (e *DNSConfigError) Error() string {
	return "error reading DNS config: " + e.Err.Error()
}

func (e *DNSConfigError) Timeout() bool   { return false }
func (e *DNSConfigError) Temporary() bool { return false }

type writerOnly struct {
	io.Writer
}

// Fallback implementation of io.ReaderFrom's ReadFrom, when sendfile isn't
// applicable.
func genericReadFrom(w io.Writer, r io.Reader) (n int64, err error) {
	// Use wrapper to hide existing r.ReadFrom from io.Copy.
	return io.Copy(writerOnly{w}, r)
}

// deadline is an atomically-accessed number of nanoseconds since 1970
// or 0, if no deadline is set.
type deadline struct {
	sync.Mutex
	val int64
}

func (d *deadline) expired() bool {
	t := d.value()
	return t > 0 && time.Now().UnixNano() >= t
}

func (d *deadline) value() (v int64) {
	d.Lock()
	v = d.val
	d.Unlock()
	return
}

func (d *deadline) set(v int64) {
	d.Lock()
	d.val = v
	d.Unlock()
}

func (d *deadline) setTime(t time.Time) {
	if t.IsZero() {
		d.set(0)
	} else {
		d.set(t.UnixNano())
	}
}
<commit_msg>net: document that File reverts connection to blocking mode.<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
Package net provides a portable interface for network I/O, including
TCP/IP, UDP, domain name resolution, and Unix domain sockets.

Although the package provides access to low-level networking
primitives, most clients will need only the basic interface provided
by the Dial, Listen, and Accept functions and the associated
Conn and Listener interfaces. The crypto/tls package uses
the same interfaces and similar Dial and Listen functions.

The Dial function connects to a server:

	conn, err := net.Dial("tcp", "google.com:80")
	if err != nil {
		// handle error
	}
	fmt.Fprintf(conn, "GET / HTTP/1.0\r\n\r\n")
	status, err := bufio.NewReader(conn).ReadString('\n')
	// ...

The Listen function creates servers:

	ln, err := net.Listen("tcp", ":8080")
	if err != nil {
		// handle error
	}
	for {
		conn, err := ln.Accept()
		if err != nil {
			// handle error
			continue
		}
		go handleConnection(conn)
	}
*/
package net

// TODO(rsc):
//	support for raw ethernet sockets

import (
	"errors"
	"io"
	"os"
	"sync"
	"syscall"
	"time"
)

// Addr represents a network end point address.
type Addr interface {
	Network() string // name of the network
	String() string  // string form of address
}

// Conn is a generic stream-oriented network connection.
//
// Multiple goroutines may invoke methods on a Conn simultaneously.
type Conn interface {
	// Read reads data from the connection.
	// Read can be made to time out and return a Error with Timeout() == true
	// after a fixed time limit; see SetDeadline and SetReadDeadline.
	Read(b []byte) (n int, err error)

	// Write writes data to the connection.
	// Write can be made to time out and return a Error with Timeout() == true
	// after a fixed time limit; see SetDeadline and SetWriteDeadline.
	Write(b []byte) (n int, err error)

	// Close closes the connection.
	// Any blocked Read or Write operations will be unblocked and return errors.
	Close() error

	// LocalAddr returns the local network address.
	LocalAddr() Addr

	// RemoteAddr returns the remote network address.
	RemoteAddr() Addr

	// SetDeadline sets the read and write deadlines associated
	// with the connection. It is equivalent to calling both
	// SetReadDeadline and SetWriteDeadline.
	//
	// A deadline is an absolute time after which I/O operations
	// fail with a timeout (see type Error) instead of
	// blocking. The deadline applies to all future I/O, not just
	// the immediately following call to Read or Write.
	//
	// An idle timeout can be implemented by repeatedly extending
	// the deadline after successful Read or Write calls.
	//
	// A zero value for t means I/O operations will not time out.
	SetDeadline(t time.Time) error

	// SetReadDeadline sets the deadline for future Read calls.
	// A zero value for t means Read will not time out.
	SetReadDeadline(t time.Time) error

	// SetWriteDeadline sets the deadline for future Write calls.
	// Even if write times out, it may return n > 0, indicating that
	// some of the data was successfully written.
	// A zero value for t means Write will not time out.
	SetWriteDeadline(t time.Time) error
}

type conn struct {
	fd *netFD
}

func (c *conn) ok() bool { return c != nil && c.fd != nil }

// Implementation of the Conn interface.

// Read implements the Conn Read method.
func (c *conn) Read(b []byte) (int, error) {
	if !c.ok() {
		return 0, syscall.EINVAL
	}
	return c.fd.Read(b)
}

// Write implements the Conn Write method.
func (c *conn) Write(b []byte) (int, error) {
	if !c.ok() {
		return 0, syscall.EINVAL
	}
	return c.fd.Write(b)
}

// Close closes the connection.
func (c *conn) Close() error {
	if !c.ok() {
		return syscall.EINVAL
	}
	return c.fd.Close()
}

// LocalAddr returns the local network address.
func (c *conn) LocalAddr() Addr {
	if !c.ok() {
		return nil
	}
	return c.fd.laddr
}

// RemoteAddr returns the remote network address.
func (c *conn) RemoteAddr() Addr {
	if !c.ok() {
		return nil
	}
	return c.fd.raddr
}

// SetDeadline implements the Conn SetDeadline method.
func (c *conn) SetDeadline(t time.Time) error {
	if !c.ok() {
		return syscall.EINVAL
	}
	return setDeadline(c.fd, t)
}

// SetReadDeadline implements the Conn SetReadDeadline method.
func (c *conn) SetReadDeadline(t time.Time) error {
	if !c.ok() {
		return syscall.EINVAL
	}
	return setReadDeadline(c.fd, t)
}

// SetWriteDeadline implements the Conn SetWriteDeadline method.
func (c *conn) SetWriteDeadline(t time.Time) error {
	if !c.ok() {
		return syscall.EINVAL
	}
	return setWriteDeadline(c.fd, t)
}

// SetReadBuffer sets the size of the operating system's
// receive buffer associated with the connection.
func (c *conn) SetReadBuffer(bytes int) error {
	if !c.ok() {
		return syscall.EINVAL
	}
	return setReadBuffer(c.fd, bytes)
}

// SetWriteBuffer sets the size of the operating system's
// transmit buffer associated with the connection.
func (c *conn) SetWriteBuffer(bytes int) error {
	if !c.ok() {
		return syscall.EINVAL
	}
	return setWriteBuffer(c.fd, bytes)
}

// File sets the underlying os.File to blocking mode and returns a copy.
// It is the caller's responsibility to close f when finished.
// Closing c does not affect f, and closing f does not affect c.
//
// The returned os.File's file descriptor is different from the connection's.
// Attempting to change properties of the original using this duplicate
// may or may not have the desired effect.
func (c *conn) File() (f *os.File, err error) { return c.fd.dup() }

// An Error represents a network error.
type Error interface {
	error
	Timeout() bool   // Is the error a timeout?
	Temporary() bool // Is the error temporary?
}

// PacketConn is a generic packet-oriented network connection.
//
// Multiple goroutines may invoke methods on a PacketConn simultaneously.
type PacketConn interface {
	// ReadFrom reads a packet from the connection,
	// copying the payload into b.  It returns the number of
	// bytes copied into b and the return address that
	// was on the packet.
	// ReadFrom can be made to time out and return
	// an error with Timeout() == true after a fixed time limit;
	// see SetDeadline and SetReadDeadline.
	ReadFrom(b []byte) (n int, addr Addr, err error)

	// WriteTo writes a packet with payload b to addr.
	// WriteTo can be made to time out and return
	// an error with Timeout() == true after a fixed time limit;
	// see SetDeadline and SetWriteDeadline.
	// On packet-oriented connections, write timeouts are rare.
	WriteTo(b []byte, addr Addr) (n int, err error)

	// Close closes the connection.
	// Any blocked ReadFrom or WriteTo operations will be unblocked and return errors.
	Close() error

	// LocalAddr returns the local network address.
	LocalAddr() Addr

	// SetDeadline sets the read and write deadlines associated
	// with the connection.
	SetDeadline(t time.Time) error

	// SetReadDeadline sets the deadline for future Read calls.
	// If the deadline is reached, Read will fail with a timeout
	// (see type Error) instead of blocking.
	// A zero value for t means Read will not time out.
	SetReadDeadline(t time.Time) error

	// SetWriteDeadline sets the deadline for future Write calls.
	// If the deadline is reached, Write will fail with a timeout
	// (see type Error) instead of blocking.
	// A zero value for t means Write will not time out.
	// Even if write times out, it may return n > 0, indicating that
	// some of the data was successfully written.
	SetWriteDeadline(t time.Time) error
}

// A Listener is a generic network listener for stream-oriented protocols.
//
// Multiple goroutines may invoke methods on a Listener simultaneously.
type Listener interface {
	// Accept waits for and returns the next connection to the listener.
	Accept() (c Conn, err error)

	// Close closes the listener.
	// Any blocked Accept operations will be unblocked and return errors.
	Close() error

	// Addr returns the listener's network address.
	Addr() Addr
}

var errMissingAddress = errors.New("missing address")

type OpError struct {
	Op   string
	Net  string
	Addr Addr
	Err  error
}

func (e *OpError) Error() string {
	if e == nil {
		return "<nil>"
	}
	s := e.Op
	if e.Net != "" {
		s += " " + e.Net
	}
	if e.Addr != nil {
		s += " " + e.Addr.String()
	}
	s += ": " + e.Err.Error()
	return s
}

type temporary interface {
	Temporary() bool
}

func (e *OpError) Temporary() bool {
	t, ok := e.Err.(temporary)
	return ok && t.Temporary()
}

var noDeadline = time.Time{}

type timeout interface {
	Timeout() bool
}

func (e *OpError) Timeout() bool {
	t, ok := e.Err.(timeout)
	return ok && t.Timeout()
}

type timeoutError struct{}

func (e *timeoutError) Error() string   { return "i/o timeout" }
func (e *timeoutError) Timeout() bool   { return true }
func (e *timeoutError) Temporary() bool { return true }

var errTimeout error = &timeoutError{}

var errClosing = errors.New("use of closed network connection")

type AddrError struct {
	Err  string
	Addr string
}

func (e *AddrError) Error() string {
	if e == nil {
		return "<nil>"
	}
	s := e.Err
	if e.Addr != "" {
		s += " " + e.Addr
	}
	return s
}

func (e *AddrError) Temporary() bool {
	return false
}

func (e *AddrError) Timeout() bool {
	return false
}

type UnknownNetworkError string

func (e UnknownNetworkError) Error() string   { return "unknown network " + string(e) }
func (e UnknownNetworkError) Temporary() bool { return false }
func (e UnknownNetworkError) Timeout() bool   { return false }

// DNSConfigError represents an error reading the machine's DNS configuration.
type DNSConfigError struct {
	Err error
}

func (e *DNSConfigError) Error() string {
	return "error reading DNS config: " + e.Err.Error()
}

func (e *DNSConfigError) Timeout() bool   { return false }
func (e *DNSConfigError) Temporary() bool { return false }

type writerOnly struct {
	io.Writer
}

// Fallback implementation of io.ReaderFrom's ReadFrom, when sendfile isn't
// applicable.
func genericReadFrom(w io.Writer, r io.Reader) (n int64, err error) {
	// Use wrapper to hide existing r.ReadFrom from io.Copy.
	return io.Copy(writerOnly{w}, r)
}

// deadline is an atomically-accessed number of nanoseconds since 1970
// or 0, if no deadline is set.
type deadline struct {
	sync.Mutex
	val int64
}

func (d *deadline) expired() bool {
	t := d.value()
	return t > 0 && time.Now().UnixNano() >= t
}

func (d *deadline) value() (v int64) {
	d.Lock()
	v = d.val
	d.Unlock()
	return
}

func (d *deadline) set(v int64) {
	d.Lock()
	d.val = v
	d.Unlock()
}

func (d *deadline) setTime(t time.Time) {
	if t.IsZero() {
		d.set(0)
	} else {
		d.set(t.UnixNano())
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 The etcd 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 raft

import (
	"fmt"
	"log"

	pb "go.etcd.io/etcd/raft/v3/raftpb"
)

type raftLog struct {
	// storage contains all stable entries since the last snapshot.
	storage Storage

	// unstable contains all unstable entries and snapshot.
	// they will be saved into storage.
	unstable unstable

	// committed is the highest log position that is known to be in
	// stable storage on a quorum of nodes.
	committed uint64
	// applied is the highest log position that the application has
	// been instructed to apply to its state machine.
	// Invariant: applied <= committed
	applied uint64

	logger Logger

	// maxNextCommittedEntsSize is the maximum number aggregate byte size of the
	// messages returned from calls to nextCommittedEnts.
	maxNextCommittedEntsSize uint64
}

// newLog returns log using the given storage and default options. It
// recovers the log to the state that it just commits and applies the
// latest snapshot.
func newLog(storage Storage, logger Logger) *raftLog {
	return newLogWithSize(storage, logger, noLimit)
}

// newLogWithSize returns a log using the given storage and max
// message size.
func newLogWithSize(storage Storage, logger Logger, maxNextCommittedEntsSize uint64) *raftLog {
	if storage == nil {
		log.Panic("storage must not be nil")
	}
	log := &raftLog{
		storage:                  storage,
		logger:                   logger,
		maxNextCommittedEntsSize: maxNextCommittedEntsSize,
	}
	firstIndex, err := storage.FirstIndex()
	if err != nil {
		panic(err) // TODO(bdarnell)
	}
	lastIndex, err := storage.LastIndex()
	if err != nil {
		panic(err) // TODO(bdarnell)
	}
	log.unstable.offset = lastIndex + 1
	log.unstable.logger = logger
	// Initialize our committed and applied pointers to the time of the last compaction.
	log.committed = firstIndex - 1
	log.applied = firstIndex - 1

	return log
}

func (l *raftLog) String() string {
	return fmt.Sprintf("committed=%d, applied=%d, unstable.offset=%d, len(unstable.Entries)=%d", l.committed, l.applied, l.unstable.offset, len(l.unstable.entries))
}

// maybeAppend returns (0, false) if the entries cannot be appended. Otherwise,
// it returns (last index of new entries, true).
func (l *raftLog) maybeAppend(index, logTerm, committed uint64, ents ...pb.Entry) (lastnewi uint64, ok bool) {
	if l.matchTerm(index, logTerm) {
		lastnewi = index + uint64(len(ents))
		ci := l.findConflict(ents)
		switch {
		case ci == 0:
		case ci <= l.committed:
			l.logger.Panicf("entry %d conflict with committed entry [committed(%d)]", ci, l.committed)
		default:
			offset := index + 1
			if ci-offset > uint64(len(ents)) {
				l.logger.Panicf("index, %d, is out of range [%d]", ci-offset, len(ents))
			}
			l.append(ents[ci-offset:]...)
		}
		l.commitTo(min(committed, lastnewi))
		return lastnewi, true
	}
	return 0, false
}

func (l *raftLog) append(ents ...pb.Entry) uint64 {
	if len(ents) == 0 {
		return l.lastIndex()
	}
	if after := ents[0].Index - 1; after < l.committed {
		l.logger.Panicf("after(%d) is out of range [committed(%d)]", after, l.committed)
	}
	l.unstable.truncateAndAppend(ents)
	return l.lastIndex()
}

// findConflict finds the index of the conflict.
// It returns the first pair of conflicting entries between the existing
// entries and the given entries, if there are any.
// If there is no conflicting entries, and the existing entries contains
// all the given entries, zero will be returned.
// If there is no conflicting entries, but the given entries contains new
// entries, the index of the first new entry will be returned.
// An entry is considered to be conflicting if it has the same index but
// a different term.
// The index of the given entries MUST be continuously increasing.
func (l *raftLog) findConflict(ents []pb.Entry) uint64 {
	for _, ne := range ents {
		if !l.matchTerm(ne.Index, ne.Term) {
			if ne.Index <= l.lastIndex() {
				l.logger.Infof("found conflict at index %d [existing term: %d, conflicting term: %d]",
					ne.Index, l.zeroTermOnErrCompacted(l.term(ne.Index)), ne.Term)
			}
			return ne.Index
		}
	}
	return 0
}

// findConflictByTerm takes an (index, term) pair (indicating a conflicting log
// entry on a leader/follower during an append) and finds the largest index in
// log l with a term <= `term` and an index <= `index`. If no such index exists
// in the log, the log's first index is returned.
//
// The index provided MUST be equal to or less than l.lastIndex(). Invalid
// inputs log a warning and the input index is returned.
func (l *raftLog) findConflictByTerm(index uint64, term uint64) uint64 {
	if li := l.lastIndex(); index > li {
		// NB: such calls should not exist, but since there is a straightfoward
		// way to recover, do it.
		//
		// It is tempting to also check something about the first index, but
		// there is odd behavior with peers that have no log, in which case
		// lastIndex will return zero and firstIndex will return one, which
		// leads to calls with an index of zero into this method.
		l.logger.Warningf("index(%d) is out of range [0, lastIndex(%d)] in findConflictByTerm",
			index, li)
		return index
	}
	for {
		logTerm, err := l.term(index)
		if logTerm <= term || err != nil {
			break
		}
		index--
	}
	return index
}

func (l *raftLog) unstableEntries() []pb.Entry {
	if len(l.unstable.entries) == 0 {
		return nil
	}
	return l.unstable.entries
}

// nextCommittedEnts returns all the available entries for execution.
// If applied is smaller than the index of snapshot, it returns all committed
// entries after the index of snapshot.
func (l *raftLog) nextCommittedEnts() (ents []pb.Entry) {
	off := max(l.applied+1, l.firstIndex())
	if l.committed+1 > off {
		ents, err := l.slice(off, l.committed+1, l.maxNextCommittedEntsSize)
		if err != nil {
			l.logger.Panicf("unexpected error when getting unapplied entries (%v)", err)
		}
		return ents
	}
	return nil
}

// hasNextCommittedEnts returns if there is any available entries for execution.
// This is a fast check without heavy raftLog.slice() in nextCommittedEnts().
func (l *raftLog) hasNextCommittedEnts() bool {
	off := max(l.applied+1, l.firstIndex())
	return l.committed+1 > off
}

// hasPendingSnapshot returns if there is pending snapshot waiting for applying.
func (l *raftLog) hasPendingSnapshot() bool {
	return l.unstable.snapshot != nil && !IsEmptySnap(*l.unstable.snapshot)
}

func (l *raftLog) snapshot() (pb.Snapshot, error) {
	if l.unstable.snapshot != nil {
		return *l.unstable.snapshot, nil
	}
	return l.storage.Snapshot()
}

func (l *raftLog) firstIndex() uint64 {
	if i, ok := l.unstable.maybeFirstIndex(); ok {
		return i
	}
	index, err := l.storage.FirstIndex()
	if err != nil {
		panic(err) // TODO(bdarnell)
	}
	return index
}

func (l *raftLog) lastIndex() uint64 {
	if i, ok := l.unstable.maybeLastIndex(); ok {
		return i
	}
	i, err := l.storage.LastIndex()
	if err != nil {
		panic(err) // TODO(bdarnell)
	}
	return i
}

func (l *raftLog) commitTo(tocommit uint64) {
	// never decrease commit
	if l.committed < tocommit {
		if l.lastIndex() < tocommit {
			l.logger.Panicf("tocommit(%d) is out of range [lastIndex(%d)]. Was the raft log corrupted, truncated, or lost?", tocommit, l.lastIndex())
		}
		l.committed = tocommit
	}
}

func (l *raftLog) appliedTo(i uint64) {
	if i == 0 {
		return
	}
	if l.committed < i || i < l.applied {
		l.logger.Panicf("applied(%d) is out of range [prevApplied(%d), committed(%d)]", i, l.applied, l.committed)
	}
	l.applied = i
}

func (l *raftLog) stableTo(i, t uint64) { l.unstable.stableTo(i, t) }

func (l *raftLog) stableSnapTo(i uint64) { l.unstable.stableSnapTo(i) }

func (l *raftLog) lastTerm() uint64 {
	t, err := l.term(l.lastIndex())
	if err != nil {
		l.logger.Panicf("unexpected error when getting the last term (%v)", err)
	}
	return t
}

func (l *raftLog) term(i uint64) (uint64, error) {
	// the valid term range is [index of dummy entry, last index]
	dummyIndex := l.firstIndex() - 1
	if i < dummyIndex || i > l.lastIndex() {
		// TODO: return an error instead?
		return 0, nil
	}

	if t, ok := l.unstable.maybeTerm(i); ok {
		return t, nil
	}

	t, err := l.storage.Term(i)
	if err == nil {
		return t, nil
	}
	if err == ErrCompacted || err == ErrUnavailable {
		return 0, err
	}
	panic(err) // TODO(bdarnell)
}

func (l *raftLog) entries(i, maxsize uint64) ([]pb.Entry, error) {
	if i > l.lastIndex() {
		return nil, nil
	}
	return l.slice(i, l.lastIndex()+1, maxsize)
}

// allEntries returns all entries in the log.
func (l *raftLog) allEntries() []pb.Entry {
	ents, err := l.entries(l.firstIndex(), noLimit)
	if err == nil {
		return ents
	}
	if err == ErrCompacted { // try again if there was a racing compaction
		return l.allEntries()
	}
	// TODO (xiangli): handle error?
	panic(err)
}

// isUpToDate determines if the given (lastIndex,term) log is more up-to-date
// by comparing the index and term of the last entries in the existing logs.
// If the logs have last entries with different terms, then the log with the
// later term is more up-to-date. If the logs end with the same term, then
// whichever log has the larger lastIndex is more up-to-date. If the logs are
// the same, the given log is up-to-date.
func (l *raftLog) isUpToDate(lasti, term uint64) bool {
	return term > l.lastTerm() || (term == l.lastTerm() && lasti >= l.lastIndex())
}

func (l *raftLog) matchTerm(i, term uint64) bool {
	t, err := l.term(i)
	if err != nil {
		return false
	}
	return t == term
}

func (l *raftLog) maybeCommit(maxIndex, term uint64) bool {
	if maxIndex > l.committed && l.zeroTermOnErrCompacted(l.term(maxIndex)) == term {
		l.commitTo(maxIndex)
		return true
	}
	return false
}

func (l *raftLog) restore(s pb.Snapshot) {
	l.logger.Infof("log [%s] starts to restore snapshot [index: %d, term: %d]", l, s.Metadata.Index, s.Metadata.Term)
	l.committed = s.Metadata.Index
	l.unstable.restore(s)
}

// slice returns a slice of log entries from lo through hi-1, inclusive.
func (l *raftLog) slice(lo, hi, maxSize uint64) ([]pb.Entry, error) {
	err := l.mustCheckOutOfBounds(lo, hi)
	if err != nil {
		return nil, err
	}
	if lo == hi {
		return nil, nil
	}
	var ents []pb.Entry
	if lo < l.unstable.offset {
		storedEnts, err := l.storage.Entries(lo, min(hi, l.unstable.offset), maxSize)
		if err == ErrCompacted {
			return nil, err
		} else if err == ErrUnavailable {
			l.logger.Panicf("entries[%d:%d) is unavailable from storage", lo, min(hi, l.unstable.offset))
		} else if err != nil {
			panic(err) // TODO(bdarnell)
		}

		// check if ents has reached the size limitation
		if uint64(len(storedEnts)) < min(hi, l.unstable.offset)-lo {
			return storedEnts, nil
		}

		ents = storedEnts
	}
	if hi > l.unstable.offset {
		unstable := l.unstable.slice(max(lo, l.unstable.offset), hi)
		if len(ents) > 0 {
			combined := make([]pb.Entry, len(ents)+len(unstable))
			n := copy(combined, ents)
			copy(combined[n:], unstable)
			ents = combined
		} else {
			ents = unstable
		}
	}
	return limitSize(ents, maxSize), nil
}

// l.firstIndex <= lo <= hi <= l.firstIndex + len(l.entries)
func (l *raftLog) mustCheckOutOfBounds(lo, hi uint64) error {
	if lo > hi {
		l.logger.Panicf("invalid slice %d > %d", lo, hi)
	}
	fi := l.firstIndex()
	if lo < fi {
		return ErrCompacted
	}

	length := l.lastIndex() + 1 - fi
	if hi > fi+length {
		l.logger.Panicf("slice[%d,%d) out of bound [%d,%d]", lo, hi, fi, l.lastIndex())
	}
	return nil
}

func (l *raftLog) zeroTermOnErrCompacted(t uint64, err error) uint64 {
	if err == nil {
		return t
	}
	if err == ErrCompacted {
		return 0
	}
	l.logger.Panicf("unexpected error (%v)", err)
	return 0
}
<commit_msg>raft: remove IsEmptySnap check from raftLog.hasPendingSnapshot<commit_after>// Copyright 2015 The etcd 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 raft

import (
	"fmt"
	"log"

	pb "go.etcd.io/etcd/raft/v3/raftpb"
)

type raftLog struct {
	// storage contains all stable entries since the last snapshot.
	storage Storage

	// unstable contains all unstable entries and snapshot.
	// they will be saved into storage.
	unstable unstable

	// committed is the highest log position that is known to be in
	// stable storage on a quorum of nodes.
	committed uint64
	// applied is the highest log position that the application has
	// been instructed to apply to its state machine.
	// Invariant: applied <= committed
	applied uint64

	logger Logger

	// maxNextCommittedEntsSize is the maximum number aggregate byte size of the
	// messages returned from calls to nextCommittedEnts.
	maxNextCommittedEntsSize uint64
}

// newLog returns log using the given storage and default options. It
// recovers the log to the state that it just commits and applies the
// latest snapshot.
func newLog(storage Storage, logger Logger) *raftLog {
	return newLogWithSize(storage, logger, noLimit)
}

// newLogWithSize returns a log using the given storage and max
// message size.
func newLogWithSize(storage Storage, logger Logger, maxNextCommittedEntsSize uint64) *raftLog {
	if storage == nil {
		log.Panic("storage must not be nil")
	}
	log := &raftLog{
		storage:                  storage,
		logger:                   logger,
		maxNextCommittedEntsSize: maxNextCommittedEntsSize,
	}
	firstIndex, err := storage.FirstIndex()
	if err != nil {
		panic(err) // TODO(bdarnell)
	}
	lastIndex, err := storage.LastIndex()
	if err != nil {
		panic(err) // TODO(bdarnell)
	}
	log.unstable.offset = lastIndex + 1
	log.unstable.logger = logger
	// Initialize our committed and applied pointers to the time of the last compaction.
	log.committed = firstIndex - 1
	log.applied = firstIndex - 1

	return log
}

func (l *raftLog) String() string {
	return fmt.Sprintf("committed=%d, applied=%d, unstable.offset=%d, len(unstable.Entries)=%d", l.committed, l.applied, l.unstable.offset, len(l.unstable.entries))
}

// maybeAppend returns (0, false) if the entries cannot be appended. Otherwise,
// it returns (last index of new entries, true).
func (l *raftLog) maybeAppend(index, logTerm, committed uint64, ents ...pb.Entry) (lastnewi uint64, ok bool) {
	if l.matchTerm(index, logTerm) {
		lastnewi = index + uint64(len(ents))
		ci := l.findConflict(ents)
		switch {
		case ci == 0:
		case ci <= l.committed:
			l.logger.Panicf("entry %d conflict with committed entry [committed(%d)]", ci, l.committed)
		default:
			offset := index + 1
			if ci-offset > uint64(len(ents)) {
				l.logger.Panicf("index, %d, is out of range [%d]", ci-offset, len(ents))
			}
			l.append(ents[ci-offset:]...)
		}
		l.commitTo(min(committed, lastnewi))
		return lastnewi, true
	}
	return 0, false
}

func (l *raftLog) append(ents ...pb.Entry) uint64 {
	if len(ents) == 0 {
		return l.lastIndex()
	}
	if after := ents[0].Index - 1; after < l.committed {
		l.logger.Panicf("after(%d) is out of range [committed(%d)]", after, l.committed)
	}
	l.unstable.truncateAndAppend(ents)
	return l.lastIndex()
}

// findConflict finds the index of the conflict.
// It returns the first pair of conflicting entries between the existing
// entries and the given entries, if there are any.
// If there is no conflicting entries, and the existing entries contains
// all the given entries, zero will be returned.
// If there is no conflicting entries, but the given entries contains new
// entries, the index of the first new entry will be returned.
// An entry is considered to be conflicting if it has the same index but
// a different term.
// The index of the given entries MUST be continuously increasing.
func (l *raftLog) findConflict(ents []pb.Entry) uint64 {
	for _, ne := range ents {
		if !l.matchTerm(ne.Index, ne.Term) {
			if ne.Index <= l.lastIndex() {
				l.logger.Infof("found conflict at index %d [existing term: %d, conflicting term: %d]",
					ne.Index, l.zeroTermOnErrCompacted(l.term(ne.Index)), ne.Term)
			}
			return ne.Index
		}
	}
	return 0
}

// findConflictByTerm takes an (index, term) pair (indicating a conflicting log
// entry on a leader/follower during an append) and finds the largest index in
// log l with a term <= `term` and an index <= `index`. If no such index exists
// in the log, the log's first index is returned.
//
// The index provided MUST be equal to or less than l.lastIndex(). Invalid
// inputs log a warning and the input index is returned.
func (l *raftLog) findConflictByTerm(index uint64, term uint64) uint64 {
	if li := l.lastIndex(); index > li {
		// NB: such calls should not exist, but since there is a straightfoward
		// way to recover, do it.
		//
		// It is tempting to also check something about the first index, but
		// there is odd behavior with peers that have no log, in which case
		// lastIndex will return zero and firstIndex will return one, which
		// leads to calls with an index of zero into this method.
		l.logger.Warningf("index(%d) is out of range [0, lastIndex(%d)] in findConflictByTerm",
			index, li)
		return index
	}
	for {
		logTerm, err := l.term(index)
		if logTerm <= term || err != nil {
			break
		}
		index--
	}
	return index
}

func (l *raftLog) unstableEntries() []pb.Entry {
	if len(l.unstable.entries) == 0 {
		return nil
	}
	return l.unstable.entries
}

// nextCommittedEnts returns all the available entries for execution.
// If applied is smaller than the index of snapshot, it returns all committed
// entries after the index of snapshot.
func (l *raftLog) nextCommittedEnts() (ents []pb.Entry) {
	off := max(l.applied+1, l.firstIndex())
	if l.committed+1 > off {
		ents, err := l.slice(off, l.committed+1, l.maxNextCommittedEntsSize)
		if err != nil {
			l.logger.Panicf("unexpected error when getting unapplied entries (%v)", err)
		}
		return ents
	}
	return nil
}

// hasNextCommittedEnts returns if there is any available entries for execution.
// This is a fast check without heavy raftLog.slice() in nextCommittedEnts().
func (l *raftLog) hasNextCommittedEnts() bool {
	off := max(l.applied+1, l.firstIndex())
	return l.committed+1 > off
}

// hasPendingSnapshot returns if there is pending snapshot waiting for applying.
func (l *raftLog) hasPendingSnapshot() bool {
	return l.unstable.snapshot != nil
}

func (l *raftLog) snapshot() (pb.Snapshot, error) {
	if l.unstable.snapshot != nil {
		return *l.unstable.snapshot, nil
	}
	return l.storage.Snapshot()
}

func (l *raftLog) firstIndex() uint64 {
	if i, ok := l.unstable.maybeFirstIndex(); ok {
		return i
	}
	index, err := l.storage.FirstIndex()
	if err != nil {
		panic(err) // TODO(bdarnell)
	}
	return index
}

func (l *raftLog) lastIndex() uint64 {
	if i, ok := l.unstable.maybeLastIndex(); ok {
		return i
	}
	i, err := l.storage.LastIndex()
	if err != nil {
		panic(err) // TODO(bdarnell)
	}
	return i
}

func (l *raftLog) commitTo(tocommit uint64) {
	// never decrease commit
	if l.committed < tocommit {
		if l.lastIndex() < tocommit {
			l.logger.Panicf("tocommit(%d) is out of range [lastIndex(%d)]. Was the raft log corrupted, truncated, or lost?", tocommit, l.lastIndex())
		}
		l.committed = tocommit
	}
}

func (l *raftLog) appliedTo(i uint64) {
	if i == 0 {
		return
	}
	if l.committed < i || i < l.applied {
		l.logger.Panicf("applied(%d) is out of range [prevApplied(%d), committed(%d)]", i, l.applied, l.committed)
	}
	l.applied = i
}

func (l *raftLog) stableTo(i, t uint64) { l.unstable.stableTo(i, t) }

func (l *raftLog) stableSnapTo(i uint64) { l.unstable.stableSnapTo(i) }

func (l *raftLog) lastTerm() uint64 {
	t, err := l.term(l.lastIndex())
	if err != nil {
		l.logger.Panicf("unexpected error when getting the last term (%v)", err)
	}
	return t
}

func (l *raftLog) term(i uint64) (uint64, error) {
	// the valid term range is [index of dummy entry, last index]
	dummyIndex := l.firstIndex() - 1
	if i < dummyIndex || i > l.lastIndex() {
		// TODO: return an error instead?
		return 0, nil
	}

	if t, ok := l.unstable.maybeTerm(i); ok {
		return t, nil
	}

	t, err := l.storage.Term(i)
	if err == nil {
		return t, nil
	}
	if err == ErrCompacted || err == ErrUnavailable {
		return 0, err
	}
	panic(err) // TODO(bdarnell)
}

func (l *raftLog) entries(i, maxsize uint64) ([]pb.Entry, error) {
	if i > l.lastIndex() {
		return nil, nil
	}
	return l.slice(i, l.lastIndex()+1, maxsize)
}

// allEntries returns all entries in the log.
func (l *raftLog) allEntries() []pb.Entry {
	ents, err := l.entries(l.firstIndex(), noLimit)
	if err == nil {
		return ents
	}
	if err == ErrCompacted { // try again if there was a racing compaction
		return l.allEntries()
	}
	// TODO (xiangli): handle error?
	panic(err)
}

// isUpToDate determines if the given (lastIndex,term) log is more up-to-date
// by comparing the index and term of the last entries in the existing logs.
// If the logs have last entries with different terms, then the log with the
// later term is more up-to-date. If the logs end with the same term, then
// whichever log has the larger lastIndex is more up-to-date. If the logs are
// the same, the given log is up-to-date.
func (l *raftLog) isUpToDate(lasti, term uint64) bool {
	return term > l.lastTerm() || (term == l.lastTerm() && lasti >= l.lastIndex())
}

func (l *raftLog) matchTerm(i, term uint64) bool {
	t, err := l.term(i)
	if err != nil {
		return false
	}
	return t == term
}

func (l *raftLog) maybeCommit(maxIndex, term uint64) bool {
	if maxIndex > l.committed && l.zeroTermOnErrCompacted(l.term(maxIndex)) == term {
		l.commitTo(maxIndex)
		return true
	}
	return false
}

func (l *raftLog) restore(s pb.Snapshot) {
	l.logger.Infof("log [%s] starts to restore snapshot [index: %d, term: %d]", l, s.Metadata.Index, s.Metadata.Term)
	l.committed = s.Metadata.Index
	l.unstable.restore(s)
}

// slice returns a slice of log entries from lo through hi-1, inclusive.
func (l *raftLog) slice(lo, hi, maxSize uint64) ([]pb.Entry, error) {
	err := l.mustCheckOutOfBounds(lo, hi)
	if err != nil {
		return nil, err
	}
	if lo == hi {
		return nil, nil
	}
	var ents []pb.Entry
	if lo < l.unstable.offset {
		storedEnts, err := l.storage.Entries(lo, min(hi, l.unstable.offset), maxSize)
		if err == ErrCompacted {
			return nil, err
		} else if err == ErrUnavailable {
			l.logger.Panicf("entries[%d:%d) is unavailable from storage", lo, min(hi, l.unstable.offset))
		} else if err != nil {
			panic(err) // TODO(bdarnell)
		}

		// check if ents has reached the size limitation
		if uint64(len(storedEnts)) < min(hi, l.unstable.offset)-lo {
			return storedEnts, nil
		}

		ents = storedEnts
	}
	if hi > l.unstable.offset {
		unstable := l.unstable.slice(max(lo, l.unstable.offset), hi)
		if len(ents) > 0 {
			combined := make([]pb.Entry, len(ents)+len(unstable))
			n := copy(combined, ents)
			copy(combined[n:], unstable)
			ents = combined
		} else {
			ents = unstable
		}
	}
	return limitSize(ents, maxSize), nil
}

// l.firstIndex <= lo <= hi <= l.firstIndex + len(l.entries)
func (l *raftLog) mustCheckOutOfBounds(lo, hi uint64) error {
	if lo > hi {
		l.logger.Panicf("invalid slice %d > %d", lo, hi)
	}
	fi := l.firstIndex()
	if lo < fi {
		return ErrCompacted
	}

	length := l.lastIndex() + 1 - fi
	if hi > fi+length {
		l.logger.Panicf("slice[%d,%d) out of bound [%d,%d]", lo, hi, fi, l.lastIndex())
	}
	return nil
}

func (l *raftLog) zeroTermOnErrCompacted(t uint64, err error) uint64 {
	if err == nil {
		return t
	}
	if err == ErrCompacted {
		return 0
	}
	l.logger.Panicf("unexpected error (%v)", err)
	return 0
}
<|endoftext|>


<commit_before>package orbitus

import (
	"errors"
)

const (
	RECEIVER     = iota
	JOURNALER    = iota
	REPLICATOR   = iota
	UNMARSHALLER = iota
	EXECUTOR     = iota
)

// inputOrbiter unmarshals messages and coordinates journalling and replication.
type inputOrbiter struct {
	orbiter

	// Receiver message buffer
	receiverBuffer chan []byte
}

// NewReceiverOrbiter initializes a new inputOrbiter.
//
// All indexes are set to 0 and Handlers are assigned.
//
// Space for the buffer is allocated and is filled with empty Message objects.
//
// It returns a pointer to the initialized inputOrbiter.
func NewReceiverOrbiter(
	size uint64,
	receiver Handler,
	journaler Handler,
	replicator Handler,
	unmarshaller Handler,
	executor Handler,
) *inputOrbiter {
	orbiter := &inputOrbiter{
		// Allocate the buffer
		orbiter: orbiter{
			buffer_size: size,
			buffer:      make([]*Message, size),

			// Start in stopped state
			running: false,

			// Create handler and index arrays
			handler: make([]Handler, 5),
			index:   make([]uint64, 5),
			channel: make([]chan int, 5),
		},

		// Create the channel for the receiverBuffer
		receiverBuffer: make(chan []byte, 4096),
	}
	// Assign Handlers
	orbiter.handler[RECEIVER] = receiver
	orbiter.handler[JOURNALER] = journaler
	orbiter.handler[REPLICATOR] = replicator
	orbiter.handler[UNMARSHALLER] = unmarshaller
	orbiter.handler[EXECUTOR] = executor

	// Start at index 4 so we don't have index underflow
	orbiter.Reset(4)

	// Create 'size' new Message objects and store them in the buffer
	var i uint64
	for i = 0; i < size; i++ {
		orbiter.buffer[i] = new(Message)
	}

	return orbiter
}

// Reset sets all indexes to a given value.
// This is useful for rebuilding Orbiter state from an input file
// (eg: journaled output) instead of manually looping through the buffer until
// the desired index is reached.
//
// Returns an error if called while Orbiter is running. Stop Orbiter with
// Orbiter.Stop() before resetting.
func (o *inputOrbiter) Reset(i uint64) error {
	if o.running {
		return errors.New("Cannot reset a running Orbiter")
	}

	// Bypass the setters otherwise their sanity checks will error
	var j uint64
	for j = 0; j <= EXECUTOR; j++ {
		// The first item in index should be first in the buffer
		o.index[j] = i - j
	}

	return nil
}

// Start starts the Orbiter processing.
// It launches a number of goroutines (one for each Handler + one manager).
//
// These goroutines handle the index checking logic and call the provided
// Handler function when there is data in the buffer available for it to
// process.
func (o *inputOrbiter) Start() {
	// Allocate channels
	for i := range o.channel {
		o.channel[i] = make(chan int)
	}

	go o.run()
}

// Stop stops the Orbiter processing.
// It closes the input stream and then closes all channels, effectively
// killing all goroutines.
func (o *inputOrbiter) Stop() {
	o.running = false
	for i := 0; i <= EXECUTOR; i++ {
		close(o.channel[i])
	}
}

// GetIndex returns the inputOrbiter's current index for the provided Consumer.
// This index may be larger than the buffer size, as the modulus is used to get
// a valid array index.
//
// h is the handler to fetch the index for.
func (o *inputOrbiter) GetIndex(h int) uint64 {
	return o.index[h]
}

// SetExecutorIndex sets the inputOrbiter's executorIndex to the given value.
//
// The provided value is checked to ensure that it is within acceptable bounds.
// Specifically, it cannot be less than the current index or greater than the
// current unmarshallerIndex.
//
// If the above rules are broken an error is returned, else nil.
func (o *inputOrbiter) SetExecutorIndex(i uint64) error {
	if i < o.GetIndex(EXECUTOR) {
		return errors.New("New executor index cannot be less than current " +
			"index")
	} else if i > o.GetIndex(UNMARSHALLER)-1 {
		return errors.New("New executor index cannot be greater than the " +
			"current unmarshaller index")
	}

	o.index[EXECUTOR] = i
	return nil
}

// SetReceiverIndex sets the inputOrbiter's receiverIndex to the given value.
//
// The provided value is checked to ensure that it is within acceptable bounds.
// Specifically, it cannot be less than the current index or greater than the
// current executorIndex.
//
// If the above rules are broken an error is returned, else nil.
func (o *inputOrbiter) SetReceiverIndex(i uint64) error {
	if i < o.GetIndex(RECEIVER) {
		return errors.New("New receiver index cannot be less than current " +
			"index")
	} else if i >= o.GetIndex(EXECUTOR)+o.GetBufferSize() {
		return errors.New("The Receiver Consumer cannot pass the Business " +
			"Logic Consumer")
	}

	o.index[RECEIVER] = i
	return nil
}

// SetJournalerIndex sets the inputOrbiter's journalerIndex to the given value.
//
// The provided value is checked to ensure that it is within acceptable bounds.
// Specifically, it cannot be less than the current index or greater than the
// current receiverIndex.
//
// If the above rules are broken an error is returned, else nil.
func (o *inputOrbiter) SetJournalerIndex(i uint64) error {
	if i < o.GetIndex(JOURNALER) {
		return errors.New("New journaler index cannot be less than current " +
			"index")
	} else if i > o.GetIndex(RECEIVER)-1 {
		return errors.New("New journaler index cannot be greater than the " +
			"current receiver index")
	}

	o.index[JOURNALER] = i
	return nil
}

// SetReplicatorIndex sets the inputOrbiter's replicatorIndex to the given
// value.
//
// The provided value is checked to ensure that it is within acceptable bounds.
// Specifically, it cannot be less than the current index or greater than the
// current journalerIndex.
//
// If the above rules are broken an error is returned, else nil.
func (o *inputOrbiter) SetReplicatorIndex(i uint64) error {
	if i < o.GetIndex(REPLICATOR) {
		return errors.New("New replicator index cannot be less than current " +
			"index")
	} else if i > o.GetIndex(JOURNALER)-1 {
		return errors.New("New replicator index cannot be greater than the " +
			"current journaler index")
	}

	o.index[REPLICATOR] = i
	return nil
}

// SetUnmarshallerIndex sets the inputOrbiter's unmarshallerIndex to the given
// value.
//
// The provided value is checked to ensure that it is within acceptable bounds.
// Specifically, it cannot be less than the current index or greater than the
// current replicatorIndex.
//
// If the above rules are broken an error is returned, else nil.
func (o *inputOrbiter) SetUnmarshallerIndex(i uint64) error {
	if i < o.GetIndex(UNMARSHALLER) {
		return errors.New("New unmarshaller index cannot be less than " +
			"current index")
	} else if i > o.GetIndex(REPLICATOR)-1 {
		return errors.New("New unmarshaller index cannot be greater than the " +
			"current replicator index")
	}

	o.index[UNMARSHALLER] = i
	return nil
}

// runOrbiter starts all the Handler management goroutines.
func (o *inputOrbiter) run() {
	o.running = true
	go o.runReceiver(o.handler[RECEIVER])
	go o.runHandler(o.handler[JOURNALER], JOURNALER)
	go o.runHandler(o.handler[REPLICATOR], REPLICATOR)
	go o.runHandler(o.handler[UNMARSHALLER], UNMARSHALLER)
	go o.runHandler(o.handler[EXECUTOR], EXECUTOR)
}

// runReceiver processes messages sent to it until the channel is closed.
func (o *inputOrbiter) runReceiver(h Handler) {
	var i uint64
	journalChannel := o.channel[RECEIVER+1]
	for msg := range o.receiverBuffer {
		i = o.GetIndex(RECEIVER)

		// Store message and current index
		elem := o.buffer[i%o.GetBufferSize()]
		elem.id = i
		elem.marshalled = msg

		// Run handler
		if h != nil {
			h(o, []uint64{i})
		}

		// Let the next handler know it can proceed
		if len(journalChannel) == 0 {
			journalChannel <- 1
		}
	}
}

// runHandler loops, calling the Handler when Messages are available to process.
//
// TODO gracefully handle Orbiter.Stop(). Currently all handlers stop
// immediately. Better behaviour would be for Receiver to stop first and the
// rest of the handlers finish processing anything available to them before
// stopping. This could be achieved better by the Orbiter.Stop() function
// closing the channel buffer and the receiver exiting on no more data.
func (o *inputOrbiter) runHandler(h Handler, t int) {
	var this, last, i, j uint64
	nextChannel := o.channel[(t+1)%(EXECUTOR+1)]
	for _ = range o.channel[t] {
		// Get the current indexes.
		// this - current index of this Handler
		// last - highest index that this Handler can process
		this = o.GetIndex(t)
		last = o.GetIndex(t-1) - 1

		// Check if we can process anything
		if this < last {
			// Build list of indexes to process
			indexes := make([]uint64, last-this)
			for i, j = this+1, 0; i <= last; i, j = i+1, j+1 {
				indexes[j] = i
			}

			// Call the Handler
			if h != nil {
				h(o, indexes)
			}

			// Let the next handler know it can proceed
			if len(nextChannel) == 0 && o.running && t != EXECUTOR {
				nextChannel <- 1
			}
		}
	}
}
<commit_msg>misc cleanups<commit_after>package orbitus

import (
	"errors"
)

const (
	RECEIVER = iota
	JOURNALER
	REPLICATOR
	UNMARSHALLER
	EXECUTOR
)

// inputOrbiter unmarshals messages and coordinates journalling and replication.
type inputOrbiter struct {
	orbiter

	// Receiver message buffer
	receiverBuffer chan []byte
}

// NewReceiverOrbiter initializes a new inputOrbiter.
//
// All indexes are set to 0 and Handlers are assigned.
//
// Space for the buffer is allocated and is filled with empty Message objects.
//
// It returns a pointer to the initialized inputOrbiter.
func NewReceiverOrbiter(
	size uint64,
	receiver Handler,
	journaler Handler,
	replicator Handler,
	unmarshaller Handler,
	executor Handler,
) *inputOrbiter {
	orbiter := &inputOrbiter{
		// Allocate the buffer
		orbiter: orbiter{
			buffer_size: size,
			buffer:      make([]*Message, size),

			// Start in stopped state
			running: false,

			// Create handler and index arrays
			handler: make([]Handler, 5),
			index:   make([]uint64, 5),
			channel: make([]chan int, 5),
		},

		// Create the channel for the receiverBuffer
		receiverBuffer: make(chan []byte, 4096),
	}
	// Assign Handlers
	orbiter.handler[RECEIVER] = receiver
	orbiter.handler[JOURNALER] = journaler
	orbiter.handler[REPLICATOR] = replicator
	orbiter.handler[UNMARSHALLER] = unmarshaller
	orbiter.handler[EXECUTOR] = executor

	// Start at index 4 so we don't have index underflow
	orbiter.Reset(4)

	// Create 'size' new Message objects and store them in the buffer.
	// This avoids costly object creation and GC while streaming data.
	var i uint64
	for i = 0; i < size; i++ {
		orbiter.buffer[i] = new(Message)
	}

	return orbiter
}

// Reset sets all indexes to a given value.
// This is useful for rebuilding Orbiter state from an input file
// (eg: journaled output) instead of manually looping through the buffer until
// the desired index is reached.
//
// Returns an error if called while Orbiter is running. Stop Orbiter with
// Orbiter.Stop() before resetting.
func (o *inputOrbiter) Reset(i uint64) error {
	if o.running {
		return errors.New("Cannot reset a running Orbiter")
	}

	// Bypass the setters otherwise their sanity checks will error
	var j uint64
	for j = 0; j <= EXECUTOR; j++ {
		// The first item in index should be first in the buffer
		o.index[j] = i - j
	}

	return nil
}

// Start starts the Orbiter processing.
// It launches a number of goroutines (one for each Handler + one manager).
//
// These goroutines handle the index checking logic and call the provided
// Handler function when there is data in the buffer available for it to
// process.
func (o *inputOrbiter) Start() {
	// Allocate channels
	for i := range o.channel {
		o.channel[i] = make(chan int)
	}

	go o.run()
}

// Stop stops the Orbiter processing.
// It closes the input stream and then closes all channels, effectively
// killing all goroutines.
func (o *inputOrbiter) Stop() {
	o.running = false
	for i := range o.handler {
		close(o.channel[i])
	}
}

// GetIndex returns the inputOrbiter's current index for the provided Consumer.
// This index may be larger than the buffer size, as the modulus is used to get
// a valid array index.
//
// h is the handler to fetch the index for.
func (o *inputOrbiter) GetIndex(h int) uint64 {
	return o.index[h]
}

// SetExecutorIndex sets the inputOrbiter's executorIndex to the given value.
//
// The provided value is checked to ensure that it is within acceptable bounds.
// Specifically, it cannot be less than the current index or greater than the
// current unmarshallerIndex.
//
// If the above rules are broken an error is returned, else nil.
func (o *inputOrbiter) SetExecutorIndex(i uint64) error {
	if i < o.GetIndex(EXECUTOR) {
		return errors.New("New executor index cannot be less than current " +
			"index")
	} else if i > o.GetIndex(UNMARSHALLER)-1 {
		return errors.New("New executor index cannot be greater than the " +
			"current unmarshaller index")
	}

	o.index[EXECUTOR] = i
	return nil
}

// SetReceiverIndex sets the inputOrbiter's receiverIndex to the given value.
//
// The provided value is checked to ensure that it is within acceptable bounds.
// Specifically, it cannot be less than the current index or greater than the
// current executorIndex.
//
// If the above rules are broken an error is returned, else nil.
func (o *inputOrbiter) SetReceiverIndex(i uint64) error {
	if i < o.GetIndex(RECEIVER) {
		return errors.New("New receiver index cannot be less than current " +
			"index")
	} else if i >= o.GetIndex(EXECUTOR)+o.GetBufferSize() {
		return errors.New("The Receiver Consumer cannot pass the Business " +
			"Logic Consumer")
	}

	o.index[RECEIVER] = i
	return nil
}

// SetJournalerIndex sets the inputOrbiter's journalerIndex to the given value.
//
// The provided value is checked to ensure that it is within acceptable bounds.
// Specifically, it cannot be less than the current index or greater than the
// current receiverIndex.
//
// If the above rules are broken an error is returned, else nil.
func (o *inputOrbiter) SetJournalerIndex(i uint64) error {
	if i < o.GetIndex(JOURNALER) {
		return errors.New("New journaler index cannot be less than current " +
			"index")
	} else if i > o.GetIndex(RECEIVER)-1 {
		return errors.New("New journaler index cannot be greater than the " +
			"current receiver index")
	}

	o.index[JOURNALER] = i
	return nil
}

// SetReplicatorIndex sets the inputOrbiter's replicatorIndex to the given
// value.
//
// The provided value is checked to ensure that it is within acceptable bounds.
// Specifically, it cannot be less than the current index or greater than the
// current journalerIndex.
//
// If the above rules are broken an error is returned, else nil.
func (o *inputOrbiter) SetReplicatorIndex(i uint64) error {
	if i < o.GetIndex(REPLICATOR) {
		return errors.New("New replicator index cannot be less than current " +
			"index")
	} else if i > o.GetIndex(JOURNALER)-1 {
		return errors.New("New replicator index cannot be greater than the " +
			"current journaler index")
	}

	o.index[REPLICATOR] = i
	return nil
}

// SetUnmarshallerIndex sets the inputOrbiter's unmarshallerIndex to the given
// value.
//
// The provided value is checked to ensure that it is within acceptable bounds.
// Specifically, it cannot be less than the current index or greater than the
// current replicatorIndex.
//
// If the above rules are broken an error is returned, else nil.
func (o *inputOrbiter) SetUnmarshallerIndex(i uint64) error {
	if i < o.GetIndex(UNMARSHALLER) {
		return errors.New("New unmarshaller index cannot be less than " +
			"current index")
	} else if i > o.GetIndex(REPLICATOR)-1 {
		return errors.New("New unmarshaller index cannot be greater than the " +
			"current replicator index")
	}

	o.index[UNMARSHALLER] = i
	return nil
}

// runOrbiter starts all the Handler management goroutines.
func (o *inputOrbiter) run() {
	o.running = true
	go o.runReceiver(o.handler[RECEIVER])
	go o.runHandler(o.handler[JOURNALER], JOURNALER)
	go o.runHandler(o.handler[REPLICATOR], REPLICATOR)
	go o.runHandler(o.handler[UNMARSHALLER], UNMARSHALLER)
	go o.runHandler(o.handler[EXECUTOR], EXECUTOR)
}

// runReceiver processes messages sent to it until the channel is closed.
func (o *inputOrbiter) runReceiver(h Handler) {
	var i uint64
	journalChannel := o.channel[RECEIVER+1]
	for msg := range o.receiverBuffer {
		i = o.GetIndex(RECEIVER)

		// Store message and current index
		elem := o.buffer[i%o.GetBufferSize()]
		elem.id = i
		elem.marshalled = msg

		// Run handler
		if h != nil {
			h(o, []uint64{i})
		}

		// Let the next handler know it can proceed
		if len(journalChannel) == 0 {
			journalChannel <- 1
		}
	}
}

// runHandler loops, calling the Handler when Messages are available to process.
//
// TODO gracefully handle Orbiter.Stop(). Currently all handlers stop
// immediately. Better behaviour would be for Receiver to stop first and the
// rest of the handlers finish processing anything available to them before
// stopping. This could be achieved better by the Orbiter.Stop() function
// closing the channel buffer and the receiver exiting on no more data.
func (o *inputOrbiter) runHandler(h Handler, t int) {
	var this, last, i, j uint64
	nextChannel := o.channel[(t+1)%(EXECUTOR+1)]
	for _ = range o.channel[t] {
		// Get the current indexes.
		// this - current index of this Handler
		// last - highest index that this Handler can process
		this = o.GetIndex(t)
		last = o.GetIndex(t-1) - 1

		// Check if we can process anything
		if this < last {
			// Build list of indexes to process
			indexes := make([]uint64, last-this)
			for i, j = this+1, 0; i <= last; i, j = i+1, j+1 {
				indexes[j] = i
			}

			// Call the Handler
			if h != nil {
				h(o, indexes)
			}

			// Let the next handler know it can proceed
			if len(nextChannel) == 0 && o.running && t != EXECUTOR {
				nextChannel <- 1
			}
		}
	}
}
<|endoftext|>