<commit_before>package main

type MessageQueue struct {
	outputCh chan interface{}
	inputCh  chan interface{}
	selector chan *MessageQueue
}

func (mq *MessageQueue) Put(m interface{}) {
	mq.inputCh <- m
}

func (mq *MessageQueue) Get() interface{} {
	return <-mq.outputCh
}

func (mq *MessageQueue) Shutdown() {
	close(mq.inputCh)
}

func (mq *MessageQueue) loop() {
	buffer := make([]interface{}, 0, 10)
	for {
		var selector chan *MessageQueue
		var outputChan chan interface{}
		var outputValue interface{}
		if len(buffer) > 0 {
			selector = mq.selector
			outputChan = mq.outputCh
			outputValue = buffer[0]
		}
		select {
		case value, ok := <-mq.inputCh:
			if !ok {
				return
			}
			buffer = append(buffer, value)
		case outputChan <- outputValue:
			buffer = buffer[1:]
		case selector <- mq:
		}
	}
}

func NewMessageQueue(selector chan *MessageQueue) *MessageQueue {
	mq := &MessageQueue{
		outputCh: make(chan interface{}),
		inputCh:  make(chan interface{}, 1),
		selector: selector,
	}
	go mq.loop()
	return mq
}
<commit_msg>MessageQueue: dump all the remaining messages on shutdown<commit_after>package main

type MessageQueue struct {
	outputCh chan interface{}
	inputCh  chan interface{}
	dumpCh   chan []interface{}
	selector chan *MessageQueue
}

func (mq *MessageQueue) Put(m interface{}) {
	mq.inputCh <- m
}

func (mq *MessageQueue) Get() interface{} {
	return <-mq.outputCh
}

func (mq *MessageQueue) Shutdown() []interface{} {
	close(mq.inputCh)
	return <-mq.dumpCh
}

func (mq *MessageQueue) loop() {
	buffer := make([]interface{}, 0, 10)
	for {
		var selector chan *MessageQueue
		var outputChan chan interface{}
		var outputValue interface{}
		if len(buffer) > 0 {
			selector = mq.selector
			outputChan = mq.outputCh
			outputValue = buffer[0]
		}
		select {
		case value, ok := <-mq.inputCh:
			if !ok {
				mq.dumpCh <- buffer
				return
			}
			buffer = append(buffer, value)
		case outputChan <- outputValue:
			buffer = buffer[1:]
		case selector <- mq:
		}
	}
}

func NewMessageQueue(selector chan *MessageQueue) *MessageQueue {
	mq := &MessageQueue{
		outputCh: make(chan interface{}),
		inputCh:  make(chan interface{}, 1),
		dumpCh:   make(chan []interface{}, 1),
		selector: selector,
	}
	go mq.loop()
	return mq
}
<|endoftext|>


<commit_before>package xlsx

import (
	"fmt"
	"math"
	"strconv"
)

type CellType int

const (
	CellTypeString CellType = iota
	CellTypeFormula
	CellTypeNumeric
	CellTypeBool
	CellTypeInline
	CellTypeError
)

// Cell is a high level structure intended to provide user access to
// the contents of Cell within an xlsx.Row.
type Cell struct {
	Row      *Row
	Value    string
	formula  string
	style    *Style
	numFmt   string
	date1904 bool
	Hidden   bool
	cellType CellType
}

// CellInterface defines the public API of the Cell.
type CellInterface interface {
	String() string
	FormattedValue() string
}

func NewCell(r *Row) *Cell {
	return &Cell{style: NewStyle(), Row: r}
}

func (c *Cell) Type() CellType {
	return c.cellType
}

// Set string
func (c *Cell) SetString(s string) {
	c.Value = s
	c.formula = ""
	c.cellType = CellTypeString
}

// String returns the value of a Cell as a string.
func (c *Cell) String() string {
	return c.FormattedValue()
}

// Set float
func (c *Cell) SetFloat(n float64) {
	c.SetFloatWithFormat(n, "0.00e+00")
}

/*
	Set float with format. The followings are samples of format samples.

	* "0.00e+00"
	* "0", "#,##0"
	* "0.00", "#,##0.00", "@"
	* "#,##0 ;(#,##0)", "#,##0 ;[red](#,##0)"
	* "#,##0.00;(#,##0.00)", "#,##0.00;[red](#,##0.00)"
	* "0%", "0.00%"
	* "0.00e+00", "##0.0e+0"
*/
func (c *Cell) SetFloatWithFormat(n float64, format string) {
	// tmp value. final value is formatted by FormattedValue() method
	c.Value = fmt.Sprintf("%e", n)
	c.numFmt = format
	c.Value = c.FormattedValue()
	c.formula = ""
	c.cellType = CellTypeNumeric
}

// Returns the value of cell as a number
func (c *Cell) Float() (float64, error) {
	f, err := strconv.ParseFloat(c.Value, 64)
	if err != nil {
		return math.NaN(), err
	}
	return f, nil
}

// Set a 64-bit integer
func (c *Cell) SetInt64(n int64) {
	c.Value = fmt.Sprintf("%d", n)
	c.numFmt = "0"
	c.formula = ""
	c.cellType = CellTypeNumeric
}

// Returns the value of cell as 64-bit integer
func (c *Cell) Int64() (int64, error) {
	f, err := strconv.ParseInt(c.Value, 10, 64)
	if err != nil {
		return -1, err
	}
	return f, nil
}

// Set integer
func (c *Cell) SetInt(n int) {
	c.Value = fmt.Sprintf("%d", n)
	c.numFmt = "0"
	c.formula = ""
	c.cellType = CellTypeNumeric
}

// Returns the value of cell as integer
// Has max 53 bits of precision
// See: float64(int64(math.MaxInt))
func (c *Cell) Int() (int, error) {
	f, err := strconv.ParseFloat(c.Value, 64)
	if err != nil {
		return -1, err
	}
	return int(f), nil
}

// Set boolean
func (c *Cell) SetBool(b bool) {
	if b {
		c.Value = "1"
	} else {
		c.Value = "0"
	}
	c.cellType = CellTypeBool
}

// Get boolean
func (c *Cell) Bool() bool {
	return c.Value == "1"
}

// Set formula
func (c *Cell) SetFormula(formula string) {
	c.formula = formula
	c.cellType = CellTypeFormula
}

// Returns formula
func (c *Cell) Formula() string {
	return c.formula
}

// GetStyle returns the Style associated with a Cell
func (c *Cell) GetStyle() *Style {
	return c.style
}

// SetStyle sets the style of a cell.
func (c *Cell) SetStyle(style *Style) {
	c.style = style
}

// The number format string is returnable from a cell.
func (c *Cell) GetNumberFormat() string {
	return c.numFmt
}

func (c *Cell) formatToTime(format string) string {
	f, err := strconv.ParseFloat(c.Value, 64)
	if err != nil {
		return err.Error()
	}
	return TimeFromExcelTime(f, c.date1904).Format(format)
}

func (c *Cell) formatToFloat(format string) string {
	f, err := strconv.ParseFloat(c.Value, 64)
	if err != nil {
		return err.Error()
	}
	return fmt.Sprintf(format, f)
}

func (c *Cell) formatToInt(format string) string {
	f, err := strconv.ParseFloat(c.Value, 64)
	if err != nil {
		return err.Error()
	}
	return fmt.Sprintf(format, int(f))
}

// Return the formatted version of the value.
func (c *Cell) FormattedValue() string {
	if c.Type() == CellTypeString {
		return c.Value
	}
	var numberFormat string = c.GetNumberFormat()
	switch numberFormat {
	case "general":
		return c.Value
	case "0", "#,##0":
		return c.formatToInt("%d")
	case "0.00", "#,##0.00", "@":
		return c.formatToFloat("%.2f")
	case "#,##0 ;(#,##0)", "#,##0 ;[red](#,##0)":
		f, err := strconv.ParseFloat(c.Value, 64)
		if err != nil {
			return err.Error()
		}
		if f < 0 {
			i := int(math.Abs(f))
			return fmt.Sprintf("(%d)", i)
		}
		i := int(f)
		return fmt.Sprintf("%d", i)
	case "#,##0.00;(#,##0.00)", "#,##0.00;[red](#,##0.00)":
		f, err := strconv.ParseFloat(c.Value, 64)
		if err != nil {
			return err.Error()
		}
		if f < 0 {
			return fmt.Sprintf("(%.2f)", f)
		}
		return fmt.Sprintf("%.2f", f)
	case "0%":
		f, err := strconv.ParseFloat(c.Value, 64)
		if err != nil {
			return err.Error()
		}
		f = f * 100
		return fmt.Sprintf("%d%%", int(f))
	case "0.00%":
		f, err := strconv.ParseFloat(c.Value, 64)
		if err != nil {
			return err.Error()
		}
		f = f * 100
		return fmt.Sprintf("%.2f%%", f)
	case "0.00e+00", "##0.0e+0":
		return c.formatToFloat("%e")
	case "mm-dd-yy":
		return c.formatToTime("01-02-06")
	case "d-mmm-yy":
		return c.formatToTime("2-Jan-06")
	case "d-mmm":
		return c.formatToTime("2-Jan")
	case "mmm-yy":
		return c.formatToTime("Jan-06")
	case "h:mm am/pm":
		return c.formatToTime("3:04 pm")
	case "h:mm:ss am/pm":
		return c.formatToTime("3:04:05 pm")
	case "h:mm":
		return c.formatToTime("15:04")
	case "h:mm:ss":
		return c.formatToTime("15:04:05")
	case "m/d/yy h:mm":
		return c.formatToTime("1/2/06 15:04")
	case "mm:ss":
		return c.formatToTime("04:05")
	case "[h]:mm:ss":
		f, err := strconv.ParseFloat(c.Value, 64)
		if err != nil {
			return err.Error()
		}
		t := TimeFromExcelTime(f, c.date1904)
		if t.Hour() > 0 {
			return t.Format("15:04:05")
		}
		return t.Format("04:05")
	case "mmss.0":
		f, err := strconv.ParseFloat(c.Value, 64)
		if err != nil {
			return err.Error()
		}
		t := TimeFromExcelTime(f, c.date1904)
		return fmt.Sprintf("%0d%0d.%d", t.Minute(), t.Second(), t.Nanosecond()/1000)

	case "yyyy\\-mm\\-dd":
		return c.formatToTime("2006\\-01\\-02")
	case "dd/mm/yy":
		return c.formatToTime("02/01/06")
	case "hh:mm:ss":
		return c.formatToTime("15:04:05")
	case "dd/mm/yy\\ hh:mm":
		return c.formatToTime("02/01/06\\ 15:04")
	case "dd/mm/yyyy hh:mm:ss":
		return c.formatToTime("02/01/2006 15:04:05")
	case "yy-mm-dd":
		return c.formatToTime("06-01-02")
	case "d-mmm-yyyy":
		return c.formatToTime("2-Jan-2006")
	case "m/d/yy":
		return c.formatToTime("1/2/06")
	case "m/d/yyyy":
		return c.formatToTime("1/2/2006")
	case "dd-mmm-yyyy":
		return c.formatToTime("02-Jan-2006")
	case "dd/mm/yyyy":
		return c.formatToTime("02/01/2006")
	case "mm/dd/yy hh:mm am/pm":
		return c.formatToTime("01/02/06 03:04 pm")
	case "mm/dd/yyyy hh:mm:ss":
		return c.formatToTime("01/02/2006 15:04:05")
	case "yyyy-mm-dd hh:mm:ss":
		return c.formatToTime("2006-01-02 15:04:05")
	}
	return c.Value
}
<commit_msg>Fixes #101 without breaking the tests.<commit_after>package xlsx

import (
	"fmt"
	"math"
	"strconv"
)

type CellType int

const (
	CellTypeString CellType = iota
	CellTypeFormula
	CellTypeNumeric
	CellTypeBool
	CellTypeInline
	CellTypeError
)

// Cell is a high level structure intended to provide user access to
// the contents of Cell within an xlsx.Row.
type Cell struct {
	Row      *Row
	Value    string
	formula  string
	style    *Style
	numFmt   string
	date1904 bool
	Hidden   bool
	cellType CellType
}

// CellInterface defines the public API of the Cell.
type CellInterface interface {
	String() string
	FormattedValue() string
}

func NewCell(r *Row) *Cell {
	return &Cell{style: NewStyle(), Row: r}
}

func (c *Cell) Type() CellType {
	return c.cellType
}

// Set string
func (c *Cell) SetString(s string) {
	c.Value = s
	c.formula = ""
	c.cellType = CellTypeString
}

// String returns the value of a Cell as a string.
func (c *Cell) String() string {
	return c.FormattedValue()
}

// Set float
func (c *Cell) SetFloat(n float64) {
	c.SetFloatWithFormat(n, "0.00e+00")
}

/*
	Set float with format. The followings are samples of format samples.

	* "0.00e+00"
	* "0", "#,##0"
	* "0.00", "#,##0.00", "@"
	* "#,##0 ;(#,##0)", "#,##0 ;[red](#,##0)"
	* "#,##0.00;(#,##0.00)", "#,##0.00;[red](#,##0.00)"
	* "0%", "0.00%"
	* "0.00e+00", "##0.0e+0"
*/
func (c *Cell) SetFloatWithFormat(n float64, format string) {
	// tmp value. final value is formatted by FormattedValue() method
	c.Value = fmt.Sprintf("%e", n)
	c.numFmt = format
	c.Value = c.FormattedValue()
	c.formula = ""
	c.cellType = CellTypeNumeric
}

// Returns the value of cell as a number
func (c *Cell) Float() (float64, error) {
	f, err := strconv.ParseFloat(c.Value, 64)
	if err != nil {
		return math.NaN(), err
	}
	return f, nil
}

// Set a 64-bit integer
func (c *Cell) SetInt64(n int64) {
	c.Value = fmt.Sprintf("%d", n)
	c.numFmt = "0"
	c.formula = ""
	c.cellType = CellTypeNumeric
}

// Returns the value of cell as 64-bit integer
func (c *Cell) Int64() (int64, error) {
	f, err := strconv.ParseInt(c.Value, 10, 64)
	if err != nil {
		return -1, err
	}
	return f, nil
}

// Set integer
func (c *Cell) SetInt(n int) {
	c.Value = fmt.Sprintf("%d", n)
	c.numFmt = "0"
	c.formula = ""
	c.cellType = CellTypeNumeric
}

