<commit_before>/* Copyright (C) 2017 Matthias S. Benkmann
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this file (originally named deb.go) and associated documentation files
 * (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is furnished
 * to do so, subject to the following conditions:
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

// Various re-usable utility functions.
package util

import (
         "strings"
         "strconv"
       )

// Returns true if v1 is older than v2 according to Debian version
// comparison rules.
//   See https://www.debian.org/doc/debian-policy/ch-controlfields.html
//   section "5.6.12 Version"
func DebVersionLess(v1,v2 string) bool {
  return DebVersionCompare(v1,v2) < 0
}

// Returns -1, 0, +1 if v1 is less, equal, greater than v2 according to Debian version
// comparison rules.
//   See https://www.debian.org/doc/debian-policy/ch-controlfields.html
//   section "5.6.12 Version"
func DebVersionCompare(v1,v2 string) int {
  epoch1, v1, rev1 := debSplit(v1)
  epoch2, v2, rev2 := debSplit(v2)
  if epoch1 < epoch2 { return -1 }
  if epoch2 < epoch1 { return +1 }
  if v1 == v2 {
    return debVersionPartCompare(rev1,rev2)
  }
  return debVersionPartCompare(v1,v2)
}

func debSplit(v1 string) (epoch, vers, rev string) {
  epoch1i := strings.Index(v1, ":")
  epoch = "0"
  if epoch1i > 0 {
    epoch = v1[0:epoch1i]
    v1 = v1[epoch1i+1:]
  }
  rev1i :=  strings.LastIndex(v1, "-")
  rev = "0"
  if rev1i >= 0 {
    rev = v1[rev1i+1:]
    v1 = v1[0:rev1i]
  }
  vers = v1
  return epoch, vers, rev
}

func debVersionPartCompare(v1,v2 string) int {
  i := 0
  for {
    c1 := -256 // end of string sorts before 0
    c2 := -256
    if i < len(v1) {
      c1 = int(v1[i])
    }
    if i < len(v2) {
      c2 = int(v2[i])
    }
    if c1 == int('~') {
      c1 = -512 // '~' sorts before everything, even end of string
    }
    if c2 == int('~') {
      c2 = -512 // '~' sorts before everything, even end of string
    }
    if (c1 >= int('A') && c1 <= int('Z')) || (c1 >= int('a') && c1 <= int('z')) {
      c1 -= 128 // letters sort before non-letters
    }
    if (c2 >= int('A') && c2 <= int('Z')) || (c2 >= int('a') && c2 <= int('z')) {
      c2 -= 128 // letters sort before non-letters
    }

    if c1 >= int('0') && c1 <= int('9') {
      c1 = -192 // digit is end of part which sorts after end of string
    }
    if c2 >= int('0') && c2 <= int('9') {
      c2 = -192 // digit is end of part which sorts after end of string
    }

    if c1 == -192 && c2 == -192 { // number compare required
      k1 := i
      for k1 < len(v1) && v1[k1] >= '0' && v1[k1] <= '9' { k1++ }
      k2 := i
      for k2 < len(v2) && v2[k2] >= '0' && v2[k2] <= '9' { k2++ }
      num1, e1 := strconv.Atoi(v1[i:k1])
      num2, e2 := strconv.Atoi(v2[i:k2])
      if e1 == nil && e2 == nil {
        c1 = num1
        c2 = num2
        // if k1 != k2 usually c1 != c2, if not for leading 0s, so
        // we will exit the loop and i doesn't matter.
        // if there are leading 0s, the comparison result will be messed
        // up, but who cares. GIGO.
        i = k1-1 // -1 because we increment later
      }
    }

    if c1 < c2 { return -1 }
    if c2 < c1 { return +1 }

    if i >= len(v1) { break }

    i++ // increment after the test against len(v1) because we want to execute the loop for len(v1)!
  }
  return 0
}

<commit_msg>another small corner case bugfix to util.DebVersionCompare()<commit_after>/* Copyright (C) 2017 Matthias S. Benkmann
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this file (originally named deb.go) and associated documentation files
 * (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is furnished
 * to do so, subject to the following conditions:
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

// Various re-usable utility functions.
package util

import (
         "strings"
         "strconv"
       )

// Returns true if v1 is older than v2 according to Debian version
// comparison rules.
//   See https://www.debian.org/doc/debian-policy/ch-controlfields.html
//   section "5.6.12 Version"
func DebVersionLess(v1,v2 string) bool {
  return DebVersionCompare(v1,v2) < 0
}

// Returns -1, 0, +1 if v1 is less, equal, greater than v2 according to Debian version
// comparison rules.
//   See https://www.debian.org/doc/debian-policy/ch-controlfields.html
//   section "5.6.12 Version"
func DebVersionCompare(v1,v2 string) int {
  epoch1, v1, rev1 := debSplit(v1)
  epoch2, v2, rev2 := debSplit(v2)
  if epoch1 < epoch2 { return -1 }
  if epoch2 < epoch1 { return +1 }
  if v1 == v2 {
    return debVersionPartCompare(rev1,rev2)
  }
  return debVersionPartCompare(v1,v2)
}

func debSplit(v1 string) (epoch, vers, rev string) {
  epoch1i := strings.Index(v1, ":")
  epoch = "0"
  if epoch1i > 0 {
    epoch = v1[0:epoch1i]
    v1 = v1[epoch1i+1:]
  }
  rev1i :=  strings.LastIndex(v1, "-")
  rev = "0"
  if rev1i >= 0 {
    rev = v1[rev1i+1:]
    v1 = v1[0:rev1i]
    if rev == "" { rev = "0" }
  }
  vers = v1
  return epoch, vers, rev
}

func debVersionPartCompare(v1,v2 string) int {
  i := 0
  for {
    c1 := -256 // end of string sorts before 0
    c2 := -256
    if i < len(v1) {
      c1 = int(v1[i])
    }
    if i < len(v2) {
      c2 = int(v2[i])
    }
    if c1 == int('~') {
      c1 = -512 // '~' sorts before everything, even end of string
    }
    if c2 == int('~') {
      c2 = -512 // '~' sorts before everything, even end of string
    }
    if (c1 >= int('A') && c1 <= int('Z')) || (c1 >= int('a') && c1 <= int('z')) {
      c1 -= 128 // letters sort before non-letters
    }
    if (c2 >= int('A') && c2 <= int('Z')) || (c2 >= int('a') && c2 <= int('z')) {
      c2 -= 128 // letters sort before non-letters
    }

    if c1 >= int('0') && c1 <= int('9') {
      c1 = -192 // digit is end of part which sorts after end of string
    }
    if c2 >= int('0') && c2 <= int('9') {
      c2 = -192 // digit is end of part which sorts after end of string
    }

    if c1 == -192 && c2 == -192 { // number compare required
      k1 := i
      for k1 < len(v1) && v1[k1] >= '0' && v1[k1] <= '9' { k1++ }
      k2 := i
      for k2 < len(v2) && v2[k2] >= '0' && v2[k2] <= '9' { k2++ }
      num1, e1 := strconv.Atoi(v1[i:k1])
      num2, e2 := strconv.Atoi(v2[i:k2])
      if e1 == nil && e2 == nil {
        c1 = num1
        c2 = num2
        // if k1 != k2 usually c1 != c2, if not for leading 0s, so
        // we will exit the loop and i doesn't matter.
        // if there are leading 0s, the comparison result will be messed
        // up, but who cares. GIGO.
        i = k1-1 // -1 because we increment later
      }
    }

    if c1 < c2 { return -1 }
    if c2 < c1 { return +1 }

    if i >= len(v1) { break }

    i++ // increment after the test against len(v1) because we want to execute the loop for len(v1)!
  }
  return 0
}

<|endoftext|>


<commit_before>package util

import (
	"fmt"
	"os"

	logging "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/op/go-logging"
)

func init() {
	SetupLogging()
}

var log = Logger("util")

var ansiGray = "\033[0;37m"

// LogFormats is a map of formats used for our logger, keyed by name.
var LogFormats = map[string]string{
	"default": "%{color}%{time:2006-01-02 15:04:05.999999} %{level} %{shortfile}:	%{color:reset}%{message}",
	"color": ansiGray + "%{time:15:04:05.999} %{color}%{level}:	%{color:reset}%{message} " + ansiGray + "%{shortfile}%{color:reset}",
}

// Logging environment variables
const (
	envLogging    = "IPFS_LOGGING"
	envLoggingFmt = "IPFS_LOGGING_FMT"
)

// loggers is the set of loggers in the system
var loggers = map[string]*logging.Logger{}

// POut is a shorthand printing function to output to Stdout.
func POut(format string, a ...interface{}) {
	fmt.Fprintf(os.Stdout, format, a...)
}

// SetupLogging will initialize the logger backend and set the flags.
func SetupLogging() {

	fmt := LogFormats[os.Getenv(envLoggingFmt)]
	if fmt == "" {
		fmt = LogFormats["default"]
	}

	backend := logging.NewLogBackend(os.Stderr, "", 0)
	logging.SetBackend(backend)
	logging.SetFormatter(logging.MustStringFormatter(fmt))

	lvl := logging.ERROR

	if logenv := os.Getenv(envLogging); logenv != "" {
		var err error
		lvl, err = logging.LogLevel(logenv)
		if err != nil {
			log.Error("logging.LogLevel() Error: %q", err)
			lvl = logging.ERROR // reset to ERROR, could be undefined now(?)
		}
	}

	Debug = GetenvBool("IPFS_DEBUG")
	if Debug {
		lvl = logging.DEBUG
	}

	SetAllLoggers(lvl)

}

// SetAllLoggers changes the logging.Level of all loggers to lvl
func SetAllLoggers(lvl logging.Level) {
	logging.SetLevel(lvl, "")
	for n, log := range loggers {
		logging.SetLevel(lvl, n)
		log.Notice("setting logger: %q to %v", n, lvl)
	}
}

// Logger retrieves a particular logger
func Logger(name string) *logging.Logger {
	log := logging.MustGetLogger(name)
	loggers[name] = log
	return log
}

// SetLogLevel changes the log level of a specific subsystem
// name=="*" changes all subsystems
func SetLogLevel(name, level string) error {
	lvl, err := logging.LogLevel(level)
	if err != nil {
		return err
	}

	// wildcard, change all
	if name == "*" {
		SetAllLoggers(lvl)
		return nil
	}

	// Check if we have a logger by that name
	// logging.SetLevel() can't tell us...
	_, ok := loggers[name]
	if !ok {
		return ErrNoSuchLogger
	}

	logging.SetLevel(lvl, name)

	return nil
}
<commit_msg>nicer, greppable logging<commit_after>package util

import (
	"fmt"
	"os"

	logging "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/op/go-logging"
)

func init() {
	SetupLogging()
}

var log = Logger("util")

var ansiGray = "\033[0;37m"
var ansiBlue = "\033[0;34m"

// LogFormats is a map of formats used for our logger, keyed by name.
var LogFormats = map[string]string{
	"default": "%{color}%{time:2006-01-02 15:04:05.000000} %{level} %{module} %{shortfile}:	%{color:reset}%{message}",
	"color": ansiGray + "%{time:15:04:05.000} %{color}%{level:5.5s} " + ansiBlue +
		"%{module:10.10s}: %{color:reset}%{message} " + ansiGray + "%{shortfile}%{color:reset}",
}

// Logging environment variables
const (
	envLogging    = "IPFS_LOGGING"
	envLoggingFmt = "IPFS_LOGGING_FMT"
)

// loggers is the set of loggers in the system
var loggers = map[string]*logging.Logger{}

// POut is a shorthand printing function to output to Stdout.
func POut(format string, a ...interface{}) {
	fmt.Fprintf(os.Stdout, format, a...)
}

// SetupLogging will initialize the logger backend and set the flags.
func SetupLogging() {

	fmt := LogFormats[os.Getenv(envLoggingFmt)]
	if fmt == "" {
		fmt = LogFormats["default"]
	}

	backend := logging.NewLogBackend(os.Stderr, "", 0)
	logging.SetBackend(backend)
	logging.SetFormatter(logging.MustStringFormatter(fmt))

	lvl := logging.ERROR

	if logenv := os.Getenv(envLogging); logenv != "" {
		var err error
		lvl, err = logging.LogLevel(logenv)
		if err != nil {
			log.Error("logging.LogLevel() Error: %q", err)
			lvl = logging.ERROR // reset to ERROR, could be undefined now(?)
		}
	}

	Debug = GetenvBool("IPFS_DEBUG")
	if Debug {
		lvl = logging.DEBUG
	}

	SetAllLoggers(lvl)

}

// SetAllLoggers changes the logging.Level of all loggers to lvl
func SetAllLoggers(lvl logging.Level) {
	logging.SetLevel(lvl, "")
	for n, log := range loggers {
		logging.SetLevel(lvl, n)
		log.Notice("setting logger: %q to %v", n, lvl)
	}
}

// Logger retrieves a particular logger
func Logger(name string) *logging.Logger {
	log := logging.MustGetLogger(name)
	loggers[name] = log
	return log
}

// SetLogLevel changes the log level of a specific subsystem
// name=="*" changes all subsystems
func SetLogLevel(name, level string) error {
	lvl, err := logging.LogLevel(level)
	if err != nil {
		return err
	}

	// wildcard, change all
	if name == "*" {
		SetAllLoggers(lvl)
		return nil
	}

	// Check if we have a logger by that name
	// logging.SetLevel() can't tell us...
	_, ok := loggers[name]
	if !ok {
		return ErrNoSuchLogger
	}

	logging.SetLevel(lvl, name)

	return nil
}
<|endoftext|>


<commit_before>package schema

// ResourceImporter defines how a resource is imported in Terraform. This
// can be set onto a Resource struct to make it Importable. Not all resources
// have to be importable; if a Resource doesn't have a ResourceImporter then
// it won't be importable.
//
// "Importing" in Terraform is the process of taking an already-created
// resource and bringing it under Terraform management. This can include
// updating Terraform state, generating Terraform configuration, etc.
type ResourceImporter struct {
	// The functions below must all be implemented for importing to work.

	// State is called to convert an ID to one or more InstanceState to
	// insert into the Terraform state. If this isn't specified, then
	// the ID is passed straight through.
	State StateFunc
}

// StateFunc is the function called to import a resource into the
// Terraform state. It is given a ResourceData with only ID set. This
// ID is going to be an arbitrary value given by the user and may not map
// directly to the ID format that the resource expects, so that should
// be validated.
//
// This should return a slice of ResourceData that turn into the state
// that was imported. This might be as simple as returning only the argument
// that was given to the function. In other cases (such as AWS security groups),
// an import may fan out to multiple resources and this will have to return
// multiple.
//
// To create the ResourceData structures for other resource types (if
// you have to), instantiate your resource and call the Data function.
type StateFunc func(*ResourceData, interface{}) ([]*ResourceData, error)

// InternalValidate should be called to validate the structure of this
// importer. This should be called in a unit test.
//
// Resource.InternalValidate() will automatically call this, so this doesn't
// need to be called manually. Further, Resource.InternalValidate() is
// automatically called by Provider.InternalValidate(), so you only need
// to internal validate the provider.
func (r *ResourceImporter) InternalValidate() error {
	return nil
}
<commit_msg>helper/schema: pass through import state func<commit_after>package schema

// ResourceImporter defines how a resource is imported in Terraform. This
// can be set onto a Resource struct to make it Importable. Not all resources
// have to be importable; if a Resource doesn't have a ResourceImporter then
// it won't be importable.
//
// "Importing" in Terraform is the process of taking an already-created
// resource and bringing it under Terraform management. This can include
// updating Terraform state, generating Terraform configuration, etc.
type ResourceImporter struct {
	// The functions below must all be implemented for importing to work.

	// State is called to convert an ID to one or more InstanceState to
	// insert into the Terraform state. If this isn't specified, then
	// the ID is passed straight through.
	State StateFunc
}

// StateFunc is the function called to import a resource into the
// Terraform state. It is given a ResourceData with only ID set. This
// ID is going to be an arbitrary value given by the user and may not map
// directly to the ID format that the resource expects, so that should
// be validated.
//
// This should return a slice of ResourceData that turn into the state
// that was imported. This might be as simple as returning only the argument
// that was given to the function. In other cases (such as AWS security groups),
// an import may fan out to multiple resources and this will have to return
// multiple.
//
// To create the ResourceData structures for other resource types (if
// you have to), instantiate your resource and call the Data function.
type StateFunc func(*ResourceData, interface{}) ([]*ResourceData, error)

// InternalValidate should be called to validate the structure of this
// importer. This should be called in a unit test.
//
// Resource.InternalValidate() will automatically call this, so this doesn't
// need to be called manually. Further, Resource.InternalValidate() is
// automatically called by Provider.InternalValidate(), so you only need
// to internal validate the provider.
func (r *ResourceImporter) InternalValidate() error {
	return nil
}

// ImportStatePassthrough is an implementation of StateFunc that can be
// used to simply pass the ID directly through. This should be used only
// in the case that an ID-only refresh is possible.
func ImportStatePassthrough(d *ResourceData, m interface{}) ([]*ResourceData, error) {
	return []*ResourceData{d}, nil
}
<|endoftext|>


<commit_before>package app

import (
	"errors"
	"fmt"
	"io"
	"sync"
	"time"

	godocker "github.com/fsouza/go-dockerclient"
	"github.com/moncho/dry/appui"
	drydocker "github.com/moncho/dry/docker"
	"github.com/moncho/dry/ui"
)

const (
	//TimeBetweenRefresh defines the time that has to pass between dry refreshes
	TimeBetweenRefresh = 10 * time.Second
)

//Dry represents the application.
type Dry struct {
	containerToInspect *godocker.Container
	dockerDaemon       drydocker.ContainerDaemon
	info               *godocker.Env
	renderer           *appui.DockerPs
	State              *State
	stats              *drydocker.Stats
	orderedCids        []string
	output             chan string
	dockerEvents       chan *godocker.APIEvents
	lastRefresh        time.Time
	refreshTimeMutex   sync.Locker
}

//Changed is true if the application state has changed
func (d *Dry) Changed() bool {
	return d.State.changed
}

//Close closes dry, releasing any resources held by it
func (d *Dry) Close() {
	d.dockerDaemon.StopReceivingEvents(d.dockerEvents)
	close(d.output)
	close(d.dockerEvents)
}

//Inspect set dry for inspecting container at the given position
func (d *Dry) Inspect(position int) {
	if id, shortID, err := d.dockerDaemon.ContainerIDAt(position); err == nil {
		c, err := d.dockerDaemon.Inspect(id)
		if err == nil {
			d.State.viewMode = InspectMode
			d.containerToInspect = c
		} else {
			d.errormessage(shortID, "inspecting", err)
		}
	} else {
		d.errormessage(shortID, "inspecting", err)
	}
}

//Kill the docker container at the given position
func (d *Dry) Kill(position int) {
	if id, shortID, err := d.dockerDaemon.ContainerIDAt(position); err == nil {
		d.actionmessage(shortID, "Killing")
		err := d.dockerDaemon.Kill(id)
		if err == nil {
			d.actionmessage(shortID, "killed")
		} else {
			d.errormessage(shortID, "killing", err)
		}
	}

}

//Logs retrieves the log of the docker container at the given position
func (d *Dry) Logs(position int) (io.ReadCloser, error) {
	id, _, err := d.dockerDaemon.ContainerIDAt(position)
	if err == nil {
		return d.dockerDaemon.Logs(id), nil
	}
	return nil, err
}

//OuputChannel returns the channel where dry messages are written
func (d *Dry) OuputChannel() <-chan string {
	return d.output
}

//Ok returns the state of dry
func (d *Dry) Ok() (bool, error) {
	return d.dockerDaemon.Ok()
}

//Refresh forces a dry refresh
func (d *Dry) Refresh() {
	d.refreshTimeMutex.Lock()
	defer d.refreshTimeMutex.Unlock()
	d.doRefresh()
	d.resetTimer()
}

func (d *Dry) doRefresh() {
	d.State.changed = true
	d.dockerDaemon.Refresh(d.State.showingAllContainers)
}

//RemoveAllStoppedContainers removes all stopped containers
func (d *Dry) RemoveAllStoppedContainers() {
	d.appmessage(fmt.Sprintf("<red>Removing all stopped containers</>"))
	if err := d.dockerDaemon.RemoveAllStoppedContainers(); err == nil {
		d.appmessage(fmt.Sprintf("<red>Removed all stopped containers</>"))
	} else {
		d.appmessage(
			fmt.Sprintf(
				"<red>Error removing all stopped containers. %s</>", err))
	}
}

func (d *Dry) resetTimer() {
	d.lastRefresh = time.Now()
}

//Rm removes the container at the given position
func (d *Dry) Rm(position int) {
	if id, shortID, err := d.dockerDaemon.ContainerIDAt(position); err == nil {
		d.actionmessage(shortID, "Removing")
		if err := d.dockerDaemon.Rm(id); err == nil {
			d.actionmessage(shortID, "Removed")
		} else {
			d.errormessage(shortID, "removing", err)
		}
	} else {
		d.errormessage(id, "removing", err)
	}
}

//ShowContainers changes the state of dry to show the container list
func (d *Dry) ShowContainers() {
	d.State.changed = true
	d.State.viewMode = Main
}

//ShowHelp changes the state of dry to show the extended help
func (d *Dry) ShowHelp() {
	d.State.viewMode = HelpMode
}

//ShowInfo retrieves Docker Host info.
func (d *Dry) ShowInfo() error {
	info, err := d.dockerDaemon.Info()
	if err == nil {
		d.State.viewMode = InfoMode
		d.info = info
		return nil
	}
	return err

}

//Sort rotates to the next sort mode.
//SortByContainerID -> SortByImage -> SortByStatus -> SortByName -> SortByContainerID
func (d *Dry) Sort() {
	switch d.State.SortMode {
	case drydocker.SortByContainerID:
		d.State.SortMode = drydocker.SortByImage
	case drydocker.SortByImage:
		d.State.SortMode = drydocker.SortByStatus
	case drydocker.SortByStatus:
		d.State.SortMode = drydocker.SortByName
	case drydocker.SortByName:
		d.State.SortMode = drydocker.SortByContainerID
	default:
	}
	d.dockerDaemon.Sort(d.State.SortMode)
	d.State.changed = true

}

func (d *Dry) startDry() {
	go func() {
		//The event is not relevant, dry must refresh
		for range d.dockerEvents {
			d.Refresh()
		}
	}()

	go func() {
		for range time.Tick(60 * time.Second) {
			d.tryRefresh()
		}
	}()
}

//StartContainer (re)starts the container at the given position
func (d *Dry) StartContainer(position int) {
	if id, shortID, err := d.dockerDaemon.ContainerIDAt(position); err == nil {
		d.actionmessage(shortID, "Restarting")
		go func() {
			err := d.dockerDaemon.RestartContainer(id)
			if err == nil {
				d.actionmessage(shortID, "Restarted")
			} else {
				d.errormessage(shortID, "restarting", err)
			}
		}()
	} else {
		d.errormessage(shortID, "restarting", err)
	}

}

//Stats get stats of container in the given position until a
//message is sent to the done channel
func (d *Dry) Stats(position int) (chan<- bool, <-chan error, error) {
	id, _, err := d.dockerDaemon.ContainerIDAt(position)
	if err == nil {
		if d.dockerDaemon.IsContainerRunning(id) {
			done := make(chan bool, 1)
			statsC, dockerDoneChannel, errC := d.dockerDaemon.Stats(id)
			if err == nil {
				go func() {
					for {
						select {
						case s := <-statsC:
							d.stats = s
							d.State.viewMode = StatsMode
						case <-done:
							dockerDoneChannel <- true
							return
						}
					}
				}()
				return done, errC, nil
			}
			dockerDoneChannel <- true
		}
		d.appmessage(
			fmt.Sprintf("<red>Cannot run stats on stopped container. Id: </><white>%s</>", id))
		err = errors.New("Cannot run stats on stopped container.")
	}
	return nil, nil, err
}

//StopContainer stops the container at the given position
func (d *Dry) StopContainer(position int) {
	if id, shortID, err := d.dockerDaemon.ContainerIDAt(position); err == nil {
		d.actionmessage(shortID, "Stopping")
		go func() {
			if err := d.dockerDaemon.StopContainer(id); err == nil {
				d.actionmessage(shortID, "Stopped")
			} else {
				d.errormessage(shortID, "stopping", err)
			}
		}()
	}
}

//ToggleShowAllContainers changes between showing running containers and
//showing running and stopped containers.
func (d *Dry) ToggleShowAllContainers() {
	d.State.showingAllContainers = !d.State.showingAllContainers
	d.Refresh()
	if d.State.showingAllContainers {
		d.appmessage("<white>Showing all containers</>")
	} else {
		d.appmessage("<white>Showing running containers</>")
	}
}

//tryRefresh refreshes dry if dry has not been refreshed in the last
//TimeBetweenRefresh
func (d *Dry) tryRefresh() {
	d.refreshTimeMutex.Lock()
	defer d.refreshTimeMutex.Unlock()
	if time.Since(d.lastRefresh) > TimeBetweenRefresh {
		d.resetTimer()
		d.doRefresh()
	}
}

func (d *Dry) appmessage(message string) {
	go func() {
		select {
		case d.output <- message:
		default:
		}
	}()
}

func (d *Dry) actionmessage(cid string, action string) {
	d.appmessage(fmt.Sprintf("<red>%s container with id </><white>%s</>",
		action, cid))
}
func (d *Dry) cleanStats() {
	d.stats = nil
}

func (d *Dry) errormessage(cid string, action string, err error) {
	d.appmessage(
		fmt.Sprintf(
			"<red>Error %s container </><white>%s. %s</>",
			action, cid, err.Error()))
}

func newDry(screen *ui.Screen, d *drydocker.DockerDaemon, err error) (*Dry, error) {
	if err == nil {
		dockerEvents, err := d.Events()
		if err == nil {

			state := &State{
				changed:              true,
				Paused:               false,
				showingAllContainers: false,
				SortMode:             drydocker.SortByContainerID,
				viewMode:             Main,
			}
			d.Sort(state.SortMode)
			app := &Dry{}
			app.State = state
			app.dockerDaemon = d
			app.renderer = appui.NewDockerPsRenderer(
				app.dockerDaemon,
				screen.Cursor,
				state.SortMode)
			app.output = make(chan string)
			app.dockerEvents = dockerEvents
			app.refreshTimeMutex = &sync.Mutex{}
			app.resetTimer()
			app.startDry()
			return app, nil
		}
		return nil, err
	}
	return nil, err
}

//NewDryApp creates a new dry application
func NewDryApp(screen *ui.Screen) (*Dry, error) {
	d, err := drydocker.ConnectToDaemon()
	return newDry(screen, d, err)
}

//NewDryAppWithDockerEnv creates a new dry application
func NewDryAppWithDockerEnv(screen *ui.Screen, env *drydocker.DockerEnv) (*Dry, error) {
	d, err := drydocker.ConnectToDaemonUsingEnv(env)
	return newDry(screen, d, err)
}
<commit_msg>Reduce dry autorefresh timer to 15 seconds, resolve #5<commit_after>package app

import (
	"errors"
	"fmt"
	"io"
	"sync"
	"time"

	godocker "github.com/fsouza/go-dockerclient"
	"github.com/moncho/dry/appui"
	drydocker "github.com/moncho/dry/docker"
	"github.com/moncho/dry/ui"
)

const (
	//TimeBetweenRefresh defines the time that has to pass between dry refreshes
	TimeBetweenRefresh = 10 * time.Second
)

//Dry represents the application.
type Dry struct {
	containerToInspect *godocker.Container
	dockerDaemon       drydocker.ContainerDaemon
	info               *godocker.Env
	renderer           *appui.DockerPs
	State              *State
	stats              *drydocker.Stats
	orderedCids        []string
	output             chan string
	dockerEvents       chan *godocker.APIEvents
	lastRefresh        time.Time
	refreshTimeMutex   sync.Locker
}

//Changed is true if the application state has changed
func (d *Dry) Changed() bool {
	return d.State.changed
}

//Close closes dry, releasing any resources held by it
func (d *Dry) Close() {
	d.dockerDaemon.StopEventChannel(d.dockerEvents)
	close(d.output)
	close(d.dockerEvents)
}

//Inspect set dry for inspecting container at the given position
func (d *Dry) Inspect(position int) {
	if id, shortID, err := d.dockerDaemon.ContainerIDAt(position); err == nil {
		c, err := d.dockerDaemon.Inspect(id)
		if err == nil {
			d.State.viewMode = InspectMode
			d.containerToInspect = c
		} else {
			d.errormessage(shortID, "inspecting", err)
		}
	} else {
		d.errormessage(shortID, "inspecting", err)
	}
}

//Kill the docker container at the given position
func (d *Dry) Kill(position int) {
	if id, shortID, err := d.dockerDaemon.ContainerIDAt(position); err == nil {
		d.actionmessage(shortID, "Killing")
		err := d.dockerDaemon.Kill(id)
		if err == nil {
			d.actionmessage(shortID, "killed")
		} else {
			d.errormessage(shortID, "killing", err)
		}
	}

}

//Logs retrieves the log of the docker container at the given position
func (d *Dry) Logs(position int) (io.ReadCloser, error) {
	id, _, err := d.dockerDaemon.ContainerIDAt(position)
	if err == nil {
		return d.dockerDaemon.Logs(id), nil
	}
	return nil, err
}

//OuputChannel returns the channel where dry messages are written
func (d *Dry) OuputChannel() <-chan string {
	return d.output
}

//Ok returns the state of dry
func (d *Dry) Ok() (bool, error) {
	return d.dockerDaemon.Ok()
}

//Refresh forces a dry refresh
func (d *Dry) Refresh() {
	d.refreshTimeMutex.Lock()
	defer d.refreshTimeMutex.Unlock()
	d.doRefresh()
	d.resetTimer()
}

func (d *Dry) doRefresh() {
	d.State.changed = true
	d.dockerDaemon.Refresh(d.State.showingAllContainers)
}

//RemoveAllStoppedContainers removes all stopped containers
func (d *Dry) RemoveAllStoppedContainers() {
	d.appmessage(fmt.Sprintf("<red>Removing all stopped containers</>"))
	if err := d.dockerDaemon.RemoveAllStoppedContainers(); err == nil {
		d.appmessage(fmt.Sprintf("<red>Removed all stopped containers</>"))
	} else {
		d.appmessage(
			fmt.Sprintf(
				"<red>Error removing all stopped containers. %s</>", err))
	}
}

func (d *Dry) resetTimer() {
	d.lastRefresh = time.Now()
}

//Rm removes the container at the given position
func (d *Dry) Rm(position int) {
	if id, shortID, err := d.dockerDaemon.ContainerIDAt(position); err == nil {
		d.actionmessage(shortID, "Removing")
		if err := d.dockerDaemon.Rm(id); err == nil {
			d.actionmessage(shortID, "Removed")
		} else {
			d.errormessage(shortID, "removing", err)
		}
	} else {
		d.errormessage(id, "removing", err)
	}
}

//ShowContainers changes the state of dry to show the container list
func (d *Dry) ShowContainers() {
	d.State.changed = true
	d.State.viewMode = Main
}

//ShowHelp changes the state of dry to show the extended help
func (d *Dry) ShowHelp() {
	d.State.viewMode = HelpMode
}

//ShowInfo retrieves Docker Host info.
func (d *Dry) ShowInfo() error {
	info, err := d.dockerDaemon.Info()
	if err == nil {
		d.State.viewMode = InfoMode
		d.info = info
		return nil
	}
	return err

}

//Sort rotates to the next sort mode.
//SortByContainerID -> SortByImage -> SortByStatus -> SortByName -> SortByContainerID
func (d *Dry) Sort() {
	switch d.State.SortMode {
	case drydocker.SortByContainerID:
		d.State.SortMode = drydocker.SortByImage
	case drydocker.SortByImage:
		d.State.SortMode = drydocker.SortByStatus
	case drydocker.SortByStatus:
		d.State.SortMode = drydocker.SortByName
	case drydocker.SortByName:
		d.State.SortMode = drydocker.SortByContainerID
	default:
	}
	d.dockerDaemon.Sort(d.State.SortMode)
	d.State.changed = true

}

func (d *Dry) startDry() {
	go func() {
		//The event is not relevant, dry must refresh
		for range d.dockerEvents {
			d.Refresh()
		}
	}()

	go func() {
		for range time.Tick(15 * time.Second) {
			d.tryRefresh()
		}
	}()
}

//StartContainer (re)starts the container at the given position
func (d *Dry) StartContainer(position int) {
	if id, shortID, err := d.dockerDaemon.ContainerIDAt(position); err == nil {
		d.actionmessage(shortID, "Restarting")
		go func() {
			err := d.dockerDaemon.RestartContainer(id)
			if err == nil {
				d.actionmessage(shortID, "Restarted")
			} else {
				d.errormessage(shortID, "restarting", err)
			}
		}()
	} else {
		d.errormessage(shortID, "restarting", err)
	}

}

//Stats get stats of container in the given position until a
//message is sent to the done channel
func (d *Dry) Stats(position int) (chan<- bool, <-chan error, error) {
	id, _, err := d.dockerDaemon.ContainerIDAt(position)
	if err == nil {
		if d.dockerDaemon.IsContainerRunning(id) {
			done := make(chan bool, 1)
			statsC, dockerDoneChannel, errC := d.dockerDaemon.Stats(id)
			if err == nil {
				go func() {
					for {
						select {
						case s := <-statsC:
							d.stats = s
							d.State.viewMode = StatsMode
						case <-done:
							dockerDoneChannel <- true
							return
						}
					}
				}()
				return done, errC, nil
			}
			dockerDoneChannel <- true
		}
		d.appmessage(
			fmt.Sprintf("<red>Cannot run stats on stopped container. Id: </><white>%s</>", id))
		err = errors.New("Cannot run stats on stopped container.")
	}
	return nil, nil, err
}

//StopContainer stops the container at the given position
func (d *Dry) StopContainer(position int) {
	if id, shortID, err := d.dockerDaemon.ContainerIDAt(position); err == nil {
		d.actionmessage(shortID, "Stopping")
		go func() {
			if err := d.dockerDaemon.StopContainer(id); err == nil {
				d.actionmessage(shortID, "Stopped")
			} else {
				d.errormessage(shortID, "stopping", err)
			}
		}()
	}
}

//ToggleShowAllContainers changes between showing running containers and
//showing running and stopped containers.
func (d *Dry) ToggleShowAllContainers() {
	d.State.showingAllContainers = !d.State.showingAllContainers
	d.Refresh()
	if d.State.showingAllContainers {
		d.appmessage("<white>Showing all containers</>")
	} else {
		d.appmessage("<white>Showing running containers</>")
	}
}

//tryRefresh refreshes dry if dry has not been refreshed in the last
//TimeBetweenRefresh
func (d *Dry) tryRefresh() {
	d.refreshTimeMutex.Lock()
	defer d.refreshTimeMutex.Unlock()
	if time.Since(d.lastRefresh) > TimeBetweenRefresh {
		d.resetTimer()
		d.doRefresh()
	}
}

func (d *Dry) appmessage(message string) {
	go func() {
		select {
		case d.output <- message:
		default:
		}
	}()
}

func (d *Dry) actionmessage(cid string, action string) {
	d.appmessage(fmt.Sprintf("<red>%s container with id </><white>%s</>",
		action, cid))
}
func (d *Dry) cleanStats() {
	d.stats = nil
}

func (d *Dry) errormessage(cid string, action string, err error) {
	d.appmessage(
		fmt.Sprintf(
			"<red>Error %s container </><white>%s. %s</>",
			action, cid, err.Error()))
}

func newDry(screen *ui.Screen, d *drydocker.DockerDaemon, err error) (*Dry, error) {
	if err == nil {
		dockerEvents, err := d.Events()
		if err == nil {

			state := &State{
				changed:              true,
				Paused:               false,
				showingAllContainers: false,
				SortMode:             drydocker.SortByContainerID,
				viewMode:             Main,
			}
			d.Sort(state.SortMode)
			app := &Dry{}
			app.State = state
			app.dockerDaemon = d
			app.renderer = appui.NewDockerPsRenderer(
				app.dockerDaemon,
				screen.Cursor,
				state.SortMode)
			app.output = make(chan string)
			app.dockerEvents = dockerEvents
			app.refreshTimeMutex = &sync.Mutex{}
			app.resetTimer()
			app.startDry()
			return app, nil
		}
		return nil, err
	}
	return nil, err
}

//NewDryApp creates a new dry application
func NewDryApp(screen *ui.Screen) (*Dry, error) {
	d, err := drydocker.ConnectToDaemon()
	return newDry(screen, d, err)
}

//NewDryAppWithDockerEnv creates a new dry application
func NewDryAppWithDockerEnv(screen *ui.Screen, env *drydocker.DockerEnv) (*Dry, error) {
	d, err := drydocker.ConnectToDaemonUsingEnv(env)
	return newDry(screen, d, err)
}
<|endoftext|>


<commit_before>// Copyright 2015 The Cockroach Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.
//
// Author: Tobias Schottdorf (tobias.schottdorf@gmail.com)

package tracing

import (
	"bytes"
	"encoding/gob"
	"fmt"

	"golang.org/x/net/context"

	"github.com/cockroachdb/cockroach/util/caller"
	"github.com/cockroachdb/cockroach/util/envutil"
	"github.com/lightstep/lightstep-tracer-go"
	basictracer "github.com/opentracing/basictracer-go"
	"github.com/opentracing/basictracer-go/events"
	opentracing "github.com/opentracing/opentracing-go"
	"github.com/opentracing/opentracing-go/ext"
	otlog "github.com/opentracing/opentracing-go/log"
)

// Snowball is set as Baggage on traces which are used for snowball tracing.
const Snowball = "sb"

// maxLogsPerSpan limits the number of logs in a Span; use a comfortable limit.
const maxLogsPerSpan = 1000

// A CallbackRecorder immediately invokes itself on received trace spans.
type CallbackRecorder func(sp basictracer.RawSpan)

// RecordSpan implements basictracer.SpanRecorder.
func (cr CallbackRecorder) RecordSpan(sp basictracer.RawSpan) {
	cr(sp)
}

// JoinOrNew creates a new Span joined to the provided DelegatingCarrier or
// creates Span from the given tracer.
func JoinOrNew(tr opentracing.Tracer, carrier *Span, opName string) (opentracing.Span, error) {
	if carrier != nil {
		wireContext, err := tr.Extract(basictracer.Delegator, carrier)
		switch err {
		case nil:
			sp := tr.StartSpan(opName, opentracing.FollowsFrom(wireContext))

			// Copy baggage items to tags so they show up in the Lightstep UI.
			sp.Context().ForeachBaggageItem(func(k, v string) bool { sp.SetTag(k, v); return true })

			sp.LogEvent(opName)
			return sp, nil
		case opentracing.ErrSpanContextNotFound:
		default:
			return nil, err
		}
	}
	return tr.StartSpan(opName), nil
}

// JoinOrNewSnowball returns a Span which records directly via the specified
// callback. If the given DelegatingCarrier is nil, a new Span is created.
// otherwise, the created Span is a child.
//
// The recorder should be nil if we don't need to record spans.
//
// TODO(andrei): JoinOrNewSnowball creates a new tracer, which is not kosher.
// Also this can't use the lightstep tracer.
func JoinOrNewSnowball(
	opName string, carrier *Span, recorder func(sp basictracer.RawSpan),
) (opentracing.Span, error) {
	tr := basictracer.NewWithOptions(basictracerOptions(recorder))
	sp, err := JoinOrNew(tr, carrier, opName)
	if err == nil {
		// We definitely want to sample a Snowball trace.
		// This must be set *before* SetBaggageItem, as that will otherwise be ignored.
		ext.SamplingPriority.Set(sp, 1)
		sp.SetBaggageItem(Snowball, "1")
	}
	return sp, err
}

// NewTracerAndSpanFor7881 creates a new tracer and a root span. The tracer is
// to be used for tracking down #7881; it runs a callback for each finished span
// (and the callback used accumulates the spans in a SQL txn).
func NewTracerAndSpanFor7881(
	callback func(sp basictracer.RawSpan),
) (opentracing.Span, opentracing.Tracer, error) {
	opts := basictracerOptions(callback)
	// Don't trim the logs in "unsampled" spans". Note that this tracer does not
	// use sampling; instead it uses an ad-hoc mechanism for marking spans of
	// interest.
	opts.TrimUnsampledSpans = false
	tr := basictracer.NewWithOptions(opts)
	sp, err := JoinOrNew(tr, nil, "sql txn")
	return sp, tr, err
}

// ForkCtxSpan checks if ctx has a Span open; if it does, it creates a new Span
// that follows from the original Span. This allows the resulting context to be
// used in an async task that might outlive the original operation.
//
// Returns the new context and a function that closes the span.
func ForkCtxSpan(ctx context.Context, opName string) (context.Context, func()) {
	if span := opentracing.SpanFromContext(ctx); span != nil {
		if span.BaggageItem(Snowball) == "1" {
			// If we are doing snowball tracing, the span might outlive the snowball
			// tracer (calling the record function when it is no longer legal to do
			// so). Return a context with no span in this case.
			return opentracing.ContextWithSpan(ctx, nil), func() {}
		}
		tr := span.Tracer()
		newSpan := tr.StartSpan(opName, opentracing.FollowsFrom(span.Context()))
		return opentracing.ContextWithSpan(ctx, newSpan), func() { newSpan.Finish() }
	}
	return ctx, func() {}
}

// ChildSpan opens a span as a child of the current span in the context (if
// there is one).
//
// Returns the new context and a function that closes the span.
func ChildSpan(ctx context.Context, opName string) (context.Context, func()) {
	span := opentracing.SpanFromContext(ctx)
	if span == nil {
		return ctx, func() {}
	}
	newSpan := span.Tracer().StartSpan(opName, opentracing.ChildOf(span.Context()))
	return opentracing.ContextWithSpan(ctx, newSpan), func() { newSpan.Finish() }
}

// basicTracerOptions initializes options for basictracer.
// The recorder should be nil if we don't need to record spans.
func basictracerOptions(recorder func(basictracer.RawSpan)) basictracer.Options {
	opts := basictracer.DefaultOptions()
	opts.ShouldSample = func(traceID uint64) bool { return false }
	opts.TrimUnsampledSpans = true
	opts.NewSpanEventListener = events.NetTraceIntegrator
	opts.DebugAssertUseAfterFinish = true // provoke crash on use-after-Finish
	if recorder == nil {
		opts.Recorder = CallbackRecorder(func(_ basictracer.RawSpan) {})
		// If we are not recording the spans, there is no need to keep them in
		// memory. Events still get passed to the NetTraceIntegrator.
		opts.DropAllLogs = true
	} else {
		opts.Recorder = CallbackRecorder(recorder)
		// Set a comfortable limit of log events per span.
		opts.MaxLogsPerSpan = maxLogsPerSpan
	}
	return opts
}

var lightstepToken = envutil.EnvOrDefaultString("COCKROACH_LIGHTSTEP_TOKEN", "")

// By default, if a lightstep token is specified we trace to both Lightstep and
// net/trace. If this flag is enabled, we will only trace to Lightstep.
var lightstepOnly = envutil.EnvOrDefaultBool("COCKROACH_LIGHTSTEP_ONLY", false)

// newTracer implements NewTracer and allows that function to be mocked out via Disable().
var newTracer = func() opentracing.Tracer {
	if lightstepToken != "" {
		lsTr := lightstep.NewTracer(lightstep.Options{
			AccessToken:    lightstepToken,
			MaxLogsPerSpan: maxLogsPerSpan,
		})
		if lightstepOnly {
			return lsTr
		}
		basicTr := basictracer.NewWithOptions(basictracerOptions(nil))
		// The TeeTracer uses the first tracer for serialization of span contexts;
		// lightspan needs to be first because it correlates spans between nodes.
		return NewTeeTracer(lsTr, basicTr)
	}
	return basictracer.NewWithOptions(basictracerOptions(nil))
}

// NewTracer creates a Tracer which records to the net/trace
// endpoint.
func NewTracer() opentracing.Tracer {
	return newTracer()
}

// EnsureContext checks whether the given context.Context contains a Span. If
// not, it creates one using the provided Tracer and wraps it in the returned
// Span. The returned closure must be called after the request has been fully
// processed.
func EnsureContext(ctx context.Context, tracer opentracing.Tracer) (context.Context, func()) {
	_, _, funcName := caller.Lookup(1)
	if opentracing.SpanFromContext(ctx) == nil {
		sp := tracer.StartSpan(funcName)
		return opentracing.ContextWithSpan(ctx, sp), sp.Finish
	}
	return ctx, func() {}
}

// Disable is for benchmarking use and causes all future tracers to deal in
// no-ops. Calling the returned closure undoes this effect. There is no
// synchronization, so no moving parts are allowed while Disable and the
// closure are called.
func Disable() func() {
	orig := newTracer
	newTracer = func() opentracing.Tracer { return opentracing.NoopTracer{} }
	return func() {
		newTracer = orig
	}
}

// EncodeRawSpan encodes a raw span into bytes, using the given dest slice
// as a buffer.
func EncodeRawSpan(rawSpan *basictracer.RawSpan, dest []byte) ([]byte, error) {
	// This is not a greatly efficient (but convenient) use of gob.
	buf := bytes.NewBuffer(dest[:0])
	e := gob.NewEncoder(buf)
	var err error

	encode := func(arg interface{}) {
		if err == nil {
			err = e.Encode(arg)
		}
	}

	// We cannot use gob for the Logs (because Field doesn't export the necessary
	// fields). We use it for the other fields.
	encode(rawSpan.Context)
	encode(rawSpan.ParentSpanID)
	encode(rawSpan.Operation)
	encode(rawSpan.Start)
	encode(rawSpan.Duration)
	encode(rawSpan.Tags)

	// Encode the number of LogRecords, then the records.
	encode(int32(len(rawSpan.Logs)))
	for _, lr := range rawSpan.Logs {
		encode(lr.Timestamp)
		// Encode the number of Fields.
		encode(int32(len(lr.Fields)))
		for _, f := range lr.Fields {
			encode(f.Key())
			// Encode the field value as a string.
			encode(fmt.Sprint(f.Value()))
		}
	}

	return buf.Bytes(), err
}

// DecodeRawSpan unmarshals into the given RawSpan.
func DecodeRawSpan(enc []byte, dest *basictracer.RawSpan) error {
	d := gob.NewDecoder(bytes.NewBuffer(enc))
	var err error
	decode := func(arg interface{}) {
		if err == nil {
			err = d.Decode(arg)
		}
	}

	decode(&dest.Context)
	decode(&dest.ParentSpanID)
	decode(&dest.Operation)
	decode(&dest.Start)
	decode(&dest.Duration)
	decode(&dest.Tags)

	var numLogs int32
	decode(&numLogs)
	dest.Logs = make([]opentracing.LogRecord, numLogs)
	for i := range dest.Logs {
		lr := &dest.Logs[i]
		decode(&lr.Timestamp)

		var numFields int32
		decode(&numFields)
		lr.Fields = make([]otlog.Field, numFields)
		for j := range lr.Fields {
			var key, val string
			decode(&key)
			decode(&val)
			lr.Fields[j] = otlog.String(key, val)
		}
	}

	return err
}

// contextTracerKeyType is an empty type for the handle associated with the
// tracer value (see context.Value).
type contextTracerKeyType struct{}

// WithTracer returns a context derived from the given context, for which
// TracerFromCtx returns the given tracer.
func WithTracer(ctx context.Context, tracer opentracing.Tracer) context.Context {
	return context.WithValue(ctx, contextTracerKeyType{}, tracer)
}

// TracerFromCtx returns the tracer set on the context (or a parent context) via
// WithTracer.
func TracerFromCtx(ctx context.Context) opentracing.Tracer {
	if tracerVal := ctx.Value(contextTracerKeyType{}); tracerVal != nil {
		return tracerVal.(opentracing.Tracer)
	}
	return nil
}
<commit_msg>tracing: temporarily reduce the number of events in net/trace<commit_after>// Copyright 2015 The Cockroach Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.
//
// Author: Tobias Schottdorf (tobias.schottdorf@gmail.com)

package tracing

import (
	"bytes"
	"encoding/gob"
	"fmt"

	"golang.org/x/net/context"
	"golang.org/x/net/trace"

	"github.com/cockroachdb/cockroach/util/caller"
	"github.com/cockroachdb/cockroach/util/envutil"
	"github.com/lightstep/lightstep-tracer-go"
	basictracer "github.com/opentracing/basictracer-go"
	opentracing "github.com/opentracing/opentracing-go"
	"github.com/opentracing/opentracing-go/ext"
	otlog "github.com/opentracing/opentracing-go/log"
)

// Snowball is set as Baggage on traces which are used for snowball tracing.
const Snowball = "sb"

// maxLogsPerSpan limits the number of logs in a Span; use a comfortable limit.
const maxLogsPerSpan = 1000

// A CallbackRecorder immediately invokes itself on received trace spans.
type CallbackRecorder func(sp basictracer.RawSpan)

// RecordSpan implements basictracer.SpanRecorder.
func (cr CallbackRecorder) RecordSpan(sp basictracer.RawSpan) {
	cr(sp)
}

// JoinOrNew creates a new Span joined to the provided DelegatingCarrier or
// creates Span from the given tracer.
func JoinOrNew(tr opentracing.Tracer, carrier *Span, opName string) (opentracing.Span, error) {
	if carrier != nil {
		wireContext, err := tr.Extract(basictracer.Delegator, carrier)
		switch err {
		case nil:
			sp := tr.StartSpan(opName, opentracing.FollowsFrom(wireContext))

			// Copy baggage items to tags so they show up in the Lightstep UI.
			sp.Context().ForeachBaggageItem(func(k, v string) bool { sp.SetTag(k, v); return true })

			sp.LogEvent(opName)
			return sp, nil
		case opentracing.ErrSpanContextNotFound:
		default:
			return nil, err
		}
	}
	return tr.StartSpan(opName), nil
}

// JoinOrNewSnowball returns a Span which records directly via the specified
// callback. If the given DelegatingCarrier is nil, a new Span is created.
// otherwise, the created Span is a child.
//
// The recorder should be nil if we don't need to record spans.
//
// TODO(andrei): JoinOrNewSnowball creates a new tracer, which is not kosher.
// Also this can't use the lightstep tracer.
func JoinOrNewSnowball(
	opName string, carrier *Span, recorder func(sp basictracer.RawSpan),
) (opentracing.Span, error) {
	tr := basictracer.NewWithOptions(basictracerOptions(recorder))
	sp, err := JoinOrNew(tr, carrier, opName)
	if err == nil {
		// We definitely want to sample a Snowball trace.
		// This must be set *before* SetBaggageItem, as that will otherwise be ignored.
		ext.SamplingPriority.Set(sp, 1)
		sp.SetBaggageItem(Snowball, "1")
	}
	return sp, err
}

// NewTracerAndSpanFor7881 creates a new tracer and a root span. The tracer is
// to be used for tracking down #7881; it runs a callback for each finished span
// (and the callback used accumulates the spans in a SQL txn).
func NewTracerAndSpanFor7881(
	callback func(sp basictracer.RawSpan),
) (opentracing.Span, opentracing.Tracer, error) {
	opts := basictracerOptions(callback)
	// Don't trim the logs in "unsampled" spans". Note that this tracer does not
	// use sampling; instead it uses an ad-hoc mechanism for marking spans of
	// interest.
	opts.TrimUnsampledSpans = false
	tr := basictracer.NewWithOptions(opts)
	sp, err := JoinOrNew(tr, nil, "sql txn")
	return sp, tr, err
}

// ForkCtxSpan checks if ctx has a Span open; if it does, it creates a new Span
// that follows from the original Span. This allows the resulting context to be
// used in an async task that might outlive the original operation.
//
// Returns the new context and a function that closes the span.
func ForkCtxSpan(ctx context.Context, opName string) (context.Context, func()) {
	if span := opentracing.SpanFromContext(ctx); span != nil {
		if span.BaggageItem(Snowball) == "1" {
			// If we are doing snowball tracing, the span might outlive the snowball
			// tracer (calling the record function when it is no longer legal to do
			// so). Return a context with no span in this case.
			return opentracing.ContextWithSpan(ctx, nil), func() {}
		}
		tr := span.Tracer()
		newSpan := tr.StartSpan(opName, opentracing.FollowsFrom(span.Context()))
		return opentracing.ContextWithSpan(ctx, newSpan), func() { newSpan.Finish() }
	}
	return ctx, func() {}
}

// ChildSpan opens a span as a child of the current span in the context (if
// there is one).
//
// Returns the new context and a function that closes the span.
func ChildSpan(ctx context.Context, opName string) (context.Context, func()) {
	span := opentracing.SpanFromContext(ctx)
	if span == nil {
		return ctx, func() {}
	}
	newSpan := span.Tracer().StartSpan(opName, opentracing.ChildOf(span.Context()))
	return opentracing.ContextWithSpan(ctx, newSpan), func() { newSpan.Finish() }
}

// netTraceIntegrator is passed into basictracer as NewSpanEventListener
// and causes all traces to be registered with the net/trace endpoint.
func netTraceIntegrator() func(basictracer.SpanEvent) {
	var tr trace.Trace
	return func(e basictracer.SpanEvent) {
		switch t := e.(type) {
		case basictracer.EventCreate:
			tr = trace.New("tracing", t.OperationName)
			// TODO(radu): call SetMaxEvents when #9748 is fixed.
		case basictracer.EventFinish:
			tr.Finish()
		case basictracer.EventTag:
			tr.LazyPrintf("%s:%v", t.Key, t.Value)
		case basictracer.EventLogFields:
			var buf bytes.Buffer
			for i, f := range t.Fields {
				if i > 0 {
					buf.WriteByte(' ')
				}
				fmt.Fprintf(&buf, "%s:%v", f.Key(), f.Value())
			}

			tr.LazyPrintf("%s", buf.String())
		case basictracer.EventLog:
			if t.Payload != nil {
				tr.LazyPrintf("%s (payload %v)", t.Event, t.Payload)
			} else {
				tr.LazyPrintf("%s", t.Event)
			}
		}
	}
}

// basicTracerOptions initializes options for basictracer.
// The recorder should be nil if we don't need to record spans.
func basictracerOptions(recorder func(basictracer.RawSpan)) basictracer.Options {
	opts := basictracer.DefaultOptions()
	opts.ShouldSample = func(traceID uint64) bool { return false }
	opts.TrimUnsampledSpans = true
	opts.NewSpanEventListener = netTraceIntegrator
	opts.DebugAssertUseAfterFinish = true // provoke crash on use-after-Finish
	if recorder == nil {
		opts.Recorder = CallbackRecorder(func(_ basictracer.RawSpan) {})
		// If we are not recording the spans, there is no need to keep them in
		// memory. Events still get passed to netTraceIntegrator.
		opts.DropAllLogs = true
	} else {
		opts.Recorder = CallbackRecorder(recorder)
		// Set a comfortable limit of log events per span.
		opts.MaxLogsPerSpan = maxLogsPerSpan
	}
	return opts
}

var lightstepToken = envutil.EnvOrDefaultString("COCKROACH_LIGHTSTEP_TOKEN", "")

// By default, if a lightstep token is specified we trace to both Lightstep and
// net/trace. If this flag is enabled, we will only trace to Lightstep.
var lightstepOnly = envutil.EnvOrDefaultBool("COCKROACH_LIGHTSTEP_ONLY", false)

// newTracer implements NewTracer and allows that function to be mocked out via Disable().
var newTracer = func() opentracing.Tracer {
	if lightstepToken != "" {
		lsTr := lightstep.NewTracer(lightstep.Options{
			AccessToken:    lightstepToken,
			MaxLogsPerSpan: maxLogsPerSpan,
		})
		if lightstepOnly {
			return lsTr
		}
		basicTr := basictracer.NewWithOptions(basictracerOptions(nil))
		// The TeeTracer uses the first tracer for serialization of span contexts;
		// lightspan needs to be first because it correlates spans between nodes.
		return NewTeeTracer(lsTr, basicTr)
	}
	return basictracer.NewWithOptions(basictracerOptions(nil))
}

// NewTracer creates a Tracer which records to the net/trace
// endpoint.
func NewTracer() opentracing.Tracer {
	return newTracer()
}

// EnsureContext checks whether the given context.Context contains a Span. If
// not, it creates one using the provided Tracer and wraps it in the returned
// Span. The returned closure must be called after the request has been fully
// processed.
func EnsureContext(ctx context.Context, tracer opentracing.Tracer) (context.Context, func()) {
	_, _, funcName := caller.Lookup(1)
	if opentracing.SpanFromContext(ctx) == nil {
		sp := tracer.StartSpan(funcName)
		return opentracing.ContextWithSpan(ctx, sp), sp.Finish
	}
	return ctx, func() {}
}

// Disable is for benchmarking use and causes all future tracers to deal in
// no-ops. Calling the returned closure undoes this effect. There is no
// synchronization, so no moving parts are allowed while Disable and the
// closure are called.
func Disable() func() {
	orig := newTracer
	newTracer = func() opentracing.Tracer { return opentracing.NoopTracer{} }
	return func() {
		newTracer = orig
	}
}

// EncodeRawSpan encodes a raw span into bytes, using the given dest slice
// as a buffer.
func EncodeRawSpan(rawSpan *basictracer.RawSpan, dest []byte) ([]byte, error) {
	// This is not a greatly efficient (but convenient) use of gob.
	buf := bytes.NewBuffer(dest[:0])
	e := gob.NewEncoder(buf)
	var err error

	encode := func(arg interface{}) {
		if err == nil {
			err = e.Encode(arg)
		}
	}

	// We cannot use gob for the Logs (because Field doesn't export the necessary
	// fields). We use it for the other fields.
	encode(rawSpan.Context)
	encode(rawSpan.ParentSpanID)
	encode(rawSpan.Operation)
	encode(rawSpan.Start)
	encode(rawSpan.Duration)
	encode(rawSpan.Tags)

	// Encode the number of LogRecords, then the records.
	encode(int32(len(rawSpan.Logs)))
	for _, lr := range rawSpan.Logs {
		encode(lr.Timestamp)
		// Encode the number of Fields.
		encode(int32(len(lr.Fields)))
		for _, f := range lr.Fields {
			encode(f.Key())
			// Encode the field value as a string.
			encode(fmt.Sprint(f.Value()))
		}
	}

	return buf.Bytes(), err
}

// DecodeRawSpan unmarshals into the given RawSpan.
func DecodeRawSpan(enc []byte, dest *basictracer.RawSpan) error {
	d := gob.NewDecoder(bytes.NewBuffer(enc))
	var err error
	decode := func(arg interface{}) {
		if err == nil {
			err = d.Decode(arg)
		}
	}

	decode(&dest.Context)
	decode(&dest.ParentSpanID)
	decode(&dest.Operation)
	decode(&dest.Start)
	decode(&dest.Duration)
	decode(&dest.Tags)

	var numLogs int32
	decode(&numLogs)
	dest.Logs = make([]opentracing.LogRecord, numLogs)
	for i := range dest.Logs {
		lr := &dest.Logs[i]
		decode(&lr.Timestamp)

		var numFields int32
		decode(&numFields)
		lr.Fields = make([]otlog.Field, numFields)
		for j := range lr.Fields {
			var key, val string
			decode(&key)
			decode(&val)
			lr.Fields[j] = otlog.String(key, val)
		}
	}

	return err
}

// contextTracerKeyType is an empty type for the handle associated with the
// tracer value (see context.Value).
type contextTracerKeyType struct{}

// WithTracer returns a context derived from the given context, for which
// TracerFromCtx returns the given tracer.
func WithTracer(ctx context.Context, tracer opentracing.Tracer) context.Context {
	return context.WithValue(ctx, contextTracerKeyType{}, tracer)
}

// TracerFromCtx returns the tracer set on the context (or a parent context) via
// WithTracer.
func TracerFromCtx(ctx context.Context) opentracing.Tracer {
	if tracerVal := ctx.Value(contextTracerKeyType{}); tracerVal != nil {
		return tracerVal.(opentracing.Tracer)
	}
	return nil
}
<|endoftext|>


<commit_before>package connpool

import (
	"fmt"
	"io/ioutil"
	"math/rand"
	"net"
	"sync"
	"sync/atomic"
	"testing"
	"time"

	"github.com/getlantern/fdcount"
	"github.com/getlantern/testify/assert"
	"github.com/getlantern/waitforserver"
)

var (
	msg          = []byte("HELLO")
	fillTime     = 100 * time.Millisecond
	claimTimeout = 1 * time.Second
)

func TestIt(t *testing.T) {
	poolSize := 20

	addr, err := startTestServer()
	if err != nil {
		t.Fatalf("Unable to start test server: %s", err)
	}

	_, fdc, err := fdcount.Matching("TCP")
	if err != nil {
		t.Fatal(err)
	}

	randomlyClose := int32(0)

	p := New(Config{
		Size:         poolSize,
		ClaimTimeout: claimTimeout,
		Dial: func() (net.Conn, error) {
			conn, err := net.DialTimeout("tcp", addr, 15*time.Millisecond)
			if atomic.LoadInt32(&randomlyClose) == 1 {
				// Close about half of the connections immediately to test
				/// closed checking
				if err == nil && rand.Float32() > 0.5 {
					if err := conn.Close(); err != nil {
						t.Fatalf("Unable to close connection: %v", err)
					}
				}
			}
			return conn, err
		},
	})

	time.Sleep(fillTime)

	assert.NoError(t, fdc.AssertDelta(0), "Pool should initially contain no conns")

	// Use more than the pooled connections
	connectAndRead(t, p, poolSize*2)

	time.Sleep(fillTime)
	assert.NoError(t, fdc.AssertDelta(poolSize), "Pool should fill itself back up to the right number of conns")

	// Wait for connections to time out
	time.Sleep(claimTimeout * 2)

	assert.NoError(t, fdc.AssertDelta(0), "After connections time out, but before dialing again, pool should be empty")

	// Test our connections again
	connectAndRead(t, p, poolSize*2)

	time.Sleep(fillTime)
	assert.NoError(t, fdc.AssertDelta(poolSize), "After pooled conns time out, pool should fill itself back up to the right number of conns")

	atomic.StoreInt32(&randomlyClose, 1)

	// Make sure we can still get connections and use them
	connectAndRead(t, p, poolSize)

	// Wait for pool to fill again
	time.Sleep(fillTime)

	p.Close()
	// Run another Close() concurrently just to make sure it doesn't muck things up
	go p.Close()

	assert.NoError(t, fdc.AssertDelta(0), "After stopping pool, there should be no more open conns")
}

func TestDialFailure(t *testing.T) {
	fail := int32(1)
	dialAttempts := int32(0)

	addr, err := startTestServer()
	if err != nil {
		t.Fatalf("Unable to start test server: %s", err)
	}

	_, fdc, err := fdcount.Matching("TCP")
	if err != nil {
		t.Fatal(err)
	}

	poolSize := 10

	p := New(Config{
		Size: poolSize,
		Dial: func() (net.Conn, error) {
			atomic.AddInt32(&dialAttempts, 1)
			if fail == int32(1) {
				return nil, fmt.Errorf("I'm failing intentionally!")
			}
			return net.DialTimeout("tcp", addr, 15*time.Millisecond)
		},
	})

	// Try to get connection, make sure it fails
	conn, err := p.Get()
	if !assert.Error(t, err, "Dialing should have failed") {
		if err := conn.Close(); err != nil {
			t.Fatalf("Unable to close connection: %v", err)
		}
	}

	// Wait for fill to run for a while with a failing connection
	time.Sleep(1 * time.Second)
	assert.Equal(t, 1, atomic.LoadInt32(&dialAttempts), fmt.Sprintf("There should have been only 1 dial attempt"))
	assert.NoError(t, fdc.AssertDelta(0), "There should be no additional file descriptors open")

	// Now make connection succeed and verify that it works
	atomic.StoreInt32(&fail, 0)
	time.Sleep(100 * time.Millisecond)
	connectAndRead(t, p, 1)

	time.Sleep(fillTime)
	log.Debug("Testing")
	assert.NoError(t, fdc.AssertDelta(10), "Pool should have filled")

	// Now make the connection fail again so that when we stop, we're stopping
	// while failing (tests a different code path for stopping)
	atomic.StoreInt32(&fail, 1)
	time.Sleep(100 * time.Millisecond)

	p.Close()

	assert.NoError(t, fdc.AssertDelta(0), "All connections should be closed")
}

func TestPropertyChange(t *testing.T) {
	claimTimeout := 5 * time.Second

	cfg := &Config{
		ClaimTimeout: claimTimeout,
	}
	p := New(*cfg)
	defer p.Close()

	cfg.ClaimTimeout = 7 * time.Second
	assert.Equal(t, claimTimeout, p.(*pool).Config.ClaimTimeout, "Property changed on config shouldn't be reflected in pool")
}

func connectAndRead(t *testing.T, p Pool, loops int) {
	var wg sync.WaitGroup

	for i := 0; i < loops; i++ {
		wg.Add(1)

		func(wg *sync.WaitGroup) {
			c, err := p.Get()
			if err != nil {
				t.Fatalf("Error getting connection: %s", err)
			}
			read, err := ioutil.ReadAll(c)
			if err != nil {
				t.Fatalf("Error reading from connection: %s", err)
			}
			assert.Equal(t, msg, read, "Should have received %s from server", string(msg))
			if err := c.Close(); err != nil {
				t.Fatalf("Unable to close connection: %v", err)
			}

			wg.Done()
		}(&wg)
	}

	wg.Wait()
}

func startTestServer() (string, error) {
	l, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		return "", err
	}
	err = waitforserver.WaitForServer("tcp", l.Addr().String(), 1*time.Second)
	if err != nil {
		return "", err
	}
	go func() {
		for {
			c, err := l.Accept()
			if err != nil {
				log.Fatalf("Error listening: %s", err)
			}
			if _, err = c.Write(msg); err != nil {
				log.Fatalf("Unable to write message: %s", err)
			}
			if err := c.Close(); err != nil {
				log.Fatalf("Unable to close connection: %v", err)
			}
		}
	}()
	return l.Addr().String(), nil
}
<commit_msg>Updates from lantern<commit_after>package connpool

import (
	"fmt"
	"io/ioutil"
	"math/rand"
	"net"
	"sync"
	"sync/atomic"
	"testing"
	"time"

	"github.com/getlantern/fdcount"
	"github.com/getlantern/waitforserver"
	"github.com/stretchr/testify/assert"
)

var (
	msg          = []byte("HELLO")
	fillTime     = 100 * time.Millisecond
	claimTimeout = 1 * time.Second
)

func TestIt(t *testing.T) {
	poolSize := 20

	addr, err := startTestServer()
	if err != nil {
		t.Fatalf("Unable to start test server: %s", err)
	}

	_, fdc, err := fdcount.Matching("TCP")
	if err != nil {
		t.Fatal(err)
	}

	randomlyClose := int32(0)

	p := New(Config{
		Size:         poolSize,
		ClaimTimeout: claimTimeout,
		Dial: func() (net.Conn, error) {
			conn, err := net.DialTimeout("tcp", addr, 15*time.Millisecond)
			if atomic.LoadInt32(&randomlyClose) == 1 {
				// Close about half of the connections immediately to test
				/// closed checking
				if err == nil && rand.Float32() > 0.5 {
					if err := conn.Close(); err != nil {
						t.Fatalf("Unable to close connection: %v", err)
					}
				}
			}
			return conn, err
		},
	})

	time.Sleep(fillTime)

	assert.NoError(t, fdc.AssertDelta(0), "Pool should initially contain no conns")

	// Use more than the pooled connections
	connectAndRead(t, p, poolSize*2)

	time.Sleep(fillTime)
	assert.NoError(t, fdc.AssertDelta(poolSize), "Pool should fill itself back up to the right number of conns")

	// Wait for connections to time out
	time.Sleep(claimTimeout * 2)

	assert.NoError(t, fdc.AssertDelta(0), "After connections time out, but before dialing again, pool should be empty")

	// Test our connections again
	connectAndRead(t, p, poolSize*2)

	time.Sleep(fillTime)
	assert.NoError(t, fdc.AssertDelta(poolSize), "After pooled conns time out, pool should fill itself back up to the right number of conns")

	atomic.StoreInt32(&randomlyClose, 1)

	// Make sure we can still get connections and use them
	connectAndRead(t, p, poolSize)

	// Wait for pool to fill again
	time.Sleep(fillTime)

	p.Close()
	// Run another Close() concurrently just to make sure it doesn't muck things up
	go p.Close()

	assert.NoError(t, fdc.AssertDelta(0), "After stopping pool, there should be no more open conns")
}

func TestDialFailure(t *testing.T) {
	fail := int32(1)
	dialAttempts := int32(0)

	addr, err := startTestServer()
	if err != nil {
		t.Fatalf("Unable to start test server: %s", err)
	}

	_, fdc, err := fdcount.Matching("TCP")
	if err != nil {
		t.Fatal(err)
	}

	poolSize := 10

	p := New(Config{
		Size: poolSize,
		Dial: func() (net.Conn, error) {
			atomic.AddInt32(&dialAttempts, 1)
			if atomic.LoadInt32(&fail) == int32(1) {
				return nil, fmt.Errorf("I'm failing intentionally!")
			}
			return net.DialTimeout("tcp", addr, 15*time.Millisecond)
		},
	})

	// Try to get connection, make sure it fails
	conn, err := p.Get()
	if !assert.Error(t, err, "Dialing should have failed") {
		if err := conn.Close(); err != nil {
			t.Fatalf("Unable to close connection: %v", err)
		}
	}

	// Wait for fill to run for a while with a failing connection
	time.Sleep(1 * time.Second)
	assert.EqualValues(t, 1, atomic.LoadInt32(&dialAttempts), fmt.Sprintf("There should have been only 1 dial attempt"))
	assert.NoError(t, fdc.AssertDelta(0), "There should be no additional file descriptors open")

	// Now make connection succeed and verify that it works
	atomic.StoreInt32(&fail, 0)
	time.Sleep(100 * time.Millisecond)
	connectAndRead(t, p, 1)

	time.Sleep(fillTime)
	log.Debug("Testing")
	assert.NoError(t, fdc.AssertDelta(10), "Pool should have filled")

	// Now make the connection fail again so that when we stop, we're stopping
	// while failing (tests a different code path for stopping)
	atomic.StoreInt32(&fail, 1)
	time.Sleep(100 * time.Millisecond)

	p.Close()

	assert.NoError(t, fdc.AssertDelta(0), "All connections should be closed")
}

func TestPropertyChange(t *testing.T) {
	claimTimeout := 5 * time.Second

	cfg := &Config{
		ClaimTimeout: claimTimeout,
	}
	p := New(*cfg)
	defer p.Close()

	cfg.ClaimTimeout = 7 * time.Second
	assert.Equal(t, claimTimeout, p.(*pool).Config.ClaimTimeout, "Property changed on config shouldn't be reflected in pool")
}

func connectAndRead(t *testing.T, p Pool, loops int) {
	var wg sync.WaitGroup

	for i := 0; i < loops; i++ {
		wg.Add(1)

		func(wg *sync.WaitGroup) {
			c, err := p.Get()
			if err != nil {
				t.Fatalf("Error getting connection: %s", err)
			}
			read, err := ioutil.ReadAll(c)
			if err != nil {
				t.Fatalf("Error reading from connection: %s", err)
			}
			assert.Equal(t, msg, read, "Should have received %s from server", string(msg))
			if err := c.Close(); err != nil {
				t.Fatalf("Unable to close connection: %v", err)
			}

			wg.Done()
		}(&wg)
	}

	wg.Wait()
}

func startTestServer() (string, error) {
	l, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		return "", err
	}
	err = waitforserver.WaitForServer("tcp", l.Addr().String(), 1*time.Second)
	if err != nil {
		return "", err
	}
	go func() {
		for {
			c, err := l.Accept()
			if err != nil {
				log.Fatalf("Error listening: %s", err)
			}
			if _, err = c.Write(msg); err != nil {
				log.Fatalf("Unable to write message: %s", err)
			}
			if err := c.Close(); err != nil {
				log.Fatalf("Unable to close connection: %v", err)
			}
		}
	}()
	return l.Addr().String(), nil
}
<|endoftext|>


<commit_before>package configstack

import (
	"fmt"
	"github.com/gruntwork-io/terragrunt/options"
	"io"
	"path/filepath"
	"strings"
)

// WriteDot is used to emit a GraphViz compatible definition
// for a directed graph. It can be used to dump a .dot file.
func WriteDot(w io.Writer, terragruntOptions *options.TerragruntOptions, modules []*TerraformModule) error {

	w.Write([]byte("digraph {\n"))
	defer w.Write([]byte("}\n"))

	// all paths are relative to the TerragruntConfigPath
	prefix := filepath.Dir(terragruntOptions.TerragruntConfigPath) + "/"

	for _, source := range modules {
		// apply a different coloring for excluded nodes
		style := ""
		if source.FlagExcluded {
			style = fmt.Sprintf("[color=red]")
		}

		nodeLine := fmt.Sprintf("\t\"%s\" %s;\n",
			strings.TrimPrefix(source.Path, prefix), style)

		w.Write([]byte(nodeLine))
		for _, target := range source.Dependencies {
			line := fmt.Sprintf("\t\"%s\" -> \"%s\";\n",
				strings.TrimPrefix(source.Path, prefix),
				strings.TrimPrefix(target.Path, prefix),
			)
			w.Write([]byte(line))
		}
	}

	return nil
}
<commit_msg>document custom implementation reason<commit_after>package configstack

import (
	"fmt"
	"github.com/gruntwork-io/terragrunt/options"
	"io"
	"path/filepath"
	"strings"
)

// WriteDot is used to emit a GraphViz compatible definition
// for a directed graph. It can be used to dump a .dot file.
// This is a similar implementation to terraform's digraph https://github.com/hashicorp/terraform/blob/master/digraph/graphviz.go
// adding some styling to modules that are excluded from the execution in *-all commands
func WriteDot(w io.Writer, terragruntOptions *options.TerragruntOptions, modules []*TerraformModule) error {

	w.Write([]byte("digraph {\n"))
	defer w.Write([]byte("}\n"))

	// all paths are relative to the TerragruntConfigPath
	prefix := filepath.Dir(terragruntOptions.TerragruntConfigPath) + "/"

	for _, source := range modules {
		// apply a different coloring for excluded nodes
		style := ""
		if source.FlagExcluded {
			style = fmt.Sprintf("[color=red]")
		}

		nodeLine := fmt.Sprintf("\t\"%s\" %s;\n",
			strings.TrimPrefix(source.Path, prefix), style)

		w.Write([]byte(nodeLine))
		for _, target := range source.Dependencies {
			line := fmt.Sprintf("\t\"%s\" -> \"%s\";\n",
				strings.TrimPrefix(source.Path, prefix),
				strings.TrimPrefix(target.Path, prefix),
			)
			w.Write([]byte(line))
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"math"
	"os"

	"github.com/krasin/stl"
	//	"github.com/krasin/voxel/nptl"
	"github.com/krasin/voxel/raster"
	"github.com/krasin/voxel/surface"
	"github.com/krasin/voxel/timing"
	"github.com/krasin/voxel/triangle"
	"github.com/krasin/voxel/volume"
)

const (
	VoxelSide      = 512
	MeshMultiplier = 2048
)

var (
	// For neighbours4
	n6dx = []int{1, 0, -1, 0, 0, 0}
	n6dy = []int{0, 1, 0, -1, 0, 0}
	n6dz = []int{0, 0, 0, 0, 1, -1}

	n4dx = n6dx[0:4]
	n4dy = n6dy[0:4]
)

type Uint16Volume interface {
	volume.BoolVoxelVolume
	Set(x, y, z int, v uint16)
	GetV(x, y, z int) uint16
	SetAllFilled(threshold, val uint16)
	MapBoundary(f func(x, y, z int))
	Volume() int64
}

func Index(vol Uint16Volume, x, y, z int) int {
	return x*vol.YLen()*vol.ZLen() + y*vol.ZLen() + z
}

func Coord(vol Uint16Volume, index int) (x, y, z int) {
	z = index % vol.ZLen()
	index /= vol.ZLen()
	y = index % vol.YLen()
	index /= vol.YLen()
	x = index
	return
}

func Optimize(vol Uint16Volume, n int) {
	var q, q2 []int
	vol.SetAllFilled(1, math.MaxUint16-3)
	vol.MapBoundary(func(x, y, z int) {
		if z > 8 {
			vol.Set(x, y, z, 1)
			q = append(q, Index(vol, x, y, z))
			return
		}
	})

	for len(q) > 0 {
		fmt.Fprintf(os.Stderr, "len(q): %d\n", len(q))
		q, q2 = q2[:0], q
		for _, index := range q2 {
			x, y, z := Coord(vol, index)
			v := vol.GetV(x, y, z)
			if v == 0 {
				panic(fmt.Sprintf("x: %d, y: %d, z: %d, v == 0", x, y, z))
			}
			for k := 0; k < 6; k++ {
				x1 := x + n6dx[k]
				y1 := y + n6dy[k]
				z1 := z + n6dz[k]
				v1 := vol.GetV(x1, y1, z1)
				if v1 > v+1 && int(v)+1 <= n {
					vol.Set(x1, y1, z1, v+1)
					q = append(q, Index(vol, x1, y1, z1))
				}
			}
		}
	}
	vol.SetAllFilled(uint16(n+1), 0)

	return
}

type VolumeSetter interface {
	Set(x, y, z int, val uint16)
}

type Location16 [2]int16

var sSourcePoint = [3]surface.Vector{
	{0.35, 0.35, 0.35},
	{0.35, 0.65, 0.35},
	{0.65, 0.35, 0.65},
}

func sampleField(fX, fY, fZ float64) float64 {
	if math.Abs(fX) < 0.1 || math.Abs(fY) < 0.1 || math.Abs(fZ) < 0.1 ||
		math.Abs(fX) > 0.9 || math.Abs(fY) > 0.9 || math.Abs(fZ) > 0.9 {
		return 0
	}
	fResult := 0.0
	fDx := fX - sSourcePoint[0].X
	fDy := fY - sSourcePoint[0].Y
	fResult += 0.5 / (fDx*fDx + fDy*fDy)

	fDx = fX - sSourcePoint[1].X
	fDz := fZ - sSourcePoint[1].Z
	fResult += 0.75 / (fDx*fDx + fDz*fDz)

	fDy = fY - sSourcePoint[2].Y
	fDz = fZ - sSourcePoint[2].Z
	fResult += 1.0 / (fDy*fDy + fDz*fDz)

	return fResult
}

func sampleField2(fX, fY, fZ float64) float64 {
	var fResult float64
	var fDx, fDy, fDz float64
	fDx = fX - sSourcePoint[0].X
	fDy = fY - sSourcePoint[0].Y
	fDz = fZ - sSourcePoint[0].Z
	fResult += 0.5 / (fDx*fDx + fDy*fDy + fDz*fDz)

	fDx = fX - sSourcePoint[1].X
	fDy = fY - sSourcePoint[1].Y
	fDz = fZ - sSourcePoint[1].Z
	fResult += 1.0 / (fDx*fDx + fDy*fDy + fDz*fDz)

	fDx = fX - sSourcePoint[2].X
	fDy = fY - sSourcePoint[2].Y
	fDz = fZ - sSourcePoint[2].Z
	fResult += 1.5 / (fDx*fDx + fDy*fDy + fDz*fDz)

	return fResult
}

func main() {
	timing.StartTiming("total")
	timing.StartTiming("Read STL from Stdin")
	triangles, err := stl.Read(os.Stdin)
	if err != nil {
		log.Fatalf("stl.Read: %v", err)
	}
	timing.StopTiming("Read STL from Stdin")

	timing.StartTiming("STLToMesh")
	mesh := raster.STLToMesh(VoxelSide*MeshMultiplier, triangles)
	timing.StopTiming("STLToMesh")

	timing.StartTiming("MeshVolume")
	volume := triangle.MeshVolume(mesh.Triangle, 1)
	if volume < 0 {
		volume = -volume
	}
	fmt.Fprintf(os.Stderr, "Mesh volume (in mesh units): %d\n", volume)
	fmt.Fprintf(os.Stderr, "Mesh volume (original units): %f\n", float64(volume)/float64(mesh.N[0]*mesh.N[1]*mesh.N[2])*(mesh.P1[0]-mesh.P0[0])*(mesh.P1[1]-mesh.P0[1])*(mesh.P1[2]-mesh.P0[2]))
	timing.StopTiming("MeshVolume")

	timing.StartTiming("Rasterize")
	vol := raster.Rasterize(mesh, VoxelSide)
	timing.StopTiming("Rasterize")

	timing.StartTiming("Optimize")
	Optimize(vol, 22)
	timing.StopTiming("Optimize")

	/*	timing.StartTiming("Write nptl")
		if err = nptl.Write(os.Stdout, vol, mesh.Grid); err != nil {
			log.Fatalf("nptl.Write: %v", err)
		}
		v := vol.Volume()
		fmt.Fprintf(os.Stderr, "Volume is filled by %v%%\n", float64(v)*float64(100)/(float64(vol.XLen())*float64(vol.YLen())*float64(vol.ZLen())))
		timing.StopTiming("Write nptl")
	*/

	t := surface.MarchingCubes(sampleField2, 256, 48)
	var f *os.File
	if f, err = os.OpenFile("output.stl", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644); err != nil {
		log.Fatal(err)
	}
	if err = stl.Write(f, t); err != nil {
		log.Fatalf("stl.Write: %v", err)
	}
	f.Close()

	timing.StopTiming("total")
	timing.PrintTimings(os.Stderr)
}
<commit_msg>Run marching cubes on the volume; the optimizer works; the output is pixelized and the size is not yet preserved<commit_after>package main

