<commit_before>package taskworkpool

import (
	"bytes"
	"encoding/json"
	"net/http"
	"os"
	"regexp"

	"github.com/cloudfoundry-incubator/bbs/db"
	"github.com/cloudfoundry-incubator/bbs/models"
	"github.com/cloudfoundry-incubator/cf_http"
	"github.com/cloudfoundry/gunk/workpool"
	"github.com/pivotal-golang/lager"
)

const MAX_CB_RETRIES = 3

//go:generate counterfeiter . TaskCompletionClient

type CompletedTaskHandler func(logger lager.Logger, httpClient *http.Client, taskDB db.TaskDB, task *models.Task)

type TaskCompletionClient interface {
	Submit(taskDB db.TaskDB, task *models.Task)
}

type TaskCompletionWorkPool struct {
	logger           lager.Logger
	maxWorkers       int
	callbackHandler  CompletedTaskHandler
	callbackWorkPool *workpool.WorkPool
	httpClient       *http.Client
}

func New(logger lager.Logger, maxWorkers int, cbHandler CompletedTaskHandler) *TaskCompletionWorkPool {
	if cbHandler == nil {
		panic("callbackHandler cannot be nil")
	}
	return &TaskCompletionWorkPool{
		logger:          logger,
		maxWorkers:      maxWorkers,
		callbackHandler: cbHandler,
		httpClient:      cf_http.NewClient(),
	}
}

func (twp *TaskCompletionWorkPool) Run(signals <-chan os.Signal, ready chan<- struct{}) error {
	cbWorkPool, err := workpool.NewWorkPool(twp.maxWorkers)
	if err != nil {
		twp.logger.Error("callback-workpool-creation-failed", err)
		return err
	}
	twp.callbackWorkPool = cbWorkPool
	close(ready)

	<-signals
	go twp.callbackWorkPool.Stop()

	return nil
}

func (twp *TaskCompletionWorkPool) Submit(taskDB db.TaskDB, task *models.Task) {
	if twp.callbackWorkPool == nil {
		panic("called submit before workpool was started")
	}
	twp.callbackWorkPool.Submit(func() {
		twp.callbackHandler(twp.logger, twp.httpClient, taskDB, task)
	})
}

func HandleCompletedTask(logger lager.Logger, httpClient *http.Client, taskDB db.TaskDB, task *models.Task) {
	logger = logger.WithData(lager.Data{"task-guid": task.TaskGuid})

	if task.CompletionCallbackUrl != "" {
		logger.Info("resolving-task")
		modelErr := taskDB.ResolvingTask(logger, task.TaskGuid)
		if modelErr != nil {
			logger.Error("marking-task-as-resolving-failed", modelErr)
			return
		}

		logger = logger.WithData(lager.Data{"callback_url": task.CompletionCallbackUrl})

		json, err := json.Marshal(&models.TaskCallbackResponse{
			TaskGuid:      task.TaskGuid,
			Failed:        task.Failed,
			FailureReason: task.FailureReason,
			Result:        task.Result,
			Annotation:    task.Annotation,
			CreatedAt:     task.CreatedAt,
		})
		if err != nil {
			logger.Error("marshalling-task-failed", err)
			return
		}

		var statusCode int

		for i := 0; i < MAX_CB_RETRIES; i++ {
			request, err := http.NewRequest("POST", task.CompletionCallbackUrl, bytes.NewReader(json))
			if err != nil {
				logger.Error("building-request-failed", err)
				return
			}

			request.Header.Set("Content-Type", "application/json")
			response, err := httpClient.Do(request)
			if err != nil {
				matched, _ := regexp.MatchString("Client.Timeout|use of closed network connection", err.Error())
				if matched {
					continue
				}
				logger.Error("doing-request-failed", err)
				return
			}
			defer response.Body.Close()

			statusCode = response.StatusCode
			if shouldResolve(statusCode) {
				modelErr := taskDB.DeleteTask(logger, task.TaskGuid)
				if modelErr != nil {
					logger.Error("delete-task-failed", modelErr)
					return
				}

				logger.Info("resolved-task", lager.Data{"status_code": statusCode})
				return
			}
		}

		logger.Info("callback-failed", lager.Data{"status_code": statusCode})
	}
	return
}

func shouldResolve(status int) bool {
	switch status {
	case http.StatusServiceUnavailable, http.StatusGatewayTimeout:
		return false
	default:
		return true
	}
}
<commit_msg>Add better logging around completion callbacks<commit_after>package taskworkpool

import (
	"bytes"
	"encoding/json"
	"net/http"
	"os"
	"regexp"

	"github.com/cloudfoundry-incubator/bbs/db"
	"github.com/cloudfoundry-incubator/bbs/models"
	"github.com/cloudfoundry-incubator/cf_http"
	"github.com/cloudfoundry/gunk/workpool"
	"github.com/pivotal-golang/lager"
)

const MAX_CB_RETRIES = 3

//go:generate counterfeiter . TaskCompletionClient

type CompletedTaskHandler func(logger lager.Logger, httpClient *http.Client, taskDB db.TaskDB, task *models.Task)

type TaskCompletionClient interface {
	Submit(taskDB db.TaskDB, task *models.Task)
}

type TaskCompletionWorkPool struct {
	logger           lager.Logger
	maxWorkers       int
	callbackHandler  CompletedTaskHandler
	callbackWorkPool *workpool.WorkPool
	httpClient       *http.Client
}

func New(logger lager.Logger, maxWorkers int, cbHandler CompletedTaskHandler) *TaskCompletionWorkPool {
	if cbHandler == nil {
		panic("callbackHandler cannot be nil")
	}
	return &TaskCompletionWorkPool{
		logger:          logger,
		maxWorkers:      maxWorkers,
		callbackHandler: cbHandler,
		httpClient:      cf_http.NewClient(),
	}
}

func (twp *TaskCompletionWorkPool) Run(signals <-chan os.Signal, ready chan<- struct{}) error {
	cbWorkPool, err := workpool.NewWorkPool(twp.maxWorkers)
	if err != nil {
		twp.logger.Error("callback-workpool-creation-failed", err)
		return err
	}
	twp.callbackWorkPool = cbWorkPool
	close(ready)

	<-signals
	go twp.callbackWorkPool.Stop()

	return nil
}

func (twp *TaskCompletionWorkPool) Submit(taskDB db.TaskDB, task *models.Task) {
	if twp.callbackWorkPool == nil {
		panic("called submit before workpool was started")
	}
	twp.callbackWorkPool.Submit(func() {
		twp.callbackHandler(twp.logger, twp.httpClient, taskDB, task)
	})
}

func HandleCompletedTask(logger lager.Logger, httpClient *http.Client, taskDB db.TaskDB, task *models.Task) {
	logger.Session("handle-completed-task", lager.Data{"task-guid": task.TaskGuid})

	if task.CompletionCallbackUrl != "" {
		logger.Info("resolving-task")
		modelErr := taskDB.ResolvingTask(logger, task.TaskGuid)
		if modelErr != nil {
			logger.Error("marking-task-as-resolving-failed", modelErr)
			return
		}

		logger = logger.WithData(lager.Data{"callback_url": task.CompletionCallbackUrl})

		json, err := json.Marshal(&models.TaskCallbackResponse{
			TaskGuid:      task.TaskGuid,
			Failed:        task.Failed,
			FailureReason: task.FailureReason,
			Result:        task.Result,
			Annotation:    task.Annotation,
			CreatedAt:     task.CreatedAt,
		})
		if err != nil {
			logger.Error("marshalling-task-failed", err)
			return
		}

		var statusCode int

		for i := 0; i < MAX_CB_RETRIES; i++ {
			request, err := http.NewRequest("POST", task.CompletionCallbackUrl, bytes.NewReader(json))
			if err != nil {
				logger.Error("building-request-failed", err)
				return
			}

			request.Header.Set("Content-Type", "application/json")
			response, err := httpClient.Do(request)
			if err != nil {
				matched, _ := regexp.MatchString("Client.Timeout|use of closed network connection", err.Error())
				if matched {
					continue
				}
				logger.Error("doing-request-failed", err)
				return
			}
			defer response.Body.Close()

			statusCode = response.StatusCode
			if shouldResolve(statusCode) {
				modelErr := taskDB.DeleteTask(logger, task.TaskGuid)
				if modelErr != nil {
					logger.Error("delete-task-failed", modelErr)
					return
				}

				logger.Info("resolved-task", lager.Data{"status_code": statusCode})
				return
			}
		}

		logger.Info("callback-failed", lager.Data{"status_code": statusCode})
	}
	return
}