// Returns the value of cell as integer
// Has max 53 bits of precision
// See: float64(int64(math.MaxInt))
func (c *Cell) Int() (int, error) {
	f, err := strconv.ParseFloat(c.Value, 64)
	if err != nil {
		return -1, err
	}
	return int(f), nil
}

// Set boolean
func (c *Cell) SetBool(b bool) {
	if b {
		c.Value = "1"
	} else {
		c.Value = "0"
	}
	c.cellType = CellTypeBool
}

// Get boolean
func (c *Cell) Bool() bool {
	return c.Value == "1"
}

// Set formula
func (c *Cell) SetFormula(formula string) {
	c.formula = formula
	c.cellType = CellTypeFormula
}

// Returns formula
func (c *Cell) Formula() string {
	return c.formula
}

// GetStyle returns the Style associated with a Cell
func (c *Cell) GetStyle() *Style {
	return c.style
}

// SetStyle sets the style of a cell.
func (c *Cell) SetStyle(style *Style) {
	c.style = style
}

// The number format string is returnable from a cell.
func (c *Cell) GetNumberFormat() string {
	return c.numFmt
}

func (c *Cell) formatToTime(format string) string {
	f, err := strconv.ParseFloat(c.Value, 64)
	if err != nil {
		return err.Error()
	}
	return TimeFromExcelTime(f, c.date1904).Format(format)
}

func (c *Cell) formatToFloat(format string) string {
	f, err := strconv.ParseFloat(c.Value, 64)
	if err != nil {
		return err.Error()
	}
	return fmt.Sprintf(format, f)
}

func (c *Cell) formatToInt(format string) string {
	f, err := strconv.ParseFloat(c.Value, 64)
	if err != nil {
		return err.Error()
	}
	return fmt.Sprintf(format, int(f))
}

// Return the formatted version of the value.
func (c *Cell) FormattedValue() string {
	var numberFormat string = c.GetNumberFormat()
	isText := numberFormat == "general" && numberFormat == "@"
	if c.Type() == CellTypeString && isText {
		return c.Value
	}
	switch numberFormat {
	case "general":
		return c.Value
	case "0", "#,##0":
		return c.formatToInt("%d")
	case "0.00", "#,##0.00", "@":
		return c.formatToFloat("%.2f")
	case "#,##0 ;(#,##0)", "#,##0 ;[red](#,##0)":
		f, err := strconv.ParseFloat(c.Value, 64)
		if err != nil {
			return err.Error()
		}
		if f < 0 {
			i := int(math.Abs(f))
			return fmt.Sprintf("(%d)", i)
		}
		i := int(f)
		return fmt.Sprintf("%d", i)
	case "#,##0.00;(#,##0.00)", "#,##0.00;[red](#,##0.00)":
		f, err := strconv.ParseFloat(c.Value, 64)
		if err != nil {
			return err.Error()
		}
		if f < 0 {
			return fmt.Sprintf("(%.2f)", f)
		}
		return fmt.Sprintf("%.2f", f)
	case "0%":
		f, err := strconv.ParseFloat(c.Value, 64)
		if err != nil {
			return err.Error()
		}
		f = f * 100
		return fmt.Sprintf("%d%%", int(f))
	case "0.00%":
		f, err := strconv.ParseFloat(c.Value, 64)
		if err != nil {
			return err.Error()
		}
		f = f * 100
		return fmt.Sprintf("%.2f%%", f)
	case "0.00e+00", "##0.0e+0":
		return c.formatToFloat("%e")
	case "mm-dd-yy":
		return c.formatToTime("01-02-06")
	case "d-mmm-yy":
		return c.formatToTime("2-Jan-06")
	case "d-mmm":
		return c.formatToTime("2-Jan")
	case "mmm-yy":
		return c.formatToTime("Jan-06")
	case "h:mm am/pm":
		return c.formatToTime("3:04 pm")
	case "h:mm:ss am/pm":
		return c.formatToTime("3:04:05 pm")
	case "h:mm":
		return c.formatToTime("15:04")
	case "h:mm:ss":
		return c.formatToTime("15:04:05")
	case "m/d/yy h:mm":
		return c.formatToTime("1/2/06 15:04")
	case "mm:ss":
		return c.formatToTime("04:05")
	case "[h]:mm:ss":
		f, err := strconv.ParseFloat(c.Value, 64)
		if err != nil {
			return err.Error()
		}
		t := TimeFromExcelTime(f, c.date1904)
		if t.Hour() > 0 {
			return t.Format("15:04:05")
		}
		return t.Format("04:05")
	case "mmss.0":
		f, err := strconv.ParseFloat(c.Value, 64)
		if err != nil {
			return err.Error()
		}
		t := TimeFromExcelTime(f, c.date1904)
		return fmt.Sprintf("%0d%0d.%d", t.Minute(), t.Second(), t.Nanosecond()/1000)

	case "yyyy\\-mm\\-dd":
		return c.formatToTime("2006\\-01\\-02")
	case "dd/mm/yy":
		return c.formatToTime("02/01/06")
	case "hh:mm:ss":
		return c.formatToTime("15:04:05")
	case "dd/mm/yy\\ hh:mm":
		return c.formatToTime("02/01/06\\ 15:04")
	case "dd/mm/yyyy hh:mm:ss":
		return c.formatToTime("02/01/2006 15:04:05")
	case "yy-mm-dd":
		return c.formatToTime("06-01-02")
	case "d-mmm-yyyy":
		return c.formatToTime("2-Jan-2006")
	case "m/d/yy":
		return c.formatToTime("1/2/06")
	case "m/d/yyyy":
		return c.formatToTime("1/2/2006")
	case "dd-mmm-yyyy":
		return c.formatToTime("02-Jan-2006")
	case "dd/mm/yyyy":
		return c.formatToTime("02/01/2006")
	case "mm/dd/yy hh:mm am/pm":
		return c.formatToTime("01/02/06 03:04 pm")
	case "mm/dd/yyyy hh:mm:ss":
		return c.formatToTime("01/02/2006 15:04:05")
	case "yyyy-mm-dd hh:mm:ss":
		return c.formatToTime("2006-01-02 15:04:05")
	}
	return c.Value
}
<|endoftext|>


<commit_before>package sudoku

import (
	"log"
	"math/rand"
	"strconv"
	"strings"
)

const NUM_NEIGHBORS = (DIM-1)*3 - (BLOCK_DIM-1)*2

type SymmetryType int

const (
	SYMMETRY_NONE SymmetryType = iota
	SYMMETRY_ANY
	SYMMETRY_HORIZONTAL
	SYMMETRY_VERTICAL
	SYMMETRY_BOTH
)

//Cell represents a single cell within a grid. It maintains information about the number that is filled, the numbers that are
//currently legal given the filled status of its neighbors, and whether any possibilities have been
//explicitly excluded by solve techniques. Cells should not be constructed on their own; create a Grid
//and grab references to the cells from there.
type Cell struct {
	grid *Grid
	//The number if it's explicitly set. Number() will return it if it's explicitly or implicitly set.
	number      int
	Row         int
	Col         int
	Block       int
	neighbors   CellList
	impossibles [DIM]int
	excluded    [DIM]bool
}

func newCell(grid *Grid, row int, col int) Cell {
	//TODO: we should not set the number until neighbors are initialized.
	return Cell{grid: grid, Row: row, Col: col, Block: grid.blockForCell(row, col)}
}

//InGrid returns a reference to a cell in the provided grid that has the same row/column as this cell.
//Effectively, this cell's analogue in the other grid.
func (self *Cell) InGrid(grid *Grid) *Cell {
	//Returns our analogue in the given grid.
	if grid == nil {
		return nil
	}
	return grid.Cell(self.Row, self.Col)
}

func (self *Cell) load(data string) {
	//Format, for now, is just the number itself, or 0 if no number.
	data = strings.Replace(data, ALT_0, "0", -1)
	num, _ := strconv.Atoi(data)
	self.SetNumber(num)
}

//Number returns the number the cell is currently set to.
func (self *Cell) Number() int {
	//A layer of indirection since number needs to be used from the Setter.
	return self.number
}

//SetNumber explicitly sets the number of the cell. This operation could cause the grid to become
//invalid if it conflicts with its neighbors' numbers. This operation will affect the Possiblities()
//of its neighbor cells.
func (self *Cell) SetNumber(number int) {
	//Sets the explicit number. This will affect its neighbors possibles list.
	if self.number == number {
		//No work to do now.
		return
	}
	oldNumber := self.number
	self.number = number
	if oldNumber > 0 {
		for i := 1; i <= DIM; i++ {
			if i == oldNumber {
				continue
			}
			self.setPossible(i)
		}
		self.alertNeighbors(oldNumber, true)
	}
	if number > 0 {
		for i := 1; i <= DIM; i++ {
			if i == number {
				continue
			}
			self.setImpossible(i)
		}
		self.alertNeighbors(number, false)
	}
	if self.grid != nil {
		self.grid.cellModified(self)
		if (oldNumber > 0 && number == 0) || (oldNumber == 0 && number > 0) {
			//Our rank will have changed.
			//TODO: figure out how to test this.
			self.grid.cellRankChanged(self)
		}
	}
}

func (self *Cell) alertNeighbors(number int, possible bool) {
	for _, cell := range self.Neighbors() {
		if possible {
			cell.setPossible(number)
		} else {
			cell.setImpossible(number)
		}
	}
}

func (self *Cell) setPossible(number int) {
	//Number is 1 indexed, but we store it as 0-indexed
	number--
	if number < 0 || number >= DIM {
		return
	}
	if self.impossibles[number] == 0 {
		log.Println("We were told to mark something that was already possible to possible.")
		return
	}
	self.impossibles[number]--
	if self.impossibles[number] == 0 && self.grid != nil {
		//TODO: should we check exclusion to save work?
		//Our rank will have changed.
		self.grid.cellRankChanged(self)
		//We may have just become valid.
		self.checkInvalid()
	}

}

func (self *Cell) setImpossible(number int) {
	//Number is 1 indexed, but we store it as 0-indexed
	number--
	if number < 0 || number >= DIM {
		return
	}
	self.impossibles[number]++
	if self.impossibles[number] == 1 && self.grid != nil {
		//TODO: should we check exclusion to save work?
		//Our rank will have changed.
		self.grid.cellRankChanged(self)
		//We may have just become invalid.
		self.checkInvalid()
	}
}

//SetExcluded defines whether a possibility is considered not feasible, even if not directly precluded
//by the Number()s of the cell's neighbors. This is used by advanced HumanSolve techniques that
//cull possibilities that are logically excluded by the state of the grid, in a non-direct way.
//The state of Excluded bits will affect the results of this cell's Possibilities() list.
func (self *Cell) SetExcluded(number int, excluded bool) {
	number--
	if number < 0 || number >= DIM {
		return
	}
	self.excluded[number] = excluded
	//Our rank may have changed.
	//TODO: should we check if we're invalid already?
	if self.grid != nil {
		self.grid.cellRankChanged(self)
		self.checkInvalid()
	}
}

//ResetExcludes sets all excluded bits to false, so that Possibilities() will be based purely
//on direct implications of the Number()s of neighbors. See also SetExcluded.
func (self *Cell) ResetExcludes() {
	for i := 0; i < DIM; i++ {
		self.excluded[i] = false
	}
	//Our rank may have changed.
	//TODO: should we check if we're invalid already?
	if self.grid != nil {
		self.grid.cellRankChanged(self)
		self.checkInvalid()
	}
}

//Possible returns whether or not a given number is legal to fill via SetNumber, given the state of the grid (specifically,
//the cell's neighbors) and the numbers the cell was told to explicitly exclude via SetExclude.
//If the cell is already filled with a number, it will return false for all numbers.
func (self *Cell) Possible(number int) bool {
	//Number is 1 indexed, but we store it as 0-indexed
	number--
	if number < 0 || number >= DIM {
		return false
	}
	return self.impossibles[number] == 0 && !self.excluded[number]
}

//Possibilities returns a list of all current possibilities for this cell: all numbers for which cell.Possible
//returns true.
func (self *Cell) Possibilities() (result IntSlice) {
	if self.number != 0 {
		return nil
	}
	for i := 1; i <= DIM; i++ {
		if self.Possible(i) {
			result = append(result, i)
		}
	}
	return result
}

func (self *Cell) checkInvalid() {
	if self.grid == nil {
		return
	}
	if self.Invalid() {
		self.grid.cellIsInvalid(self)
	} else {
		self.grid.cellIsValid(self)
	}
}

func (self *Cell) Invalid() bool {
	//Returns true if no numbers are possible.
	//TODO: figure out a way to send this back up to the solver when it happens.
	for i, counter := range self.impossibles {
		if counter == 0 && !self.excluded[i] {
			return false
		}
	}
	return true
}

func (self *Cell) rank() int {
	if self.number != 0 {
		return 0
	}
	count := 0
	for _, counter := range self.impossibles {
		if counter == 0 {
			count++
		}
	}
	return count
}

func (self *Cell) ref() cellRef {
	return cellRef{self.Row, self.Col}
}

//Sets ourselves to a random one of our possibilities.
func (self *Cell) pickRandom() {
	possibilities := self.Possibilities()
	choice := possibilities[rand.Intn(len(possibilities))]
	self.SetNumber(choice)
}

func (self *Cell) implicitNumber() int {
	//Impossibles is in 0-index space, but represents nubmers in 1-indexed space.
	result := -1
	for i, counter := range self.impossibles {
		if counter == 0 {
			//Is there someone else competing for this? If so there's no implicit number
			if result != -1 {
				return 0
			}
			result = i
		}
	}
	//convert from 0-indexed to 1-indexed
	return result + 1
}