import (
	"fmt"
	"log"
	"math"
	"os"

	"github.com/krasin/stl"
	//	"github.com/krasin/voxel/nptl"
	"github.com/krasin/voxel/raster"
	"github.com/krasin/voxel/surface"
	"github.com/krasin/voxel/timing"
	"github.com/krasin/voxel/triangle"
	"github.com/krasin/voxel/volume"
)

const (
	VoxelSide      = 512
	MeshMultiplier = 2048
)

var (
	// For neighbours4
	n6dx = []int{1, 0, -1, 0, 0, 0}
	n6dy = []int{0, 1, 0, -1, 0, 0}
	n6dz = []int{0, 0, 0, 0, 1, -1}

	n4dx = n6dx[0:4]
	n4dy = n6dy[0:4]
)

type Uint16Volume interface {
	volume.BoolVoxelVolume
	Set(x, y, z int, v uint16)
	GetV(x, y, z int) uint16
	SetAllFilled(threshold, val uint16)
	MapBoundary(f func(x, y, z int))
	Volume() int64
}

func Index(vol Uint16Volume, x, y, z int) int {
	return x*vol.YLen()*vol.ZLen() + y*vol.ZLen() + z
}

func Coord(vol Uint16Volume, index int) (x, y, z int) {
	z = index % vol.ZLen()
	index /= vol.ZLen()
	y = index % vol.YLen()
	index /= vol.YLen()
	x = index
	return
}