func shouldResolve(status int) bool {
	switch status {
	case http.StatusServiceUnavailable, http.StatusGatewayTimeout:
		return false
	default:
		return true
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software 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.

package instrument

import (
	"fmt"
	"os"
	"runtime"
	"strings"
	"sync/atomic"
	"time"

	"github.com/uber-go/tally"
)

// ExtendedMetricsType is a type of extended metrics to report.
type ExtendedMetricsType int

const (
	// NoExtendedMetrics describes no extended metrics.
	NoExtendedMetrics ExtendedMetricsType = iota

	// SimpleExtendedMetrics describes just a simple level of extended metrics:
	// - number of active goroutines
	// - number of configured gomaxprocs
	SimpleExtendedMetrics

	// ModerateExtendedMetrics describes a moderately verbose level of extended metrics:
	// - number of active goroutines
	// - number of configured gomaxprocs
	// - number of file descriptors
	ModerateExtendedMetrics

	// DetailedExtendedMetrics describes a detailed level of extended metrics:
	// - number of active goroutines
	// - number of configured gomaxprocs
	// - number of file descriptors
	// - memory allocated running count
	// - memory used by heap
	// - memory used by heap that is idle
	// - memory used by heap that is in use
	// - memory used by stack
	// - number of garbage collections
	// - GC pause times
	DetailedExtendedMetrics

	// DefaultExtendedMetricsType is the default extended metrics level.
	DefaultExtendedMetricsType = SimpleExtendedMetrics
)

var (
	validExtendedMetricsTypes = []ExtendedMetricsType{
		NoExtendedMetrics,
		SimpleExtendedMetrics,
		ModerateExtendedMetrics,
		DetailedExtendedMetrics,
	}
)

func (t ExtendedMetricsType) String() string {
	switch t {
	case NoExtendedMetrics:
		return "none"
	case SimpleExtendedMetrics:
		return "simple"
	case ModerateExtendedMetrics:
		return "moderate"
	case DetailedExtendedMetrics:
		return "detailed"
	}
	return "unknown"
}

// UnmarshalYAML unmarshals an ExtendedMetricsType into a valid type from string.
func (t *ExtendedMetricsType) UnmarshalYAML(unmarshal func(interface{}) error) error {
	var str string
	if err := unmarshal(&str); err != nil {
		return err
	}
	if str == "" {
		*t = DefaultExtendedMetricsType
		return nil
	}
	strs := make([]string, len(validExtendedMetricsTypes))
	for _, valid := range validExtendedMetricsTypes {
		if str == valid.String() {
			*t = valid
			return nil
		}
		strs = append(strs, "'"+valid.String()+"'")
	}
	return fmt.Errorf("invalid ExtendedMetricsType '%s' valid types are: %s",
		str, strings.Join(strs, ", "))
}

// StartReportingExtendedMetrics creates a extend metrics reporter and starts
// the reporter returning it so it may be stopped if successfully started.
func StartReportingExtendedMetrics(
	scope tally.Scope,
	reportInterval time.Duration,
	metricsType ExtendedMetricsType,
) (Reporter, error) {
	reporter := NewExtendedMetricsReporter(scope, reportInterval, metricsType)
	if err := reporter.Start(); err != nil {
		return nil, err
	}
	return reporter, nil
}

type runtimeMetrics struct {
	NumGoRoutines   tally.Gauge
	GoMaxProcs      tally.Gauge
	MemoryAllocated tally.Gauge
	MemoryHeap      tally.Gauge
	MemoryHeapIdle  tally.Gauge
	MemoryHeapInuse tally.Gauge
	MemoryStack     tally.Gauge
	NumGC           tally.Counter
	GcPauseMs       tally.Timer
	lastNumGC       uint32
}

func (r *runtimeMetrics) report(metricsType ExtendedMetricsType) {
	if metricsType == NoExtendedMetrics {
		return
	}

	r.NumGoRoutines.Update(float64(runtime.NumGoroutine()))
	r.GoMaxProcs.Update(float64(runtime.GOMAXPROCS(0)))
	if metricsType < DetailedExtendedMetrics {
		return
	}

	var memStats runtime.MemStats
	runtime.ReadMemStats(&memStats)
	r.MemoryAllocated.Update(float64(memStats.Alloc))
	r.MemoryHeap.Update(float64(memStats.HeapAlloc))
	r.MemoryHeapIdle.Update(float64(memStats.HeapIdle))
	r.MemoryHeapInuse.Update(float64(memStats.HeapInuse))
	r.MemoryStack.Update(float64(memStats.StackInuse))

	// memStats.NumGC is a perpetually incrementing counter (unless it wraps at 2^32).
	num := memStats.NumGC
	lastNum := atomic.SwapUint32(&r.lastNumGC, num)
	if delta := num - lastNum; delta > 0 {
		r.NumGC.Inc(int64(delta))
		if delta > 255 {
			// too many GCs happened, the timestamps buffer got wrapped around. Report only the last 256.
			lastNum = num - 256
		}
		for i := lastNum; i != num; i++ {
			pause := memStats.PauseNs[i%256]
			r.GcPauseMs.Record(time.Duration(pause))
		}
	}
}

type extendedMetricsReporter struct {
	baseReporter

	metricsType ExtendedMetricsType
	runtime     runtimeMetrics
	process     processMetrics
}

// NewExtendedMetricsReporter creates a new extended metrics reporter
// that reports runtime and process metrics.
func NewExtendedMetricsReporter(
	scope tally.Scope,
	reportInterval time.Duration,
	metricsType ExtendedMetricsType,
) Reporter {
	r := new(extendedMetricsReporter)
	r.metricsType = metricsType
	r.init(reportInterval, func() {
		r.runtime.report(r.metricsType)
		if r.metricsType >= ModerateExtendedMetrics {
			r.process.report()
		}
	})
	if r.metricsType == NoExtendedMetrics {
		return r
	}

	runtimeScope := scope.SubScope("runtime")
	processScope := scope.SubScope("process")
	r.runtime.NumGoRoutines = runtimeScope.Gauge("num-goroutines")
	r.runtime.GoMaxProcs = runtimeScope.Gauge("gomaxprocs")
	r.process.NumFDs = processScope.Gauge("num-fds")
	r.process.NumFDErrors = processScope.Counter("num-fd-errors")
	r.process.pid = os.Getpid()
	if r.metricsType < DetailedExtendedMetrics {
		return r
	}

	var memstats runtime.MemStats
	runtime.ReadMemStats(&memstats)
	memoryScope := runtimeScope.SubScope("memory")
	r.runtime.MemoryAllocated = memoryScope.Gauge("allocated")
	r.runtime.MemoryHeap = memoryScope.Gauge("heap")
	r.runtime.MemoryHeapIdle = memoryScope.Gauge("heapidle")
	r.runtime.MemoryHeapInuse = memoryScope.Gauge("heapinuse")
	r.runtime.MemoryStack = memoryScope.Gauge("stack")
	r.runtime.NumGC = memoryScope.Counter("num-gc")
	r.runtime.GcPauseMs = memoryScope.Timer("gc-pause-ms")
	r.runtime.lastNumGC = memstats.NumGC

	return r
}
<commit_msg>[instrument] Add metric for GC CPU Fraction (#114)<commit_after>// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software 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.

package instrument

import (
	"fmt"
	"os"
	"runtime"
	"strings"
	"sync/atomic"
	"time"

	"github.com/uber-go/tally"
)

// ExtendedMetricsType is a type of extended metrics to report.
type ExtendedMetricsType int

const (
	// NoExtendedMetrics describes no extended metrics.
	NoExtendedMetrics ExtendedMetricsType = iota

	// SimpleExtendedMetrics describes just a simple level of extended metrics:
	// - number of active goroutines
	// - number of configured gomaxprocs
	SimpleExtendedMetrics

	// ModerateExtendedMetrics describes a moderately verbose level of extended metrics:
	// - number of active goroutines
	// - number of configured gomaxprocs
	// - number of file descriptors
	ModerateExtendedMetrics

	// DetailedExtendedMetrics describes a detailed level of extended metrics:
	// - number of active goroutines
	// - number of configured gomaxprocs
	// - number of file descriptors
	// - memory allocated running count
	// - memory used by heap
	// - memory used by heap that is idle
	// - memory used by heap that is in use
	// - memory used by stack
	// - number of garbage collections
	// - GC pause times
	DetailedExtendedMetrics

	// DefaultExtendedMetricsType is the default extended metrics level.
	DefaultExtendedMetricsType = SimpleExtendedMetrics
)

var (
	validExtendedMetricsTypes = []ExtendedMetricsType{
		NoExtendedMetrics,
		SimpleExtendedMetrics,
		ModerateExtendedMetrics,
		DetailedExtendedMetrics,
	}
)

func (t ExtendedMetricsType) String() string {
	switch t {
	case NoExtendedMetrics:
		return "none"
	case SimpleExtendedMetrics:
		return "simple"
	case ModerateExtendedMetrics:
		return "moderate"
	case DetailedExtendedMetrics:
		return "detailed"
	}
	return "unknown"
}

// UnmarshalYAML unmarshals an ExtendedMetricsType into a valid type from string.
func (t *ExtendedMetricsType) UnmarshalYAML(unmarshal func(interface{}) error) error {
	var str string
	if err := unmarshal(&str); err != nil {
		return err
	}
	if str == "" {
		*t = DefaultExtendedMetricsType
		return nil
	}
	strs := make([]string, len(validExtendedMetricsTypes))
	for _, valid := range validExtendedMetricsTypes {
		if str == valid.String() {
			*t = valid
			return nil
		}
		strs = append(strs, "'"+valid.String()+"'")
	}
	return fmt.Errorf("invalid ExtendedMetricsType '%s' valid types are: %s",
		str, strings.Join(strs, ", "))
}

// StartReportingExtendedMetrics creates a extend metrics reporter and starts
// the reporter returning it so it may be stopped if successfully started.
func StartReportingExtendedMetrics(
	scope tally.Scope,
	reportInterval time.Duration,
	metricsType ExtendedMetricsType,
) (Reporter, error) {
	reporter := NewExtendedMetricsReporter(scope, reportInterval, metricsType)
	if err := reporter.Start(); err != nil {
		return nil, err
	}
	return reporter, nil
}

type runtimeMetrics struct {
	NumGoRoutines   tally.Gauge
	GoMaxProcs      tally.Gauge
	MemoryAllocated tally.Gauge
	MemoryHeap      tally.Gauge
	MemoryHeapIdle  tally.Gauge
	MemoryHeapInuse tally.Gauge
	MemoryStack     tally.Gauge
	GCCPUFraction   tally.Gauge
	NumGC           tally.Counter
	GcPauseMs       tally.Timer
	lastNumGC       uint32
}

func (r *runtimeMetrics) report(metricsType ExtendedMetricsType) {
	if metricsType == NoExtendedMetrics {
		return
	}

	r.NumGoRoutines.Update(float64(runtime.NumGoroutine()))
	r.GoMaxProcs.Update(float64(runtime.GOMAXPROCS(0)))
	if metricsType < DetailedExtendedMetrics {
		return
	}

	var memStats runtime.MemStats
	runtime.ReadMemStats(&memStats)
	r.MemoryAllocated.Update(float64(memStats.Alloc))
	r.MemoryHeap.Update(float64(memStats.HeapAlloc))
	r.MemoryHeapIdle.Update(float64(memStats.HeapIdle))
	r.MemoryHeapInuse.Update(float64(memStats.HeapInuse))
	r.MemoryStack.Update(float64(memStats.StackInuse))
	r.GCCPUFraction.Update(memStats.GCCPUFraction)

	// memStats.NumGC is a perpetually incrementing counter (unless it wraps at 2^32).
	num := memStats.NumGC
	lastNum := atomic.SwapUint32(&r.lastNumGC, num)
	if delta := num - lastNum; delta > 0 {
		r.NumGC.Inc(int64(delta))
		if delta > 255 {
			// too many GCs happened, the timestamps buffer got wrapped around. Report only the last 256.
			lastNum = num - 256
		}
		for i := lastNum; i != num; i++ {
			pause := memStats.PauseNs[i%256]
			r.GcPauseMs.Record(time.Duration(pause))
		}
	}
}

type extendedMetricsReporter struct {
	baseReporter

	metricsType ExtendedMetricsType
	runtime     runtimeMetrics
	process     processMetrics
}

// NewExtendedMetricsReporter creates a new extended metrics reporter
// that reports runtime and process metrics.
func NewExtendedMetricsReporter(
	scope tally.Scope,
	reportInterval time.Duration,
	metricsType ExtendedMetricsType,
) Reporter {
	r := new(extendedMetricsReporter)
	r.metricsType = metricsType
	r.init(reportInterval, func() {
		r.runtime.report(r.metricsType)
		if r.metricsType >= ModerateExtendedMetrics {
			r.process.report()
		}
	})
	if r.metricsType == NoExtendedMetrics {
		return r
	}

	runtimeScope := scope.SubScope("runtime")
	processScope := scope.SubScope("process")
	r.runtime.NumGoRoutines = runtimeScope.Gauge("num-goroutines")
	r.runtime.GoMaxProcs = runtimeScope.Gauge("gomaxprocs")
	r.process.NumFDs = processScope.Gauge("num-fds")
	r.process.NumFDErrors = processScope.Counter("num-fd-errors")
	r.process.pid = os.Getpid()
	if r.metricsType < DetailedExtendedMetrics {
		return r
	}

	var memstats runtime.MemStats
	runtime.ReadMemStats(&memstats)
	memoryScope := runtimeScope.SubScope("memory")
	r.runtime.MemoryAllocated = memoryScope.Gauge("allocated")
	r.runtime.MemoryHeap = memoryScope.Gauge("heap")
	r.runtime.MemoryHeapIdle = memoryScope.Gauge("heapidle")
	r.runtime.MemoryHeapInuse = memoryScope.Gauge("heapinuse")
	r.runtime.MemoryStack = memoryScope.Gauge("stack")
	r.runtime.GCCPUFraction = memoryScope.Gauge("gc-cpu-fraction")
	r.runtime.NumGC = memoryScope.Counter("num-gc")
	r.runtime.GcPauseMs = memoryScope.Timer("gc-pause-ms")
	r.runtime.lastNumGC = memstats.NumGC

	return r
}
<|endoftext|>


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

package ioutil

import (
	"os"
	"path/filepath"
	"strconv"
	"time"
)

// Random number state, accessed without lock; racy but harmless.
// We generate random temporary file names so that there's a good
// chance the file doesn't exist yet - keeps the number of tries in
// TempFile to a minimum.
var rand uint32

func reseed() uint32 {
	return uint32(time.Now().UnixNano() + int64(os.Getpid()))
}

func nextSuffix() string {
	r := rand
	if r == 0 {
		r = reseed()
	}
	r = r*1664525 + 1013904223 // constants from Numerical Recipes
	rand = r
	return strconv.Itoa(int(1e9 + r%1e9))[1:]
}

// TempFile creates a new temporary file in the directory dir
// with a name beginning with prefix, opens the file for reading
// and writing, and returns the resulting *os.File.
// If dir is the empty string, TempFile uses the default directory
// for temporary files (see os.TempDir).
// Multiple programs calling TempFile simultaneously
// will not choose the same file.  The caller can use f.Name()
// to find the name of the file.  It is the caller's responsibility to
// remove the file when no longer needed.
func TempFile(dir, prefix string) (f *os.File, err error) {
	if dir == "" {
		dir = os.TempDir()
	}

	nconflict := 0
	for i := 0; i < 10000; i++ {
		name := filepath.Join(dir, prefix+nextSuffix())
		f, err = os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
		if os.IsExist(err) {
			if nconflict++; nconflict > 10 {
				rand = reseed()
			}
			continue
		}
		break
	}
	return
}

// TempDir creates a new temporary directory in the directory dir
// with a name beginning with prefix and returns the path of the
// new directory.  If dir is the empty string, TempDir uses the
// default directory for temporary files (see os.TempDir).
// Multiple programs calling TempDir simultaneously
// will not choose the same directory.  It is the caller's responsibility
// to remove the directory when no longer needed.
func TempDir(dir, prefix string) (name string, err error) {
	if dir == "" {
		dir = os.TempDir()
	}

	nconflict := 0
	for i := 0; i < 10000; i++ {
		try := filepath.Join(dir, prefix+nextSuffix())
		err = os.Mkdir(try, 0700)
		if os.IsExist(err) {
			if nconflict++; nconflict > 10 {
				rand = reseed()
			}
			continue
		}
		if err == nil {
			name = try
		}
		break
	}
	return
}
<commit_msg>io/ioutil: fix data race on rand Fixes #4212.<commit_after>// Copyright 2010 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ioutil

import (
	"os"
	"path/filepath"
	"strconv"
	"sync"
	"time"
)

// Random number state, accessed without lock; racy but harmless.
// We generate random temporary file names so that there's a good
// chance the file doesn't exist yet - keeps the number of tries in
// TempFile to a minimum.
var rand uint32
var randmu sync.Mutex

func reseed() uint32 {
	return uint32(time.Now().UnixNano() + int64(os.Getpid()))
}

func nextSuffix() string {
	randmu.Lock()
	r := rand
	if r == 0 {
		r = reseed()
	}
	r = r*1664525 + 1013904223 // constants from Numerical Recipes
	rand = r
	randmu.Unlock()
	return strconv.Itoa(int(1e9 + r%1e9))[1:]
}

// TempFile creates a new temporary file in the directory dir
// with a name beginning with prefix, opens the file for reading
// and writing, and returns the resulting *os.File.
// If dir is the empty string, TempFile uses the default directory
// for temporary files (see os.TempDir).
// Multiple programs calling TempFile simultaneously
// will not choose the same file.  The caller can use f.Name()
// to find the name of the file.  It is the caller's responsibility to
// remove the file when no longer needed.
func TempFile(dir, prefix string) (f *os.File, err error) {
	if dir == "" {
		dir = os.TempDir()
	}

	nconflict := 0
	for i := 0; i < 10000; i++ {
		name := filepath.Join(dir, prefix+nextSuffix())
		f, err = os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
		if os.IsExist(err) {
			if nconflict++; nconflict > 10 {
				rand = reseed()
			}
			continue
		}
		break
	}
	return
}

// TempDir creates a new temporary directory in the directory dir
// with a name beginning with prefix and returns the path of the
// new directory.  If dir is the empty string, TempDir uses the
// default directory for temporary files (see os.TempDir).
// Multiple programs calling TempDir simultaneously
// will not choose the same directory.  It is the caller's responsibility
// to remove the directory when no longer needed.
func TempDir(dir, prefix string) (name string, err error) {
	if dir == "" {
		dir = os.TempDir()
	}

	nconflict := 0
	for i := 0; i < 10000; i++ {
		try := filepath.Join(dir, prefix+nextSuffix())
		err = os.Mkdir(try, 0700)
		if os.IsExist(err) {
			if nconflict++; nconflict > 10 {
				rand = reseed()
			}
			continue
		}
		if err == nil {
			name = try
		}
		break
	}
	return
}
<|endoftext|>


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

package ioutil

import (
	"os"
	"path/filepath"
	"strconv"
	"sync"
	"time"
)

// Random number state, accessed without lock; racy but harmless.
// We generate random temporary file names so that there's a good
// chance the file doesn't exist yet - keeps the number of tries in
// TempFile to a minimum.
var rand uint32
var randmu sync.Mutex

func reseed() uint32 {
	return uint32(time.Now().UnixNano() + int64(os.Getpid()))
}

func nextSuffix() string {
	randmu.Lock()
	r := rand
	if r == 0 {
		r = reseed()
	}
	r = r*1664525 + 1013904223 // constants from Numerical Recipes
	rand = r
	randmu.Unlock()
	return strconv.Itoa(int(1e9 + r%1e9))[1:]
}

// TempFile creates a new temporary file in the directory dir
// with a name beginning with prefix, opens the file for reading
// and writing, and returns the resulting *os.File.
// If dir is the empty string, TempFile uses the default directory
// for temporary files (see os.TempDir).
// Multiple programs calling TempFile simultaneously
// will not choose the same file.  The caller can use f.Name()
// to find the name of the file.  It is the caller's responsibility to
// remove the file when no longer needed.
func TempFile(dir, prefix string) (f *os.File, err error) {
	if dir == "" {
		dir = os.TempDir()
	}

	nconflict := 0
	for i := 0; i < 10000; i++ {
		name := filepath.Join(dir, prefix+nextSuffix())
		f, err = os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
		if os.IsExist(err) {
			if nconflict++; nconflict > 10 {
				rand = reseed()
			}
			continue
		}
		break
	}
	return
}

// TempDir creates a new temporary directory in the directory dir
// with a name beginning with prefix and returns the path of the
// new directory.  If dir is the empty string, TempDir uses the
// default directory for temporary files (see os.TempDir).
// Multiple programs calling TempDir simultaneously
// will not choose the same directory.  It is the caller's responsibility
// to remove the directory when no longer needed.
func TempDir(dir, prefix string) (name string, err error) {
	if dir == "" {
		dir = os.TempDir()
	}

	nconflict := 0
	for i := 0; i < 10000; i++ {
		try := filepath.Join(dir, prefix+nextSuffix())
		err = os.Mkdir(try, 0700)
		if os.IsExist(err) {
			if nconflict++; nconflict > 10 {
				rand = reseed()
			}
			continue
		}
		if err == nil {
			name = try
		}
		break
	}
	return
}
<commit_msg>io/ioutil: use pathname instead of name in docs to avoid confusion caller of ioutil.TempFile() can use f.Name() to get "pathname" of the temporary file, instead of just the "name" of the file.<commit_after>// Copyright 2010 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ioutil

import (
	"os"
	"path/filepath"
	"strconv"
	"sync"
	"time"
)

// Random number state.
// We generate random temporary file names so that there's a good
// chance the file doesn't exist yet - keeps the number of tries in
// TempFile to a minimum.
var rand uint32
var randmu sync.Mutex

func reseed() uint32 {
	return uint32(time.Now().UnixNano() + int64(os.Getpid()))
}

func nextSuffix() string {
	randmu.Lock()
	r := rand
	if r == 0 {
		r = reseed()
	}
	r = r*1664525 + 1013904223 // constants from Numerical Recipes
	rand = r
	randmu.Unlock()
	return strconv.Itoa(int(1e9 + r%1e9))[1:]
}

// TempFile creates a new temporary file in the directory dir
// with a name beginning with prefix, opens the file for reading
// and writing, and returns the resulting *os.File.
// If dir is the empty string, TempFile uses the default directory
// for temporary files (see os.TempDir).
// Multiple programs calling TempFile simultaneously
// will not choose the same file.  The caller can use f.Name()
// to find the pathname of the file.  It is the caller's responsibility
// to remove the file when no longer needed.
func TempFile(dir, prefix string) (f *os.File, err error) {
	if dir == "" {
		dir = os.TempDir()
	}

	nconflict := 0
	for i := 0; i < 10000; i++ {
		name := filepath.Join(dir, prefix+nextSuffix())
		f, err = os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
		if os.IsExist(err) {
			if nconflict++; nconflict > 10 {
				rand = reseed()
			}
			continue
		}
		break
	}
	return
}

// TempDir creates a new temporary directory in the directory dir
// with a name beginning with prefix and returns the path of the
// new directory.  If dir is the empty string, TempDir uses the
// default directory for temporary files (see os.TempDir).
// Multiple programs calling TempDir simultaneously
// will not choose the same directory.  It is the caller's responsibility
// to remove the directory when no longer needed.
func TempDir(dir, prefix string) (name string, err error) {
	if dir == "" {
		dir = os.TempDir()
	}

	nconflict := 0
	for i := 0; i < 10000; i++ {
		try := filepath.Join(dir, prefix+nextSuffix())
		err = os.Mkdir(try, 0700)
		if os.IsExist(err) {
			if nconflict++; nconflict > 10 {
				rand = reseed()
			}
			continue
		}
		if err == nil {
			name = try
		}
		break
	}
	return
}
<|endoftext|>


<commit_before>package ast

import (
	"monkey/token"
)

type Node interface {
	TokenLiteral() string
}

type Statement interface {
	Node
	statementNode()
}

type Expression interface {
	Node
	expressionNode()
}

type Program struct {
	Statements []Statement
}

func(p *Program) TokenLiteral() string {
	if len(p.Statements) > 0 {
		return p.Statements[0].TokenLiteral()
	} else {
		return ""
	}
}

type LetStatement struct {
	Token token.Token
	Name  *Identifier
	Value Expression
}

func (ls *LetStatement) statementNode() {}
func (ls *LetStatement) TokenLiteral() string {
	return ls.Token.Literal
}

type Identifier struct {
	Token token.Token
	Value string
}

func (i *Identifier) expressionNode() {}
func (i *Identifier) TokenLiteral() string {
	return i.Token.Literal
}

type ReturnStatement struct {
	Token       token.Token
	ReturnValue Expression
}

func (rs *ReturnStatement) statementNode() {}
func (rs *ReturnStatement) TokenLiteral() string {
	return rs.Token.Literal
}<commit_msg>add expression statement<commit_after>package ast

import (
	"bytes"
	"monkey/token"
)

type Node interface {
	TokenLiteral() string
	String() string
}

type Statement interface {
	Node
	statementNode()
}

type Expression interface {
	Node
	expressionNode()
}

type Program struct {
	Statements []Statement
}

func(p *Program) TokenLiteral() string {
	if len(p.Statements) > 0 {
		return p.Statements[0].TokenLiteral()
	} else {
		return ""
	}
}
func (p *Program) String() string {
	var out bytes.Buffer

	for _, s := range p.Statements {
		out.WriteString(s.String())
	}

	return out.String()
}

type LetStatement struct {
	Token token.Token
	Name  *Identifier
	Value Expression
}

func (ls *LetStatement) statementNode() {}
func (ls *LetStatement) TokenLiteral() string {
	return ls.Token.Literal
}
func (ls *LetStatement) String() string {
	var out bytes.Buffer

	out.WriteString(ls.TokenLiteral() + " ")
	out.WriteString(ls.Name.String())
	out.WriteString(" = ")

	if ls.Value != nil {
		out.WriteString(ls.Value.String())
	}

	out.WriteString(";")

	return out.String()
}

type Identifier struct {
	Token token.Token
	Value string
}

func (i *Identifier) expressionNode() {}
func (i *Identifier) TokenLiteral() string {
	return i.Token.Literal
}
func (i *Identifier) String() string {
	return i.Value
}

type ReturnStatement struct {
	Token       token.Token
	ReturnValue Expression
}

func (rs *ReturnStatement) statementNode() {}
func (rs *ReturnStatement) TokenLiteral() string {
	return rs.Token.Literal
}
func (rs *ReturnStatement) String() string {
	var out bytes.Buffer

	out.WriteString(rs.TokenLiteral() + " ")

	if rs.ReturnValue != nil {
		out.WriteString(rs.ReturnValue.String())
	}

	out.WriteString(";")

	return out.String()
}

type ExpressionStatement struct {
	Token      token.Token
	Expression Expression
}

func (es *ExpressionStatement) statementNode() {}
func (es *ExpressionStatement) TokenLiteral() string {
	retunr es.Token.Literal
}
func (es *ExpressionStatement) String() string {
	if es.Expression != nil {
		return es.Expression.String()
	}
	return ""
}<|endoftext|>


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

// Parse "zoneinfo" time zone file.
// This is a fairly standard file format used on OS X, Linux, BSD, Sun, and others.
// See tzfile(5), http://en.wikipedia.org/wiki/Zoneinfo,
// and ftp://munnari.oz.au/pub/oldtz/

package time

import (
	"io/ioutil"
	"os"
	"sync"
)

const (
	headerSize = 4 + 16 + 4*7
	zoneDir    = "/usr/share/zoneinfo/"
	zoneDir2   = "/usr/share/lib/zoneinfo/"
)

// Simple I/O interface to binary blob of data.
type data struct {
	p     []byte
	error bool
}

func (d *data) read(n int) []byte {
	if len(d.p) < n {
		d.p = nil
		d.error = true
		return nil
	}
	p := d.p[0:n]
	d.p = d.p[n:]
	return p
}

func (d *data) big4() (n uint32, ok bool) {
	p := d.read(4)
	if len(p) < 4 {
		d.error = true
		return 0, false
	}
	return uint32(p[0])<<24 | uint32(p[1])<<16 | uint32(p[2])<<8 | uint32(p[3]), true
}

func (d *data) byte() (n byte, ok bool) {
	p := d.read(1)
	if len(p) < 1 {
		d.error = true
		return 0, false
	}
	return p[0], true
}

// Make a string by stopping at the first NUL
func byteString(p []byte) string {
	for i := 0; i < len(p); i++ {
		if p[i] == 0 {
			return string(p[0:i])
		}
	}
	return string(p)
}

// Parsed representation
type zone struct {
	utcoff int
	isdst  bool
	name   string
}

type zonetime struct {
	time         int32 // transition time, in seconds since 1970 GMT
	zone         *zone // the zone that goes into effect at that time
	isstd, isutc bool  // ignored - no idea what these mean
}

func parseinfo(bytes []byte) (zt []zonetime, ok bool) {
	d := data{bytes, false}

	// 4-byte magic "TZif"
	if magic := d.read(4); string(magic) != "TZif" {
		return nil, false
	}

	// 1-byte version, then 15 bytes of padding
	var p []byte
	if p = d.read(16); len(p) != 16 || p[0] != 0 && p[0] != '2' {
		return nil, false
	}

	// six big-endian 32-bit integers:
	//	number of UTC/local indicators
	//	number of standard/wall indicators
	//	number of leap seconds
	//	number of transition times
	//	number of local time zones
	//	number of characters of time zone abbrev strings
	const (
		NUTCLocal = iota
		NStdWall
		NLeap
		NTime
		NZone
		NChar
	)
	var n [6]int
	for i := 0; i < 6; i++ {
		nn, ok := d.big4()
		if !ok {
			return nil, false
		}
		n[i] = int(nn)
	}

	// Transition times.
	txtimes := data{d.read(n[NTime] * 4), false}

	// Time zone indices for transition times.
	txzones := d.read(n[NTime])

	// Zone info structures
	zonedata := data{d.read(n[NZone] * 6), false}

	// Time zone abbreviations.
	abbrev := d.read(n[NChar])

	// Leap-second time pairs
	d.read(n[NLeap] * 8)

	// Whether tx times associated with local time types
	// are specified as standard time or wall time.
	isstd := d.read(n[NStdWall])

	// Whether tx times associated with local time types
	// are specified as UTC or local time.
	isutc := d.read(n[NUTCLocal])

	if d.error { // ran out of data
		return nil, false
	}

	// If version == 2, the entire file repeats, this time using
	// 8-byte ints for txtimes and leap seconds.
	// We won't need those until 2106.

	// Now we can build up a useful data structure.
	// First the zone information.
	//	utcoff[4] isdst[1] nameindex[1]
	z := make([]zone, n[NZone])
	for i := 0; i < len(z); i++ {
		var ok bool
		var n uint32
		if n, ok = zonedata.big4(); !ok {
			return nil, false
		}
		z[i].utcoff = int(n)
		var b byte
		if b, ok = zonedata.byte(); !ok {
			return nil, false
		}
		z[i].isdst = b != 0
		if b, ok = zonedata.byte(); !ok || int(b) >= len(abbrev) {
			return nil, false
		}
		z[i].name = byteString(abbrev[b:])
	}

	// Now the transition time info.
	zt = make([]zonetime, n[NTime])
	for i := 0; i < len(zt); i++ {
		var ok bool
		var n uint32
		if n, ok = txtimes.big4(); !ok {
			return nil, false
		}
		zt[i].time = int32(n)
		if int(txzones[i]) >= len(z) {
			return nil, false
		}
		zt[i].zone = &z[txzones[i]]
		if i < len(isstd) {
			zt[i].isstd = isstd[i] != 0
		}
		if i < len(isutc) {
			zt[i].isutc = isutc[i] != 0
		}
	}
	return zt, true
}

func readinfofile(name string) ([]zonetime, bool) {
	buf, err := ioutil.ReadFile(name)
	if err != nil {
		return nil, false
	}
	return parseinfo(buf)
}

var zones []zonetime
var onceSetupZone sync.Once

func setupZone() {
	// consult $TZ to find the time zone to use.
	// no $TZ means use the system default /etc/localtime.
	// $TZ="" means use UTC.
	// $TZ="foo" means use /usr/share/zoneinfo/foo.

	tz, err := os.Getenverror("TZ")
	switch {
	case err == os.ENOENV:
		zones, _ = readinfofile("/etc/localtime")
	case len(tz) > 0:
		var ok bool
		zones, ok = readinfofile(zoneDir + tz)
		if !ok {
			zones, _ = readinfofile(zoneDir2 + tz)
		}
	case len(tz) == 0:
		// do nothing: use UTC
	}
}

// Look up the correct time zone (daylight savings or not) for the given unix time, in the current location.
func lookupTimezone(sec int64) (zone string, offset int) {
	onceSetupZone.Do(setupZone)
	if len(zones) == 0 {
		return "UTC", 0
	}

	// Binary search for entry with largest time <= sec
	tz := zones
	for len(tz) > 1 {
		m := len(tz) / 2
		if sec < int64(tz[m].time) {
			tz = tz[0:m]
		} else {
			tz = tz[m:]
		}
	}
	z := tz[0].zone
	return z.name, z.utcoff
}

// lookupByName returns the time offset for the
// time zone with the given abbreviation. It only considers
// time zones that apply to the current system.
// For example, for a system configured as being in New York,
// it only recognizes "EST" and "EDT".
// For a system in San Francisco, "PST" and "PDT".
// For a system in Sydney, "EST" and "EDT", though they have
// different meanings than they do in New York.
func lookupByName(name string) (off int, found bool) {
	onceSetupZone.Do(setupZone)
	for _, z := range zones {
		if name == z.zone.name {
			return z.zone.utcoff, true
		}
	}
	return 0, false
}
<commit_msg>time: Support Irix 6 location for zoneinfo files.<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Parse "zoneinfo" time zone file.
// This is a fairly standard file format used on OS X, Linux, BSD, Sun, and others.
// See tzfile(5), http://en.wikipedia.org/wiki/Zoneinfo,
// and ftp://munnari.oz.au/pub/oldtz/

package time

import (
	"io/ioutil"
	"os"
	"sync"
)

const (
	headerSize = 4 + 16 + 4*7
)

// Simple I/O interface to binary blob of data.
type data struct {
	p     []byte
	error bool
}

func (d *data) read(n int) []byte {
	if len(d.p) < n {
		d.p = nil
		d.error = true
		return nil
	}
	p := d.p[0:n]
	d.p = d.p[n:]
	return p
}

func (d *data) big4() (n uint32, ok bool) {
	p := d.read(4)
	if len(p) < 4 {
		d.error = true
		return 0, false
	}
	return uint32(p[0])<<24 | uint32(p[1])<<16 | uint32(p[2])<<8 | uint32(p[3]), true
}

func (d *data) byte() (n byte, ok bool) {
	p := d.read(1)
	if len(p) < 1 {
		d.error = true
		return 0, false
	}
	return p[0], true
}

// Make a string by stopping at the first NUL
func byteString(p []byte) string {
	for i := 0; i < len(p); i++ {
		if p[i] == 0 {
			return string(p[0:i])
		}
	}
	return string(p)
}

// Parsed representation
type zone struct {
	utcoff int
	isdst  bool
	name   string
}

type zonetime struct {
	time         int32 // transition time, in seconds since 1970 GMT
	zone         *zone // the zone that goes into effect at that time
	isstd, isutc bool  // ignored - no idea what these mean
}

func parseinfo(bytes []byte) (zt []zonetime, ok bool) {
	d := data{bytes, false}

	// 4-byte magic "TZif"
	if magic := d.read(4); string(magic) != "TZif" {
		return nil, false
	}

	// 1-byte version, then 15 bytes of padding
	var p []byte
	if p = d.read(16); len(p) != 16 || p[0] != 0 && p[0] != '2' {
		return nil, false
	}

	// six big-endian 32-bit integers:
	//	number of UTC/local indicators
	//	number of standard/wall indicators
	//	number of leap seconds
	//	number of transition times
	//	number of local time zones
	//	number of characters of time zone abbrev strings
	const (
		NUTCLocal = iota
		NStdWall
		NLeap
		NTime
		NZone
		NChar
	)
	var n [6]int
	for i := 0; i < 6; i++ {
		nn, ok := d.big4()
		if !ok {
			return nil, false
		}
		n[i] = int(nn)
	}

	// Transition times.
	txtimes := data{d.read(n[NTime] * 4), false}

	// Time zone indices for transition times.
	txzones := d.read(n[NTime])

	// Zone info structures
	zonedata := data{d.read(n[NZone] * 6), false}

	// Time zone abbreviations.
	abbrev := d.read(n[NChar])

	// Leap-second time pairs
	d.read(n[NLeap] * 8)

	// Whether tx times associated with local time types
	// are specified as standard time or wall time.
	isstd := d.read(n[NStdWall])

	// Whether tx times associated with local time types
	// are specified as UTC or local time.
	isutc := d.read(n[NUTCLocal])

	if d.error { // ran out of data
		return nil, false
	}

	// If version == 2, the entire file repeats, this time using
	// 8-byte ints for txtimes and leap seconds.
	// We won't need those until 2106.

	// Now we can build up a useful data structure.
	// First the zone information.
	//	utcoff[4] isdst[1] nameindex[1]
	z := make([]zone, n[NZone])
	for i := 0; i < len(z); i++ {
		var ok bool
		var n uint32
		if n, ok = zonedata.big4(); !ok {
			return nil, false
		}
		z[i].utcoff = int(n)
		var b byte
		if b, ok = zonedata.byte(); !ok {
			return nil, false
		}
		z[i].isdst = b != 0
		if b, ok = zonedata.byte(); !ok || int(b) >= len(abbrev) {
			return nil, false
		}
		z[i].name = byteString(abbrev[b:])
	}

	// Now the transition time info.
	zt = make([]zonetime, n[NTime])
	for i := 0; i < len(zt); i++ {
		var ok bool
		var n uint32
		if n, ok = txtimes.big4(); !ok {
			return nil, false
		}
		zt[i].time = int32(n)
		if int(txzones[i]) >= len(z) {
			return nil, false
		}
		zt[i].zone = &z[txzones[i]]
		if i < len(isstd) {
			zt[i].isstd = isstd[i] != 0
		}
		if i < len(isutc) {
			zt[i].isutc = isutc[i] != 0
		}
	}
	return zt, true
}

func readinfofile(name string) ([]zonetime, bool) {
	buf, err := ioutil.ReadFile(name)
	if err != nil {
		return nil, false
	}
	return parseinfo(buf)
}

var zones []zonetime
var onceSetupZone sync.Once

func setupZone() {
	// consult $TZ to find the time zone to use.
	// no $TZ means use the system default /etc/localtime.
	// $TZ="" means use UTC.
	// $TZ="foo" means use /usr/share/zoneinfo/foo.
	// Many systems use /usr/share/zoneinfo, Solaris 2 has
	// /usr/share/lib/zoneinfo, IRIX 6 has /usr/lib/locale/TZ.
	zoneDirs := []string{"/usr/share/zoneinfo/",
		"/usr/share/lib/zoneinfo/",
		"/usr/lib/locale/TZ/"}

	tz, err := os.Getenverror("TZ")
	switch {
	case err == os.ENOENV:
		zones, _ = readinfofile("/etc/localtime")
	case len(tz) > 0:
		for _, zoneDir := range zoneDirs {
			var ok bool
			if zones, ok = readinfofile(zoneDir + tz); ok {
				break
			}
		}
	case len(tz) == 0:
		// do nothing: use UTC
	}
}

// Look up the correct time zone (daylight savings or not) for the given unix time, in the current location.
func lookupTimezone(sec int64) (zone string, offset int) {
	onceSetupZone.Do(setupZone)
	if len(zones) == 0 {
		return "UTC", 0
	}

	// Binary search for entry with largest time <= sec
	tz := zones
	for len(tz) > 1 {
		m := len(tz) / 2
		if sec < int64(tz[m].time) {
			tz = tz[0:m]
		} else {
			tz = tz[m:]
		}
	}
	z := tz[0].zone
	return z.name, z.utcoff
}

// lookupByName returns the time offset for the
// time zone with the given abbreviation. It only considers
// time zones that apply to the current system.
// For example, for a system configured as being in New York,
// it only recognizes "EST" and "EDT".
// For a system in San Francisco, "PST" and "PDT".
// For a system in Sydney, "EST" and "EDT", though they have
// different meanings than they do in New York.
func lookupByName(name string) (off int, found bool) {
	onceSetupZone.Do(setupZone)
	for _, z := range zones {
		if name == z.zone.name {
			return z.zone.utcoff, true
		}
	}
	return 0, false
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"

	"gopkg.in/urfave/cli.v2"
)

func main() {
	app := cli.NewApp()
	app.Name = "andrec"
	app.Usage = "screen recorder for Android"
	app.Action = func(c *cli.Context) error {
		fmt.Println("boom! I say!")
		return nil
	}

	app.Action = func(c *cli.Context) error {
		filename := "Nefertiti"
		if c.NArg() > 0 {
			filename = c.Args().Get(0)
		}

		record(filename)

		return nil
	}

	app.Run(os.Args)
}

func record(filename string) {
	c1 := exec.Command("adb", "shell", "screenrecord", "--size 360x640", "--output-format=h264", "-")
	c2 := exec.Command("ffmpeg", "-i", "-", "-y", filename)

	r, w := io.Pipe()
	c1.Stdout = w
	c2.Stdin = r

	if err := c1.Start(); err != nil {
		log.Fatal(err)
	}
	if err := c2.Start(); err != nil {
		log.Fatal(err)
	}

	fmt.Println("Recording screen to", filename)
	fmt.Println("Press enter key to stop recording")

	bufio.NewReader(os.Stdin).ReadBytes('\n')

	c1.Process.Kill()
	w.Close()
	c2.Wait()
}
<commit_msg>Show error when output file is not specified<commit_after>package main

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"

	"gopkg.in/urfave/cli.v2"
)

func main() {
	app := cli.NewApp()
	app.Name = "andrec"
	app.Usage = "screen recorder for Android"
	app.Action = func(c *cli.Context) error {
		fmt.Println("boom! I say!")
		return nil
	}

	app.Action = func(c *cli.Context) error {
		if c.NArg() == 0 {
			log.Fatal("output file not found")
		}

		filename := c.Args().Get(0)
		record(filename)

		return nil
	}

	app.Run(os.Args)
}

func record(filename string) {
	c1 := exec.Command("adb", "shell", "screenrecord", "--size 360x640", "--output-format=h264", "-")
	c2 := exec.Command("ffmpeg", "-i", "-", "-y", filename)

	r, w := io.Pipe()
	c1.Stdout = w
	c2.Stdin = r

	if err := c1.Start(); err != nil {
		log.Fatal(err)
	}
	if err := c2.Start(); err != nil {
		log.Fatal(err)
	}

	fmt.Println("Recording screen to", filename)
	fmt.Println("Press enter key to stop recording")

	bufio.NewReader(os.Stdin).ReadBytes('\n')

	c1.Process.Kill()
	w.Close()
	c2.Wait()
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/termie/go-shutil"
	"gopkg.in/yaml.v2"
	"io/ioutil"
	"os"
	"path/filepath"
)

type snappyPackageMetaService struct {
	Name        string
	Description string
	Start       string
}

type snappyPackageMetaIntegration struct {
	AppArmorProfile string `yaml:"apparmor-profile"`
}

type snappyPackageMeta struct {
	Name         string
	Vendor       string
	Architecture string
	Version      string
	Icon         string
	Frameworks   string
	Services     []snappyPackageMetaService
	Integration  map[string]snappyPackageMetaIntegration `yaml:"integration,omitempty"`
}

func buildSnappyPackage(pkg *NinjaPackage, ctx *buildContext, arch string, arguments map[string]interface{}) {
	dockerCurr := filepath.Join(ctx.stagingDocker, "snappy-"+arch)
	stagingCurr := filepath.Join(ctx.stagingHost, "snappy-"+arch)
	os.MkdirAll(stagingCurr, 0750)

	metaCurr := filepath.Join(stagingCurr, "meta")
	os.MkdirAll(metaCurr, 0750)

	pkgSuffix := ""
	if ns := arguments["--snappy-namespace"]; ns != nil {
		pkgSuffix = "." + ns.(string)
	}

	if arch != "multi" {
		// binary itself
		binCurr := filepath.Join(stagingCurr, pkg.ShortName())
		shutil.Copy(ctx.archBinaries[arch], binCurr, false)

		// package.json
		srcFile := filepath.Join(pkg.BasePath, "package.json")
		pkgCurr := filepath.Join(stagingCurr, "package.json")
		shutil.Copy(srcFile, pkgCurr, true) // don't copy symlink itself, just the real file

		meta := &snappyPackageMeta{
			Name:         pkg.ShortName() + pkgSuffix,
			Vendor:       pkg.Author(),
			Architecture: arch,
			Version:      pkg.Version(),
			Icon:         "meta/null.svg",
			Frameworks:   "ninjasphere",
			Services: []snappyPackageMetaService{
				{
					Name:        pkg.ShortName(),
					Description: pkg.ShortName() + " service",
					Start:       "ninja-shim ./" + pkg.ShortName(),
				},
			},
			Integration: map[string]snappyPackageMetaIntegration{
				pkg.ShortName(): snappyPackageMetaIntegration{
					AppArmorProfile: "meta/" + pkg.ShortName() + ".profile",
				},
			},
		}

		metaBytes, err := yaml.Marshal(&meta)
		if err != nil {
			panic(err) // FIXME: meh
		}

		// meta/package.yaml
		metaPackageFile := filepath.Join(metaCurr, "package.yaml")
		ioutil.WriteFile(metaPackageFile, metaBytes, 0644)

		// meta/readme.md
		metaReadmeFile := filepath.Join(metaCurr, "readme.md")
		ioutil.WriteFile(metaReadmeFile, []byte(pkg.Description()), 0644)

		// meta/<pkg-name>.profile
		metaProfileFile := filepath.Join(metaCurr, pkg.ShortName()+".profile")
		ioutil.WriteFile(metaProfileFile, []byte(ninjaAppProfileRediculouslyPermissive), 0644)

		// ninja-shim
		stagingShimFile := filepath.Join(stagingCurr, "ninja-shim")
		ioutil.WriteFile(stagingShimFile, []byte(ninjaLaunchShim), 0755)

		// and all the files specified
		for _, fn := range pkg.PathsToCopy() {
			srcPath := filepath.Join(pkg.BasePath, fn)
			dstPath := filepath.Join(stagingCurr, fn)
			copyAnything(srcPath, dstPath)
		}

		runNativeDockerCommand(ctx.dockerVolumeArgs, "sh", "-c", "cd "+ctx.outputDocker+"; snappy build "+dockerCurr+"")
	} else {
		panic("Multi-arch snaps not supported yet, FIXME add shim wrapper here")
	}
}

func copyAnything(from string, to string) error {
	fromStat, err := os.Stat(from)
	if err != nil {
		return err
	}

	if fromStat.IsDir() {
		return shutil.CopyTree(from, to, nil)
	} else {
		_, err = shutil.Copy(from, to, true)
		return err
	}
}
<commit_msg>apply gofmt<commit_after>package main

import (
	"github.com/termie/go-shutil"
	"gopkg.in/yaml.v2"
	"io/ioutil"
	"os"
	"path/filepath"
)

type snappyPackageMetaService struct {
	Name        string
	Description string
	Start       string
}

type snappyPackageMetaIntegration struct {
	AppArmorProfile string `yaml:"apparmor-profile"`
}

type snappyPackageMeta struct {
	Name         string
	Vendor       string
	Architecture string
	Version      string
	Icon         string
	Frameworks   string
	Services     []snappyPackageMetaService
	Integration  map[string]snappyPackageMetaIntegration `yaml:"integration,omitempty"`
}

func buildSnappyPackage(pkg *NinjaPackage, ctx *buildContext, arch string, arguments map[string]interface{}) {
	dockerCurr := filepath.Join(ctx.stagingDocker, "snappy-"+arch)
	stagingCurr := filepath.Join(ctx.stagingHost, "snappy-"+arch)
	os.MkdirAll(stagingCurr, 0750)

	metaCurr := filepath.Join(stagingCurr, "meta")
	os.MkdirAll(metaCurr, 0750)

	pkgSuffix := ""
	if ns := arguments["--snappy-namespace"]; ns != nil {
		pkgSuffix = "." + ns.(string)
	}

	if arch != "multi" {
		// binary itself
		binCurr := filepath.Join(stagingCurr, pkg.ShortName())
		shutil.Copy(ctx.archBinaries[arch], binCurr, false)

		// package.json
		srcFile := filepath.Join(pkg.BasePath, "package.json")
		pkgCurr := filepath.Join(stagingCurr, "package.json")
		shutil.Copy(srcFile, pkgCurr, true) // don't copy symlink itself, just the real file

		meta := &snappyPackageMeta{
			Name:         pkg.ShortName() + pkgSuffix,
			Vendor:       pkg.Author(),
			Architecture: arch,
			Version:      pkg.Version(),
			Icon:         "meta/null.svg",
			Frameworks:   "ninjasphere",
			Services: []snappyPackageMetaService{
				{
					Name:        pkg.ShortName(),
					Description: pkg.ShortName() + " service",
					Start:       "ninja-shim ./" + pkg.ShortName(),
				},
			},
			Integration: map[string]snappyPackageMetaIntegration{
				pkg.ShortName(): {
					AppArmorProfile: "meta/" + pkg.ShortName() + ".profile",
				},
			},
		}

		metaBytes, err := yaml.Marshal(&meta)
		if err != nil {
			panic(err) // FIXME: meh
		}

		// meta/package.yaml
		metaPackageFile := filepath.Join(metaCurr, "package.yaml")
		ioutil.WriteFile(metaPackageFile, metaBytes, 0644)

		// meta/readme.md
		metaReadmeFile := filepath.Join(metaCurr, "readme.md")
		ioutil.WriteFile(metaReadmeFile, []byte(pkg.Description()), 0644)

		// meta/<pkg-name>.profile
		metaProfileFile := filepath.Join(metaCurr, pkg.ShortName()+".profile")
		ioutil.WriteFile(metaProfileFile, []byte(ninjaAppProfileRediculouslyPermissive), 0644)

		// ninja-shim
		stagingShimFile := filepath.Join(stagingCurr, "ninja-shim")
		ioutil.WriteFile(stagingShimFile, []byte(ninjaLaunchShim), 0755)

		// and all the files specified
		for _, fn := range pkg.PathsToCopy() {
			srcPath := filepath.Join(pkg.BasePath, fn)
			dstPath := filepath.Join(stagingCurr, fn)
			copyAnything(srcPath, dstPath)
		}

		runNativeDockerCommand(ctx.dockerVolumeArgs, "sh", "-c", "cd "+ctx.outputDocker+"; snappy build "+dockerCurr+"")
	} else {
		panic("Multi-arch snaps not supported yet, FIXME add shim wrapper here")
	}
}

func copyAnything(from string, to string) error {
	fromStat, err := os.Stat(from)
	if err != nil {
		return err
	}

	if fromStat.IsDir() {
		return shutil.CopyTree(from, to, nil)
	} else {
		_, err = shutil.Copy(from, to, true)
		return err
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"github.com/xeipuuv/gojsonschema"
)

type testCaseLoader struct {
	suits   []TestSuite
	rootDir string
}

func (s *testCaseLoader) loadDir(dir string) ([]TestSuite, error) {
	s.rootDir = dir
	err := filepath.Walk(dir, s.loadFile)
	if err != nil {
		return nil, err
	}

	return s.suits, nil
}

func (s *testCaseLoader) loadFile(path string, info os.FileInfo, err error) error {
	if err != nil {
		return nil
	}

	if info.IsDir() {
		return nil
	}

	if !strings.HasSuffix(info.Name(), ".json") {
		return nil
	}

	ok := isSuite(path)
	if !ok {
		return nil
	}

	err = validateSuite(path)
	if err != nil {
		fmt.Printf("Invalid suite file: %s\n%s\n", path, err.Error())
		return nil
	}

	debugMsgF("Process file: %s\n", info.Name())
	content, e := ioutil.ReadFile(path)

	if e != nil {
		debugMsgF("File error: %v\n", e)
		return filepath.SkipDir
	}

	var testCases []TestCase
	err = json.Unmarshal(content, &testCases)
	if err != nil {
		debugMsgF("Parse error: %v\n", err)
		return nil
	}

	dir, _ := filepath.Rel(s.rootDir, filepath.Dir(path))
	su := TestSuite{
		Name:  strings.TrimSuffix(info.Name(), filepath.Ext(info.Name())),
		Dir:   dir,
		Cases: testCases,
	}
	fmt.Printf("%v+\n", su)
	s.suits = append(s.suits, su)
	return nil
}

func isSuite(path string) bool {
	schemaLoader := gojsonschema.NewStringLoader(suiteShapeSchema)

	path, _ = filepath.Abs(path)
	documentLoader := gojsonschema.NewReferenceLoader("file:///" + path)

	result, err := gojsonschema.Validate(schemaLoader, documentLoader)
	if err != nil {
		return false
	}

	return result.Valid()
}

func validateSuite(path string) error {
	schemaLoader := gojsonschema.NewStringLoader(suiteDetailedSchema)

	path, _ = filepath.Abs(path)
	documentLoader := gojsonschema.NewReferenceLoader("file:///" + path)

	result, err := gojsonschema.Validate(schemaLoader, documentLoader)
	if err != nil {
		return err
	}

	if !result.Valid() {
		var msg string
		for _, desc := range result.Errors() {
			msg = fmt.Sprintf(msg+"%s\n", desc)
		}
		return errors.New(msg)
	}

	return nil
}

// used to detect suite
const suiteShapeSchema = `
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "array",
  "items": {
    "type": "object",
    "properties": {
      "description": {
        "type": "string"
      },
      "calls": {
        "type": "array"
      }
    },
    "required": [
      "description",
      "calls"
    ]
  }
}
`

// used to validate suite
const suiteDetailedSchema = `
{
	"$schema": "http://json-schema.org/draft-04/schema#",
	"type": "array",
	"items": {
		"type": "object",
		"properties": {
			"description": {
				"type": "string"
			},
			"calls": {
				"type": "array",
				"items": {
					"type": "object",
					"properties": {
						"on": {
							"type": "object",
							"properties": {
								"method": {
									"type": "string"
								},
								"url": {
									"type": "string"
								},
								"headers": {
									"type": "object"
								},
								"params": {
									"type": "object"
								}
							},
							"required": [
								"method",
								"url"
							]
						},
						"expect": {
							"type": "object",
							"properties": {
								"statusCode": {
									"type": "integer"
								},
								"contentType": {
									"type": "string"
								},
								"body": {
									"type": "object"
								}
							}
						}
					},
					"required": [
						"on",
						"expect"
					]
				}
			}
		},
		"required": [
			"calls"
		]
	}
}
`
<commit_msg>clean up<commit_after>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"github.com/xeipuuv/gojsonschema"
)

type testCaseLoader struct {
	suits   []TestSuite
	rootDir string
}

func (s *testCaseLoader) loadDir(dir string) ([]TestSuite, error) {
	s.rootDir = dir
	err := filepath.Walk(dir, s.loadFile)
	if err != nil {
		return nil, err
	}

	return s.suits, nil
}

func (s *testCaseLoader) loadFile(path string, info os.FileInfo, err error) error {
	if err != nil {
		return nil
	}

	if info.IsDir() {
		return nil
	}

	if !strings.HasSuffix(info.Name(), ".json") {
		return nil
	}

	ok := isSuite(path)
	if !ok {
		return nil
	}

	err = validateSuite(path)
	if err != nil {
		fmt.Printf("Invalid suite file: %s\n%s\n", path, err.Error())
		return nil
	}

	debugMsgF("Process file: %s\n", info.Name())
	content, e := ioutil.ReadFile(path)

	if e != nil {
		debugMsgF("File error: %v\n", e)
		return filepath.SkipDir
	}

	var testCases []TestCase
	err = json.Unmarshal(content, &testCases)
	if err != nil {
		debugMsgF("Parse error: %v\n", err)
		return nil
	}

	dir, _ := filepath.Rel(s.rootDir, filepath.Dir(path))
	su := TestSuite{
		Name:  strings.TrimSuffix(info.Name(), filepath.Ext(info.Name())),
		Dir:   dir,
		Cases: testCases,
	}
	s.suits = append(s.suits, su)
	return nil
}

func isSuite(path string) bool {
	schemaLoader := gojsonschema.NewStringLoader(suiteShapeSchema)

	path, _ = filepath.Abs(path)
	documentLoader := gojsonschema.NewReferenceLoader("file:///" + path)

	result, err := gojsonschema.Validate(schemaLoader, documentLoader)
	if err != nil {
		return false
	}

	return result.Valid()
}

func validateSuite(path string) error {
	schemaLoader := gojsonschema.NewStringLoader(suiteDetailedSchema)

	path, _ = filepath.Abs(path)
	documentLoader := gojsonschema.NewReferenceLoader("file:///" + path)

	result, err := gojsonschema.Validate(schemaLoader, documentLoader)
	if err != nil {
		return err
	}

	if !result.Valid() {
		var msg string
		for _, desc := range result.Errors() {
			msg = fmt.Sprintf(msg+"%s\n", desc)
		}
		return errors.New(msg)
	}

	return nil
}

// used to detect suite
const suiteShapeSchema = `
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "array",
  "items": {
    "type": "object",
    "properties": {
      "description": {
        "type": "string"
      },
      "calls": {
        "type": "array"
      }
    },
    "required": [
      "description",
      "calls"
    ]
  }
}
`

// used to validate suite
const suiteDetailedSchema = `
{
	"$schema": "http://json-schema.org/draft-04/schema#",
	"type": "array",
	"items": {
		"type": "object",
		"properties": {
			"description": {
				"type": "string"
			},
			"calls": {
				"type": "array",
				"items": {
					"type": "object",
					"properties": {
						"on": {
							"type": "object",
							"properties": {
								"method": {
									"type": "string"
								},
								"url": {
									"type": "string"
								},
								"headers": {
									"type": "object"
								},
								"params": {
									"type": "object"
								}
							},
							"required": [
								"method",
								"url"
							]
						},
						"expect": {
							"type": "object",
							"properties": {
								"statusCode": {
									"type": "integer"
								},
								"contentType": {
									"type": "string"
								},
								"body": {
									"type": "object"
								}
							}
						}
					},
					"required": [
						"on",
						"expect"
					]
				}
			}
		},
		"required": [
			"calls"
		]
	}
}
`
<|endoftext|>


<commit_before>package consensus

import (
	"errors"
	"math/big"
)

var (
	ErrOverflow = errors.New("Currency overflowed 128 bits")
)

// A Currency is a 128-bit unsigned integer. Currency operations are performed
// via math/big.
//
// The Currency object also keeps track of whether an overflow has occurred
// during arithmetic operations. Once the 'overflow' flag has been set to
// true, all subsequent operations will return an error, and the result of the
// operation is undefined. This flag can never be reset; a new Currency must
// be created. Callers can also manually check for overflow using the Overflow
// method.
//
// TODO: Find better names for the currency variables.
type Currency struct {
	i  big.Int
	of bool // has an overflow ever occurred?
}

func NewCurrency(b *big.Int) (c Currency, err error) {
	if b.BitLen() > 128 || b.Sign() < 0 {
		c.of = true
		err = ErrOverflow
		return
	}
	c.i = *b
	return
}

func NewCurrency64(x uint64) Currency {
	// no possibility of error
	c, _ := NewCurrency(new(big.Int).SetUint64(x))
	return c
}

func (c *Currency) SetBig(b *big.Int) (err error) {
	oldOF := c.of
	*c, err = NewCurrency(b)
	c.of = c.of || oldOF // preserve overflow flag
	return
}

func (c *Currency) Big() *big.Int {
	return &c.i
}

func (c *Currency) Add(y Currency) error {
	if c.of {
		return ErrOverflow
	}
	return c.SetBig(c.i.Add(&c.i, &y.i))
}

func (c *Currency) Sub(y Currency) error {
	if c.of {
		return ErrOverflow
	}
	return c.SetBig(c.i.Sub(&c.i, &y.i))
}

func (c *Currency) Mul(y Currency) error {
	if c.of {
		return ErrOverflow
	}
	return c.SetBig(c.i.Mul(&c.i, &y.i))
}

func (c *Currency) MulFloat(x float64) (err error) {
	if c.of {
		return ErrOverflow
	}

	cBig := c.Big()
	cRat := new(big.Rat).SetInt(cBig)
	xRat := new(big.Rat).SetFloat64(x)
	cRat.Mul(cRat, xRat)
	*c, err = NewCurrency(c.Big().Div(cRat.Num(), cRat.Denom()))
	if err != nil {
		return
	}
	return
}

func (c *Currency) Div(y Currency) error {
	if c.of {
		return ErrOverflow
	}
	return c.SetBig(c.i.Div(&c.i, &y.i))
}

func (c *Currency) Sqrt() *Currency {
	f, _ := new(big.Rat).SetInt(&c.i).Float64()
	rat := new(big.Rat).SetFloat64(f)
	s, _ := NewCurrency(new(big.Int).Div(rat.Num(), rat.Denom()))
	s.of = c.of // preserve overflow
	return &s
}

func (c *Currency) RoundDown(nearest int64) error {
	if c.of {
		return ErrOverflow
	}
	round := big.NewInt(nearest)
	c.i.Div(&c.i, round)
	c.i.Mul(&c.i, round)
	return nil
}

func (c *Currency) IsZero() bool {
	return c.i.Sign() == 0
}

func (c *Currency) Cmp(y Currency) int {
	return c.i.Cmp(&y.i)
}

func (c *Currency) Overflow() bool {
	return c.of
}

func (c Currency) MarshalSia() []byte {
	b := make([]byte, 16)
	copy(b, c.i.Bytes())
	return b
}

func (c *Currency) UnmarshalSia(b []byte) int {
	var err error
	*c, err = NewCurrency(new(big.Int).SetBytes(b[:16]))
	if err != nil {
		return -1
	}
	return 16
}
<commit_msg>remove size restriction from Currency<commit_after>package consensus

import (
	"math"
	"math/big"
)

// A Currency represents a number of siacoins or siafunds. Internally, a
// Currency value is unbounded; however, Currency values sent over the wire
// protocol are subject to a maximum size of 255 bytes (approximately 10^614).
// Unlike the math/big library, whose methods modify their receiver, all
// arithmetic Currency methods return a new value. This is necessary to
// preserve the immutability of types containing Currency fields.
type Currency struct {
	i big.Int
}

func NewCurrency(b *big.Int) (c Currency) {
	c.i = *b
	return
}

func NewCurrency64(x uint64) (c Currency) {
	c.i.SetUint64(x)
	return
}

func (c *Currency) Big() *big.Int {
	return &c.i
}

func (c *Currency) Cmp(y Currency) int {
	return c.i.Cmp(&y.i)
}

func (c *Currency) IsZero() bool {
	return c.i.Sign() == 0
}

func (c *Currency) Add(x Currency) (y Currency) {
	y.i.Add(&c.i, &x.i)
	return
}

func (c *Currency) Sub(x Currency) (y Currency) {
	y.i.Sub(&c.i, &x.i)
	return
}

func (c *Currency) Mul(x Currency) (y Currency) {
	y.i.Mul(&c.i, &x.i)
	return
}

func (c *Currency) Div(x Currency) (y Currency) {
	y.i.Div(&c.i, &x.i)
	return
}

func (c *Currency) MulFloat(x float64) (y Currency) {
	yRat := new(big.Rat).Mul(
		new(big.Rat).SetInt(&c.i),
		new(big.Rat).SetFloat64(x),
	)
	y.i.Div(yRat.Num(), yRat.Denom())
	return
}

func (c *Currency) Sqrt() (y Currency) {
	f, _ := new(big.Rat).SetInt(&c.i).Float64()
	sqrt := new(big.Rat).SetFloat64(math.Sqrt(f))
	y.i.Div(sqrt.Num(), sqrt.Denom())
	return
}

func (c *Currency) RoundDown(nearest int64) error {
	round := big.NewInt(nearest)
	c.i.Div(&c.i, round)
	c.i.Mul(&c.i, round)
	return nil
}

// MarshalSia implements the encoding.SiaMarshaler interface. It returns the
// byte-slice representation of the Currency's internal big.Int, prepended
// with a single byte indicating the length of the slice. This implies a
// maximum encodable value of 2^(255 * 8), or approximately 10^614.
//
// Note that as the bytes of the big.Int correspond to the absolute value of
// the integer, there is no way to marshal a negative Currency.
func (c Currency) MarshalSia() []byte {
	b := c.i.Bytes()
	return append(
		[]byte{byte(len(b))},
		b...,
	)
}

// UnmarshalSia implements the encoding.SiaUnmarshaler interface. See
// MarshalSia for a description of how Currency values are marshalled.
func (c *Currency) UnmarshalSia(b []byte) int {
	var n int
	n, b = int(b[0]), b[1:]
	c.i.SetBytes(b[:n])
	return 1 + n
}
<|endoftext|>


<commit_before>package nsenter

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"
	"testing"

	"github.com/opencontainers/runc/libcontainer"
	"github.com/vishvananda/netlink/nl"
	"golang.org/x/sys/unix"
)

type pid struct {
	Pid int `json:"Pid"`
}

type logentry struct {
	Msg   string `json:"msg"`
	Level string `json:"level"`
}

func TestNsenterValidPaths(t *testing.T) {
	args := []string{"nsenter-exec"}
	parent, child, err := newPipe()
	if err != nil {
		t.Fatalf("failed to create pipe %v", err)
	}

	namespaces := []string{
		// join pid ns of the current process
		fmt.Sprintf("pid:/proc/%d/ns/pid", os.Getpid()),
	}
	cmd := &exec.Cmd{
		Path:       os.Args[0],
		Args:       args,
		ExtraFiles: []*os.File{child},
		Env:        []string{"_LIBCONTAINER_INITPIPE=3"},
		Stdout:     os.Stdout,
		Stderr:     os.Stderr,
	}

	if err := cmd.Start(); err != nil {
		t.Fatalf("nsenter failed to start %v", err)
	}

	// write cloneFlags
	r := nl.NewNetlinkRequest(int(libcontainer.InitMsg), 0)
	r.AddData(&libcontainer.Int32msg{
		Type:  libcontainer.CloneFlagsAttr,
		Value: uint32(unix.CLONE_NEWNET),
	})
	r.AddData(&libcontainer.Bytemsg{
		Type:  libcontainer.NsPathsAttr,
		Value: []byte(strings.Join(namespaces, ",")),
	})
	if _, err := io.Copy(parent, bytes.NewReader(r.Serialize())); err != nil {
		t.Fatal(err)
	}

	initWaiter(t, parent)

	decoder := json.NewDecoder(parent)
	var pid *pid

	if err := cmd.Wait(); err != nil {
		t.Fatalf("nsenter exits with a non-zero exit status")
	}
	if err := decoder.Decode(&pid); err != nil {
		dir, _ := ioutil.ReadDir(fmt.Sprintf("/proc/%d/ns", os.Getpid()))
		for _, d := range dir {
			t.Log(d.Name())
		}
		t.Fatalf("%v", err)
	}

	p, err := os.FindProcess(pid.Pid)
	if err != nil {
		t.Fatalf("%v", err)
	}
	_, _ = p.Wait()
}

func TestNsenterInvalidPaths(t *testing.T) {
	args := []string{"nsenter-exec"}
	parent, child, err := newPipe()
	if err != nil {
		t.Fatalf("failed to create pipe %v", err)
	}

	namespaces := []string{
		// join pid ns of the current process
		fmt.Sprintf("pid:/proc/%d/ns/pid", -1),
	}
	cmd := &exec.Cmd{
		Path:       os.Args[0],
		Args:       args,
		ExtraFiles: []*os.File{child},
		Env:        []string{"_LIBCONTAINER_INITPIPE=3"},
	}

	if err := cmd.Start(); err != nil {
		t.Fatal(err)
	}
	// write cloneFlags
	r := nl.NewNetlinkRequest(int(libcontainer.InitMsg), 0)
	r.AddData(&libcontainer.Int32msg{
		Type:  libcontainer.CloneFlagsAttr,
		Value: uint32(unix.CLONE_NEWNET),
	})
	r.AddData(&libcontainer.Bytemsg{
		Type:  libcontainer.NsPathsAttr,
		Value: []byte(strings.Join(namespaces, ",")),
	})
	if _, err := io.Copy(parent, bytes.NewReader(r.Serialize())); err != nil {
		t.Fatal(err)
	}

	initWaiter(t, parent)
	if err := cmd.Wait(); err == nil {
		t.Fatalf("nsenter exits with a zero exit status")
	}
}

func TestNsenterIncorrectPathType(t *testing.T) {
	args := []string{"nsenter-exec"}
	parent, child, err := newPipe()
	if err != nil {
		t.Fatalf("failed to create pipe %v", err)
	}

	namespaces := []string{
		// join pid ns of the current process
		fmt.Sprintf("net:/proc/%d/ns/pid", os.Getpid()),
	}
	cmd := &exec.Cmd{
		Path:       os.Args[0],
		Args:       args,
		ExtraFiles: []*os.File{child},
		Env:        []string{"_LIBCONTAINER_INITPIPE=3"},
	}

	if err := cmd.Start(); err != nil {
		t.Fatal(err)
	}
	// write cloneFlags
	r := nl.NewNetlinkRequest(int(libcontainer.InitMsg), 0)
	r.AddData(&libcontainer.Int32msg{
		Type:  libcontainer.CloneFlagsAttr,
		Value: uint32(unix.CLONE_NEWNET),
	})
	r.AddData(&libcontainer.Bytemsg{
		Type:  libcontainer.NsPathsAttr,
		Value: []byte(strings.Join(namespaces, ",")),
	})
	if _, err := io.Copy(parent, bytes.NewReader(r.Serialize())); err != nil {
		t.Fatal(err)
	}

	initWaiter(t, parent)
	if err := cmd.Wait(); err == nil {
		t.Fatalf("nsenter exits with a zero exit status")
	}
}

func TestNsenterChildLogging(t *testing.T) {
	args := []string{"nsenter-exec"}
	parent, child, err := newPipe()
	if err != nil {
		t.Fatalf("failed to create exec pipe %v", err)
	}
	logread, logwrite, err := os.Pipe()
	if err != nil {
		t.Fatalf("failed to create log pipe %v", err)
	}
	defer func() {
		_ = logwrite.Close()
		_ = logread.Close()
	}()

	namespaces := []string{
		// join pid ns of the current process
		fmt.Sprintf("pid:/proc/%d/ns/pid", os.Getpid()),
	}
	cmd := &exec.Cmd{
		Path:       os.Args[0],
		Args:       args,
		ExtraFiles: []*os.File{child, logwrite},
		Env:        []string{"_LIBCONTAINER_INITPIPE=3", "_LIBCONTAINER_LOGPIPE=4"},
		Stdout:     os.Stdout,
		Stderr:     os.Stderr,
	}

	if err := cmd.Start(); err != nil {
		t.Fatalf("nsenter failed to start %v", err)
	}
	// write cloneFlags
	r := nl.NewNetlinkRequest(int(libcontainer.InitMsg), 0)
	r.AddData(&libcontainer.Int32msg{
		Type:  libcontainer.CloneFlagsAttr,
		Value: uint32(unix.CLONE_NEWNET),
	})
	r.AddData(&libcontainer.Bytemsg{
		Type:  libcontainer.NsPathsAttr,
		Value: []byte(strings.Join(namespaces, ",")),
	})
	if _, err := io.Copy(parent, bytes.NewReader(r.Serialize())); err != nil {
		t.Fatal(err)
	}

	initWaiter(t, parent)

	logsDecoder := json.NewDecoder(logread)
	var logentry *logentry

	err = logsDecoder.Decode(&logentry)
	if err != nil {
		t.Fatalf("child log: %v", err)
	}
	if logentry.Level == "" || logentry.Msg == "" {
		t.Fatalf("child log: empty log fields: level=\"%s\" msg=\"%s\"", logentry.Level, logentry.Msg)
	}

	if err := cmd.Wait(); err != nil {
		t.Fatalf("nsenter exits with a non-zero exit status")
	}
}

func init() {
	if strings.HasPrefix(os.Args[0], "nsenter-") {
		os.Exit(0)
	}
}

func newPipe() (parent *os.File, child *os.File, err error) {
	fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_STREAM|unix.SOCK_CLOEXEC, 0)
	if err != nil {
		return nil, nil, err
	}
	return os.NewFile(uintptr(fds[1]), "parent"), os.NewFile(uintptr(fds[0]), "child"), nil
}