func (self *Cell) SymmetricalPartner(symmetry SymmetryType) *Cell {

	if symmetry == SYMMETRY_ANY {
		//TODO: don't chose a type of smmetry that doesn't have a partner
		typesOfSymmetry := []SymmetryType{SYMMETRY_BOTH, SYMMETRY_HORIZONTAL, SYMMETRY_HORIZONTAL, SYMMETRY_VERTICAL}
		symmetry = typesOfSymmetry[rand.Intn(len(typesOfSymmetry))]
	}

	switch symmetry {
	case SYMMETRY_BOTH:
		if cell := self.grid.Cell(DIM-self.Row-1, DIM-self.Col-1); cell != self {
			return cell
		}
	case SYMMETRY_HORIZONTAL:
		if cell := self.grid.Cell(DIM-self.Row-1, self.Col); cell != self {
			return cell
		}
	case SYMMETRY_VERTICAL:
		if cell := self.grid.Cell(self.Row, DIM-self.Col-1); cell != self {
			return cell
		}
	}

	//If the cell was the same as self, or SYMMETRY_NONE
	return nil
}

func (self *Cell) Neighbors() CellList {
	if self.grid == nil || !self.grid.initalized {
		return nil
	}
	if self.neighbors == nil {
		//We don't want duplicates, so we will collect in a map (used as a set) and then reduce.
		neighborsMap := make(map[*Cell]bool)
		for _, cell := range self.grid.Row(self.Row) {
			if cell == self {
				continue
			}
			neighborsMap[cell] = true
		}
		for _, cell := range self.grid.Col(self.Col) {
			if cell == self {
				continue
			}
			neighborsMap[cell] = true
		}
		for _, cell := range self.grid.Block(self.Block) {
			if cell == self {
				continue
			}
			neighborsMap[cell] = true
		}
		self.neighbors = make([]*Cell, len(neighborsMap))
		i := 0
		for cell, _ := range neighborsMap {
			self.neighbors[i] = cell
			i++
		}
	}
	return self.neighbors

}

func (self *Cell) DataString() string {
	result := strconv.Itoa(self.Number())
	return strings.Replace(result, "0", ALT_0, -1)
}

func (self *Cell) String() string {
	return "Cell[" + strconv.Itoa(self.Row) + "][" + strconv.Itoa(self.Col) + "]:" + strconv.Itoa(self.Number()) + "\n"
}

func (self *Cell) positionInBlock() (top, right, bottom, left bool) {
	if self.grid == nil {
		return
	}
	topRow, topCol, bottomRow, bottomCol := self.grid.blockExtents(self.Block)
	top = self.Row == topRow
	right = self.Col == bottomCol
	bottom = self.Row == bottomRow
	left = self.Col == topCol
	return
}

func (self *Cell) diagramRows() (rows []string) {
	//We'll only draw barriers at our bottom right edge.
	_, right, bottom, _ := self.positionInBlock()
	current := 0
	for r := 0; r < BLOCK_DIM; r++ {
		row := ""
		for c := 0; c < BLOCK_DIM; c++ {
			if self.number != 0 {
				//Print just the number.
				if r == BLOCK_DIM/2 && c == BLOCK_DIM/2 {
					row += strconv.Itoa(self.number)
				} else {
					row += DIAGRAM_NUMBER
				}
			} else {
				//Print the possibles.
				if self.Possible(current + 1) {
					row += strconv.Itoa(current + 1)
				} else {
					row += DIAGRAM_IMPOSSIBLE
				}
			}
			current++
		}
		rows = append(rows, row)
	}

	//Do we need to pad each row with | on the right?
	if !right {
		for i, data := range rows {
			rows[i] = data + DIAGRAM_RIGHT
		}
	}
	//Do we need an extra bottom row?
	if !bottom {
		rows = append(rows, strings.Repeat(DIAGRAM_BOTTOM, BLOCK_DIM))
		// Does it need a + at the end?
		if !right {
			rows[len(rows)-1] = rows[len(rows)-1] + DIAGRAM_CORNER
		}
	}

	return rows
}

func (self *Cell) Diagram() string {
	return strings.Join(self.diagramRows(), "\n")
}
<commit_msg>Added a TODO in cell.Invalid<commit_after>package sudoku

import (
	"log"
	"math/rand"
	"strconv"
	"strings"
)

const NUM_NEIGHBORS = (DIM-1)*3 - (BLOCK_DIM-1)*2

type SymmetryType int

const (
	SYMMETRY_NONE SymmetryType = iota
	SYMMETRY_ANY
	SYMMETRY_HORIZONTAL
	SYMMETRY_VERTICAL
	SYMMETRY_BOTH
)

//Cell represents a single cell within a grid. It maintains information about the number that is filled, the numbers that are
//currently legal given the filled status of its neighbors, and whether any possibilities have been
//explicitly excluded by solve techniques. Cells should not be constructed on their own; create a Grid
//and grab references to the cells from there.
type Cell struct {
	grid *Grid
	//The number if it's explicitly set. Number() will return it if it's explicitly or implicitly set.
	number      int
	Row         int
	Col         int
	Block       int
	neighbors   CellList
	impossibles [DIM]int
	excluded    [DIM]bool
}

func newCell(grid *Grid, row int, col int) Cell {
	//TODO: we should not set the number until neighbors are initialized.
	return Cell{grid: grid, Row: row, Col: col, Block: grid.blockForCell(row, col)}
}

//InGrid returns a reference to a cell in the provided grid that has the same row/column as this cell.
//Effectively, this cell's analogue in the other grid.
func (self *Cell) InGrid(grid *Grid) *Cell {
	//Returns our analogue in the given grid.
	if grid == nil {
		return nil
	}
	return grid.Cell(self.Row, self.Col)
}

func (self *Cell) load(data string) {
	//Format, for now, is just the number itself, or 0 if no number.
	data = strings.Replace(data, ALT_0, "0", -1)
	num, _ := strconv.Atoi(data)
	self.SetNumber(num)
}

//Number returns the number the cell is currently set to.
func (self *Cell) Number() int {
	//A layer of indirection since number needs to be used from the Setter.
	return self.number
}

//SetNumber explicitly sets the number of the cell. This operation could cause the grid to become
//invalid if it conflicts with its neighbors' numbers. This operation will affect the Possiblities()
//of its neighbor cells.
func (self *Cell) SetNumber(number int) {
	//Sets the explicit number. This will affect its neighbors possibles list.
	if self.number == number {
		//No work to do now.
		return
	}
	oldNumber := self.number
	self.number = number
	if oldNumber > 0 {
		for i := 1; i <= DIM; i++ {
			if i == oldNumber {
				continue
			}
			self.setPossible(i)
		}
		self.alertNeighbors(oldNumber, true)
	}
	if number > 0 {
		for i := 1; i <= DIM; i++ {
			if i == number {
				continue
			}
			self.setImpossible(i)
		}
		self.alertNeighbors(number, false)
	}
	if self.grid != nil {
		self.grid.cellModified(self)
		if (oldNumber > 0 && number == 0) || (oldNumber == 0 && number > 0) {
			//Our rank will have changed.
			//TODO: figure out how to test this.
			self.grid.cellRankChanged(self)
		}
	}
}

func (self *Cell) alertNeighbors(number int, possible bool) {
	for _, cell := range self.Neighbors() {
		if possible {
			cell.setPossible(number)
		} else {
			cell.setImpossible(number)
		}
	}
}

func (self *Cell) setPossible(number int) {
	//Number is 1 indexed, but we store it as 0-indexed
	number--
	if number < 0 || number >= DIM {
		return
	}
	if self.impossibles[number] == 0 {
		log.Println("We were told to mark something that was already possible to possible.")
		return
	}
	self.impossibles[number]--
	if self.impossibles[number] == 0 && self.grid != nil {
		//TODO: should we check exclusion to save work?
		//Our rank will have changed.
		self.grid.cellRankChanged(self)
		//We may have just become valid.
		self.checkInvalid()
	}

}

func (self *Cell) setImpossible(number int) {
	//Number is 1 indexed, but we store it as 0-indexed
	number--
	if number < 0 || number >= DIM {
		return
	}
	self.impossibles[number]++
	if self.impossibles[number] == 1 && self.grid != nil {
		//TODO: should we check exclusion to save work?
		//Our rank will have changed.
		self.grid.cellRankChanged(self)
		//We may have just become invalid.
		self.checkInvalid()
	}
}

//SetExcluded defines whether a possibility is considered not feasible, even if not directly precluded
//by the Number()s of the cell's neighbors. This is used by advanced HumanSolve techniques that
//cull possibilities that are logically excluded by the state of the grid, in a non-direct way.
//The state of Excluded bits will affect the results of this cell's Possibilities() list.
func (self *Cell) SetExcluded(number int, excluded bool) {
	number--
	if number < 0 || number >= DIM {
		return
	}
	self.excluded[number] = excluded
	//Our rank may have changed.
	//TODO: should we check if we're invalid already?
	if self.grid != nil {
		self.grid.cellRankChanged(self)
		self.checkInvalid()
	}
}

//ResetExcludes sets all excluded bits to false, so that Possibilities() will be based purely
//on direct implications of the Number()s of neighbors. See also SetExcluded.
func (self *Cell) ResetExcludes() {
	for i := 0; i < DIM; i++ {
		self.excluded[i] = false
	}
	//Our rank may have changed.
	//TODO: should we check if we're invalid already?
	if self.grid != nil {
		self.grid.cellRankChanged(self)
		self.checkInvalid()
	}
}

//Possible returns whether or not a given number is legal to fill via SetNumber, given the state of the grid (specifically,
//the cell's neighbors) and the numbers the cell was told to explicitly exclude via SetExclude.
//If the cell is already filled with a number, it will return false for all numbers.
func (self *Cell) Possible(number int) bool {
	//Number is 1 indexed, but we store it as 0-indexed
	number--
	if number < 0 || number >= DIM {
		return false
	}
	return self.impossibles[number] == 0 && !self.excluded[number]
}

//Possibilities returns a list of all current possibilities for this cell: all numbers for which cell.Possible
//returns true.
func (self *Cell) Possibilities() (result IntSlice) {
	if self.number != 0 {
		return nil
	}
	for i := 1; i <= DIM; i++ {
		if self.Possible(i) {
			result = append(result, i)
		}
	}
	return result
}

func (self *Cell) checkInvalid() {
	if self.grid == nil {
		return
	}
	if self.Invalid() {
		self.grid.cellIsInvalid(self)
	} else {
		self.grid.cellIsValid(self)
	}
}

func (self *Cell) Invalid() bool {
	//Returns true if no numbers are possible.
	//TODO: figure out a way to send this back up to the solver when it happens.
	//TODO: shouldn't this always return true if there is a number set?
	for i, counter := range self.impossibles {
		if counter == 0 && !self.excluded[i] {
			return false
		}
	}
	return true
}

func (self *Cell) rank() int {
	if self.number != 0 {
		return 0
	}
	count := 0
	for _, counter := range self.impossibles {
		if counter == 0 {
			count++
		}
	}
	return count
}

func (self *Cell) ref() cellRef {
	return cellRef{self.Row, self.Col}
}

//Sets ourselves to a random one of our possibilities.
func (self *Cell) pickRandom() {
	possibilities := self.Possibilities()
	choice := possibilities[rand.Intn(len(possibilities))]
	self.SetNumber(choice)
}

func (self *Cell) implicitNumber() int {
	//Impossibles is in 0-index space, but represents nubmers in 1-indexed space.
	result := -1
	for i, counter := range self.impossibles {
		if counter == 0 {
			//Is there someone else competing for this? If so there's no implicit number
			if result != -1 {
				return 0
			}
			result = i
		}
	}
	//convert from 0-indexed to 1-indexed
	return result + 1
}

func (self *Cell) SymmetricalPartner(symmetry SymmetryType) *Cell {

	if symmetry == SYMMETRY_ANY {
		//TODO: don't chose a type of smmetry that doesn't have a partner
		typesOfSymmetry := []SymmetryType{SYMMETRY_BOTH, SYMMETRY_HORIZONTAL, SYMMETRY_HORIZONTAL, SYMMETRY_VERTICAL}
		symmetry = typesOfSymmetry[rand.Intn(len(typesOfSymmetry))]
	}

	switch symmetry {
	case SYMMETRY_BOTH:
		if cell := self.grid.Cell(DIM-self.Row-1, DIM-self.Col-1); cell != self {
			return cell
		}
	case SYMMETRY_HORIZONTAL:
		if cell := self.grid.Cell(DIM-self.Row-1, self.Col); cell != self {
			return cell
		}
	case SYMMETRY_VERTICAL:
		if cell := self.grid.Cell(self.Row, DIM-self.Col-1); cell != self {
			return cell
		}
	}

	//If the cell was the same as self, or SYMMETRY_NONE
	return nil
}

func (self *Cell) Neighbors() CellList {
	if self.grid == nil || !self.grid.initalized {
		return nil
	}
	if self.neighbors == nil {
		//We don't want duplicates, so we will collect in a map (used as a set) and then reduce.
		neighborsMap := make(map[*Cell]bool)
		for _, cell := range self.grid.Row(self.Row) {
			if cell == self {
				continue
			}
			neighborsMap[cell] = true
		}
		for _, cell := range self.grid.Col(self.Col) {
			if cell == self {
				continue
			}
			neighborsMap[cell] = true
		}
		for _, cell := range self.grid.Block(self.Block) {
			if cell == self {
				continue
			}
			neighborsMap[cell] = true
		}
		self.neighbors = make([]*Cell, len(neighborsMap))
		i := 0
		for cell, _ := range neighborsMap {
			self.neighbors[i] = cell
			i++
		}
	}
	return self.neighbors

}

func (self *Cell) DataString() string {
	result := strconv.Itoa(self.Number())
	return strings.Replace(result, "0", ALT_0, -1)
}

func (self *Cell) String() string {
	return "Cell[" + strconv.Itoa(self.Row) + "][" + strconv.Itoa(self.Col) + "]:" + strconv.Itoa(self.Number()) + "\n"
}

func (self *Cell) positionInBlock() (top, right, bottom, left bool) {
	if self.grid == nil {
		return
	}
	topRow, topCol, bottomRow, bottomCol := self.grid.blockExtents(self.Block)
	top = self.Row == topRow
	right = self.Col == bottomCol
	bottom = self.Row == bottomRow
	left = self.Col == topCol
	return
}