func Optimize(vol Uint16Volume, n int) {
	var q, q2 []int
	vol.SetAllFilled(1, math.MaxUint16-3)
	vol.MapBoundary(func(x, y, z int) {
		if z > 8 {
			vol.Set(x, y, z, 1)
			q = append(q, Index(vol, x, y, z))
			return
		}
	})

	for len(q) > 0 {
		fmt.Fprintf(os.Stderr, "len(q): %d\n", len(q))
		q, q2 = q2[:0], q
		for _, index := range q2 {
			x, y, z := Coord(vol, index)
			v := vol.GetV(x, y, z)
			if v == 0 {
				panic(fmt.Sprintf("x: %d, y: %d, z: %d, v == 0", x, y, z))
			}
			for k := 0; k < 6; k++ {
				x1 := x + n6dx[k]
				y1 := y + n6dy[k]
				z1 := z + n6dz[k]
				v1 := vol.GetV(x1, y1, z1)
				if v1 > v+1 && int(v)+1 <= n {
					vol.Set(x1, y1, z1, v+1)
					q = append(q, Index(vol, x1, y1, z1))
				}
			}
		}
	}
	vol.SetAllFilled(uint16(n+1), 0)

	return
}

type VolumeSetter interface {
	Set(x, y, z int, val uint16)
}