// initWaiter reads back the initial \0 from runc init
func initWaiter(t *testing.T, r io.Reader) {
	inited := make([]byte, 1)
	n, err := r.Read(inited)
	if err == nil {
		if n < 1 {
			err = errors.New("short read")
		} else if inited[0] != 0 {
			err = fmt.Errorf("unexpected %d != 0", inited[0])
		} else {
			return
		}
	}
	t.Fatalf("waiting for init preliminary setup: %v", err)
}
<commit_msg>libct/nsenter: test: improve newPipe<commit_after>package nsenter

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"
	"testing"

	"github.com/opencontainers/runc/libcontainer"
	"github.com/vishvananda/netlink/nl"
	"golang.org/x/sys/unix"
)

type pid struct {
	Pid int `json:"Pid"`
}

type logentry struct {
	Msg   string `json:"msg"`
	Level string `json:"level"`
}

func TestNsenterValidPaths(t *testing.T) {
	args := []string{"nsenter-exec"}
	parent, child := newPipe(t)

	namespaces := []string{
		// join pid ns of the current process
		fmt.Sprintf("pid:/proc/%d/ns/pid", os.Getpid()),
	}
	cmd := &exec.Cmd{
		Path:       os.Args[0],
		Args:       args,
		ExtraFiles: []*os.File{child},
		Env:        []string{"_LIBCONTAINER_INITPIPE=3"},
		Stdout:     os.Stdout,
		Stderr:     os.Stderr,
	}

	if err := cmd.Start(); err != nil {
		t.Fatalf("nsenter failed to start %v", err)
	}
	child.Close()

	// write cloneFlags
	r := nl.NewNetlinkRequest(int(libcontainer.InitMsg), 0)
	r.AddData(&libcontainer.Int32msg{
		Type:  libcontainer.CloneFlagsAttr,
		Value: uint32(unix.CLONE_NEWNET),
	})
	r.AddData(&libcontainer.Bytemsg{
		Type:  libcontainer.NsPathsAttr,
		Value: []byte(strings.Join(namespaces, ",")),
	})
	if _, err := io.Copy(parent, bytes.NewReader(r.Serialize())); err != nil {
		t.Fatal(err)
	}

	initWaiter(t, parent)

	decoder := json.NewDecoder(parent)
	var pid *pid

	if err := cmd.Wait(); err != nil {
		t.Fatalf("nsenter exits with a non-zero exit status")
	}
	if err := decoder.Decode(&pid); err != nil {
		dir, _ := ioutil.ReadDir(fmt.Sprintf("/proc/%d/ns", os.Getpid()))
		for _, d := range dir {
			t.Log(d.Name())
		}
		t.Fatalf("%v", err)
	}

	p, err := os.FindProcess(pid.Pid)
	if err != nil {
		t.Fatalf("%v", err)
	}
	_, _ = p.Wait()
}