func (self *Cell) diagramRows() (rows []string) {
	//We'll only draw barriers at our bottom right edge.
	_, right, bottom, _ := self.positionInBlock()
	current := 0
	for r := 0; r < BLOCK_DIM; r++ {
		row := ""
		for c := 0; c < BLOCK_DIM; c++ {
			if self.number != 0 {
				//Print just the number.
				if r == BLOCK_DIM/2 && c == BLOCK_DIM/2 {
					row += strconv.Itoa(self.number)
				} else {
					row += DIAGRAM_NUMBER
				}
			} else {
				//Print the possibles.
				if self.Possible(current + 1) {
					row += strconv.Itoa(current + 1)
				} else {
					row += DIAGRAM_IMPOSSIBLE
				}
			}
			current++
		}
		rows = append(rows, row)
	}

	//Do we need to pad each row with | on the right?
	if !right {
		for i, data := range rows {
			rows[i] = data + DIAGRAM_RIGHT
		}
	}
	//Do we need an extra bottom row?
	if !bottom {
		rows = append(rows, strings.Repeat(DIAGRAM_BOTTOM, BLOCK_DIM))
		// Does it need a + at the end?
		if !right {
			rows[len(rows)-1] = rows[len(rows)-1] + DIAGRAM_CORNER
		}
	}

	return rows
}

func (self *Cell) Diagram() string {
	return strings.Join(self.diagramRows(), "\n")
}
<|endoftext|>


<commit_before>package blockchain

import (
	"math"
	"sync"
	"time"

	flow "github.com/tendermint/tendermint/Godeps/_workspace/src/code.google.com/p/mxk/go1/flowcontrol"
	. "github.com/tendermint/tendermint/common"
	"github.com/tendermint/tendermint/types"
)

const (
	requestIntervalMS         = 500
	maxTotalRequests          = 300
	maxPendingRequests        = maxTotalRequests
	maxPendingRequestsPerPeer = 50
	peerTimeoutSeconds        = 15
	minRecvRate               = 10240 // 10Kb/s
)

/*
	Peers self report their heights when we join the block pool.
	Starting from our latest pool.height, we request blocks
	in sequence from peers that reported higher heights than ours.
	Every so often we ask peers what height they're on so we can keep going.

	Requests are continuously made for blocks of heigher heights until
	the limits. If most of the requests have no available peers, and we
	are not at peer limits, we can probably switch to consensus reactor
*/

type BlockPool struct {
	QuitService
	startTime time.Time

	// block requests
	mtx        sync.Mutex
	requests   map[int]*bpRequester
	height     int   // the lowest key in requests.
	numPending int32 // number of requests pending assignment or block response

	// peers
	peersMtx sync.Mutex
	peers    map[string]*bpPeer

	requestsCh chan<- BlockRequest
	timeoutsCh chan<- string
}

func NewBlockPool(start int, requestsCh chan<- BlockRequest, timeoutsCh chan<- string) *BlockPool {
	bp := &BlockPool{
		peers: make(map[string]*bpPeer),

		requests:   make(map[int]*bpRequester),
		height:     start,
		numPending: 0,

		requestsCh: requestsCh,
		timeoutsCh: timeoutsCh,
	}
	bp.QuitService = *NewQuitService(log, "BlockPool", bp)
	return bp
}

func (pool *BlockPool) OnStart() error {
	pool.QuitService.OnStart()
	go pool.makeRequestsRoutine()
	pool.startTime = time.Now()
	return nil
}

func (pool *BlockPool) OnStop() {
	pool.QuitService.OnStop()
}

// Run spawns requests as needed.
func (pool *BlockPool) makeRequestsRoutine() {
	for {
		if !pool.IsRunning() {
			break
		}
		_, numPending := pool.GetStatus()
		if numPending >= maxPendingRequests {
			// sleep for a bit.
			time.Sleep(requestIntervalMS * time.Millisecond)
			// check for timed out peers
			pool.removeTimedoutPeers()
		} else if len(pool.requests) >= maxTotalRequests {
			// sleep for a bit.
			time.Sleep(requestIntervalMS * time.Millisecond)
			// check for timed out peers
			pool.removeTimedoutPeers()
		} else {
			// request for more blocks.
			pool.makeNextRequest()
		}
	}
}

func (pool *BlockPool) removeTimedoutPeers() {
	for _, peer := range pool.peers {
		if !peer.didTimeout && peer.numPending > 0 {
			curRate := peer.recvMonitor.Status().CurRate
			// XXX remove curRate != 0
			if curRate != 0 && curRate < minRecvRate {
				pool.sendTimeout(peer.id)
				log.Warn("SendTimeout", "peer", peer.id, "reason", "curRate too low")
				peer.didTimeout = true
			}
		}
		if peer.didTimeout {
			pool.peersMtx.Lock() // Lock
			pool.removePeer(peer.id)
			pool.peersMtx.Unlock()
		}
	}
}

func (pool *BlockPool) GetStatus() (height int, numPending int32) {
	pool.mtx.Lock() // Lock
	defer pool.mtx.Unlock()

	return pool.height, pool.numPending
}

// TODO: relax conditions, prevent abuse.
func (pool *BlockPool) IsCaughtUp() bool {
	pool.mtx.Lock()
	height := pool.height
	pool.mtx.Unlock()

	pool.peersMtx.Lock()
	numPeers := len(pool.peers)
	maxPeerHeight := 0
	for _, peer := range pool.peers {
		maxPeerHeight = MaxInt(maxPeerHeight, peer.height)
	}
	pool.peersMtx.Unlock()

	return numPeers >= 3 && (height > 0 || time.Now().Sub(pool.startTime) > 30*time.Second) && (maxPeerHeight == 0 || height == maxPeerHeight)
}

// We need to see the second block's Validation to validate the first block.
// So we peek two blocks at a time.
func (pool *BlockPool) PeekTwoBlocks() (first *types.Block, second *types.Block) {
	pool.mtx.Lock() // Lock
	defer pool.mtx.Unlock()

	if r := pool.requests[pool.height]; r != nil {
		first = r.block
	}
	if r := pool.requests[pool.height+1]; r != nil {
		second = r.block
	}
	return
}

// Pop the first block at pool.height
// It must have been validated by 'second'.Validation from PeekTwoBlocks().
func (pool *BlockPool) PopRequest() {
	pool.mtx.Lock() // Lock
	defer pool.mtx.Unlock()

	if r := pool.requests[pool.height]; r == nil || r.block == nil {
		PanicSanity("PopRequest() requires a valid block")
	}

	delete(pool.requests, pool.height)
	pool.height++
}

// Invalidates the block at pool.height,
// Remove the peer and redo request from others.
func (pool *BlockPool) RedoRequest(height int) {
	pool.mtx.Lock() // Lock
	defer pool.mtx.Unlock()

	request := pool.requests[height]
	if request.block == nil {
		PanicSanity("Expected block to be non-nil")
	}
	// RemovePeer will redo all requests associated with this peer.
	// TODO: record this malfeasance
	pool.RemovePeer(request.peerID) // Lock on peersMtx.
}

// TODO: ensure that blocks come in order for each peer.
func (pool *BlockPool) AddBlock(peerID string, block *types.Block, blockSize int) {
	pool.mtx.Lock() // Lock
	defer pool.mtx.Unlock()

	request := pool.requests[block.Height]
	if request == nil {
		return
	}

	if request.setBlock(block, peerID) {
		pool.numPending--
		peer := pool.getPeer(peerID)
		peer.decrPending(blockSize)
	} else {
		// Bad peer?
	}
}

// Sets the peer's alleged blockchain height.
func (pool *BlockPool) SetPeerHeight(peerID string, height int) {
	pool.peersMtx.Lock() // Lock
	defer pool.peersMtx.Unlock()

	peer := pool.peers[peerID]
	if peer != nil {
		peer.height = height
	} else {
		peer = newBPPeer(pool, peerID, height)
		pool.peers[peerID] = peer
	}
}

func (pool *BlockPool) RemovePeer(peerID string) {
	pool.peersMtx.Lock() // Lock
	defer pool.peersMtx.Unlock()

	pool.removePeer(peerID)
}

func (pool *BlockPool) removePeer(peerID string) {
	for _, request := range pool.requests {
		if request.getPeerID() == peerID {
			pool.numPending++
			go request.redo() // pick another peer and ...
		}
	}
	delete(pool.peers, peerID)
}

func (pool *BlockPool) getPeer(peerID string) *bpPeer {
	pool.peersMtx.Lock() // Lock
	defer pool.peersMtx.Unlock()

	peer := pool.peers[peerID]
	return peer
}

// Pick an available peer with at least the given minHeight.
// If no peers are available, returns nil.
func (pool *BlockPool) pickIncrAvailablePeer(minHeight int) *bpPeer {
	pool.peersMtx.Lock()
	defer pool.peersMtx.Unlock()

	for _, peer := range pool.peers {
		if peer.isBad() {
			pool.removePeer(peer.id)
			continue
		} else {
		}
		if peer.numPending >= maxPendingRequestsPerPeer {
			continue
		}
		if peer.height < minHeight {
			continue
		}
		peer.incrPending()
		return peer
	}
	return nil
}

func (pool *BlockPool) makeNextRequest() {
	pool.mtx.Lock() // Lock
	defer pool.mtx.Unlock()

	nextHeight := pool.height + len(pool.requests)
	request := newBPRequester(pool, nextHeight)

	pool.requests[nextHeight] = request
	pool.numPending++

	request.Start()
}

func (pool *BlockPool) sendRequest(height int, peerID string) {
	if !pool.IsRunning() {
		return
	}
	pool.requestsCh <- BlockRequest{height, peerID}
}

func (pool *BlockPool) sendTimeout(peerID string) {
	if !pool.IsRunning() {
		return
	}
	pool.timeoutsCh <- peerID
}

func (pool *BlockPool) debug() string {
	pool.mtx.Lock() // Lock
	defer pool.mtx.Unlock()

	str := ""
	for h := pool.height; h < pool.height+len(pool.requests); h++ {
		if pool.requests[h] == nil {
			str += Fmt("H(%v):X ", h)
		} else {
			str += Fmt("H(%v):", h)
			str += Fmt("B?(%v) ", pool.requests[h].block != nil)
		}
	}
	return str
}

//-------------------------------------

type bpPeer struct {
	pool        *BlockPool
	id          string
	height      int
	numPending  int32
	recvMonitor *flow.Monitor
	timeout     *time.Timer
	didTimeout  bool
}

func newBPPeer(pool *BlockPool, peerID string, height int) *bpPeer {
	peer := &bpPeer{
		pool:       pool,
		id:         peerID,
		height:     height,
		numPending: 0,
	}
	return peer
}

func (bpp *bpPeer) resetMonitor() {
	bpp.recvMonitor = flow.New(time.Second, time.Second*40)
	var initialValue = float64(minRecvRate) * math.E
	bpp.recvMonitor.SetREMA(initialValue)
}

func (bpp *bpPeer) resetTimeout() {
	if bpp.timeout == nil {
		bpp.timeout = time.AfterFunc(time.Second*peerTimeoutSeconds, bpp.onTimeout)
	} else {
		bpp.timeout.Reset(time.Second * peerTimeoutSeconds)
	}
}

func (bpp *bpPeer) incrPending() {
	if bpp.numPending == 0 {
		bpp.resetMonitor()
		bpp.resetTimeout()
	}
	bpp.numPending++
}

func (bpp *bpPeer) decrPending(recvSize int) {
	bpp.numPending--
	if bpp.numPending == 0 {
		bpp.timeout.Stop()
	} else {
		bpp.recvMonitor.Update(recvSize)
		bpp.resetTimeout()
	}
}

func (bpp *bpPeer) onTimeout() {
	bpp.pool.sendTimeout(bpp.id)
	log.Warn("SendTimeout", "peer", bpp.id, "reason", "onTimeout")
	bpp.didTimeout = true
}

func (bpp *bpPeer) isBad() bool {
	return bpp.didTimeout
}

//-------------------------------------

type bpRequester struct {
	QuitService
	pool       *BlockPool
	height     int
	gotBlockCh chan struct{}
	redoCh     chan struct{}

	mtx    sync.Mutex
	peerID string
	block  *types.Block
}

func newBPRequester(pool *BlockPool, height int) *bpRequester {
	bpr := &bpRequester{
		pool:       pool,
		height:     height,
		gotBlockCh: make(chan struct{}),
		redoCh:     make(chan struct{}),

		peerID: "",
		block:  nil,
	}
	bpr.QuitService = *NewQuitService(nil, "bpRequester", bpr)
	return bpr
}

func (bpr *bpRequester) OnStart() error {
	bpr.QuitService.OnStart()
	go bpr.requestRoutine()
	return nil
}

// Returns true if the peer matches
func (bpr *bpRequester) setBlock(block *types.Block, peerID string) bool {
	bpr.mtx.Lock()
	if bpr.block != nil || bpr.peerID != peerID {
		bpr.mtx.Unlock()
		return false
	}
	bpr.block = block
	bpr.mtx.Unlock()

	bpr.gotBlockCh <- struct{}{}
	return true
}

func (bpr *bpRequester) getPeerID() string {
	bpr.mtx.Lock()
	defer bpr.mtx.Unlock()
	return bpr.peerID
}

func (bpr *bpRequester) reset() {
	bpr.mtx.Lock()
	bpr.peerID = ""
	bpr.block = nil
	bpr.mtx.Unlock()
}

// Tells bpRequester to pick another peer and try again.
// NOTE: blocking
func (bpr *bpRequester) redo() {
	bpr.redoCh <- struct{}{}
}

// Responsible for making more requests as necessary
// Returns only when a block is found (e.g. AddBlock() is called)
func (bpr *bpRequester) requestRoutine() {
OUTER_LOOP:
	for {
		// Pick a peer to send request to.
		var peer *bpPeer = nil
	PICK_PEER_LOOP:
		for {
			if !bpr.IsRunning() || !bpr.pool.IsRunning() {
				return
			}
			peer = bpr.pool.pickIncrAvailablePeer(bpr.height)
			if peer == nil {
				//log.Info("No peers available", "height", height)
				time.Sleep(requestIntervalMS * time.Millisecond)
				continue PICK_PEER_LOOP
			}
			break PICK_PEER_LOOP
		}
		bpr.mtx.Lock()
		bpr.peerID = peer.id
		bpr.mtx.Unlock()

		// Send request and wait.
		bpr.pool.sendRequest(bpr.height, peer.id)
		select {
		case <-bpr.pool.Quit:
			bpr.Stop()
			return
		case <-bpr.Quit:
			return
		case <-bpr.redoCh:
			bpr.reset()
			continue OUTER_LOOP // When peer is removed
		case <-bpr.gotBlockCh:
			// We got the block, now see if it's good.
			select {
			case <-bpr.pool.Quit:
				bpr.Stop()
				return
			case <-bpr.Quit:
				return
			case <-bpr.redoCh:
				bpr.reset()
				continue OUTER_LOOP
			}
		}
	}
}