type Location16 [2]int16

var sSourcePoint = [3]surface.Vector{
	{0.35, 0.35, 0.35},
	{0.35, 0.65, 0.35},
	{0.65, 0.35, 0.65},
}

func sampleField(fX, fY, fZ float64) float64 {
	if math.Abs(fX) < 0.1 || math.Abs(fY) < 0.1 || math.Abs(fZ) < 0.1 ||
		math.Abs(fX) > 0.9 || math.Abs(fY) > 0.9 || math.Abs(fZ) > 0.9 {
		return 0
	}
	fResult := 0.0
	fDx := fX - sSourcePoint[0].X
	fDy := fY - sSourcePoint[0].Y
	fResult += 0.5 / (fDx*fDx + fDy*fDy)

	fDx = fX - sSourcePoint[1].X
	fDz := fZ - sSourcePoint[1].Z
	fResult += 0.75 / (fDx*fDx + fDz*fDz)

	fDy = fY - sSourcePoint[2].Y
	fDz = fZ - sSourcePoint[2].Z
	fResult += 1.0 / (fDy*fDy + fDz*fDz)

	return fResult
}

func sampleField2(fX, fY, fZ float64) float64 {
	var fResult float64
	var fDx, fDy, fDz float64
	fDx = fX - sSourcePoint[0].X
	fDy = fY - sSourcePoint[0].Y
	fDz = fZ - sSourcePoint[0].Z
	fResult += 0.5 / (fDx*fDx + fDy*fDy + fDz*fDz)

	fDx = fX - sSourcePoint[1].X
	fDy = fY - sSourcePoint[1].Y
	fDz = fZ - sSourcePoint[1].Z
	fResult += 1.0 / (fDx*fDx + fDy*fDy + fDz*fDz)

	fDx = fX - sSourcePoint[2].X
	fDy = fY - sSourcePoint[2].Y
	fDz = fZ - sSourcePoint[2].Z
	fResult += 1.5 / (fDx*fDx + fDy*fDy + fDz*fDz)

	return fResult
}