func TestNsenterInvalidPaths(t *testing.T) {
	args := []string{"nsenter-exec"}
	parent, child := newPipe(t)

	namespaces := []string{
		// join pid ns of the current process
		fmt.Sprintf("pid:/proc/%d/ns/pid", -1),
	}
	cmd := &exec.Cmd{
		Path:       os.Args[0],
		Args:       args,
		ExtraFiles: []*os.File{child},
		Env:        []string{"_LIBCONTAINER_INITPIPE=3"},
	}

	if err := cmd.Start(); err != nil {
		t.Fatal(err)
	}
	child.Close()

	// write cloneFlags
	r := nl.NewNetlinkRequest(int(libcontainer.InitMsg), 0)
	r.AddData(&libcontainer.Int32msg{
		Type:  libcontainer.CloneFlagsAttr,
		Value: uint32(unix.CLONE_NEWNET),
	})
	r.AddData(&libcontainer.Bytemsg{
		Type:  libcontainer.NsPathsAttr,
		Value: []byte(strings.Join(namespaces, ",")),
	})
	if _, err := io.Copy(parent, bytes.NewReader(r.Serialize())); err != nil {
		t.Fatal(err)
	}

	initWaiter(t, parent)
	if err := cmd.Wait(); err == nil {
		t.Fatalf("nsenter exits with a zero exit status")
	}
}