//-------------------------------------

type BlockRequest struct {
	Height int
	PeerID string
}
<commit_msg>blockchain pool race condition fix<commit_after>package blockchain

import (
	"math"
	"sync"
	"time"

	flow "github.com/tendermint/tendermint/Godeps/_workspace/src/code.google.com/p/mxk/go1/flowcontrol"
	. "github.com/tendermint/tendermint/common"
	"github.com/tendermint/tendermint/types"
)

const (
	requestIntervalMS         = 250
	maxTotalRequests          = 300
	maxPendingRequests        = maxTotalRequests
	maxPendingRequestsPerPeer = 75
	peerTimeoutSeconds        = 15
	minRecvRate               = 10240 // 10Kb/s
)

/*
	Peers self report their heights when we join the block pool.
	Starting from our latest pool.height, we request blocks
	in sequence from peers that reported higher heights than ours.
	Every so often we ask peers what height they're on so we can keep going.

	Requests are continuously made for blocks of heigher heights until
	the limits. If most of the requests have no available peers, and we
	are not at peer limits, we can probably switch to consensus reactor
*/

type BlockPool struct {
	QuitService
	startTime time.Time

	// block requests
	mtx        sync.Mutex
	requests   map[int]*bpRequester
	height     int   // the lowest key in requests.
	numPending int32 // number of requests pending assignment or block response

	// peers
	peersMtx sync.Mutex
	peers    map[string]*bpPeer

	requestsCh chan<- BlockRequest
	timeoutsCh chan<- string
}

func NewBlockPool(start int, requestsCh chan<- BlockRequest, timeoutsCh chan<- string) *BlockPool {
	bp := &BlockPool{
		peers: make(map[string]*bpPeer),

		requests:   make(map[int]*bpRequester),
		height:     start,
		numPending: 0,

		requestsCh: requestsCh,
		timeoutsCh: timeoutsCh,
	}
	bp.QuitService = *NewQuitService(log, "BlockPool", bp)
	return bp
}

func (pool *BlockPool) OnStart() error {
	pool.QuitService.OnStart()
	go pool.makeRequestsRoutine()
	pool.startTime = time.Now()
	return nil
}

func (pool *BlockPool) OnStop() {
	pool.QuitService.OnStop()
}

// Run spawns requests as needed.
func (pool *BlockPool) makeRequestsRoutine() {
	for {
		if !pool.IsRunning() {
			break
		}
		_, numPending := pool.GetStatus()
		if numPending >= maxPendingRequests {
			// sleep for a bit.
			time.Sleep(requestIntervalMS * time.Millisecond)
			// check for timed out peers
			pool.removeTimedoutPeers()
		} else if len(pool.requests) >= maxTotalRequests {
			// sleep for a bit.
			time.Sleep(requestIntervalMS * time.Millisecond)
			// check for timed out peers
			pool.removeTimedoutPeers()
		} else {
			// request for more blocks.
			pool.makeNextRequest()
		}
	}
}

func (pool *BlockPool) removeTimedoutPeers() {
	for _, peer := range pool.peers {
		if !peer.didTimeout && peer.numPending > 0 {
			curRate := peer.recvMonitor.Status().CurRate
			// XXX remove curRate != 0
			if curRate != 0 && curRate < minRecvRate {
				pool.sendTimeout(peer.id)
				log.Warn("SendTimeout", "peer", peer.id, "reason", "curRate too low")
				peer.didTimeout = true
			}
		}
		if peer.didTimeout {
			pool.peersMtx.Lock() // Lock
			pool.removePeer(peer.id)
			pool.peersMtx.Unlock()
		}
	}
}

func (pool *BlockPool) GetStatus() (height int, numPending int32) {
	pool.mtx.Lock() // Lock
	defer pool.mtx.Unlock()

	return pool.height, pool.numPending
}

// TODO: relax conditions, prevent abuse.
func (pool *BlockPool) IsCaughtUp() bool {
	pool.mtx.Lock()
	height := pool.height
	pool.mtx.Unlock()

	pool.peersMtx.Lock()
	numPeers := len(pool.peers)
	maxPeerHeight := 0
	for _, peer := range pool.peers {
		maxPeerHeight = MaxInt(maxPeerHeight, peer.height)
	}
	pool.peersMtx.Unlock()

	return numPeers >= 3 && (height > 0 || time.Now().Sub(pool.startTime) > 30*time.Second) && (maxPeerHeight == 0 || height == maxPeerHeight)
}

// We need to see the second block's Validation to validate the first block.
// So we peek two blocks at a time.
func (pool *BlockPool) PeekTwoBlocks() (first *types.Block, second *types.Block) {
	pool.mtx.Lock() // Lock
	defer pool.mtx.Unlock()

	if r := pool.requests[pool.height]; r != nil {
		first = r.getBlock()
	}
	if r := pool.requests[pool.height+1]; r != nil {
		second = r.getBlock()
	}
	return
}

// Pop the first block at pool.height
// It must have been validated by 'second'.Validation from PeekTwoBlocks().
func (pool *BlockPool) PopRequest() {
	pool.mtx.Lock() // Lock
	defer pool.mtx.Unlock()

	/*  The block can disappear at any time, due to removePeer().
	if r := pool.requests[pool.height]; r == nil || r.block == nil {
		PanicSanity("PopRequest() requires a valid block")
	}
	*/

	delete(pool.requests, pool.height)
	pool.height++
}

// Invalidates the block at pool.height,
// Remove the peer and redo request from others.
func (pool *BlockPool) RedoRequest(height int) {
	pool.mtx.Lock() // Lock
	defer pool.mtx.Unlock()

	request := pool.requests[height]
	if request.block == nil {
		PanicSanity("Expected block to be non-nil")
	}
	// RemovePeer will redo all requests associated with this peer.
	// TODO: record this malfeasance
	pool.RemovePeer(request.peerID) // Lock on peersMtx.
}

// TODO: ensure that blocks come in order for each peer.
func (pool *BlockPool) AddBlock(peerID string, block *types.Block, blockSize int) {
	pool.mtx.Lock() // Lock
	defer pool.mtx.Unlock()

	request := pool.requests[block.Height]
	if request == nil {
		return
	}

	if request.setBlock(block, peerID) {
		pool.numPending--
		peer := pool.getPeer(peerID)
		peer.decrPending(blockSize)
	} else {
		// Bad peer?
	}
}

// Sets the peer's alleged blockchain height.
func (pool *BlockPool) SetPeerHeight(peerID string, height int) {
	pool.peersMtx.Lock() // Lock
	defer pool.peersMtx.Unlock()

	peer := pool.peers[peerID]
	if peer != nil {
		peer.height = height
	} else {
		peer = newBPPeer(pool, peerID, height)
		pool.peers[peerID] = peer
	}
}

func (pool *BlockPool) RemovePeer(peerID string) {
	pool.peersMtx.Lock() // Lock
	defer pool.peersMtx.Unlock()

	pool.removePeer(peerID)
}

func (pool *BlockPool) removePeer(peerID string) {
	for _, request := range pool.requests {
		if request.getPeerID() == peerID {
			pool.numPending++
			go request.redo() // pick another peer and ...
		}
	}
	delete(pool.peers, peerID)
}

func (pool *BlockPool) getPeer(peerID string) *bpPeer {
	pool.peersMtx.Lock() // Lock
	defer pool.peersMtx.Unlock()

	peer := pool.peers[peerID]
	return peer
}

// Pick an available peer with at least the given minHeight.
// If no peers are available, returns nil.
func (pool *BlockPool) pickIncrAvailablePeer(minHeight int) *bpPeer {
	pool.peersMtx.Lock()
	defer pool.peersMtx.Unlock()

	for _, peer := range pool.peers {
		if peer.isBad() {
			pool.removePeer(peer.id)
			continue
		} else {
		}
		if peer.numPending >= maxPendingRequestsPerPeer {
			continue
		}
		if peer.height < minHeight {
			continue
		}
		peer.incrPending()
		return peer
	}
	return nil
}

func (pool *BlockPool) makeNextRequest() {
	pool.mtx.Lock() // Lock
	defer pool.mtx.Unlock()

	nextHeight := pool.height + len(pool.requests)
	request := newBPRequester(pool, nextHeight)

	pool.requests[nextHeight] = request
	pool.numPending++

	request.Start()
}

func (pool *BlockPool) sendRequest(height int, peerID string) {
	if !pool.IsRunning() {
		return
	}
	pool.requestsCh <- BlockRequest{height, peerID}
}

func (pool *BlockPool) sendTimeout(peerID string) {
	if !pool.IsRunning() {
		return
	}
	pool.timeoutsCh <- peerID
}

func (pool *BlockPool) debug() string {
	pool.mtx.Lock() // Lock
	defer pool.mtx.Unlock()

	str := ""
	for h := pool.height; h < pool.height+len(pool.requests); h++ {
		if pool.requests[h] == nil {
			str += Fmt("H(%v):X ", h)
		} else {
			str += Fmt("H(%v):", h)
			str += Fmt("B?(%v) ", pool.requests[h].block != nil)
		}
	}
	return str
}

//-------------------------------------

type bpPeer struct {
	pool        *BlockPool
	id          string
	height      int
	numPending  int32
	recvMonitor *flow.Monitor
	timeout     *time.Timer
	didTimeout  bool
}

func newBPPeer(pool *BlockPool, peerID string, height int) *bpPeer {
	peer := &bpPeer{
		pool:       pool,
		id:         peerID,
		height:     height,
		numPending: 0,
	}
	return peer
}

func (peer *bpPeer) resetMonitor() {
	peer.recvMonitor = flow.New(time.Second, time.Second*40)
	var initialValue = float64(minRecvRate) * math.E
	peer.recvMonitor.SetREMA(initialValue)
}

func (peer *bpPeer) resetTimeout() {
	if peer.timeout == nil {
		peer.timeout = time.AfterFunc(time.Second*peerTimeoutSeconds, peer.onTimeout)
	} else {
		peer.timeout.Reset(time.Second * peerTimeoutSeconds)
	}
}

func (peer *bpPeer) incrPending() {
	if peer.numPending == 0 {
		peer.resetMonitor()
		peer.resetTimeout()
	}
	peer.numPending++
}

func (peer *bpPeer) decrPending(recvSize int) {
	peer.numPending--
	if peer.numPending == 0 {
		peer.timeout.Stop()
	} else {
		peer.recvMonitor.Update(recvSize)
		peer.resetTimeout()
	}
}

func (peer *bpPeer) onTimeout() {
	peer.pool.sendTimeout(peer.id)
	log.Warn("SendTimeout", "peer", peer.id, "reason", "onTimeout")
	peer.didTimeout = true
}

func (peer *bpPeer) isBad() bool {
	return peer.didTimeout
}

//-------------------------------------

type bpRequester struct {
	QuitService
	pool       *BlockPool
	height     int
	gotBlockCh chan struct{}
	redoCh     chan struct{}

	mtx    sync.Mutex
	peerID string
	block  *types.Block
}

func newBPRequester(pool *BlockPool, height int) *bpRequester {
	bpr := &bpRequester{
		pool:       pool,
		height:     height,
		gotBlockCh: make(chan struct{}),
		redoCh:     make(chan struct{}),

		peerID: "",
		block:  nil,
	}
	bpr.QuitService = *NewQuitService(nil, "bpRequester", bpr)
	return bpr
}

func (bpr *bpRequester) OnStart() error {
	bpr.QuitService.OnStart()
	go bpr.requestRoutine()
	return nil
}

// Returns true if the peer matches
func (bpr *bpRequester) setBlock(block *types.Block, peerID string) bool {
	bpr.mtx.Lock()
	if bpr.block != nil || bpr.peerID != peerID {
		bpr.mtx.Unlock()
		return false
	}
	bpr.block = block
	bpr.mtx.Unlock()

	bpr.gotBlockCh <- struct{}{}
	return true
}

func (bpr *bpRequester) getBlock() *types.Block {
	bpr.mtx.Lock()
	defer bpr.mtx.Unlock()
	return bpr.block
}

func (bpr *bpRequester) getPeerID() string {
	bpr.mtx.Lock()
	defer bpr.mtx.Unlock()
	return bpr.peerID
}

func (bpr *bpRequester) reset() {
	bpr.mtx.Lock()
	bpr.peerID = ""
	bpr.block = nil
	bpr.mtx.Unlock()
}

// Tells bpRequester to pick another peer and try again.
// NOTE: blocking
func (bpr *bpRequester) redo() {
	bpr.redoCh <- struct{}{}
}

// Responsible for making more requests as necessary
// Returns only when a block is found (e.g. AddBlock() is called)
func (bpr *bpRequester) requestRoutine() {
OUTER_LOOP:
	for {
		// Pick a peer to send request to.
		var peer *bpPeer = nil
	PICK_PEER_LOOP:
		for {
			if !bpr.IsRunning() || !bpr.pool.IsRunning() {
				return
			}
			peer = bpr.pool.pickIncrAvailablePeer(bpr.height)
			if peer == nil {
				//log.Info("No peers available", "height", height)
				time.Sleep(requestIntervalMS * time.Millisecond)
				continue PICK_PEER_LOOP
			}
			break PICK_PEER_LOOP
		}
		bpr.mtx.Lock()
		bpr.peerID = peer.id
		bpr.mtx.Unlock()

		// Send request and wait.
		bpr.pool.sendRequest(bpr.height, peer.id)
		select {
		case <-bpr.pool.Quit:
			bpr.Stop()
			return
		case <-bpr.Quit:
			return
		case <-bpr.redoCh:
			bpr.reset()
			continue OUTER_LOOP // When peer is removed
		case <-bpr.gotBlockCh:
			// We got the block, now see if it's good.
			select {
			case <-bpr.pool.Quit:
				bpr.Stop()
				return
			case <-bpr.Quit:
				return
			case <-bpr.redoCh:
				bpr.reset()
				continue OUTER_LOOP
			}
		}
	}
}

//-------------------------------------