func NewVolumeField(vol Uint16Volume) surface.ScalarField {
	return func(x, y, z float64) float64 {
		if x <= 0 || x >= 1 || y <= 0 || y >= 1 || z <= 0 || z >= 1 {
			return 0
		}
		xx := int(x * float64(vol.XLen()))
		yy := int(y * float64(vol.YLen()))
		zz := int(z * float64(vol.ZLen()))
		val := vol.Get(xx, yy, zz)
		if val {
			return 100
		}
		return 0
	}
}

func main() {
	timing.StartTiming("total")
	timing.StartTiming("Read STL from Stdin")
	triangles, err := stl.Read(os.Stdin)
	if err != nil {
		log.Fatalf("stl.Read: %v", err)
	}
	timing.StopTiming("Read STL from Stdin")

	timing.StartTiming("STLToMesh")
	mesh := raster.STLToMesh(VoxelSide*MeshMultiplier, triangles)
	timing.StopTiming("STLToMesh")

	timing.StartTiming("MeshVolume")
	volume := triangle.MeshVolume(mesh.Triangle, 1)
	if volume < 0 {
		volume = -volume
	}
	fmt.Fprintf(os.Stderr, "Mesh volume (in mesh units): %d\n", volume)
	fmt.Fprintf(os.Stderr, "Mesh volume (original units): %f\n", float64(volume)/float64(mesh.N[0]*mesh.N[1]*mesh.N[2])*(mesh.P1[0]-mesh.P0[0])*(mesh.P1[1]-mesh.P0[1])*(mesh.P1[2]-mesh.P0[2]))
	timing.StopTiming("MeshVolume")

	timing.StartTiming("Rasterize")
	vol := raster.Rasterize(mesh, VoxelSide)
	timing.StopTiming("Rasterize")

	timing.StartTiming("Optimize")
	Optimize(vol, 22)
	timing.StopTiming("Optimize")

	/*	timing.StartTiming("Write nptl")
		if err = nptl.Write(os.Stdout, vol, mesh.Grid); err != nil {
			log.Fatalf("nptl.Write: %v", err)
		}
		v := vol.Volume()
		fmt.Fprintf(os.Stderr, "Volume is filled by %v%%\n", float64(v)*float64(100)/(float64(vol.XLen())*float64(vol.YLen())*float64(vol.ZLen())))
		timing.StopTiming("Write nptl")
	*/

	//	t := surface.MarchingCubes(sampleField2, 256, 48)
	t := surface.MarchingCubes(NewVolumeField(vol), 128, 48)
	var f *os.File
	if f, err = os.OpenFile("output.stl", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644); err != nil {
		log.Fatal(err)
	}
	if err = stl.Write(f, t); err != nil {
		log.Fatalf("stl.Write: %v", err)
	}
	f.Close()

	timing.StopTiming("total")
	timing.PrintTimings(os.Stderr)
}
<|endoftext|>