func TestNsenterIncorrectPathType(t *testing.T) {
	args := []string{"nsenter-exec"}
	parent, child := newPipe(t)

	namespaces := []string{
		// join pid ns of the current process
		fmt.Sprintf("net:/proc/%d/ns/pid", os.Getpid()),
	}
	cmd := &exec.Cmd{
		Path:       os.Args[0],
		Args:       args,
		ExtraFiles: []*os.File{child},
		Env:        []string{"_LIBCONTAINER_INITPIPE=3"},
	}

	if err := cmd.Start(); err != nil {
		t.Fatal(err)
	}
	child.Close()

	// write cloneFlags
	r := nl.NewNetlinkRequest(int(libcontainer.InitMsg), 0)
	r.AddData(&libcontainer.Int32msg{
		Type:  libcontainer.CloneFlagsAttr,
		Value: uint32(unix.CLONE_NEWNET),
	})
	r.AddData(&libcontainer.Bytemsg{
		Type:  libcontainer.NsPathsAttr,
		Value: []byte(strings.Join(namespaces, ",")),
	})
	if _, err := io.Copy(parent, bytes.NewReader(r.Serialize())); err != nil {
		t.Fatal(err)
	}

	initWaiter(t, parent)
	if err := cmd.Wait(); err == nil {
		t.Fatalf("nsenter exits with a zero exit status")
	}
}