type BlockRequest struct {
	Height int
	PeerID string
}
<|endoftext|>


<commit_before>// +build linux

package specs

// LinuxSpec is the full specification for linux containers.
type LinuxSpec struct {
	Spec
	// Linux is platform specific configuration for linux based containers.
	Linux Linux `json:"linux"`
}

// Linux contains platform specific configuration for linux based containers.
type Linux struct {
	// UidMapping specifies user mappings for supporting user namespaces on linux.
	UidMappings []IDMapping `json:"uidMappings"`
	// UidMapping specifies group mappings for supporting user namespaces on linux.
	GidMappings []IDMapping `json:"gidMappings"`
	// Rlimits specifies rlimit options to apply to the container's process.
	Rlimits []Rlimit `json:"rlimits"`
	// Sysctl are a set of key value pairs that are set for the container on start.
	Sysctl map[string]string `json:"sysctl"`
	// Resources contain cgroup information for handling resource constraints
	// for the container.
	Resources Resources `json:"resources"`
	// Namespaces contains the namespaces that are created and/or joined by the container.
	Namespaces []Namespace `json:"namespaces"`
	// Capabilities are linux capabilities that are kept for the container.
	Capabilities []string `json:"capabilities"`
	// Devices are a list of device nodes that are created and enabled for the container.
	Devices []string `json:"devices"`
	// RootfsPropagation is the rootfs mount propagation mode for the container.
	RootfsPropagation string `json:"rootfsPropagation"`
}

// User specifies linux specific user and group information for the container's
// main process.
type User struct {
	// Uid is the user id.
	Uid int32 `json:"uid"`
	// Gid is the group id.
	Gid int32 `json:"gid"`
	// AdditionalGids are additional group ids set for the container's process.
	AdditionalGids []int32 `json:"additionalGids"`
}

// Namespace is the configuration for a linux namespace.
type Namespace struct {
	// Type is the type of linux namespace.
	Type string `json:"type"`
	// Path is a path to an existing namespace persisted on disk that can be joined
	// and is of the same type.
	Path string `json:"path"`
}

// IDMapping specifies uid/gid mappings.
type IDMapping struct {
	// HostID is the uid/gid of the host user or group.
	HostID int32 `json:"hostID"`
	// ContainerID is the uid/gid of the container's user or group.
	ContainerID int32 `json:"containerID"`
	// Size is the length of the range of IDs mapped between the two namespaces.
	Size int32 `json:"size"`
}

// Rlimit type and restrictions.
type Rlimit struct {
	// Type of the rlimit to set.
	Type int `json:"type"`
	// Hard is the hard limit for the specified type.
	Hard uint64 `json:"hard"`
	// Soft is the soft limit for the specified type.
	Soft uint64 `json:"soft"`
}

type HugepageLimit struct {
	Pagesize string `json:"pageSize"`
	Limit    int    `json:"limit"`
}

type InterfacePriority struct {
	// Name is the name of the network interface.
	Name string `json:"name"`
	// Priority for the interface.
	Priority int64 `json:"priority"`
}

type BlockIO struct {
	// Specifies per cgroup weight, range is from 10 to 1000.
	Weight int64 `json:"blkioWeight"`
	// Weight per cgroup per device, can override BlkioWeight.
	WeightDevice string `json:"blkioWeightDevice"`
	// IO read rate limit per cgroup per device, bytes per second.
	ThrottleReadBpsDevice string `json:"blkioThrottleReadBpsDevice"`
	// IO write rate limit per cgroup per divice, bytes per second.
	ThrottleWriteBpsDevice string `json:"blkioThrottleWriteBpsDevice"`
	// IO read rate limit per cgroup per device, IO per second.
	ThrottleReadIOpsDevice string `json:"blkioThrottleReadIopsDevice"`
	// IO write rate limit per cgroup per device, IO per second.
	ThrottleWriteIOpsDevice string `json:"blkioThrottleWriteIopsDevice"`
}

type Memory struct {
	// Memory limit (in bytes)
	Limit int64 `json:"limit"`
	// Memory reservation or soft_limit (in bytes)
	Reservation int64 `json:"reservation"`
	// Total memory usage (memory + swap); set `-1' to disable swap
	Swap int64 `json:"swap"`
	// Kernel memory limit (in bytes)
	Kernel int64 `json:"kernel"`
	// How aggressive the kernel will swap memory pages. Range from 0 to 100. Set -1 to use system default.
	Swappiness int64 `json:"swappiness"`
}

type CPU struct {
	// CPU shares (relative weight vs. other cgroups with cpu shares).
	Shares int64 `json:"shares"`
	// CPU hardcap limit (in usecs). Allowed cpu time in a given period.
	Quota int64 `json:"quota"`
	// CPU period to be used for hardcapping (in usecs). 0 to use system default.
	Period int64 `json:"period"`
	// How many time CPU will use in realtime scheduling (in usecs).
	RealtimeRuntime int64 `json:"realtimeRuntime"`
	// CPU period to be used for realtime scheduling (in usecs).
	RealtimePeriod int64 `json:"realtimePeriod"`
	// CPU to use within the cpuset.
	Cpus string `json:"cpus"`
	// MEM to use within the cpuset.
	Mems string `json:"mems"`
}

type Network struct {
	// Set class identifier for container's network packets.
	ClassID string `json:"classId"`
	// Set priority of network traffic for container.
	Priorities []InterfacePriority `json:"priorities"`
}

type Resources struct {
	// DisableOOMKiller disables the OOM killer for out of memory conditions.
	DisableOOMKiller bool `json:"disableOOMKiller"`
	// Memory restriction configuration.
	Memory Memory `json:"memory"`
	// CPU resource restriction configuration.
	CPU CPU `json:"cpu"`
	// BlockIO restriction configuration.
	BlockIO BlockIO `json:"blockIO"`
	// Hugetlb limit (in bytes)
	HugepageLimits []HugepageLimit `json:"hugepageLimits"`
	// Network restriction configuration.
	Network Network `json:"network"`
}
<commit_msg>spec_linux: conform to `golint`<commit_after>// +build linux

package specs

// LinuxSpec is the full specification for Linux containers.
type LinuxSpec struct {
	Spec
	// Linux is platform specific configuration for Linux based containers.
	Linux Linux `json:"linux"`
}

// Linux contains platform specific configuration for Linux based containers.
type Linux struct {
	// UIDMapping specifies user mappings for supporting user namespaces on Linux.
	UIDMappings []IDMapping `json:"uidMappings"`
	// GIDMapping specifies group mappings for supporting user namespaces on Linux.
	GIDMappings []IDMapping `json:"gidMappings"`
	// Rlimits specifies rlimit options to apply to the container's process.
	Rlimits []Rlimit `json:"rlimits"`
	// Sysctl are a set of key value pairs that are set for the container on start.
	Sysctl map[string]string `json:"sysctl"`
	// Resources contain cgroup information for handling resource constraints
	// for the container.
	Resources Resources `json:"resources"`
	// Namespaces contains the namespaces that are created and/or joined by the container.
	Namespaces []Namespace `json:"namespaces"`
	// Capabilities are Linux capabilities that are kept for the container.
	Capabilities []string `json:"capabilities"`
	// Devices are a list of device nodes that are created and enabled for the container.
	Devices []string `json:"devices"`
	// RootfsPropagation is the rootfs mount propagation mode for the container.
	RootfsPropagation string `json:"rootfsPropagation"`
}

// User specifies Linux specific user and group information for the container's
// main process.
type User struct {
	// Uid is the user id.
	UID int32 `json:"uid"`
	// Gid is the group id.
	GID int32 `json:"gid"`
	// AdditionalGids are additional group ids set for the container's process.
	AdditionalGids []int32 `json:"additionalGids"`
}

// Namespace is the configuration for a Linux namespace.
type Namespace struct {
	// Type is the type of Linux namespace.
	Type string `json:"type"`
	// Path is a path to an existing namespace persisted on disk that can be joined
	// and is of the same type.
	Path string `json:"path"`
}

// IDMapping specifies UID/GID mappings.
type IDMapping struct {
	// HostID is the UID/GID of the host user or group.
	HostID int32 `json:"hostID"`
	// ContainerID is the UID/GID of the container's user or group.
	ContainerID int32 `json:"containerID"`
	// Size is the length of the range of IDs mapped between the two namespaces.
	Size int32 `json:"size"`
}

// Rlimit type and restrictions.
type Rlimit struct {
	// Type of the rlimit to set.
	Type int `json:"type"`
	// Hard is the hard limit for the specified type.
	Hard uint64 `json:"hard"`
	// Soft is the soft limit for the specified type.
	Soft uint64 `json:"soft"`
}

// HugepageLimit structure corresponds to limiting kernel hugepages
type HugepageLimit struct {
	Pagesize string `json:"pageSize"`
	Limit    int    `json:"limit"`
}

// InterfacePriority for network interfaces
type InterfacePriority struct {
	// Name is the name of the network interface.
	Name string `json:"name"`
	// Priority for the interface.
	Priority int64 `json:"priority"`
}

// BlockIO for Linux cgroup 'blockio' resource management
type BlockIO struct {
	// Specifies per cgroup weight, range is from 10 to 1000.
	Weight int64 `json:"blkioWeight"`
	// Weight per cgroup per device, can override BlkioWeight.
	WeightDevice string `json:"blkioWeightDevice"`
	// IO read rate limit per cgroup per device, bytes per second.
	ThrottleReadBpsDevice string `json:"blkioThrottleReadBpsDevice"`
	// IO write rate limit per cgroup per divice, bytes per second.
	ThrottleWriteBpsDevice string `json:"blkioThrottleWriteBpsDevice"`
	// IO read rate limit per cgroup per device, IO per second.
	ThrottleReadIOpsDevice string `json:"blkioThrottleReadIopsDevice"`
	// IO write rate limit per cgroup per device, IO per second.
	ThrottleWriteIOpsDevice string `json:"blkioThrottleWriteIopsDevice"`
}

// Memory for Linux cgroup 'memory' resource management
type Memory struct {
	// Memory limit (in bytes)
	Limit int64 `json:"limit"`
	// Memory reservation or soft_limit (in bytes)
	Reservation int64 `json:"reservation"`
	// Total memory usage (memory + swap); set `-1' to disable swap
	Swap int64 `json:"swap"`
	// Kernel memory limit (in bytes)
	Kernel int64 `json:"kernel"`
	// How aggressive the kernel will swap memory pages. Range from 0 to 100. Set -1 to use system default.
	Swappiness int64 `json:"swappiness"`
}

// CPU for Linux cgroup 'cpu' resource management
type CPU struct {
	// CPU shares (relative weight vs. other cgroups with cpu shares).
	Shares int64 `json:"shares"`
	// CPU hardcap limit (in usecs). Allowed cpu time in a given period.
	Quota int64 `json:"quota"`
	// CPU period to be used for hardcapping (in usecs). 0 to use system default.
	Period int64 `json:"period"`
	// How many time CPU will use in realtime scheduling (in usecs).
	RealtimeRuntime int64 `json:"realtimeRuntime"`
	// CPU period to be used for realtime scheduling (in usecs).
	RealtimePeriod int64 `json:"realtimePeriod"`
	// CPU to use within the cpuset.
	Cpus string `json:"cpus"`
	// MEM to use within the cpuset.
	Mems string `json:"mems"`
}

// Network identification and priority configuration
type Network struct {
	// Set class identifier for container's network packets.
	ClassID string `json:"classId"`
	// Set priority of network traffic for container.
	Priorities []InterfacePriority `json:"priorities"`
}

// Resources has container runtime resource constraints
type Resources struct {
	// DisableOOMKiller disables the OOM killer for out of memory conditions.
	DisableOOMKiller bool `json:"disableOOMKiller"`
	// Memory restriction configuration.
	Memory Memory `json:"memory"`
	// CPU resource restriction configuration.
	CPU CPU `json:"cpu"`
	// BlockIO restriction configuration.
	BlockIO BlockIO `json:"blockIO"`
	// Hugetlb limit (in bytes)
	HugepageLimits []HugepageLimit `json:"hugepageLimits"`
	// Network restriction configuration.
	Network Network `json:"network"`
}
<|endoftext|>


<commit_before>package speccy
<commit_msg>remove empty file<commit_after><|endoftext|>


<commit_before><commit_msg>better code for allocation through indirection<commit_after><|endoftext|>


<commit_before>package chart

import "math"

// DrawLineSeries draws a line series with a renderer.
func DrawLineSeries(r Renderer, canvasBox Box, xrange, yrange Range, s Style, vs ValueProvider) {
	if vs.Len() == 0 {
		return
	}

	ct := canvasBox.Top
	cb := canvasBox.Bottom
	cr := canvasBox.Right

	v0x, v0y := vs.GetValue(0)
	x0 := cr - xrange.Translate(v0x)
	y0 := yrange.Translate(v0y) + ct

	var vx, vy float64
	var x, y int

	fill := s.GetFillColor()
	if !fill.IsZero() {
		r.SetFillColor(fill)
		r.MoveTo(x0, y0)
		for i := 1; i < vs.Len(); i++ {
			vx, vy = vs.GetValue(i)
			x = cr - xrange.Translate(vx)
			y = yrange.Translate(vy) + ct
			r.LineTo(x, y)
		}
		r.LineTo(x, cb)
		r.LineTo(x0, cb)
		r.Close()
		r.Fill()
	}

	stroke := s.GetStrokeColor()
	r.SetStrokeColor(stroke)
	r.SetStrokeWidth(s.GetStrokeWidth(DefaultStrokeWidth))

	r.MoveTo(x0, y0)
	for i := 1; i < vs.Len(); i++ {
		vx, vy = vs.GetValue(i)
		x = cr - xrange.Translate(vx)
		y = yrange.Translate(vy) + ct
		r.LineTo(x, y)
	}
	r.Stroke()
}