func TestNsenterChildLogging(t *testing.T) {
	args := []string{"nsenter-exec"}
	parent, child := newPipe(t)
	logread, logwrite := newPipe(t)

	namespaces := []string{
		// join pid ns of the current process
		fmt.Sprintf("pid:/proc/%d/ns/pid", os.Getpid()),
	}
	cmd := &exec.Cmd{
		Path:       os.Args[0],
		Args:       args,
		ExtraFiles: []*os.File{child, logwrite},
		Env:        []string{"_LIBCONTAINER_INITPIPE=3", "_LIBCONTAINER_LOGPIPE=4"},
		Stdout:     os.Stdout,
		Stderr:     os.Stderr,
	}

	if err := cmd.Start(); err != nil {
		t.Fatalf("nsenter failed to start %v", err)
	}
	child.Close()
	logwrite.Close()

	// write cloneFlags
	r := nl.NewNetlinkRequest(int(libcontainer.InitMsg), 0)
	r.AddData(&libcontainer.Int32msg{
		Type:  libcontainer.CloneFlagsAttr,
		Value: uint32(unix.CLONE_NEWNET),
	})
	r.AddData(&libcontainer.Bytemsg{
		Type:  libcontainer.NsPathsAttr,
		Value: []byte(strings.Join(namespaces, ",")),
	})
	if _, err := io.Copy(parent, bytes.NewReader(r.Serialize())); err != nil {
		t.Fatal(err)
	}

	initWaiter(t, parent)

	logsDecoder := json.NewDecoder(logread)
	var logentry *logentry

	err := logsDecoder.Decode(&logentry)
	if err != nil {
		t.Fatalf("child log: %v", err)
	}
	if logentry.Level == "" || logentry.Msg == "" {
		t.Fatalf("child log: empty log fields: level=\"%s\" msg=\"%s\"", logentry.Level, logentry.Msg)
	}

	if err := cmd.Wait(); err != nil {
		t.Fatalf("nsenter exits with a non-zero exit status")
	}
}