// MeasureAnnotation measures how big an annotation would be.
func MeasureAnnotation(r Renderer, canvasBox Box, xrange, yrange Range, s Style, lx, ly int, label string) Box {
	r.SetFont(s.GetFont())
	r.SetFontSize(s.GetFontSize(DefaultAnnotationFontSize))
	textWidth, _ := r.MeasureText(label)
	textHeight := int(math.Floor(DefaultAnnotationFontSize))
	halfTextHeight := textHeight >> 1

	pt := s.Padding.GetTop(DefaultAnnotationPadding.Top)
	pl := s.Padding.GetLeft(DefaultAnnotationPadding.Left)
	pr := s.Padding.GetRight(DefaultAnnotationPadding.Right)
	pb := s.Padding.GetBottom(DefaultAnnotationPadding.Bottom)

	ltly := ly - (pt + halfTextHeight)
	ltrx := lx + pl + pr + textWidth
	lbry := ly + (pb + halfTextHeight)

	return Box{
		Top:    ltly,
		Left:   lx,
		Right:  ltrx,
		Bottom: lbry,
		Width:  ltrx - lx,
		Height: lbry - ltly,
	}
}

// DrawAnnotation draws an anotation with a renderer.
func DrawAnnotation(r Renderer, canvasBox Box, xrange, yrange Range, s Style, lx, ly int, label string) {
	r.SetFont(s.GetFont())
	r.SetFontSize(s.GetFontSize(DefaultAnnotationFontSize))
	textWidth, textHeight := r.MeasureText(label)
	halfTextHeight := textHeight >> 1

	pt := s.Padding.GetTop(DefaultAnnotationPadding.Top)
	pl := s.Padding.GetLeft(DefaultAnnotationPadding.Left)
	pr := s.Padding.GetRight(DefaultAnnotationPadding.Right)
	pb := s.Padding.GetBottom(DefaultAnnotationPadding.Bottom)

	textX := lx + pl + DefaultAnnotationDeltaWidth
	textY := ly + halfTextHeight

	ltlx := lx + pl + DefaultAnnotationDeltaWidth
	ltly := ly - (pt + halfTextHeight)

	ltrx := lx + pl + pr + textWidth
	ltry := ly - (pt + halfTextHeight)

	lbrx := lx + pl + pr + textWidth
	lbry := ly + (pb + halfTextHeight)

	lblx := lx + DefaultAnnotationDeltaWidth
	lbly := ly + (pb + halfTextHeight)

	//draw the shape...
	r.SetFillColor(s.GetFillColor(DefaultAnnotationFillColor))
	r.SetStrokeColor(s.GetStrokeColor())
	r.SetStrokeWidth(s.GetStrokeWidth())

	r.MoveTo(lx, ly)
	r.LineTo(ltlx, ltly)
	r.LineTo(ltrx, ltry)
	r.LineTo(lbrx, lbry)
	r.LineTo(lblx, lbly)
	r.LineTo(lx, ly)
	r.Close()
	r.FillStroke()

	r.SetFontColor(s.GetFontColor(DefaultTextColor))
	r.Text(label, textX, textY)
}
<commit_msg>tweaks<commit_after>package chart

// DrawLineSeries draws a line series with a renderer.
func DrawLineSeries(r Renderer, canvasBox Box, xrange, yrange Range, s Style, vs ValueProvider) {
	if vs.Len() == 0 {
		return
	}

	ct := canvasBox.Top
	cb := canvasBox.Bottom
	cr := canvasBox.Right

	v0x, v0y := vs.GetValue(0)
	x0 := cr - xrange.Translate(v0x)
	y0 := yrange.Translate(v0y) + ct

	var vx, vy float64
	var x, y int

	fill := s.GetFillColor()
	if !fill.IsZero() {
		r.SetFillColor(fill)
		r.MoveTo(x0, y0)
		for i := 1; i < vs.Len(); i++ {
			vx, vy = vs.GetValue(i)
			x = cr - xrange.Translate(vx)
			y = yrange.Translate(vy) + ct
			r.LineTo(x, y)
		}
		r.LineTo(x, cb)
		r.LineTo(x0, cb)
		r.Close()
		r.Fill()
	}

	stroke := s.GetStrokeColor()
	r.SetStrokeColor(stroke)
	r.SetStrokeWidth(s.GetStrokeWidth(DefaultStrokeWidth))

	r.MoveTo(x0, y0)
	for i := 1; i < vs.Len(); i++ {
		vx, vy = vs.GetValue(i)
		x = cr - xrange.Translate(vx)
		y = yrange.Translate(vy) + ct
		r.LineTo(x, y)
	}
	r.Stroke()
}

// MeasureAnnotation measures how big an annotation would be.
func MeasureAnnotation(r Renderer, canvasBox Box, xrange, yrange Range, s Style, lx, ly int, label string) Box {
	r.SetFont(s.GetFont())
	r.SetFontSize(s.GetFontSize(DefaultAnnotationFontSize))
	textWidth, textHeight := r.MeasureText(label)
	halfTextHeight := textHeight >> 1

	pt := s.Padding.GetTop(DefaultAnnotationPadding.Top)
	pl := s.Padding.GetLeft(DefaultAnnotationPadding.Left)
	pr := s.Padding.GetRight(DefaultAnnotationPadding.Right)
	pb := s.Padding.GetBottom(DefaultAnnotationPadding.Bottom)

	top := ly - (pt + halfTextHeight)
	right := lx + pl + pr + textWidth
	bottom := ly + (pb + halfTextHeight)

	return Box{
		Top:    top,
		Left:   lx,
		Right:  right,
		Bottom: bottom,
		Width:  right - lx,
		Height: bottom - top,
	}
}

// DrawAnnotation draws an anotation with a renderer.
func DrawAnnotation(r Renderer, canvasBox Box, xrange, yrange Range, s Style, lx, ly int, label string) {
	r.SetFont(s.GetFont())
	r.SetFontSize(s.GetFontSize(DefaultAnnotationFontSize))
	textWidth, textHeight := r.MeasureText(label)
	halfTextHeight := textHeight >> 1

	pt := s.Padding.GetTop(DefaultAnnotationPadding.Top)
	pl := s.Padding.GetLeft(DefaultAnnotationPadding.Left)
	pr := s.Padding.GetRight(DefaultAnnotationPadding.Right)
	pb := s.Padding.GetBottom(DefaultAnnotationPadding.Bottom)

	textX := lx + pl + DefaultAnnotationDeltaWidth
	textY := ly + halfTextHeight

	ltx := lx + pl + DefaultAnnotationDeltaWidth
	lty := ly - (pt + halfTextHeight)

	rtx := lx + pl + pr + textWidth
	rty := ly - (pt + halfTextHeight)

	rbx := lx + pl + pr + textWidth
	rby := ly + (pb + halfTextHeight)

	lbx := lx + DefaultAnnotationDeltaWidth
	lby := ly + (pb + halfTextHeight)

	//draw the shape...
	r.SetFillColor(s.GetFillColor(DefaultAnnotationFillColor))
	r.SetStrokeColor(s.GetStrokeColor())
	r.SetStrokeWidth(s.GetStrokeWidth())

	r.MoveTo(lx, ly)
	r.LineTo(ltx, lty)
	r.LineTo(rtx, rty)
	r.LineTo(rbx, rby)
	r.LineTo(lbx, lby)
	r.LineTo(lx, ly)
	r.Close()
	r.FillStroke()

	r.SetFontColor(s.GetFontColor(DefaultTextColor))
	r.Text(label, textX, textY)
}
<|endoftext|>


<commit_before>package logsrvc

import (
        "flag"
	"fmt"
	"testing"
)

var (
        logSrv string
        logger *Logger
)

func init() {
        flAddr := flag.String("address", "127.0.0.1:5988", "address of log server")
        flag.Parse()
        logSrv = *flAddr
}

func TestConnect(t *testing.T) {
	var err error

	logger, err = Connect("test-client", logSrv)
	if err != nil {
		fmt.Printf("[!] error setting up test client: %s\n", err.Error())
		t.FailNow()
	}
}

func TestPrint(t *testing.T) {
	logger.Print("hello, world")
}

func TestPrintf(t *testing.T) {
	logger.Printf("testing log server %s", logSrv)
}

func TestShutdown(t *testing.T) {
	logger.Shutdown()
}
<commit_msg>go fmt<commit_after>package logsrvc

import (
	"flag"
	"fmt"
	"testing"
)

var (
	logSrv string
	logger *Logger
)

func init() {
	flAddr := flag.String("address", "127.0.0.1:5988", "address of log server")
	flag.Parse()
	logSrv = *flAddr
}

func TestConnect(t *testing.T) {
	var err error

	logger, err = Connect("test-client", logSrv)
	if err != nil {
		fmt.Printf("[!] error setting up test client: %s\n", err.Error())
		t.FailNow()
	}
}

func TestPrint(t *testing.T) {
	logger.Print("hello, world")
}

func TestPrintf(t *testing.T) {
	logger.Printf("testing log server %s", logSrv)
}

func TestShutdown(t *testing.T) {
	logger.Shutdown()
}
<|endoftext|>


<commit_before>package browser

func openBrowser(url string) error {
	return runCmd("cmd", "/c", "start", url)
}
<commit_msg>Fix Windows code to allow multiple GET parameters<commit_after>package browser

import (
	"strings"
)

func openBrowser(url string) error {
	r := strings.NewReplacer("&", "^&")
	return runCmd("cmd", "/c", "start", r.Replace(url))
}
<|endoftext|>


<commit_before>// Copyright 2014 The Chihaya Authors. All rights reserved.
// Use of this source code is governed by the BSD 2-Clause license,
// which can be found in the LICENSE file.

package tracker

import (
	"net"

	"github.com/chihaya/chihaya/stats"
	"github.com/chihaya/chihaya/tracker/models"
)

// HandleAnnounce encapsulates all of the logic of handling a BitTorrent
// client's Announce without being coupled to any transport protocol.
func (tkr *Tracker) HandleAnnounce(ann *models.Announce, w Writer) error {
	conn, err := tkr.Pool.Get()
	if err != nil {
		return err
	}

	defer conn.Close()

	if tkr.cfg.Whitelist {
		err = conn.FindClient(ann.ClientID())
		if err == ErrClientUnapproved {
			w.WriteError(err)
			return nil
		} else if err != nil {
			return err
		}
	}

	var user *models.User
	if tkr.cfg.Private {
		user, err = conn.FindUser(ann.Passkey)
		if err == ErrUserDNE {
			w.WriteError(err)
			return nil
		} else if err != nil {
			return err
		}
	}

	var torrent *models.Torrent
	torrent, err = conn.FindTorrent(ann.Infohash)
	switch {
	case !tkr.cfg.Private && err == ErrTorrentDNE:
		torrent = &models.Torrent{
			Infohash: ann.Infohash,
			Seeders:  models.PeerMap{},
			Leechers: models.PeerMap{},
		}

		err = conn.PutTorrent(torrent)
		if err != nil {
			return err
		}
		stats.RecordEvent(stats.NewTorrent)

	case tkr.cfg.Private && err == ErrTorrentDNE:
		w.WriteError(err)
		return nil

	case err != nil:
		return err
	}

	peer := models.NewPeer(ann, user, torrent)

	created, err := updateSwarm(conn, ann, peer, torrent)
	if err != nil {
		return err
	}

	snatched, err := handleEvent(conn, ann, peer, user, torrent)
	if err != nil {
		return err
	}

	if tkr.cfg.Private {
		delta := models.NewAnnounceDelta(ann, peer, user, torrent, created, snatched)
		err = tkr.backend.RecordAnnounce(delta)
		if err != nil {
			return err
		}
	} else if tkr.cfg.PurgeInactiveTorrents && torrent.PeerCount() == 0 {
		// Rather than deleting the torrent explicitly, let the tracker driver
		// ensure there are no race conditions.
		conn.PurgeInactiveTorrent(torrent.Infohash)
		stats.RecordEvent(stats.ReapedTorrent)
	}

	return w.WriteAnnounce(newAnnounceResponse(ann, peer, torrent))
}

// updateSwarm handles the changes to a torrent's swarm given an announce.
func updateSwarm(c Conn, ann *models.Announce, p *models.Peer, t *models.Torrent) (created bool, err error) {
	c.TouchTorrent(t.Infohash)

	switch {
	case t.InSeederPool(p):
		err = c.PutSeeder(t.Infohash, p)
		if err != nil {
			return
		}
		t.Seeders[p.ID] = *p

	case t.InLeecherPool(p):
		err = c.PutLeecher(t.Infohash, p)
		if err != nil {
			return
		}
		t.Leechers[p.ID] = *p

	default:
		if ann.Left == 0 {
			err = c.PutSeeder(t.Infohash, p)
			if err != nil {
				return
			}
			t.Seeders[p.ID] = *p
			if p.IPv4() {
				stats.RecordEvent(stats.NewSeedIPv4)
			} else if p.IPv6() {
				stats.RecordEvent(stats.NewSeedIPv6)
			}

		} else {
			err = c.PutLeecher(t.Infohash, p)
			if err != nil {
				return
			}
			t.Leechers[p.ID] = *p
			if p.IPv4() {
				stats.RecordEvent(stats.NewLeechIPv4)
			} else if p.IPv6() {
				stats.RecordEvent(stats.NewLeechIPv6)
			}
		}
		created = true
	}

	return
}

// handleEvent checks to see whether an announce has an event and if it does,
// properly handles that event.
func handleEvent(c Conn, ann *models.Announce, p *models.Peer, u *models.User, t *models.Torrent) (snatched bool, err error) {
	switch {
	case ann.Event == "stopped" || ann.Event == "paused":
		if t.InSeederPool(p) {
			err = c.DeleteSeeder(t.Infohash, p.ID)
			if err != nil {
				return
			}
			delete(t.Seeders, p.ID)
			if p.IPv4() {
				stats.RecordEvent(stats.DeletedSeedIPv4)
			} else if p.IPv6() {
				stats.RecordEvent(stats.DeletedSeedIPv6)
			}

		} else if t.InLeecherPool(p) {
			err = c.DeleteLeecher(t.Infohash, p.ID)
			if err != nil {
				return
			}
			delete(t.Leechers, p.ID)
			if p.IPv4() {
				stats.RecordEvent(stats.DeletedLeechIPv4)
			} else if p.IPv6() {
				stats.RecordEvent(stats.DeletedLeechIPv6)
			}
		}

	case ann.Event == "completed":
		err = c.IncrementTorrentSnatches(t.Infohash)
		if err != nil {
			return
		}
		t.Snatches++

		if ann.Config.Private {
			err = c.IncrementUserSnatches(u.Passkey)
			if err != nil {
				return
			}
			u.Snatches++
		}

		if t.InLeecherPool(p) {
			err = leecherFinished(c, t.Infohash, p)
			if err != nil {
				return
			}
		}
		snatched = true
		if p.IPv4() {
			stats.RecordEvent(stats.CompletedIPv4)
		} else if p.IPv6() {
			stats.RecordEvent(stats.CompletedIPv6)
		}

	case t.InLeecherPool(p) && ann.Left == 0:
		// A leecher completed but the event was never received.
		err = leecherFinished(c, t.Infohash, p)
		if err != nil {
			return
		}
		// TODO Should this return snatched=true and stats for completed?
	}

	return
}