func init() {
	if strings.HasPrefix(os.Args[0], "nsenter-") {
		os.Exit(0)
	}
}

func newPipe(t *testing.T) (parent *os.File, child *os.File) {
	t.Helper()
	fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_STREAM|unix.SOCK_CLOEXEC, 0)
	if err != nil {
		t.Fatal("socketpair failed:", err)
	}
	parent = os.NewFile(uintptr(fds[1]), "parent")
	child = os.NewFile(uintptr(fds[0]), "child")
	t.Cleanup(func() {
		parent.Close()
		child.Close()
	})
	return
}

// initWaiter reads back the initial \0 from runc init
func initWaiter(t *testing.T, r io.Reader) {
	inited := make([]byte, 1)
	n, err := r.Read(inited)
	if err == nil {
		if n < 1 {
			err = errors.New("short read")
		} else if inited[0] != 0 {
			err = fmt.Errorf("unexpected %d != 0", inited[0])
		} else {
			return
		}
	}
	t.Fatalf("waiting for init preliminary setup: %v", err)
}
<|endoftext|>


<commit_before>package testerator

import (
	"os"
	"runtime"
	"sync"

	"golang.org/x/net/context"
	"google.golang.org/appengine"
	"google.golang.org/appengine/aetest"
)

type Helper func(s *Setup) error

type Setup struct {
	Instance       aetest.Instance
	Context        context.Context
	counter        int
	Setuppers      []Helper
	Cleaners       []Helper
	total          int
	ResetThreshold int
	SpinDowns      []chan struct{}

	sync.Mutex
}

var DefaultSetup *Setup

func init() {
	runtime.GOMAXPROCS(runtime.NumCPU())
	DefaultSetup = &Setup{}
}

func SpinUp() (aetest.Instance, context.Context, error) {
	err := DefaultSetup.SpinUp()
	return DefaultSetup.Instance, DefaultSetup.Context, err
}

func SpinDown() error {
	return DefaultSetup.SpinDown()
}

func IsCI() bool {
	return os.Getenv("CI") != ""
}

func (s *Setup) SpinUp() error {
	s.Lock()
	defer s.Unlock()

	if s.ResetThreshold == 0 {
		s.ResetThreshold = 15
	}

	s.total++
	s.counter++

	if s.Instance != nil {
		return nil
	}

	opt := &aetest.Options{AppID: "unittest", StronglyConsistentDatastore: true}
	inst, err := aetest.NewInstance(opt)
	if err != nil {
		return err
	}
	req, err := inst.NewRequest("GET", "/", nil)
	if err != nil {
		return err
	}

	c := appengine.NewContext(req)

	if err != nil {
		return err
	}

	s.Instance = inst
	s.Context = c

	for _, setupper := range s.Setuppers {
		err = setupper(s)
		if err != nil {
			return err
		}
	}

	return nil
}

func (s *Setup) SpinDown() error {
	s.Lock()
	defer s.Unlock()
	defer func() {
		if s.counter == 0 {
			for _, sd := range s.SpinDowns {
				<-sd
			}
			s.SpinDowns = nil
		}
	}()
	defer func() {
		if s.Instance == nil {
			return
		}

		closeInstane := func() {
			ch := make(chan struct{})
			s.SpinDowns = append(s.SpinDowns, ch)
			go func(inst aetest.Instance) {
				defer func() {
					ch <- struct{}{}
				}()
				inst.Close()
			}(s.Instance)
		}

		if s.counter == 0 {
			closeInstane()
			s.Instance = nil
		} else if s.total%s.ResetThreshold == 0 {
			// Sometimes spin down causes. avoid to saturate file descriptor.
			closeInstane()
			s.Instance = nil
		}
	}()

	s.counter--

	if s.counter == 0 {
		// server spin downed.
		return nil
	}

	// clean up environment
	for _, c := range s.Cleaners {
		err := c(s)
		if err != nil {
			return err
		}
	}

	return nil
}
<commit_msg>fix typo<commit_after>package testerator

import (
	"os"
	"runtime"
	"sync"

	"golang.org/x/net/context"
	"google.golang.org/appengine"
	"google.golang.org/appengine/aetest"
)

type Helper func(s *Setup) error

type Setup struct {
	Instance       aetest.Instance
	Context        context.Context
	counter        int
	Setuppers      []Helper
	Cleaners       []Helper
	total          int
	ResetThreshold int
	SpinDowns      []chan struct{}

	sync.Mutex
}

var DefaultSetup *Setup

func init() {
	runtime.GOMAXPROCS(runtime.NumCPU())
	DefaultSetup = &Setup{}
}

func SpinUp() (aetest.Instance, context.Context, error) {
	err := DefaultSetup.SpinUp()
	return DefaultSetup.Instance, DefaultSetup.Context, err
}

func SpinDown() error {
	return DefaultSetup.SpinDown()
}

func IsCI() bool {
	return os.Getenv("CI") != ""
}

func (s *Setup) SpinUp() error {
	s.Lock()
	defer s.Unlock()

	if s.ResetThreshold == 0 {
		s.ResetThreshold = 15
	}

	s.total++
	s.counter++

	if s.Instance != nil {
		return nil
	}

	opt := &aetest.Options{AppID: "unittest", StronglyConsistentDatastore: true}
	inst, err := aetest.NewInstance(opt)
	if err != nil {
		return err
	}
	req, err := inst.NewRequest("GET", "/", nil)
	if err != nil {
		return err
	}

	c := appengine.NewContext(req)

	if err != nil {
		return err
	}

	s.Instance = inst
	s.Context = c

	for _, setupper := range s.Setuppers {
		err = setupper(s)
		if err != nil {
			return err
		}
	}

	return nil
}

func (s *Setup) SpinDown() error {
	s.Lock()
	defer s.Unlock()
	defer func() {
		if s.counter == 0 {
			for _, sd := range s.SpinDowns {
				<-sd
			}
			s.SpinDowns = nil
		}
	}()
	defer func() {
		if s.Instance == nil {
			return
		}

		closeInstance := func() {
			ch := make(chan struct{})
			s.SpinDowns = append(s.SpinDowns, ch)
			go func(inst aetest.Instance) {
				defer func() {
					ch <- struct{}{}
				}()
				inst.Close()
			}(s.Instance)
		}

		if s.counter == 0 {
			closeInstance()
			s.Instance = nil
		} else if s.total%s.ResetThreshold == 0 {
			// Sometimes spin down causes. avoid to saturate file descriptor.
			closeInstance()
			s.Instance = nil
		}
	}()

	s.counter--

	if s.counter == 0 {
		// server spin downed.
		return nil
	}

	// clean up environment
	for _, c := range s.Cleaners {
		err := c(s)
		if err != nil {
			return err
		}
	}

	return nil
}
<|endoftext|>


<commit_before>// +build linux

package selinux_test

import (
	"os"
	"testing"

	"github.com/opencontainers/runc/libcontainer/selinux"
)

func testSetfilecon(t *testing.T) {
	if selinux.SelinuxEnabled() {
		tmp := "selinux_test"
		out, _ := os.OpenFile(tmp, os.O_WRONLY, 0)
		out.Close()
		err := selinux.Setfilecon(tmp, "system_u:object_r:bin_t:s0")
		if err != nil {
			t.Log("Setfilecon failed")
			t.Fatal(err)
		}
		os.Remove(tmp)
	}
}

func TestSELinux(t *testing.T) {
	var (
		err            error
		plabel, flabel string
	)

	if selinux.SelinuxEnabled() {
		t.Log("Enabled")
		plabel, flabel = selinux.GetLxcContexts()
		t.Log(plabel)
		t.Log(flabel)
		selinux.FreeLxcContexts(plabel)
		plabel, flabel = selinux.GetLxcContexts()
		t.Log(plabel)
		t.Log(flabel)
		selinux.FreeLxcContexts(plabel)
		t.Log("getenforce ", selinux.SelinuxGetEnforce())
		t.Log("getenforcemode ", selinux.SelinuxGetEnforceMode())
		pid := os.Getpid()
		t.Logf("PID:%d MCS:%s\n", pid, selinux.IntToMcs(pid, 1023))
		err = selinux.Setfscreatecon("unconfined_u:unconfined_r:unconfined_t:s0")
		if err == nil {
			t.Log(selinux.Getfscreatecon())
		} else {
			t.Log("setfscreatecon failed", err)
			t.Fatal(err)
		}
		err = selinux.Setfscreatecon("")
		if err == nil {
			t.Log(selinux.Getfscreatecon())
		} else {
			t.Log("setfscreatecon failed", err)
			t.Fatal(err)
		}
		t.Log(selinux.Getpidcon(1))
	} else {
		t.Log("Disabled")
	}
}
<commit_msg>Adding selinux label<commit_after>// +build linux,selinux