func newAnnounceResponse(ann *models.Announce, announcer *models.Peer, t *models.Torrent) *models.AnnounceResponse {
	seedCount := len(t.Seeders)
	leechCount := len(t.Leechers)

	res := &models.AnnounceResponse{
		Complete:    seedCount,
		Incomplete:  leechCount,
		Interval:    ann.Config.Announce.Duration,
		MinInterval: ann.Config.MinAnnounce.Duration,
		Compact:     ann.Compact,
	}

	if ann.NumWant > 0 && ann.Event != "stopped" && ann.Event != "paused" {
		res.IPv4Peers, res.IPv6Peers = getPeers(ann, announcer, t, ann.NumWant)
	}

	return res
}

// getPeers returns lists IPv4 and IPv6 peers on a given torrent sized according
// to the wanted parameter.
func getPeers(ann *models.Announce, announcer *models.Peer, t *models.Torrent, wanted int) (ipv4s, ipv6s models.PeerList) {
	ipv4s, ipv6s = models.PeerList{}, models.PeerList{}

	if ann.Left == 0 {
		// If they're seeding, give them only leechers.
		return appendPeers(ipv4s, ipv6s, ann, announcer, t.Leechers, wanted)
	}

	// If they're leeching, prioritize giving them seeders.
	ipv4s, ipv6s = appendPeers(ipv4s, ipv6s, ann, announcer, t.Seeders, wanted)
	return appendPeers(ipv4s, ipv6s, ann, announcer, t.Leechers, wanted-len(ipv4s)-len(ipv6s))
}

// appendPeers implements the logic of adding peers to the IPv4 or IPv6 lists.
func appendPeers(ipv4s, ipv6s models.PeerList, ann *models.Announce, announcer *models.Peer, peers models.PeerMap, wanted int) (models.PeerList, models.PeerList) {
	if ann.Config.PreferredSubnet {
		return appendSubnetPeers(ipv4s, ipv6s, ann, announcer, peers, wanted)
	}

	count := 0

	for _, peer := range peers {
		if count >= wanted {
			break
		}

		if peersEquivalent(&peer, announcer) {
			continue
		}

		if peer.IP.To4() != nil {
			ipv4s = append(ipv4s, peer)
		} else if peer.IP.To16() != nil {
			ipv6s = append(ipv6s, peer)
		}

		count++
	}

	return ipv4s, ipv6s
}

// appendSubnetPeers is an alternative version of appendPeers used when the
// config variable PreferredSubnet is enabled.
func appendSubnetPeers(ipv4s, ipv6s models.PeerList, ann *models.Announce, announcer *models.Peer, peers models.PeerMap, wanted int) (models.PeerList, models.PeerList) {
	var subnet net.IPNet

	if aip := announcer.IP.To4(); aip != nil {
		subnet = net.IPNet{aip, net.CIDRMask(ann.Config.PreferredIPv4Subnet, 32)}
	} else if aip := announcer.IP.To16(); aip != nil {
		subnet = net.IPNet{aip, net.CIDRMask(ann.Config.PreferredIPv6Subnet, 128)}
	} else {
		panic("impossible: missing IP")
	}

	// Iterate over the peers twice: first add only peers in the same subnet and
	// if we still need more peers grab any that haven't already been added.
	count := 0
	for _, checkInSubnet := range [2]bool{true, false} {
		for _, peer := range peers {
			if count >= wanted {
				break
			}

			if peersEquivalent(&peer, announcer) || checkInSubnet != subnet.Contains(peer.IP) {
				continue
			}

			if peer.IP.To4() != nil {
				ipv4s = append(ipv4s, peer)
			} else if peer.IP.To16() != nil {
				ipv6s = append(ipv6s, peer)
			}
			count++
		}
	}

	return ipv4s, ipv6s
}

// peersEquivalent checks if two peers are one in the same.
func peersEquivalent(a, b *models.Peer) bool {
	return a.ID == b.ID || a.UserID != 0 && a.UserID == b.UserID
}
<commit_msg>Switch deleted torrent event<commit_after>// Copyright 2014 The Chihaya Authors. All rights reserved.
// Use of this source code is governed by the BSD 2-Clause license,
// which can be found in the LICENSE file.

package tracker

import (
	"net"

	"github.com/chihaya/chihaya/stats"
	"github.com/chihaya/chihaya/tracker/models"
)

// HandleAnnounce encapsulates all of the logic of handling a BitTorrent
// client's Announce without being coupled to any transport protocol.
func (tkr *Tracker) HandleAnnounce(ann *models.Announce, w Writer) error {
	conn, err := tkr.Pool.Get()
	if err != nil {
		return err
	}

	defer conn.Close()

	if tkr.cfg.Whitelist {
		err = conn.FindClient(ann.ClientID())
		if err == ErrClientUnapproved {
			w.WriteError(err)
			return nil
		} else if err != nil {
			return err
		}
	}

	var user *models.User
	if tkr.cfg.Private {
		user, err = conn.FindUser(ann.Passkey)
		if err == ErrUserDNE {
			w.WriteError(err)
			return nil
		} else if err != nil {
			return err
		}
	}

	var torrent *models.Torrent
	torrent, err = conn.FindTorrent(ann.Infohash)
	switch {
	case !tkr.cfg.Private && err == ErrTorrentDNE:
		torrent = &models.Torrent{
			Infohash: ann.Infohash,
			Seeders:  models.PeerMap{},
			Leechers: models.PeerMap{},
		}

		err = conn.PutTorrent(torrent)
		if err != nil {
			return err
		}
		stats.RecordEvent(stats.NewTorrent)

	case tkr.cfg.Private && err == ErrTorrentDNE:
		w.WriteError(err)
		return nil

	case err != nil:
		return err
	}

	peer := models.NewPeer(ann, user, torrent)

	created, err := updateSwarm(conn, ann, peer, torrent)
	if err != nil {
		return err
	}

	snatched, err := handleEvent(conn, ann, peer, user, torrent)
	if err != nil {
		return err
	}

	if tkr.cfg.Private {
		delta := models.NewAnnounceDelta(ann, peer, user, torrent, created, snatched)
		err = tkr.backend.RecordAnnounce(delta)
		if err != nil {
			return err
		}
	} else if tkr.cfg.PurgeInactiveTorrents && torrent.PeerCount() == 0 {
		// Rather than deleting the torrent explicitly, let the tracker driver
		// ensure there are no race conditions.
		conn.PurgeInactiveTorrent(torrent.Infohash)
		stats.RecordEvent(stats.DeletedTorrent)
	}

	return w.WriteAnnounce(newAnnounceResponse(ann, peer, torrent))
}

// updateSwarm handles the changes to a torrent's swarm given an announce.
func updateSwarm(c Conn, ann *models.Announce, p *models.Peer, t *models.Torrent) (created bool, err error) {
	c.TouchTorrent(t.Infohash)

	switch {
	case t.InSeederPool(p):
		err = c.PutSeeder(t.Infohash, p)
		if err != nil {
			return
		}
		t.Seeders[p.ID] = *p

	case t.InLeecherPool(p):
		err = c.PutLeecher(t.Infohash, p)
		if err != nil {
			return
		}
		t.Leechers[p.ID] = *p

	default:
		if ann.Left == 0 {
			err = c.PutSeeder(t.Infohash, p)
			if err != nil {
				return
			}
			t.Seeders[p.ID] = *p
			if p.IPv4() {
				stats.RecordEvent(stats.NewSeedIPv4)
			} else if p.IPv6() {
				stats.RecordEvent(stats.NewSeedIPv6)
			}

		} else {
			err = c.PutLeecher(t.Infohash, p)
			if err != nil {
				return
			}
			t.Leechers[p.ID] = *p
			if p.IPv4() {
				stats.RecordEvent(stats.NewLeechIPv4)
			} else if p.IPv6() {
				stats.RecordEvent(stats.NewLeechIPv6)
			}
		}
		created = true
	}

	return
}

// handleEvent checks to see whether an announce has an event and if it does,
// properly handles that event.
func handleEvent(c Conn, ann *models.Announce, p *models.Peer, u *models.User, t *models.Torrent) (snatched bool, err error) {
	switch {
	case ann.Event == "stopped" || ann.Event == "paused":
		if t.InSeederPool(p) {
			err = c.DeleteSeeder(t.Infohash, p.ID)
			if err != nil {
				return
			}
			delete(t.Seeders, p.ID)
			if p.IPv4() {
				stats.RecordEvent(stats.DeletedSeedIPv4)
			} else if p.IPv6() {
				stats.RecordEvent(stats.DeletedSeedIPv6)
			}

		} else if t.InLeecherPool(p) {
			err = c.DeleteLeecher(t.Infohash, p.ID)
			if err != nil {
				return
			}
			delete(t.Leechers, p.ID)
			if p.IPv4() {
				stats.RecordEvent(stats.DeletedLeechIPv4)
			} else if p.IPv6() {
				stats.RecordEvent(stats.DeletedLeechIPv6)
			}
		}

	case ann.Event == "completed":
		err = c.IncrementTorrentSnatches(t.Infohash)
		if err != nil {
			return
		}
		t.Snatches++

		if ann.Config.Private {
			err = c.IncrementUserSnatches(u.Passkey)
			if err != nil {
				return
			}
			u.Snatches++
		}

		if t.InLeecherPool(p) {
			err = leecherFinished(c, t.Infohash, p)
			if err != nil {
				return
			}
		}
		snatched = true
		if p.IPv4() {
			stats.RecordEvent(stats.CompletedIPv4)
		} else if p.IPv6() {
			stats.RecordEvent(stats.CompletedIPv6)
		}

	case t.InLeecherPool(p) && ann.Left == 0:
		// A leecher completed but the event was never received.
		err = leecherFinished(c, t.Infohash, p)
		if err != nil {
			return
		}
		// TODO Should this return snatched=true and stats for completed?
	}

	return
}

func newAnnounceResponse(ann *models.Announce, announcer *models.Peer, t *models.Torrent) *models.AnnounceResponse {
	seedCount := len(t.Seeders)
	leechCount := len(t.Leechers)

	res := &models.AnnounceResponse{
		Complete:    seedCount,
		Incomplete:  leechCount,
		Interval:    ann.Config.Announce.Duration,
		MinInterval: ann.Config.MinAnnounce.Duration,
		Compact:     ann.Compact,
	}

	if ann.NumWant > 0 && ann.Event != "stopped" && ann.Event != "paused" {
		res.IPv4Peers, res.IPv6Peers = getPeers(ann, announcer, t, ann.NumWant)
	}

	return res
}

// getPeers returns lists IPv4 and IPv6 peers on a given torrent sized according
// to the wanted parameter.
func getPeers(ann *models.Announce, announcer *models.Peer, t *models.Torrent, wanted int) (ipv4s, ipv6s models.PeerList) {
	ipv4s, ipv6s = models.PeerList{}, models.PeerList{}

	if ann.Left == 0 {
		// If they're seeding, give them only leechers.
		return appendPeers(ipv4s, ipv6s, ann, announcer, t.Leechers, wanted)
	}

	// If they're leeching, prioritize giving them seeders.
	ipv4s, ipv6s = appendPeers(ipv4s, ipv6s, ann, announcer, t.Seeders, wanted)
	return appendPeers(ipv4s, ipv6s, ann, announcer, t.Leechers, wanted-len(ipv4s)-len(ipv6s))
}

// appendPeers implements the logic of adding peers to the IPv4 or IPv6 lists.
func appendPeers(ipv4s, ipv6s models.PeerList, ann *models.Announce, announcer *models.Peer, peers models.PeerMap, wanted int) (models.PeerList, models.PeerList) {
	if ann.Config.PreferredSubnet {
		return appendSubnetPeers(ipv4s, ipv6s, ann, announcer, peers, wanted)
	}

	count := 0

	for _, peer := range peers {
		if count >= wanted {
			break
		}

		if peersEquivalent(&peer, announcer) {
			continue
		}

		if peer.IP.To4() != nil {
			ipv4s = append(ipv4s, peer)
		} else if peer.IP.To16() != nil {
			ipv6s = append(ipv6s, peer)
		}

		count++
	}

	return ipv4s, ipv6s
}

// appendSubnetPeers is an alternative version of appendPeers used when the
// config variable PreferredSubnet is enabled.
func appendSubnetPeers(ipv4s, ipv6s models.PeerList, ann *models.Announce, announcer *models.Peer, peers models.PeerMap, wanted int) (models.PeerList, models.PeerList) {
	var subnet net.IPNet

	if aip := announcer.IP.To4(); aip != nil {
		subnet = net.IPNet{aip, net.CIDRMask(ann.Config.PreferredIPv4Subnet, 32)}
	} else if aip := announcer.IP.To16(); aip != nil {
		subnet = net.IPNet{aip, net.CIDRMask(ann.Config.PreferredIPv6Subnet, 128)}
	} else {
		panic("impossible: missing IP")
	}

	// Iterate over the peers twice: first add only peers in the same subnet and
	// if we still need more peers grab any that haven't already been added.
	count := 0
	for _, checkInSubnet := range [2]bool{true, false} {
		for _, peer := range peers {
			if count >= wanted {
				break
			}

			if peersEquivalent(&peer, announcer) || checkInSubnet != subnet.Contains(peer.IP) {
				continue
			}

			if peer.IP.To4() != nil {
				ipv4s = append(ipv4s, peer)
			} else if peer.IP.To16() != nil {
				ipv6s = append(ipv6s, peer)
			}
			count++
		}
	}

	return ipv4s, ipv6s
}

// peersEquivalent checks if two peers are one in the same.
func peersEquivalent(a, b *models.Peer) bool {
	return a.ID == b.ID || a.UserID != 0 && a.UserID == b.UserID
}
<|endoftext|>