package selinux_test

import (
	"os"
	"testing"

	"github.com/opencontainers/runc/libcontainer/selinux"
)

func testSetfilecon(t *testing.T) {
	if selinux.SelinuxEnabled() {
		tmp := "selinux_test"
		out, _ := os.OpenFile(tmp, os.O_WRONLY, 0)
		out.Close()
		err := selinux.Setfilecon(tmp, "system_u:object_r:bin_t:s0")
		if err != nil {
			t.Log("Setfilecon failed")
			t.Fatal(err)
		}
		os.Remove(tmp)
	}
}

func TestSELinux(t *testing.T) {
	var (
		err            error
		plabel, flabel string
	)

	if selinux.SelinuxEnabled() {
		t.Log("Enabled")
		plabel, flabel = selinux.GetLxcContexts()
		t.Log(plabel)
		t.Log(flabel)
		selinux.FreeLxcContexts(plabel)
		plabel, flabel = selinux.GetLxcContexts()
		t.Log(plabel)
		t.Log(flabel)
		selinux.FreeLxcContexts(plabel)
		t.Log("getenforce ", selinux.SelinuxGetEnforce())
		t.Log("getenforcemode ", selinux.SelinuxGetEnforceMode())
		pid := os.Getpid()
		t.Logf("PID:%d MCS:%s\n", pid, selinux.IntToMcs(pid, 1023))
		err = selinux.Setfscreatecon("unconfined_u:unconfined_r:unconfined_t:s0")
		if err == nil {
			t.Log(selinux.Getfscreatecon())
		} else {
			t.Log("setfscreatecon failed", err)
			t.Fatal(err)
		}
		err = selinux.Setfscreatecon("")
		if err == nil {
			t.Log(selinux.Getfscreatecon())
		} else {
			t.Log("setfscreatecon failed", err)
			t.Fatal(err)
		}
		t.Log(selinux.Getpidcon(1))
	} else {
		t.Log("Disabled")
	}
}
<|endoftext|>


<commit_before>package sdiscovery

import (
	"bytes"
	"net"
	"testing"
	"time"
)

// Test the broadcastAddress function
func Test_broadcastAddressFromCIDR(t *testing.T) {

	var ip net.IP
	var err error

	// Obtain the broadcast address for the provided CIDR
	if ip, err = broadcastAddressFromCIDR("192.168.1.1/24"); err != nil {
		t.Fatal(err)
	}

	// Ensure that the IP addresses match
	if !bytes.Equal(ip, net.IP{192, 168, 1, 255}) {
		t.Fatal("IP addresses do not match")
	}

	// Ensure that an error is generated for an IPv6 address
	if ip, err = broadcastAddressFromCIDR("::1/128"); err == nil {
		t.Fatal("Expected error for IPv6 address")
	}
}

// Testing the findBroadcastAddress function is virtually impossible since
// there is no way (AFAIK) to simulate an interface for testing

// Attempt to find an interface with the specified flag
func findInterfaceWithFlag(flag net.Flags) (*net.Interface, error) {

	// Obtain the list of interfaces
	ifis, err := net.Interfaces()
	if err != nil {
		return nil, err
	}

	// Return the first one that matches
	for _, ifi := range ifis {
		if ifi.Flags&flag != 0 {
			return &ifi, nil
		}
	}

	// None matched - return nil
	return nil, nil
}

// Test that packets are correctly sent and received via broadcast
func Test_connection_broadcast(t *testing.T) {

	// Attempt to find a broadcast interface
	ifi, err := findInterfaceWithFlag(net.FlagBroadcast)
	if err != nil {
		t.Fatal(err)
	}

	// Skip the test if none was found
	if ifi == nil {
		t.Skip("No broadcast interface found")
	}

	// Create the connection with a randomly chosen port
	conn, err := newConnection(ifi, 0, false)
	if err != nil {
		t.Fatal(err)
	}

	// Send a packet
	packet := []byte(`test`)
	if err := conn.Send(packet); err != nil {
		t.Fatal(err)
	}

	// Receive the packet
	select {
	case b := <-conn.PacketReceived:
		if !bytes.Equal(b, packet) {
			t.Fatal("Packet contents do not match")
		}
	case <-time.NewTicker(50 * time.Millisecond).C:
		t.Fatal("Timeout waiting for broadcast packet")
	}
}

// Test that packets are correctly sent and received via multicast
func Test_connection_multicast(t *testing.T) {
	//...
}
<commit_msg>Added test for multicast packets.<commit_after>package sdiscovery

import (
	"bytes"
	"errors"
	"net"
	"testing"
	"time"
)

// Test the broadcastAddress function
func Test_broadcastAddressFromCIDR(t *testing.T) {

	var ip net.IP
	var err error

	// Obtain the broadcast address for the provided CIDR
	if ip, err = broadcastAddressFromCIDR("192.168.1.1/24"); err != nil {
		t.Fatal(err)
	}

	// Ensure that the IP addresses match
	if !bytes.Equal(ip, net.IP{192, 168, 1, 255}) {
		t.Fatal("IP addresses do not match")
	}

	// Ensure that an error is generated for an IPv6 address
	if ip, err = broadcastAddressFromCIDR("::1/128"); err == nil {
		t.Fatal("Expected error for IPv6 address")
	}
}

// Testing the findBroadcastAddress function is virtually impossible since
// there is no way (AFAIK) to simulate an interface for testing

// Attempt to find an interface with the specified flag
func findInterfaceWithFlag(flag net.Flags) (*net.Interface, error) {

	// Obtain the list of interfaces
	ifis, err := net.Interfaces()
	if err != nil {
		return nil, err
	}

	// Return the first one that matches
	for _, ifi := range ifis {
		if ifi.Flags&flag != 0 {
			return &ifi, nil
		}
	}

	// None matched - return nil
	return nil, nil
}

// Send and receive a packet
func sendAndReceivePacket(ifi *net.Interface, multicast bool) error {

	// Create the connection with a randomly chosen port
	conn, err := newConnection(ifi, 0, multicast)
	if err != nil {
		return err
	}

	// Send a packet
	packet := []byte(`test`)
	if err := conn.Send(packet); err != nil {
		return err
	}

	// Receive the packet
	select {
	case b := <-conn.PacketReceived:
		if !bytes.Equal(b, packet) {
			return errors.New("Packet contents do not match")
		}
	case <-time.NewTicker(50 * time.Millisecond).C:
		return errors.New("Timeout waiting for broadcast packet")
	}

	return nil
}

// Test that packets are correctly sent and received via broadcast
func Test_connection_broadcast(t *testing.T) {

	// Attempt to find a broadcast interface
	ifi, err := findInterfaceWithFlag(net.FlagBroadcast)
	if err != nil {
		t.Fatal(err)
	}

	// Skip the test if none was found
	if ifi == nil {
		t.Skip("No broadcast interface found")
	}

	// Run the test
	if err := sendAndReceivePacket(ifi, false); err != nil {
		t.Fatal(err)
	}
}

// Test that packets are correctly sent and received via multicast
func Test_connection_multicast(t *testing.T) {

	// Attempt to find a multicast interface
	ifi, err := findInterfaceWithFlag(net.FlagMulticast)
	if err != nil {
		t.Fatal(err)
	}

	// Skip the test if none was found
	if ifi == nil {
		t.Skip("No multicast interface found")
	}

	// Run the test
	if err := sendAndReceivePacket(ifi, true); err != nil {
		t.Fatal(err)
	}
}
<|endoftext|>


<commit_before>// Package pfsdb contains the database schema that PFS uses.
package pfsdb

import (
	"fmt"
	"path"

	etcd "github.com/coreos/etcd/clientv3"
	"github.com/pachyderm/pachyderm/src/client/pfs"
	"github.com/pachyderm/pachyderm/src/client/pkg/uuid"
	col "github.com/pachyderm/pachyderm/src/server/pkg/collection"
)

const (
	reposPrefix          = "/repos"
	repoRefCountsPrefix  = "/repoRefCounts"
	putFileRecordsPrefix = "/putFileRecords"
	commitsPrefix        = "/commits"
	branchesPrefix       = "/branches"
	openCommitsPrefix    = "/openCommits"
)

var (
	// ProvenanceIndex is a secondary index on provenance
	ProvenanceIndex = col.Index{"Provenance", true}
)

// Repos returns a collection of repos
func Repos(etcdClient *etcd.Client, etcdPrefix string) col.Collection {
	return col.NewCollection(
		etcdClient,
		path.Join(etcdPrefix, reposPrefix),
		[]col.Index{ProvenanceIndex},
		&pfs.RepoInfo{},
		nil,
	)
}

// RepoRefCounts returns a collection of repo ref counts
func RepoRefCounts(etcdClient *etcd.Client, etcdPrefix string) col.Collection {
	return col.NewCollection(
		etcdClient,
		path.Join(etcdPrefix, repoRefCountsPrefix),
		nil,
		nil,
		nil,
	)
}

// PutFileRecords returns a collection of putFileRecords
func PutFileRecords(etcdClient *etcd.Client, etcdPrefix string) col.Collection {
	return col.NewCollection(
		etcdClient,
		path.Join(etcdPrefix, putFileRecordsPrefix),
		nil,
		nil,
		nil,
	)
}

// Commits returns a collection of commits
func Commits(etcdClient *etcd.Client, etcdPrefix string, repo string) col.Collection {
	return col.NewCollection(
		etcdClient,
		path.Join(etcdPrefix, commitsPrefix, repo),
		[]col.Index{ProvenanceIndex},
		&pfs.CommitInfo{},
		nil,
	)
}

// Branches returns a collection of branches
func Branches(etcdClient *etcd.Client, etcdPrefix string, repo string) col.Collection {
	return col.NewCollection(
		etcdClient,
		path.Join(etcdPrefix, branchesPrefix, repo),
		nil,
		&pfs.Commit{},
		func(key string) error {
			if len(key) == uuid.UUIDWithoutDashesLength {
				return fmt.Errorf("branch name cannot be of the same length as commit IDs")
			}
			return nil
		},
	)
}

// OpenCommits returns a collection of open commits
func OpenCommits(etcdClient *etcd.Client, etcdPrefix string) col.Collection {
	return col.NewCollection(
		etcdClient,
		path.Join(etcdPrefix, openCommitsPrefix),
		nil,
		&pfs.Commit{},
		nil,
	)
}
<commit_msg>Provide template for new collection for type checking<commit_after>// Package pfsdb contains the database schema that PFS uses.
package pfsdb

import (
	"fmt"
	"path"

	etcd "github.com/coreos/etcd/clientv3"
	"github.com/pachyderm/pachyderm/src/client/pfs"
	"github.com/pachyderm/pachyderm/src/client/pkg/uuid"
	col "github.com/pachyderm/pachyderm/src/server/pkg/collection"
)

const (
	reposPrefix          = "/repos"
	repoRefCountsPrefix  = "/repoRefCounts"
	putFileRecordsPrefix = "/putFileRecords"
	commitsPrefix        = "/commits"
	branchesPrefix       = "/branches"
	openCommitsPrefix    = "/openCommits"
)

var (
	// ProvenanceIndex is a secondary index on provenance
	ProvenanceIndex = col.Index{"Provenance", true}
)

// Repos returns a collection of repos
func Repos(etcdClient *etcd.Client, etcdPrefix string) col.Collection {
	return col.NewCollection(
		etcdClient,
		path.Join(etcdPrefix, reposPrefix),
		[]col.Index{ProvenanceIndex},
		&pfs.RepoInfo{},
		nil,
	)
}

// RepoRefCounts returns a collection of repo ref counts
func RepoRefCounts(etcdClient *etcd.Client, etcdPrefix string) col.Collection {
	return col.NewCollection(
		etcdClient,
		path.Join(etcdPrefix, repoRefCountsPrefix),
		nil,
		nil,
		nil,
	)
}

// PutFileRecords returns a collection of putFileRecords
func PutFileRecords(etcdClient *etcd.Client, etcdPrefix string) col.Collection {
	return col.NewCollection(
		etcdClient,
		path.Join(etcdPrefix, putFileRecordsPrefix),
		nil,
		&pfs.PutFileRecords{},
		nil,
	)
}

// Commits returns a collection of commits
func Commits(etcdClient *etcd.Client, etcdPrefix string, repo string) col.Collection {
	return col.NewCollection(
		etcdClient,
		path.Join(etcdPrefix, commitsPrefix, repo),
		[]col.Index{ProvenanceIndex},
		&pfs.CommitInfo{},
		nil,
	)
}

// Branches returns a collection of branches
func Branches(etcdClient *etcd.Client, etcdPrefix string, repo string) col.Collection {
	return col.NewCollection(
		etcdClient,
		path.Join(etcdPrefix, branchesPrefix, repo),
		nil,
		&pfs.Commit{},
		func(key string) error {
			if len(key) == uuid.UUIDWithoutDashesLength {
				return fmt.Errorf("branch name cannot be of the same length as commit IDs")
			}
			return nil
		},
	)
}

// OpenCommits returns a collection of open commits
func OpenCommits(etcdClient *etcd.Client, etcdPrefix string) col.Collection {
	return col.NewCollection(
		etcdClient,
		path.Join(etcdPrefix, openCommitsPrefix),
		nil,
		&pfs.Commit{},
		nil,
	)
}
<|endoftext|>