<commit_before>package server

import (
	"net"
	"sync"

	"github.com/nats-io/nuid"
)

// tracker is used to track connections to the server.
type tracker struct {
	connections           map[net.Conn]*trackerData
	verificationKeyLookup map[string]net.Conn
	playerNumbers         map[uint32]interface{}
	mutex                 sync.Mutex
}

// trackerData is data needed about each connection.
type trackerData struct {
	mutex           sync.Mutex
	sessionID       []byte
	number          uint32
	conn            net.Conn
	verificationKey string
}

// init initializes the tracker.
func (t *tracker) init() {
	t.connections = make(map[net.Conn]*trackerData)
	t.verificationKeyLookup = make(map[string]net.Conn)

	return
}

// add adds a connection to the tracker.
func (t *tracker) add(data *trackerData) {
	t.mutex.Lock()
	defer t.mutex.Unlock()

	t.verificationKeyLookup[data.verificationKey] = data.conn

	data.number = t.generateNumber()
	data.sessionID = t.generateSessionID()

	t.connections[data.conn] = data

	return
}

// remove removes the connection.
func (t *tracker) remove(conn net.Conn) {
	t.mutex.Lock()
	defer t.mutex.Unlock()

	if t.connections[conn] != nil {
		if t.connections[conn].verificationKey != "" {
			delete(t.verificationKeyLookup, t.connections[conn].verificationKey)
		}

		delete(t.connections, conn)
	}

	return
}

// count returns the number of connections to the server.
func (t *tracker) count() int {
	t.mutex.Lock()
	defer t.mutex.Unlock()

	return len(t.connections)
}

// getTrackerdData returns trackerdata associated with a connection
func (t *tracker) getTrackerData(c net.Conn) *trackerData {
	t.mutex.Lock()
	defer t.mutex.Unlock()

	return t.connections[c]
}

// generateNumber gets the connections number in the pool.
// This method assumes the caller is holding the mutex.
func (t *tracker) generateNumber() uint32 {
	num := uint32(1)

	for {
		if _, ok := t.playerNumbers[num]; ok {
			num = num + 1
			continue
		}

		break
	}

	t.playerNumbers[num] = nil
	return num
}

// generateSessionID generates a unique session id.
// This method assumes the caller is holding the mutex.
func (t *tracker) generateSessionID() []byte {
	n := nuid.New()

	return []byte(n.Next())
}
<commit_msg>Cleanup player numbers<commit_after>package server

import (
	"net"
	"sync"

	"github.com/nats-io/nuid"
)

// tracker is used to track connections to the server.
type tracker struct {
	connections           map[net.Conn]*trackerData
	verificationKeyLookup map[string]net.Conn
	playerNumbers         map[uint32]interface{}
	mutex                 sync.Mutex
}

// trackerData is data needed about each connection.
type trackerData struct {
	mutex           sync.Mutex
	sessionID       []byte
	number          uint32
	conn            net.Conn
	verificationKey string
}

// init initializes the tracker.
func (t *tracker) init() {
	t.connections = make(map[net.Conn]*trackerData)
	t.verificationKeyLookup = make(map[string]net.Conn)

	return
}

// add adds a connection to the tracker.
func (t *tracker) add(data *trackerData) {
	t.mutex.Lock()
	defer t.mutex.Unlock()

	t.verificationKeyLookup[data.verificationKey] = data.conn

	data.number = t.generateNumber()
	data.sessionID = t.generateSessionID()

	t.connections[data.conn] = data

	return
}

// remove removes the connection.
func (t *tracker) remove(conn net.Conn) {
	t.mutex.Lock()
	defer t.mutex.Unlock()

	if t.connections[conn] != nil {
		if t.connections[conn].number != 0 {
			delete(t.playerNumbers, t.connections[conn].number)
		}

		if t.connections[conn].verificationKey != "" {
			delete(t.verificationKeyLookup, t.connections[conn].verificationKey)
		}

		delete(t.connections, conn)
	}

	return
}

// count returns the number of connections to the server.
func (t *tracker) count() int {
	t.mutex.Lock()
	defer t.mutex.Unlock()

	return len(t.connections)
}

// getTrackerdData returns trackerdata associated with a connection
func (t *tracker) getTrackerData(c net.Conn) *trackerData {
	t.mutex.Lock()
	defer t.mutex.Unlock()

	return t.connections[c]
}

// generateNumber gets the connections number in the pool.
// This method assumes the caller is holding the mutex.
func (t *tracker) generateNumber() uint32 {
	num := uint32(1)

	for {
		if _, ok := t.playerNumbers[num]; ok {
			num = num + 1
			continue
		}

		break
	}

	t.playerNumbers[num] = nil
	return num
}

// generateSessionID generates a unique session id.
// This method assumes the caller is holding the mutex.
func (t *tracker) generateSessionID() []byte {
	n := nuid.New()

	return []byte(n.Next())
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"time"

	"github.com/gorilla/mux"

	"github.com/bazooka-ci/bazooka/commons/mongo"

	log "github.com/Sirupsen/logrus"

	lib "github.com/bazooka-ci/bazooka/commons"
)

func (c *context) getVariant(r *request) (*response, error) {
	variant, err := c.Connector.GetVariantByID(r.vars["id"])
	if err != nil {
		if err.Error() != "not found" {
			return nil, err
		}
		return notFound("variant not found")
	}

	return ok(&variant)
}

func (c *context) getVariants(r *request) (*response, error) {
	variants, err := c.Connector.GetVariants(r.vars["id"])
	if err != nil {
		return nil, err
	}

	return ok(&variants)
}

func (c *context) getVariantLog(r *request) (*response, error) {
	follow := len(r.query("follow")) > 0

	vid := r.vars["id"]

	variant, err := c.Connector.GetVariantByID(vid)

	if err != nil {
		if err.Error() != "not found" {
			return nil, err
		}
		return notFound("variant not found")
	}

	w := r.w
	w.WriteHeader(200)
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	logOutput := json.NewEncoder(w)

	query := &mongo.LogExample{
		VariantID: vid,
	}

	logs, err := c.Connector.GetLog(query)
	if !follow {
		logOutput.Encode(logs)
		return nil, nil
	}

	for _, l := range logs {
		logOutput.Encode(l)
	}
	flushResponse(w)
	lastTime := variantLastLogTime(variant, logs)

	for {
		time.Sleep(1000 * time.Millisecond)
		query.After = lastTime
		logs, err := c.Connector.GetLog(query)
		if err != nil {
			log.Errorf("Error while retrieving logs: %v", err)
			return nil, nil
		}
		if len(logs) > 0 {
			lastTime = variantLastLogTime(variant, logs)
			for _, l := range logs {
				logOutput.Encode(l)
			}
			flushResponse(w)
		}
		variant, err := c.Connector.GetVariantByID(vid)
		if err != nil {
			log.Errorf("Error while retrieving variant: %v", err)
			return nil, nil
		}
		if variant.Status != lib.JOB_RUNNING {
			return nil, nil
		}
	}
}

func variantLastLogTime(variant *lib.Variant, logs []lib.LogEntry) time.Time {
	if len(logs) == 0 {
		return variant.Started
	}
	return logs[len(logs)-1].Time
}

func (c *context) getVariantArtifacts(w http.ResponseWriter, r *http.Request) {
	vid := mux.Vars(r)["id"]
	variant, err := c.Connector.GetVariantByID(vid)

	if err != nil {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		encoder := json.NewEncoder(w)

		if err.Error() != "not found" {
			w.WriteHeader(500)
			encoder.Encode(err)
			return
		}

		w.WriteHeader(404)
		encoder.Encode(fmt.Errorf("variant not found"))
		return
	}

	buildFolder := fmt.Sprintf("/bazooka/build/%s/%s/artifacts/%s", variant.ProjectID, variant.JobID, variant.ID)
	prefix := fmt.Sprintf("/variant/%s/artifacts/", vid)
	http.StripPrefix(prefix, http.FileServer(http.Dir(buildFolder))).ServeHTTP(w, r)
}
<commit_msg>Support the strict-json mode when streaming a variant's log<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"time"

	"github.com/gorilla/mux"

	"github.com/bazooka-ci/bazooka/commons/mongo"

	log "github.com/Sirupsen/logrus"

	lib "github.com/bazooka-ci/bazooka/commons"
)

func (c *context) getVariant(r *request) (*response, error) {
	variant, err := c.Connector.GetVariantByID(r.vars["id"])
	if err != nil {
		if err.Error() != "not found" {
			return nil, err
		}
		return notFound("variant not found")
	}

	return ok(&variant)
}

func (c *context) getVariants(r *request) (*response, error) {
	variants, err := c.Connector.GetVariants(r.vars["id"])
	if err != nil {
		return nil, err
	}

	return ok(&variants)
}

func (c *context) getVariantLog(r *request) (*response, error) {
	follow := len(r.query("follow")) > 0
	strictJson := len(r.query("strict-json")) > 0

	vid := r.vars["id"]

	variant, err := c.Connector.GetVariantByID(vid)

	if err != nil {
		if err.Error() != "not found" {
			return nil, err
		}
		return notFound("variant not found")
	}

	w := r.w
	w.WriteHeader(200)
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	logOutput := json.NewEncoder(w)

	query := &mongo.LogExample{
		VariantID: vid,
	}

	logs, err := c.Connector.GetLog(query)
	if !follow {
		logOutput.Encode(logs)
		return nil, nil
	}

	if strictJson {
		w.Write([]byte("["))
	}

	writtenEntries := 0
	for _, l := range logs {
		if writtenEntries > 0 && strictJson {
			w.Write([]byte(","))
		}
		logOutput.Encode(l)
		writtenEntries++
	}
	flushResponse(w)
	lastTime := variantLastLogTime(variant, logs)

	for {
		time.Sleep(1000 * time.Millisecond)
		query.After = lastTime
		logs, err := c.Connector.GetLog(query)
		if err != nil {
			log.Errorf("Error while retrieving logs: %v", err)
			return nil, nil
		}
		if len(logs) > 0 {
			lastTime = variantLastLogTime(variant, logs)
			for _, l := range logs {
				if writtenEntries > 0 && strictJson {
					w.Write([]byte(","))
				}
				logOutput.Encode(l)
				writtenEntries++
			}
			flushResponse(w)
		}
		variant, err := c.Connector.GetVariantByID(vid)
		if err != nil {
			log.Errorf("Error while retrieving variant: %v", err)
			return nil, nil
		}
		if variant.Status != lib.JOB_RUNNING {
			if strictJson {
				w.Write([]byte("]"))
			}
			return nil, nil
		}
	}
}

func variantLastLogTime(variant *lib.Variant, logs []lib.LogEntry) time.Time {
	if len(logs) == 0 {
		return variant.Started
	}
	return logs[len(logs)-1].Time
}

func (c *context) getVariantArtifacts(w http.ResponseWriter, r *http.Request) {
	vid := mux.Vars(r)["id"]
	variant, err := c.Connector.GetVariantByID(vid)

	if err != nil {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		encoder := json.NewEncoder(w)

		if err.Error() != "not found" {
			w.WriteHeader(500)
			encoder.Encode(err)
			return
		}

		w.WriteHeader(404)
		encoder.Encode(fmt.Errorf("variant not found"))
		return
	}

	buildFolder := fmt.Sprintf("/bazooka/build/%s/%s/artifacts/%s", variant.ProjectID, variant.JobID, variant.ID)
	prefix := fmt.Sprintf("/variant/%s/artifacts/", vid)
	http.StripPrefix(prefix, http.FileServer(http.Dir(buildFolder))).ServeHTTP(w, r)
}
<|endoftext|>


<commit_before>package conf

import (
	"io/ioutil"
	"os"
)

var confile = ConfigFile

var conf_setting = `[site]
title = Golune
subtitle = 十年拿大锤，看什么都是钉子
description = 胡乱写写
summary_line = 10

[dir]
theme = blog
markdown = markdown
html = blog
storage = storage

[author]
name = guhao
avatar = /assets/avatar.png
github = guhao022
weibo = guhao`

func InitConf() {

	_, err := os.Stat(confile)
	if os.IsNotExist(err) {
		_, err := os.OpenFile(confile, os.O_WRONLY|os.O_CREATE, 0666)
		if err != nil {
			panic(err)
		}

		var confwrite = []byte(conf_setting)
		err = ioutil.WriteFile(confile, confwrite, 0666) //写入文件(字节数组)
		if err != nil {
			panic(err)
		}
	}
}

func InitDir() {
	_, err := os.Stat(confile)
	if os.IsNotExist(err) {
		InitConf()
	}

	_, err = os.Stat(DirHtml())
	if os.IsNotExist(err) {

		if err := os.MkdirAll(DirHtml(), os.ModePerm); err != nil {
			panic(err)
		}
	}

	_, err = os.Stat(DirMark())
	if os.IsNotExist(err) {

		if err := os.MkdirAll(DirMark(), os.ModePerm); err != nil {
			panic(err)
		}
	}

	_, err = os.Stat(DirStor())
	if os.IsNotExist(err) {

		if err := os.MkdirAll(DirStor(), os.ModePerm); err != nil {
			panic(err)
		}
	}

	_, err = os.Stat(DirTheme())
	if os.IsNotExist(err) {

		if err := os.MkdirAll("theme", os.ModePerm); err != nil {
			panic(err)
		}
	}

}
<commit_msg>compile template<commit_after>package conf

import (
	"io/ioutil"
	"os"
)

var confile = ConfigFile

var conf_setting = `[site]
title = Golune
subtitle = 十年拿大锤，看什么都是钉子
description = 胡乱写写
summary_line = 10

[dir]
theme = blog
markdown = markdown
html = blog
storage = storage

[author]
name = guhao
avatar = /assets/avatar.png
github = guhao022
weibo = guhao`

func InitConf() {

	_, err := os.Stat(confile)
	if os.IsNotExist(err) {
		_, err := os.OpenFile(confile, os.O_WRONLY|os.O_CREATE, 0666)
		if err != nil {
			panic(err)
		}

		var confwrite = []byte(conf_setting)
		err = ioutil.WriteFile(confile, confwrite, 0666) //写入文件(字节数组)
		if err != nil {
			panic(err)
		}
	}
}

func InitDir() {
	_, err := os.Stat(confile)
	if os.IsNotExist(err) {
		InitConf()
	}

	_, err = os.Stat(DirHtml())
	if os.IsNotExist(err) {

		if err := os.MkdirAll(DirHtml(), os.ModePerm); err != nil {
			panic(err)
		}
	}

	_, err = os.Stat(DirMark())
	if os.IsNotExist(err) {

		if err := os.MkdirAll(DirMark(), os.ModePerm); err != nil {
			panic(err)
		}
	}

	/*_, err = os.Stat(DirStor())
	if os.IsNotExist(err) {

		if err := os.MkdirAll(DirStor(), os.ModePerm); err != nil {
			panic(err)
		}
	}*/

	_, err = os.Stat(DirTheme())
	if os.IsNotExist(err) {

		if err := os.MkdirAll("theme", os.ModePerm); err != nil {
			panic(err)
		}
	}

}
<|endoftext|>


<commit_before>package rules

import (
	"strings"
)

type ruleManager struct {
	rulesBySlashCount map[int]map[DynamicRule]int
	prefixes          map[string]string
	currentIndex      int
}

func newRuleManager() ruleManager {
	rm := ruleManager{
		rulesBySlashCount: map[int]map[DynamicRule]int{},
		prefixes:          map[string]string{},
		currentIndex:      0,
	}
	return rm
}

func (rm *ruleManager) getStaticRules(key string, value *string) map[staticRule]int {
	slashCount := strings.Count(key, "/")
	out := make(map[staticRule]int)
	rules, ok := rm.rulesBySlashCount[slashCount]
	if ok {
		for rule, index := range rules {
			sRule, _, inScope := rule.makeStaticRule(key, value)
			if inScope && sRule.satisfiable(key, value) {
				out[sRule] = index
			}
		}
	}
	return out
}

func (rm *ruleManager) addRule(rule DynamicRule) int {
	for _, pattern := range rule.getPatterns() {
		slashCount := strings.Count(pattern, "/")
		rules, ok := rm.rulesBySlashCount[slashCount]
		if !ok {
			rules = map[DynamicRule]int{}
			rm.rulesBySlashCount[slashCount] = rules
		}
		rules[rule] = rm.currentIndex
	}
	for _, prefix := range rule.getPrefixes() {
		rm.prefixes[prefix] = ""
	}
	rm.prefixes = reducePrefixes(rm.prefixes)
	lastIndex := rm.currentIndex
	rm.currentIndex = rm.currentIndex + 1
	return lastIndex
}

func reducePrefixes(prefixes map[string]string) map[string]string {
	out := map[string]string{}
	sorted := sortPrefixesByLength(prefixes)
	for _, prefix := range sorted {
		add := true
		for addedPrefix, _ := range out {
			if strings.HasPrefix(addedPrefix, prefix) {
				add = false
			}
		}
		if add {
			out[prefix] = ""
		}
	}
	return out
}

func sortPrefixesByLength(prefixes map[string]string) []string {
	out := []string{}
	for prefix, _ := range prefixes {
		out = append(out, prefix)
	}
	for i := 1; i < len(out); i++ {
		x := out[i]
		j := i - 1
		for j >= 0 && len(out[j]) < len(x) {
			out[j+1] = out[j]
			j = j - 1
		}
		out[j + 1] = x
	}
	return out
}
<commit_msg>Fix formatting<commit_after>package rules

import (
	"strings"
)

type ruleManager struct {
	rulesBySlashCount map[int]map[DynamicRule]int
	prefixes          map[string]string
	currentIndex      int
}

func newRuleManager() ruleManager {
	rm := ruleManager{
		rulesBySlashCount: map[int]map[DynamicRule]int{},
		prefixes:          map[string]string{},
		currentIndex:      0,
	}
	return rm
}

func (rm *ruleManager) getStaticRules(key string, value *string) map[staticRule]int {
	slashCount := strings.Count(key, "/")
	out := make(map[staticRule]int)
	rules, ok := rm.rulesBySlashCount[slashCount]
	if ok {
		for rule, index := range rules {
			sRule, _, inScope := rule.makeStaticRule(key, value)
			if inScope && sRule.satisfiable(key, value) {
				out[sRule] = index
			}
		}
	}
	return out
}

func (rm *ruleManager) addRule(rule DynamicRule) int {
	for _, pattern := range rule.getPatterns() {
		slashCount := strings.Count(pattern, "/")
		rules, ok := rm.rulesBySlashCount[slashCount]
		if !ok {
			rules = map[DynamicRule]int{}
			rm.rulesBySlashCount[slashCount] = rules
		}
		rules[rule] = rm.currentIndex
	}
	for _, prefix := range rule.getPrefixes() {
		rm.prefixes[prefix] = ""
	}
	rm.prefixes = reducePrefixes(rm.prefixes)
	lastIndex := rm.currentIndex
	rm.currentIndex = rm.currentIndex + 1
	return lastIndex
}

func reducePrefixes(prefixes map[string]string) map[string]string {
	out := map[string]string{}
	sorted := sortPrefixesByLength(prefixes)
	for _, prefix := range sorted {
		add := true
		for addedPrefix, _ := range out {
			if strings.HasPrefix(addedPrefix, prefix) {
				add = false
			}
		}
		if add {
			out[prefix] = ""
		}
	}
	return out
}

func sortPrefixesByLength(prefixes map[string]string) []string {
	out := []string{}
	for prefix, _ := range prefixes {
		out = append(out, prefix)
	}
	for i := 1; i < len(out); i++ {
		x := out[i]
		j := i - 1
		for j >= 0 && len(out[j]) < len(x) {
			out[j+1] = out[j]
			j = j - 1
		}
		out[j+1] = x
	}
	return out
}
<|endoftext|>


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

package service

import (
	"bufio"
	"fmt"
	"io"
	"sync/atomic"
	"runtime"
	"github.com/surgemq/message"
	"encoding/binary"
	"strconv"
)

var (
	bufcnt int64
	DefaultBufferSize int64

	DeviceInBufferSize int64
	DeviceOutBufferSize int64

	MasterInBufferSize int64
	MasterOutBufferSize int64
)

const (
	smallReadBlockSize = 512
	defaultReadBlockSize = 8192
	defaultWriteBlockSize = 8192
)

/**
2016.03.03 修改
bingbuffer结构体
 */
type buffer struct {
	readIndex  int64             //读序号
	writeIndex int64             //写序号
	ringBuffer []message.Message //环形buffer指针数组
	bufferSize int64             //初始化环形buffer指针数组大小
	mask       int64             //掩码：bufferSize-1
	done       int64             //是否完成
}

/**
2016.03.03 添加
初始化ringbuffer
参数bufferSize：初始化环形buffer指针数组大小
 */
func newBuffer(size int64) (*buffer, error) {
	if size < 0 {
		return nil, bufio.ErrNegativeCount
	}
	if size == 0 {
		size = DefaultBufferSize
	}
	fmt.Printf("size=" + strconv.FormatInt(size, 10) + ",DefaultBufferSize=" + strconv.FormatInt(DefaultBufferSize, 10))
	if !powerOfTwo64(size) {
		fmt.Printf("Size must be power of two. Try %d.", roundUpPowerOfTwo64(size))
		return nil, fmt.Errorf("Size must be power of two. Try %d.", roundUpPowerOfTwo64(size))
	}

	return &buffer{
		readIndex: int64(0), //读序号
		writeIndex: int64(0), //写序号
		ringBuffer: make([]message.Message, size), //环形buffer指针数组
		bufferSize: size, //初始化环形buffer指针数组大小
		mask:size - 1,
	}, nil
}

/**
2016.03.03 添加
获取当前读序号
 */
func (this *buffer)GetCurrentReadIndex() (int64) {
	return atomic.LoadInt64(&this.readIndex)
}
/**
2016.03.03 添加
获取当前写序号
 */
func (this *buffer)GetCurrentWriteIndex() (int64) {
	return atomic.LoadInt64(&this.writeIndex)
}

/**
2016.03.03 添加
读取ringbuffer指定的buffer指针，返回该指针并清空ringbuffer该位置存在的指针内容，以及将读序号加1
 */
func (this *buffer)ReadBuffer() (p message.Message, ok bool) {
	ok = true
	p = nil

	readIndex := atomic.LoadInt64(&this.readIndex)
	writeIndex := atomic.LoadInt64(&this.writeIndex)
	switch  {
	case readIndex >= writeIndex:
		ok = false
	case writeIndex - readIndex > this.bufferSize:
		ok = false
	default:
		//index := buffer.readIndex % buffer.bufferSize
		index := readIndex & this.mask
		p = this.ringBuffer[index]
		this.ringBuffer[index] = nil
		atomic.AddInt64(&this.readIndex, 1)
		if p == nil {
			ok = false
		}
	}
	return p, ok
}

/**
2016.03.03 添加
写入ringbuffer指针，以及将写序号加1
 */
func (this *buffer)WriteBuffer(in message.Message) (ok bool) {
	ok = true

	readIndex := atomic.LoadInt64(&this.readIndex)
	writeIndex := atomic.LoadInt64(&this.writeIndex)
	switch  {
	case writeIndex - readIndex < 0:
		ok = false
	default:
		//index := buffer.writeIndex % buffer.bufferSize
		index := writeIndex & this.mask
		if this.ringBuffer[index] == nil {
			this.ringBuffer[index] = in
			atomic.AddInt64(&this.writeIndex, 1)
		}else {
			ok = false
		}
	}
	return ok
}

/**
2016.03.03 修改
关闭缓存
 */
func (this *buffer) Close() error {
	atomic.StoreInt64(&this.done, 1)
	return nil
}
/*

/**
2016.03.03 修改
向ringbuffer中写数据（从connection的中向ringbuffer中写）--生产者
*/
func (this *buffer) ReadFrom(r io.Reader) (int64, error) {
	defer this.Close()
	for {
		total := int64(0)
		if this.isDone() {
			return total, io.EOF
		}
		b := make([]byte, 5)
		n, err := r.Read(b[0:1])

		if n > 0 {
			total += int64(n)
			if err != nil {
				return total, err
			}
		}

		/**************************/
		cnt := 1

		// Let's read enough bytes to get the message header (msg type, remaining length)
		for {
			// If we have read 5 bytes and still not done, then there's a problem.
			if cnt > 4 {
				return 0, fmt.Errorf("sendrecv/peekMessageSize: 4th byte of remaining length has continuation bit set")
			}

			// Peek cnt bytes from the input buffer.
			_, err := r.Read(b[cnt:cnt + 1])
			if err != nil {
				return 0, err
			}

			// If we got enough bytes, then check the last byte to see if the continuation
			// bit is set. If so, increment cnt and continue peeking
			if b[cnt] >= 0x80 {
				cnt++
			} else {
				break
			}
		}

		// Get the remaining length of the message
		remlen, _ := binary.Uvarint(b[1:])

		// Total message length is remlen + 1 (msg type) + m (remlen bytes)
		len := int64(len(b))
		total = int64(remlen) + int64(len)

		mtype := message.MessageType(b[0] >> 4)
		/****************/
		var msg message.Message

		msg, err = mtype.New()
		if err != nil {
			return 0, err
		}
		_, err = r.Read(b[len:total])
		if err != nil {
			return 0, err
		}
		n, err = msg.Decode(b)
		if err != nil {
			return 0, err
		}

		/*************************/

		for !this.WriteBuffer(msg) {
			runtime.Gosched()
		}

		return total, nil
	}
}

/**
2016.03.03 修改
 */
func (this *buffer) WriteTo(w io.Writer) (int64, error) {
	defer this.Close()

	total := int64(0)
	for {
		if this.isDone() {
			return total, io.EOF
		}

		msg, ok := this.ReadBuffer()
		if !ok {
			runtime.Gosched()
		}
		p := make([]byte, defaultReadBlockSize)
		_, err := msg.Encode(p)
		if err != nil {
			return total, io.EOF
		}
		// There's some data, let's process it first
		if len(p) > 0 {
			n, err := w.Write(p)
			total += int64(n)
			//Log.Debugc(func() string{ return fmt.Sprintf("Wrote %d bytes, totaling %d bytes", n, total)})

			if err != nil {
				return total, err
			}
		}

		if err != nil {
			return total, err
		}
	}
}

/**
2016.03.03 修改
*/
func (this *buffer) isDone() bool {
	if atomic.LoadInt64(&this.done) == 1 {
		return true
	}

	return false
}

func powerOfTwo64(n int64) bool {
	return n != 0 && (n & (n - 1)) == 0
}

func roundUpPowerOfTwo64(n int64) int64 {
	n--
	n |= n >> 1
	n |= n >> 2
	n |= n >> 4
	n |= n >> 8
	n |= n >> 16
	n |= n >> 32
	n++

	return n
}
<commit_msg>修改buffer缓存内容的类型<commit_after>// Copyright (c) 2014 The SurgeMQ Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package service

import (
	"bufio"
	"fmt"
	"io"
	"sync/atomic"
	"runtime"
	"github.com/surgemq/message"
	"encoding/binary"
)

var (
	bufcnt int64
	DefaultBufferSize int64

	DeviceInBufferSize int64
	DeviceOutBufferSize int64

	MasterInBufferSize int64
	MasterOutBufferSize int64
)

const (
	smallReadBlockSize = 512
	defaultReadBlockSize = 8192
	defaultWriteBlockSize = 8192
)

/**
2016.03.03 修改
bingbuffer结构体
 */
type buffer struct {
	readIndex  int64         //读序号
	writeIndex int64         //写序号
	ringBuffer []interface{} //环形buffer指针数组
	bufferSize int64         //初始化环形buffer指针数组大小
	mask       int64         //掩码：bufferSize-1
	done       int64         //是否完成
}

/**
2016.03.03 添加
初始化ringbuffer
参数bufferSize：初始化环形buffer指针数组大小
 */
func newBuffer(size int64) (*buffer, error) {
	if size < 0 {
		return nil, bufio.ErrNegativeCount
	}
	if size == 0 {
		size = DefaultBufferSize
	}
	if !powerOfTwo64(size) {
		fmt.Printf("Size must be power of two. Try %d.", roundUpPowerOfTwo64(size))
		return nil, fmt.Errorf("Size must be power of two. Try %d.", roundUpPowerOfTwo64(size))
	}

	return &buffer{
		readIndex: int64(0), //读序号
		writeIndex: int64(0), //写序号
		ringBuffer: make([]interface{}, size), //环形buffer指针数组
		bufferSize: size, //初始化环形buffer指针数组大小
		mask:size - 1,
	}, nil
}

/**
2016.03.03 添加
获取当前读序号
 */
func (this *buffer)GetCurrentReadIndex() (int64) {
	return atomic.LoadInt64(&this.readIndex)
}
/**
2016.03.03 添加
获取当前写序号
 */
func (this *buffer)GetCurrentWriteIndex() (int64) {
	return atomic.LoadInt64(&this.writeIndex)
}

/**
2016.03.03 添加
读取ringbuffer指定的buffer指针，返回该指针并清空ringbuffer该位置存在的指针内容，以及将读序号加1
 */
func (this *buffer)ReadBuffer() (p interface{}, ok bool) {
	ok = true
	p = nil

	readIndex := atomic.LoadInt64(&this.readIndex)
	writeIndex := atomic.LoadInt64(&this.writeIndex)
	switch  {
	case readIndex >= writeIndex:
		ok = false
	case writeIndex - readIndex > this.bufferSize:
		ok = false
	default:
		//index := buffer.readIndex % buffer.bufferSize
		index := readIndex & this.mask
		p = this.ringBuffer[index]
		this.ringBuffer[index] = nil
		atomic.AddInt64(&this.readIndex, 1)
		if p == nil {
			ok = false
		}
	}
	return p, ok
}

/**
2016.03.03 添加
写入ringbuffer指针，以及将写序号加1
 */
func (this *buffer)WriteBuffer(in interface{}) (ok bool) {
	ok = true

	readIndex := atomic.LoadInt64(&this.readIndex)
	writeIndex := atomic.LoadInt64(&this.writeIndex)
	switch  {
	case writeIndex - readIndex < 0:
		ok = false
	default:
		//index := buffer.writeIndex % buffer.bufferSize
		index := writeIndex & this.mask
		if this.ringBuffer[index] == nil {
			this.ringBuffer[index] = in
			atomic.AddInt64(&this.writeIndex, 1)
		}else {
			ok = false
		}
	}
	return ok
}

/**
2016.03.03 修改
关闭缓存
 */
func (this *buffer) Close() error {
	atomic.StoreInt64(&this.done, 1)
	return nil
}
/*

/**
2016.03.03 修改
向ringbuffer中写数据（从connection的中向ringbuffer中写）--生产者
*/
func (this *buffer) ReadFrom(r io.Reader) (int64, error) {
	defer this.Close()
	for {
		total := int64(0)
		if this.isDone() {
			return total, io.EOF
		}
		b := make([]byte, 5)
		n, err := r.Read(b[0:1])

		if n > 0 {
			total += int64(n)
			if err != nil {
				return total, err
			}
		}

		/**************************/
		cnt := 1

		// Let's read enough bytes to get the message header (msg type, remaining length)
		for {
			// If we have read 5 bytes and still not done, then there's a problem.
			if cnt > 4 {
				return 0, fmt.Errorf("sendrecv/peekMessageSize: 4th byte of remaining length has continuation bit set")
			}

			// Peek cnt bytes from the input buffer.
			_, err := r.Read(b[cnt:cnt + 1])
			if err != nil {
				return 0, err
			}

			// If we got enough bytes, then check the last byte to see if the continuation
			// bit is set. If so, increment cnt and continue peeking
			if b[cnt] >= 0x80 {
				cnt++
			} else {
				break
			}
		}

		// Get the remaining length of the message
		remlen, _ := binary.Uvarint(b[1:])

		// Total message length is remlen + 1 (msg type) + m (remlen bytes)
		len := int64(len(b))
		total = int64(remlen) + int64(len)

		mtype := message.MessageType(b[0] >> 4)
		/****************/
		var msg message.Message

		msg, err = mtype.New()
		if err != nil {
			return 0, err
		}
		_, err = r.Read(b[len:total])
		if err != nil {
			return 0, err
		}
		n, err = msg.Decode(b)
		if err != nil {
			return 0, err
		}

		/*************************/

		for !this.WriteBuffer(msg) {
			runtime.Gosched()
		}

		return total, nil
	}
}

/**
2016.03.03 修改
 */
func (this *buffer) WriteTo(w io.Writer) (int64, error) {
	defer this.Close()

	total := int64(0)
	for {
		if this.isDone() {
			return total, io.EOF
		}

		msg, ok := this.ReadBuffer()
		if !ok {
			runtime.Gosched()
		}
		p := make([]byte, defaultReadBlockSize)
		_, err := msg.Encode(p)
		if err != nil {
			return total, io.EOF
		}
		// There's some data, let's process it first
		if len(p) > 0 {
			n, err := w.Write(p)
			total += int64(n)
			//Log.Debugc(func() string{ return fmt.Sprintf("Wrote %d bytes, totaling %d bytes", n, total)})

			if err != nil {
				return total, err
			}
		}

		if err != nil {
			return total, err
		}
	}
}

/**
2016.03.03 修改
*/
func (this *buffer) isDone() bool {
	if atomic.LoadInt64(&this.done) == 1 {
		return true
	}

	return false
}

func powerOfTwo64(n int64) bool {
	return n != 0 && (n & (n - 1)) == 0
}

func roundUpPowerOfTwo64(n int64) int64 {
	n--
	n |= n >> 1
	n |= n >> 2
	n |= n >> 4
	n |= n >> 8
	n |= n >> 16
	n |= n >> 32
	n++

	return n
}
<|endoftext|>


<commit_before>package raft

import (
	"encoding/json"
	"fmt"
	"github.com/arpith/mmapd/db"
	"net/http"
	"net/url"
	"strconv"
)

type appendEntryRequest struct {
	term         int
	leaderId     string
	prevLogIndex int
	prevLogTerm  int
	entry        db.Entry
	leaderCommit int
	returnChan   chan bool
}

type appendEntryResponse struct {
	term    int
	success bool
}

type followerResponse struct {
	serverIndex int
	resp        appendEntryResponse
}

func (s *server) appendEntry(command string, isCommitted chan bool) {
	entry := &db.Entry{command, s.term}
	index := -1
	if command != "" {
		s.db.Log.AppendEntry(*entry)
		index = len(s.db.Log.Entries)
	}
	respChan := make(chan followerResponse)
	for i := 0; i < len(s.config); i++ {
		if s.config[i] != s.id {
			go s.sendAppendEntryRequest(i, *entry, respChan)
		}
	}
	responseCount := 0
	if len(s.config) > 1 {
		for {
			_ = <-respChan
			responseCount++
			for N := s.commitIndex + 1; N < len(s.db.Log.Entries); N++ {
				//Check if there exists an N > commitIndex
				count := 0
				for i := 0; i < len(s.matchIndex); i++ {
					if s.matchIndex[i] >= N {
						count++
					}
				}
				// Check if a majority of matchIndex[i] >= N
				cond1 := count > len(s.matchIndex)/2
				// Check if log[N].term == currentTerm
				cond2 := s.db.Log.Entries[N].Term == s.term
				if cond1 && cond2 {
					// Set commitIndex to N
					s.commitIndex = N
				} else {
					break
				}
			}
			if s.commitIndex == index {
				isCommitted <- true
			}
		}
	} else {
		if command != "" {
			s.commitIndex++
			isCommitted <- true
		}
	}
}

func (s *server) sendAppendEntryRequest(followerIndex int, entry db.Entry, respChan chan followerResponse) {
	follower := s.config[followerIndex]
	v := url.Values{}
	v.Set("term", strconv.Itoa(s.term))
	v.Set("leaderID", s.id)
	v.Set("prevLogIndex", strconv.Itoa(len(s.db.Log.Entries)))
	v.Set("entry", entry.Command)
	v.Set("leaderCommit", strconv.Itoa(s.commitIndex))
	resp, err := http.PostForm("http://"+follower+"/appendEntry", v)
	if err != nil {
		fmt.Println("Couldn't send append entry request to "+follower, err)
		go s.sendAppendEntryRequest(followerIndex, entry, respChan)
		return
	}
	r := &appendEntryResponse{}
	json.NewDecoder(resp.Body).Decode(r)
	defer resp.Body.Close()
	if r.term > s.term {
		s.term = r.term
		s.state = "follower"
		s.electionTimeout.reset()
	}
	if r.success {
		s.term = r.term
		s.nextIndex[followerIndex]++
		s.matchIndex[followerIndex]++
		followerResp := &followerResponse{followerIndex, *r}
		respChan <- *followerResp
	} else {
		s.nextIndex[followerIndex]--
		go s.sendAppendEntryRequest(followerIndex, entry, respChan)
	}
}

func (s *server) handleAppendEntryRequest(req appendEntryRequest) {
	if req.term < s.term {
		req.returnChan <- false
	} else if s.db.Log.Entries[req.prevLogIndex].Term != req.prevLogTerm {
		req.returnChan <- false
	} else {
		if s.db.Log.Entries[req.prevLogIndex+1].Term != req.term {
			// If existing entry conflicts with new entry
			// Delete entry and all that follow it
			s.db.Log.SetEntries(s.db.Log.Entries[:req.prevLogIndex])
		}
		s.db.Log.AppendEntry(req.entry)
		if req.leaderCommit < s.commitIndex {
			// Set commit index to the min of the leader's commit index and index of last new entry
			if req.leaderCommit < req.prevLogIndex+1 {
				s.commitIndex = req.leaderCommit
			} else {
				s.commitIndex = req.prevLogIndex + 1
			}
		}
		req.returnChan <- true
	}
}
<commit_msg>don't retry append entry requests for now :)<commit_after>package raft

import (
	"encoding/json"
	"fmt"
	"github.com/arpith/mmapd/db"
	"net/http"
	"net/url"
	"strconv"
)

type appendEntryRequest struct {
	term         int
	leaderId     string
	prevLogIndex int
	prevLogTerm  int
	entry        db.Entry
	leaderCommit int
	returnChan   chan bool
}

type appendEntryResponse struct {
	term    int
	success bool
}

type followerResponse struct {
	serverIndex int
	resp        appendEntryResponse
}

func (s *server) appendEntry(command string, isCommitted chan bool) {
	entry := &db.Entry{command, s.term}
	index := -1
	if command != "" {
		s.db.Log.AppendEntry(*entry)
		index = len(s.db.Log.Entries)
	}
	respChan := make(chan followerResponse)
	for i := 0; i < len(s.config); i++ {
		if s.config[i] != s.id {
			go s.sendAppendEntryRequest(i, *entry, respChan)
		}
	}
	responseCount := 0
	if len(s.config) > 1 {
		for {
			_ = <-respChan
			responseCount++
			for N := s.commitIndex + 1; N < len(s.db.Log.Entries); N++ {
				//Check if there exists an N > commitIndex
				count := 0
				for i := 0; i < len(s.matchIndex); i++ {
					if s.matchIndex[i] >= N {
						count++
					}
				}
				// Check if a majority of matchIndex[i] >= N
				cond1 := count > len(s.matchIndex)/2
				// Check if log[N].term == currentTerm
				cond2 := s.db.Log.Entries[N].Term == s.term
				if cond1 && cond2 {
					// Set commitIndex to N
					s.commitIndex = N
				} else {
					break
				}
			}
			if s.commitIndex == index {
				isCommitted <- true
			}
		}
	} else {
		if command != "" {
			s.commitIndex++
			isCommitted <- true
		}
	}
}

func (s *server) sendAppendEntryRequest(followerIndex int, entry db.Entry, respChan chan followerResponse) {
	follower := s.config[followerIndex]
	v := url.Values{}
	v.Set("term", strconv.Itoa(s.term))
	v.Set("leaderID", s.id)
	v.Set("prevLogIndex", strconv.Itoa(len(s.db.Log.Entries)))
	v.Set("entry", entry.Command)
	v.Set("leaderCommit", strconv.Itoa(s.commitIndex))
	resp, err := http.PostForm("http://"+follower+"/appendEntry", v)
	if err != nil {
		fmt.Println("Couldn't send append entry request to "+follower, err)
		//		go s.sendAppendEntryRequest(followerIndex, entry, respChan)
		return
	}
	r := &appendEntryResponse{}
	json.NewDecoder(resp.Body).Decode(r)
	defer resp.Body.Close()
	if r.term > s.term {
		s.term = r.term
		s.state = "follower"
		s.electionTimeout.reset()
	}
	if r.success {
		s.term = r.term
		s.nextIndex[followerIndex]++
		s.matchIndex[followerIndex]++
		followerResp := &followerResponse{followerIndex, *r}
		respChan <- *followerResp
	} else {
		s.nextIndex[followerIndex]--
		//		go s.sendAppendEntryRequest(followerIndex, entry, respChan)
	}
}

func (s *server) handleAppendEntryRequest(req appendEntryRequest) {
	if req.term < s.term {
		req.returnChan <- false
	} else if s.db.Log.Entries[req.prevLogIndex].Term != req.prevLogTerm {
		req.returnChan <- false
	} else {
		if s.db.Log.Entries[req.prevLogIndex+1].Term != req.term {
			// If existing entry conflicts with new entry
			// Delete entry and all that follow it
			s.db.Log.SetEntries(s.db.Log.Entries[:req.prevLogIndex])
		}
		s.db.Log.AppendEntry(req.entry)
		if req.leaderCommit < s.commitIndex {
			// Set commit index to the min of the leader's commit index and index of last new entry
			if req.leaderCommit < req.prevLogIndex+1 {
				s.commitIndex = req.leaderCommit
			} else {
				s.commitIndex = req.prevLogIndex + 1
			}
		}
		req.returnChan <- true
	}
}
<|endoftext|>


<commit_before>package service

import (
	"fmt"
	"log"
	"net"
	"net/url"
	"os/exec"
	"time"

	"github.com/aandryashin/selenoid/config"
)

type Driver struct {
	Service *config.Browser
}

func (d *Driver) StartWithCancel() (*url.URL, func(), error) {
	slice, ok := d.Service.Image.([]interface{})
	if !ok {
		return nil, nil, fmt.Errorf("configuration error: image is not an array: %v", d.Service.Image)
	}
	cmdLine := []string{}
	for _, c := range slice {
		if _, ok := c.(string); !ok {
			return nil, nil, fmt.Errorf("configuration error: value is not a string: %v", c)
		}
		cmdLine = append(cmdLine, c.(string))
	}
	if len(cmdLine) == 0 {
		return nil, nil, fmt.Errorf("configuration error: image is empty")
	}
	log.Println("Trying to allocate port")
	l, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		return nil, nil, fmt.Errorf("cannot bind to port: %v", err)
	}
	u := &url.URL{Scheme: "http", Host: l.Addr().String()}
	_, port, _ := net.SplitHostPort(l.Addr().String())
	log.Println("Available port is:", port)
	cmdLine = append(cmdLine, fmt.Sprintf("--port=%s", port))
	cmd := exec.Command(cmdLine[0], cmdLine[1:]...)
	l.Close()
	log.Println("Starting process:", cmdLine)
	s := time.Now()
	err = cmd.Start()
	if err != nil {
		e := fmt.Errorf("cannot start process %v: %v", cmdLine, err)
		log.Println(e)
		return nil, nil, e
	}
	err = wait(u.String(), 10*time.Second)
	if err != nil {
		stopProcess(cmd)
		return nil, nil, err
	}
	log.Printf("Process %d started in: %v\n", cmd.Process.Pid, time.Since(s))
	log.Println("Proxying requests to:", u.String())
	return u, func() { stopProcess(cmd) }, nil
}

func stopProcess(cmd *exec.Cmd) {
	log.Println("Terminating process", cmd.Process.Pid)
	err := cmd.Process.Kill()
	if err != nil {
		log.Println("cannot terminate process %d: %v", cmd.Process.Pid, err)
		return
	}
	log.Printf("Process %d terminated\n", cmd.Process.Pid)
}
<commit_msg>Fixed log formatting for stopProcess<commit_after>package service

import (
	"fmt"
	"log"
	"net"
	"net/url"
	"os/exec"
	"time"

	"github.com/aandryashin/selenoid/config"
)

type Driver struct {
	Service *config.Browser
}

func (d *Driver) StartWithCancel() (*url.URL, func(), error) {
	slice, ok := d.Service.Image.([]interface{})
	if !ok {
		return nil, nil, fmt.Errorf("configuration error: image is not an array: %v", d.Service.Image)
	}
	cmdLine := []string{}
	for _, c := range slice {
		if _, ok := c.(string); !ok {
			return nil, nil, fmt.Errorf("configuration error: value is not a string: %v", c)
		}
		cmdLine = append(cmdLine, c.(string))
	}
	if len(cmdLine) == 0 {
		return nil, nil, fmt.Errorf("configuration error: image is empty")
	}
	log.Println("Trying to allocate port")
	l, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		return nil, nil, fmt.Errorf("cannot bind to port: %v", err)
	}
	u := &url.URL{Scheme: "http", Host: l.Addr().String()}
	_, port, _ := net.SplitHostPort(l.Addr().String())
	log.Println("Available port is:", port)
	cmdLine = append(cmdLine, fmt.Sprintf("--port=%s", port))
	cmd := exec.Command(cmdLine[0], cmdLine[1:]...)
	l.Close()
	log.Println("Starting process:", cmdLine)
	s := time.Now()
	err = cmd.Start()
	if err != nil {
		e := fmt.Errorf("Cannot start process %v: %v", cmdLine, err)
		log.Println(e)
		return nil, nil, e
	}
	err = wait(u.String(), 10*time.Second)
	if err != nil {
		stopProcess(cmd)
		return nil, nil, err
	}
	log.Printf("Process %d started in: %v\n", cmd.Process.Pid, time.Since(s))
	log.Println("Proxying requests to:", u.String())
	return u, func() { stopProcess(cmd) }, nil
}

func stopProcess(cmd *exec.Cmd) {
	log.Println("Terminating process", cmd.Process.Pid)
	err := cmd.Process.Kill()
	if err != nil {
		log.Printf("Cannot terminate process %d: %v\n", cmd.Process.Pid, err)
		return
	}
	log.Printf("Process %d terminated\n", cmd.Process.Pid)
}
<|endoftext|>


<commit_before>package toolbox

import (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"reflect"
	"strings"
)

var jsonContentType = "application/json"
var textPlainContentType = "text/plain"

const (
	MethodGet     = "GET"
	MethodHead    = "HEAD"
	MethodPost    = "POST"
	MethodPut     = "PUT"
	MethodPatch   = "PATCH" // RFC 5789
	MethodDelete  = "DELETE"
	MethodOptions = "OPTIONS"
	MethodTrace   = "TRACE"
)

var httpMethods = map[string]bool{
	MethodDelete:  true,
	MethodGet:     true,
	MethodPatch:   true,
	MethodPost:    true,
	MethodPut:     true,
	MethodHead:    true,
	MethodTrace:   true,
	MethodOptions: true,
}

//HandlerInvoker method is responsible  of passing required parameters to router handler.
type HandlerInvoker func(serviceRouting *ServiceRouting, request *http.Request, response http.ResponseWriter, uriParameters map[string]interface{}) error

//DefaultEncoderFactory  - NewJSONEncoderFactory
var DefaultEncoderFactory = NewJSONEncoderFactory()

//DefaultDecoderFactory - NewJSONDecoderFactory
var DefaultDecoderFactory = NewJSONDecoderFactory()

//ServiceRouting represents a simple web services routing rule, which is matched with http request
type ServiceRouting struct {
	URI                 string      //matching uri
	Handler             interface{} //has to be func
	HTTPMethod          string
	Parameters          []string
	ContentTypeEncoders map[string]EncoderFactory //content type encoder factory
	ContentTypeDecoders map[string]DecoderFactory //content type decoder factory
	HandlerInvoker      HandlerInvoker            //optional function that will be used instead of reflection to invoke a handler.
}

func (sr ServiceRouting) getDecoderFactory(contentType string) DecoderFactory {
	if sr.ContentTypeDecoders != nil {
		if factory, found := sr.ContentTypeDecoders[contentType]; found {
			return factory
		}
	}
	return DefaultDecoderFactory
}

func (sr ServiceRouting) getEncoderFactory(contentType string) EncoderFactory {
	if sr.ContentTypeDecoders != nil {
		if factory, found := sr.ContentTypeEncoders[contentType]; found {
			return factory
		}
	}
	return DefaultEncoderFactory
}

func (sr ServiceRouting) extractParameterFromBody(parameterName string, targetType reflect.Type, request *http.Request) (interface{}, error) {
	targetValuePointer := reflect.New(targetType)
	contentType := getContentTypeOrJSONContentType(request.Header.Get("Content-Type"))
	decoderFactory := sr.getDecoderFactory(contentType)
	decoder := decoderFactory.Create(request.Body)
	if !strings.Contains(parameterName, ":") {
		err := decoder.Decode(targetValuePointer.Interface())
		if err != nil {
			return nil, fmt.Errorf("Unable to extract %Tv due to %v", targetValuePointer.Interface(), err)
		}
	} else {
		var valueMap = make(map[string]interface{})
		pair := strings.SplitN(parameterName, ":", 2)
		valueMap[pair[1]] = targetValuePointer.Interface()
		err := decoder.Decode(&valueMap)
		if err != nil {
			return nil, fmt.Errorf("Unable to extract %T due to %v", targetValuePointer.Interface(), err)
		}
	}
	return targetValuePointer.Interface(), nil
}

func (sr ServiceRouting) extractParameters(request *http.Request, response http.ResponseWriter) (map[string]interface{}, error) {
	var result = make(map[string]interface{})
	request.ParseForm()
	functionSignature := GetFuncSignature(sr.Handler)
	uriParameters, _ := ExtractURIParameters(sr.URI, request.RequestURI)
	for _, name := range sr.Parameters {
		value, found := uriParameters[name]
		if found {
			if strings.Contains(value, ",") {
				result[name] = strings.Split(value, ",")
			} else {
				result[name] = value
			}
			continue
		}

		value = request.Form.Get(name)
		if len(value) > 0 {
			result[name] = value
		} else {
			continue
		}
	}
	if HasSliceAnyElements(sr.Parameters, "@httpRequest") {
		result["@httpRequest"] = request
	}
	if HasSliceAnyElements(sr.Parameters, "@httpResponseWriter") {
		result["@httpResponseWriter"] = response
	}

	if request.ContentLength > 0 {
		for i, parameter := range sr.Parameters {
			if _, found := result[parameter]; !found {
				value, err := sr.extractParameterFromBody(parameter, functionSignature[i], request)
				if err != nil {
					return nil, fmt.Errorf("Failed to extract parameters for %v %v due to %v", sr.HTTPMethod, sr.URI, err)
				}
				result[parameter] = value
				break
			}
		}
	}
	return result, nil
}

//ServiceRouter represents routing rule
type ServiceRouter struct {
	serviceRouting []*ServiceRouting
}

func (r *ServiceRouter) match(request *http.Request) []*ServiceRouting {
	var result = make([]*ServiceRouting, 0)
	for _, candidate := range r.serviceRouting {

		if candidate.HTTPMethod == request.Method {
			_, matched := ExtractURIParameters(candidate.URI, request.RequestURI)
			if matched {
				result = append(result, candidate)
			}
		}
	}
	return result
}

func getContentTypeOrJSONContentType(contentType string) string {
	if strings.Contains(contentType, textPlainContentType) || strings.Contains(contentType, jsonContentType) || contentType == "" {
		return jsonContentType
	}
	return contentType
}

//Route matches  service routing by http method , and number of parameters, then it call routing method, and sent back its response.
func (r *ServiceRouter) Route(response http.ResponseWriter, request *http.Request) error {
	candidates := r.match(request)
	if len(candidates) == 0 {
		var uriTemplates = make([]string, 0)
		for _, routing := range r.serviceRouting {
			uriTemplates = append(uriTemplates, routing.URI)
		}
		return fmt.Errorf("Failed to route request - unable to match %v with one of %v", request.RequestURI, strings.Join(uriTemplates, ","))
	}
	var finalError error

	for _, serviceRouting := range candidates {

		parameterValues, err := serviceRouting.extractParameters(request, response)
		if err != nil {
			finalError = fmt.Errorf("unable to extract parameters due to %v", err)
			continue
		}

		if serviceRouting.HandlerInvoker != nil {
			err := serviceRouting.HandlerInvoker(serviceRouting, request, response, parameterValues)
			if err != nil {
				finalError = fmt.Errorf("unable to extract parameters due to %v", err)
			}
			continue
		}

		functionParameters, err := BuildFunctionParameters(serviceRouting.Handler, serviceRouting.Parameters, parameterValues)
		if err != nil {
			finalError = fmt.Errorf("unable to build function parameters %T due to %v", serviceRouting.Handler, err)
			continue
		}

		result := CallFunction(serviceRouting.Handler, functionParameters...)
		if len(result) > 0 {
			err = WriteServiceRoutingResponse(response, request, serviceRouting, result[0])
			if err != nil {
				return fmt.Errorf("Failed to write response response %v, due to %v", result[0], err)
			}
			return nil
		}
		response.Header().Set("Content-Type", textPlainContentType)
	}
	if finalError != nil {
		return fmt.Errorf("Failed to route request - %v", finalError)
	}
	return nil
}

//WriteServiceRoutingResponse writes service router response
func WriteServiceRoutingResponse(response http.ResponseWriter, request *http.Request, serviceRouting *ServiceRouting, result interface{}) error {
	requestContentType := request.Header.Get("Content-Type")
	responseContentType := getContentTypeOrJSONContentType(requestContentType)
	encoderFactory := serviceRouting.getEncoderFactory(responseContentType)

	encoder := encoderFactory.Create(response)
	response.Header().Set("Content-Type", responseContentType)
	err := encoder.Encode(result)
	if err != nil {
		return fmt.Errorf("Failed to encode response %v, due to %v", response, err)
	}
	return nil

	if err != nil {
		return fmt.Errorf("Failed to write response response %v, due to %v", result, err)
	}
	return nil
}

//NewServiceRouter creates a new service router, is takes list of service routing as arguments
func NewServiceRouter(serviceRouting ...ServiceRouting) *ServiceRouter {
	var routings = make([]*ServiceRouting, 0)
	for _, routing := range serviceRouting {
		routings = append(routings, &routing)
	}
	return &ServiceRouter{routings}
}

//RouteToService calls web service url, with passed in json request, and encodes http json response into passed response
func RouteToService(method, url string, request, response interface{}) (err error) {
	return RouteToServiceWithCustomFormat(method, url, request, response, NewJSONEncoderFactory(), NewJSONDecoderFactory())
}

//RouteToServiceWithCustomFormat calls web service url, with passed in custom format request, and encodes custom format http response into passed response
func RouteToServiceWithCustomFormat(method, url string, request, response interface{}, encoderFactory EncoderFactory, decoderFactory DecoderFactory) (err error) {
	if _, found := httpMethods[strings.ToUpper(method)]; !found {
		return errors.New("Unsupported method:" + method)
	}
	var buffer *bytes.Buffer
	if request != nil {
		buffer = new(bytes.Buffer)
		err := encoderFactory.Create(buffer).Encode(&request)
		if err != nil {
			return fmt.Errorf("Failed to encode request: %v due to ", err)
		}
	}
	var serverResponse *http.Response
	var httpRequest *http.Request
	httpMethod := strings.ToUpper(method)
	if request != nil {
		httpRequest, err = http.NewRequest(httpMethod, url, buffer)
		if err != nil {
			return err
		}
		httpRequest.Header.Set("Content-Type", jsonContentType)
	} else {
		httpRequest, err = http.NewRequest(httpMethod, url, nil)
		if err != nil {
			return err
		}
	}

	serverResponse, err = http.DefaultClient.Do(httpRequest)
	if err != nil && serverResponse != nil {
		return fmt.Errorf("Failed to get response %v %v", err, serverResponse.Header.Get("error"))
	}

	if response != nil {
		if serverResponse == nil || serverResponse.Body == nil {
			return fmt.Errorf("Failed to recieve response %v", err)
		}
		body, err := ioutil.ReadAll(serverResponse.Body)
		if err != nil {
			return fmt.Errorf("Failed to read response %v", err)
		}
		err = decoderFactory.Create(strings.NewReader(string(body))).Decode(response)
		if err != nil {
			return fmt.Errorf("Failed to decode response to %T: body: %v: %v, %v", response, string(body), err, serverResponse.Header.Get("error"))
		}
	}
	return nil
}
<commit_msg>updated NewServiceRouter to take routes (without pointer) to minimaze backward compabitlity issues<commit_after>package toolbox

import (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"reflect"
	"strings"
)

var jsonContentType = "application/json"
var textPlainContentType = "text/plain"

const (
	MethodGet     = "GET"
	MethodHead    = "HEAD"
	MethodPost    = "POST"
	MethodPut     = "PUT"
	MethodPatch   = "PATCH" // RFC 5789
	MethodDelete  = "DELETE"
	MethodOptions = "OPTIONS"
	MethodTrace   = "TRACE"
)

var httpMethods = map[string]bool{
	MethodDelete:  true,
	MethodGet:     true,
	MethodPatch:   true,
	MethodPost:    true,
	MethodPut:     true,
	MethodHead:    true,
	MethodTrace:   true,
	MethodOptions: true,
}

//HandlerInvoker method is responsible  of passing required parameters to router handler.
type HandlerInvoker func(serviceRouting *ServiceRouting, request *http.Request, response http.ResponseWriter, uriParameters map[string]interface{}) error

//DefaultEncoderFactory  - NewJSONEncoderFactory
var DefaultEncoderFactory = NewJSONEncoderFactory()

//DefaultDecoderFactory - NewJSONDecoderFactory
var DefaultDecoderFactory = NewJSONDecoderFactory()

//ServiceRouting represents a simple web services routing rule, which is matched with http request
type ServiceRouting struct {
	URI                 string      //matching uri
	Handler             interface{} //has to be func
	HTTPMethod          string
	Parameters          []string
	ContentTypeEncoders map[string]EncoderFactory //content type encoder factory
	ContentTypeDecoders map[string]DecoderFactory //content type decoder factory
	HandlerInvoker      HandlerInvoker            //optional function that will be used instead of reflection to invoke a handler.
}

func (sr ServiceRouting) getDecoderFactory(contentType string) DecoderFactory {
	if sr.ContentTypeDecoders != nil {
		if factory, found := sr.ContentTypeDecoders[contentType]; found {
			return factory
		}
	}
	return DefaultDecoderFactory
}

func (sr ServiceRouting) getEncoderFactory(contentType string) EncoderFactory {
	if sr.ContentTypeDecoders != nil {
		if factory, found := sr.ContentTypeEncoders[contentType]; found {
			return factory
		}
	}
	return DefaultEncoderFactory
}

func (sr ServiceRouting) extractParameterFromBody(parameterName string, targetType reflect.Type, request *http.Request) (interface{}, error) {
	targetValuePointer := reflect.New(targetType)
	contentType := getContentTypeOrJSONContentType(request.Header.Get("Content-Type"))
	decoderFactory := sr.getDecoderFactory(contentType)
	decoder := decoderFactory.Create(request.Body)
	if !strings.Contains(parameterName, ":") {
		err := decoder.Decode(targetValuePointer.Interface())
		if err != nil {
			return nil, fmt.Errorf("Unable to extract %Tv due to %v", targetValuePointer.Interface(), err)
		}
	} else {
		var valueMap = make(map[string]interface{})
		pair := strings.SplitN(parameterName, ":", 2)
		valueMap[pair[1]] = targetValuePointer.Interface()
		err := decoder.Decode(&valueMap)
		if err != nil {
			return nil, fmt.Errorf("Unable to extract %T due to %v", targetValuePointer.Interface(), err)
		}
	}
	return targetValuePointer.Interface(), nil
}

func (sr ServiceRouting) extractParameters(request *http.Request, response http.ResponseWriter) (map[string]interface{}, error) {
	var result = make(map[string]interface{})
	request.ParseForm()
	functionSignature := GetFuncSignature(sr.Handler)
	uriParameters, _ := ExtractURIParameters(sr.URI, request.RequestURI)
	for _, name := range sr.Parameters {
		value, found := uriParameters[name]
		if found {
			if strings.Contains(value, ",") {
				result[name] = strings.Split(value, ",")
			} else {
				result[name] = value
			}
			continue
		}

		value = request.Form.Get(name)
		if len(value) > 0 {
			result[name] = value
		} else {
			continue
		}
	}
	if HasSliceAnyElements(sr.Parameters, "@httpRequest") {
		result["@httpRequest"] = request
	}
	if HasSliceAnyElements(sr.Parameters, "@httpResponseWriter") {
		result["@httpResponseWriter"] = response
	}

	if request.ContentLength > 0 {
		for i, parameter := range sr.Parameters {
			if _, found := result[parameter]; !found {
				value, err := sr.extractParameterFromBody(parameter, functionSignature[i], request)
				if err != nil {
					return nil, fmt.Errorf("Failed to extract parameters for %v %v due to %v", sr.HTTPMethod, sr.URI, err)
				}
				result[parameter] = value
				break
			}
		}
	}
	return result, nil
}

//ServiceRouter represents routing rule
type ServiceRouter struct {
	serviceRouting []*ServiceRouting
}

func (r *ServiceRouter) match(request *http.Request) []*ServiceRouting {
	var result = make([]*ServiceRouting, 0)
	for _, candidate := range r.serviceRouting {

		if candidate.HTTPMethod == request.Method {
			_, matched := ExtractURIParameters(candidate.URI, request.RequestURI)
			if matched {
				result = append(result, candidate)
			}
		}
	}
	return result
}

func getContentTypeOrJSONContentType(contentType string) string {
	if strings.Contains(contentType, textPlainContentType) || strings.Contains(contentType, jsonContentType) || contentType == "" {
		return jsonContentType
	}
	return contentType
}

//Route matches  service routing by http method , and number of parameters, then it call routing method, and sent back its response.
func (r *ServiceRouter) Route(response http.ResponseWriter, request *http.Request) error {
	candidates := r.match(request)
	if len(candidates) == 0 {
		var uriTemplates = make([]string, 0)
		for _, routing := range r.serviceRouting {
			uriTemplates = append(uriTemplates, routing.URI)
		}
		return fmt.Errorf("Failed to route request - unable to match %v with one of %v", request.RequestURI, strings.Join(uriTemplates, ","))
	}
	var finalError error

	for _, serviceRouting := range candidates {

		parameterValues, err := serviceRouting.extractParameters(request, response)
		if err != nil {
			finalError = fmt.Errorf("unable to extract parameters due to %v", err)
			continue
		}

		if serviceRouting.HandlerInvoker != nil {
			err := serviceRouting.HandlerInvoker(serviceRouting, request, response, parameterValues)
			if err != nil {
				finalError = fmt.Errorf("unable to extract parameters due to %v", err)
			}
			continue
		}

		functionParameters, err := BuildFunctionParameters(serviceRouting.Handler, serviceRouting.Parameters, parameterValues)
		if err != nil {
			finalError = fmt.Errorf("unable to build function parameters %T due to %v", serviceRouting.Handler, err)
			continue
		}

		result := CallFunction(serviceRouting.Handler, functionParameters...)
		if len(result) > 0 {
			err = WriteServiceRoutingResponse(response, request, serviceRouting, result[0])
			if err != nil {
				return fmt.Errorf("Failed to write response response %v, due to %v", result[0], err)
			}
			return nil
		}
		response.Header().Set("Content-Type", textPlainContentType)
	}
	if finalError != nil {
		return fmt.Errorf("Failed to route request - %v", finalError)
	}
	return nil
}

//WriteServiceRoutingResponse writes service router response
func WriteServiceRoutingResponse(response http.ResponseWriter, request *http.Request, serviceRouting *ServiceRouting, result interface{}) error {
	requestContentType := request.Header.Get("Content-Type")
	responseContentType := getContentTypeOrJSONContentType(requestContentType)
	encoderFactory := serviceRouting.getEncoderFactory(responseContentType)
	encoder := encoderFactory.Create(response)
	response.Header().Set("Content-Type", responseContentType)
	err := encoder.Encode(result)
	if err != nil {
		return fmt.Errorf("Failed to encode response %v, due to %v", response, err)
	}
	return nil

	if err != nil {
		return fmt.Errorf("Failed to write response response %v, due to %v", result, err)
	}
	return nil
}

//WriteResponse writes response to response writer, it used encoder factory to encode passed in response to the writer, it sets back request contenttype to response.
func (r *ServiceRouter) WriteResponse(encoderFactory EncoderFactory, response interface{}, request *http.Request, responseWriter http.ResponseWriter) error {
	requestContentType := request.Header.Get("Content-Type")
	responseContentType := getContentTypeOrJSONContentType(requestContentType)
	encoder := encoderFactory.Create(responseWriter)
	responseWriter.Header().Set("Content-Type", responseContentType)
	err := encoder.Encode(response)
	if err != nil {
		return fmt.Errorf("Failed to encode response %v, due to %v", response, err)
	}
	return nil
}

//NewServiceRouter creates a new service router, is takes list of service routing as arguments
func NewServiceRouter(serviceRouting ...ServiceRouting) *ServiceRouter {
	var routings = make([]*ServiceRouting, 0)
	for _, routing := range serviceRouting {
		routings = append(routings, &routing)
	}
	return &ServiceRouter{routings}
}

//RouteToService calls web service url, with passed in json request, and encodes http json response into passed response
func RouteToService(method, url string, request, response interface{}) (err error) {
	return RouteToServiceWithCustomFormat(method, url, request, response, NewJSONEncoderFactory(), NewJSONDecoderFactory())
}

//RouteToServiceWithCustomFormat calls web service url, with passed in custom format request, and encodes custom format http response into passed response
func RouteToServiceWithCustomFormat(method, url string, request, response interface{}, encoderFactory EncoderFactory, decoderFactory DecoderFactory) (err error) {
	if _, found := httpMethods[strings.ToUpper(method)]; !found {
		return errors.New("Unsupported method:" + method)
	}
	var buffer *bytes.Buffer
	if request != nil {
		buffer = new(bytes.Buffer)
		err := encoderFactory.Create(buffer).Encode(&request)
		if err != nil {
			return fmt.Errorf("Failed to encode request: %v due to ", err)
		}
	}
	var serverResponse *http.Response
	var httpRequest *http.Request
	httpMethod := strings.ToUpper(method)
	if request != nil {
		httpRequest, err = http.NewRequest(httpMethod, url, buffer)
		if err != nil {
			return err
		}
		httpRequest.Header.Set("Content-Type", jsonContentType)
	} else {
		httpRequest, err = http.NewRequest(httpMethod, url, nil)
		if err != nil {
			return err
		}
	}

	serverResponse, err = http.DefaultClient.Do(httpRequest)
	if err != nil && serverResponse != nil {
		return fmt.Errorf("Failed to get response %v %v", err, serverResponse.Header.Get("error"))
	}

	if response != nil {
		if serverResponse == nil || serverResponse.Body == nil {
			return fmt.Errorf("Failed to recieve response %v", err)
		}
		body, err := ioutil.ReadAll(serverResponse.Body)
		if err != nil {
			return fmt.Errorf("Failed to read response %v", err)
		}
		err = decoderFactory.Create(strings.NewReader(string(body))).Decode(response)
		if err != nil {
			return fmt.Errorf("Failed to decode response to %T: body: %v: %v, %v", response, string(body), err, serverResponse.Header.Get("error"))
		}
	}
	return nil
}
<|endoftext|>


<commit_before>// // Copyright 2014, The Serviced Authors. All rights reserved.
// // Use of this source code is governed by a
// // license that can be found in the LICENSE file.

// // Package agent implements a service that runs on a serviced node. It is
// // responsible for ensuring that a particular node is running the correct services
// // and reporting the state and health of those services back to the master
// // serviced.

package main

import (
	"encoding/json"
	"fmt"
	"github.com/zenoss/glog"
	"github.com/rcrowley/go-metrics"
	"io/ioutil"
	"net/http"
	"bufio"
	"bytes"
	"strconv"
	"strings"
	"time"
)

type StatsReporter struct {
	destination string
	username    string
	password    string
}

type containerStat struct {
	Metric    string            `json:"metric"`
	Value     string            `json:"value"`
	Timestamp int64             `json:"timestamp"`
	Tags      map[string]string `json:"tags"`
}

// Runs report every d. Blocks. Should be run as a goroutine.
func (sr StatsReporter) StartReporting(d time.Duration) {
	tc := time.Tick(d)
	for t := range tc {
		go sr.report(t)
	}
}

// Updates the default registry, fills out the metric consumer format, and posts
// the data to the TSDB.
func (sr StatsReporter) report(t time.Time) {
	fmt.Println("Reporting container stats at:", t)
	sr.UpdateSSKVint64("/sys/fs/cgroup/memory/memory.stat", "memory")
	sr.UpdateSSKVint64("/sys/fs/cgroup/cpuacct/cpuacct.stat", "cpu")
	sr.UpdateSSKVint64("/sys/fs/cgroup/blkio/blkio.sectors", "blkio")
	sr.UpdateSSKVint64("/sys/fs/cgroup/blkio/blkio.io_service_bytes", "blkio")
	sr.UpdateSSKVint64("/sys/fs/cgroup/blkio/blkio.io_serviced", "blkio")
	sr.UpdateSSKVint64("/sys/fs/cgroup/blkio/blkio.io_queued", "blkio")
	sr.UpdateSSKVint64("/sys/fs/cgroup/memory/lxc/memory.stat", "memory")
	sr.UpdateSSKVint64("/sys/fs/cgroup/cpuacct/lxc/cpuacct.stat", "cpu")
	sr.UpdateSSKVint64("/sys/fs/cgroup/blkio/lxc/blkio.sectors", "blkio")
	sr.UpdateSSKVint64("/sys/fs/cgroup/blkio/lxc/blkio.io_service_bytes", "blkio")
	sr.UpdateSSKVint64("/sys/fs/cgroup/blkio/lxc/blkio.io_serviced", "blkio")
	sr.UpdateSSKVint64("/sys/fs/cgroup/blkio/lxc/blkio.io_queued", "blkio")
	stats := []containerStat{}
	reg, _ := metrics.DefaultRegistry.(*metrics.StandardRegistry)
	reg.Each(func(n string, i interface{}) {
		switch metric := i.(type) {
		case metrics.Gauge:
			tagmap := make(map[string]string)
			tagmap["datasource"] = n
			tagmap["uuid"] = n
			stats = append(stats, containerStat{n, strconv.FormatInt(metric.Value(), 10), t.Unix(), tagmap})
		}
	})
	sr.post(stats)
}

// Send the list of stats to the TSDB.
func (sr StatsReporter) post(stats []containerStat) error {
	payload := map[string][]containerStat{"metrics": stats}
	data, err := json.Marshal(payload)
	if err != nil {
		glog.V(3).Info("Couldn't marshal stats: ", err)
		return err
	}
	statsreq, err := http.NewRequest("POST", sr.destination, bytes.NewBuffer(data))
	if err != nil {
		glog.V(3).Info("Couldn't create stats request: ", err)
		return err
	}
	statsreq.Header["User-Agent"] = []string{"Zenoss Metric Publisher"}
	statsreq.Header["Content-Type"] = []string{"application/json"}
	if glog.V(4) {
		glog.Info(string(data))
	}
	resp, reqerr := http.DefaultClient.Do(statsreq)
	if reqerr != nil {
		glog.V(3).Info("Couldn't post stats: ", reqerr)
		return reqerr
	}
	if strings.Contains(resp.Status, "200") == false {
		glog.V(3).Info("Non-success: ", resp.Status)
		return fmt.Errorf("Couldn't post stats: ", resp.Status)
	}
	resp.Body.Close()
	return nil
}

// Updates a list of metrics produced from a space-separated key-value pair
// file. The prefix is prepended to the key in the final metric name.
func (sr StatsReporter) UpdateSSKVint64(filename string, prefix string) {
	kv, _ := parseSSKVint64(filename)
	for k, v := range kv {
		name := prefix + "." + k
		gauge := metrics.GetOrRegisterGauge(name, metrics.DefaultRegistry)
		gauge.Update(v)
	}
}

// Parses a space-separated key-value pair file and returns a
// key(string):value(int64) mapping.
func parseSSKVint64(filename string) (map[string]int64, error) {
	if kv, err := parseSSKV(filename); err != nil {
		return nil, err
	} else {
		mapping := make(map[string]int64)
		for k, v := range kv {
			if n, err := strconv.ParseInt(v, 0, 64); err != nil {
				return nil, err
			} else {
				mapping[k] = n
			}
		}
		return mapping, nil
	}
	return nil, nil
}

// Parses a space-separated key-value pair file and returns a
// key(string):value(string) mapping.
func parseSSKV(filename string) (map[string]string, error) {
	if stats, err := ioutil.ReadFile(filename); err != nil {
		return nil, err
	} else {
		mapping := make(map[string]string)
		scanner := bufio.NewScanner(strings.NewReader(string(stats)))
		for scanner.Scan() {
			line := scanner.Text()
			parts := strings.Split(line, " ")
			mapping[parts[0]] = parts[1]
		}
		return mapping, nil
	}
}<commit_msg>fix comment problem<commit_after>// Copyright 2014, The Serviced Authors. All rights reserved.
// Use of this source code is governed by a
// license that can be found in the LICENSE file.

// Package agent implements a service that runs on a serviced node. It is
// responsible for ensuring that a particular node is running the correct services
// and reporting the state and health of those services back to the master
// serviced.

package main

import (
	"encoding/json"
	"fmt"
	"github.com/zenoss/glog"
	"github.com/rcrowley/go-metrics"
	"io/ioutil"
	"net/http"
	"bufio"
	"bytes"
	"strconv"
	"strings"
	"time"
)

type StatsReporter struct {
	destination string
	username    string
	password    string
}

type containerStat struct {
	Metric    string            `json:"metric"`
	Value     string            `json:"value"`
	Timestamp int64             `json:"timestamp"`
	Tags      map[string]string `json:"tags"`
}

// Runs report every d. Blocks. Should be run as a goroutine.
func (sr StatsReporter) StartReporting(d time.Duration) {
	tc := time.Tick(d)
	for t := range tc {
		go sr.report(t)
	}
}

// Updates the default registry, fills out the metric consumer format, and posts
// the data to the TSDB.
func (sr StatsReporter) report(t time.Time) {
	fmt.Println("Reporting container stats at:", t)
	sr.UpdateSSKVint64("/sys/fs/cgroup/memory/memory.stat", "memory")
	sr.UpdateSSKVint64("/sys/fs/cgroup/cpuacct/cpuacct.stat", "cpu")
	sr.UpdateSSKVint64("/sys/fs/cgroup/blkio/blkio.sectors", "blkio")
	sr.UpdateSSKVint64("/sys/fs/cgroup/blkio/blkio.io_service_bytes", "blkio")
	sr.UpdateSSKVint64("/sys/fs/cgroup/blkio/blkio.io_serviced", "blkio")
	sr.UpdateSSKVint64("/sys/fs/cgroup/blkio/blkio.io_queued", "blkio")
	sr.UpdateSSKVint64("/sys/fs/cgroup/memory/lxc/memory.stat", "memory")
	sr.UpdateSSKVint64("/sys/fs/cgroup/cpuacct/lxc/cpuacct.stat", "cpu")
	sr.UpdateSSKVint64("/sys/fs/cgroup/blkio/lxc/blkio.sectors", "blkio")
	sr.UpdateSSKVint64("/sys/fs/cgroup/blkio/lxc/blkio.io_service_bytes", "blkio")
	sr.UpdateSSKVint64("/sys/fs/cgroup/blkio/lxc/blkio.io_serviced", "blkio")
	sr.UpdateSSKVint64("/sys/fs/cgroup/blkio/lxc/blkio.io_queued", "blkio")
	stats := []containerStat{}
	reg, _ := metrics.DefaultRegistry.(*metrics.StandardRegistry)
	reg.Each(func(n string, i interface{}) {
		switch metric := i.(type) {
		case metrics.Gauge:
			tagmap := make(map[string]string)
			tagmap["datasource"] = n
			tagmap["uuid"] = n
			stats = append(stats, containerStat{n, strconv.FormatInt(metric.Value(), 10), t.Unix(), tagmap})
		}
	})
	sr.post(stats)
}

// Send the list of stats to the TSDB.
func (sr StatsReporter) post(stats []containerStat) error {
	payload := map[string][]containerStat{"metrics": stats}
	data, err := json.Marshal(payload)
	if err != nil {
		glog.V(3).Info("Couldn't marshal stats: ", err)
		return err
	}
	statsreq, err := http.NewRequest("POST", sr.destination, bytes.NewBuffer(data))
	if err != nil {
		glog.V(3).Info("Couldn't create stats request: ", err)
		return err
	}
	statsreq.Header["User-Agent"] = []string{"Zenoss Metric Publisher"}
	statsreq.Header["Content-Type"] = []string{"application/json"}
	if glog.V(4) {
		glog.Info(string(data))
	}
	resp, reqerr := http.DefaultClient.Do(statsreq)
	if reqerr != nil {
		glog.V(3).Info("Couldn't post stats: ", reqerr)
		return reqerr
	}
	if strings.Contains(resp.Status, "200") == false {
		glog.V(3).Info("Non-success: ", resp.Status)
		return fmt.Errorf("Couldn't post stats: ", resp.Status)
	}
	resp.Body.Close()
	return nil
}

// Updates a list of metrics produced from a space-separated key-value pair
// file. The prefix is prepended to the key in the final metric name.
func (sr StatsReporter) UpdateSSKVint64(filename string, prefix string) {
	kv, _ := parseSSKVint64(filename)
	for k, v := range kv {
		name := prefix + "." + k
		gauge := metrics.GetOrRegisterGauge(name, metrics.DefaultRegistry)
		gauge.Update(v)
	}
}

// Parses a space-separated key-value pair file and returns a
// key(string):value(int64) mapping.
func parseSSKVint64(filename string) (map[string]int64, error) {
	if kv, err := parseSSKV(filename); err != nil {
		return nil, err
	} else {
		mapping := make(map[string]int64)
		for k, v := range kv {
			if n, err := strconv.ParseInt(v, 0, 64); err != nil {
				return nil, err
			} else {
				mapping[k] = n
			}
		}
		return mapping, nil
	}
	return nil, nil
}

// Parses a space-separated key-value pair file and returns a
// key(string):value(string) mapping.
func parseSSKV(filename string) (map[string]string, error) {
	if stats, err := ioutil.ReadFile(filename); err != nil {
		return nil, err
	} else {
		mapping := make(map[string]string)
		scanner := bufio.NewScanner(strings.NewReader(string(stats)))
		for scanner.Scan() {
			line := scanner.Text()
			parts := strings.Split(line, " ")
			mapping[parts[0]] = parts[1]
		}
		return mapping, nil
	}
}<|endoftext|>


<commit_before>package silverback

import "net/http"

// A Handler is expected to be able to take a request and return a
// copy of itself based on that request.
type Handler interface {
	New(*http.Request) interface{}
	Path() string
}

// A BeforeHandler is a controller type that needs to perform some
// operation before every request.
type BeforeHandler interface {
	Handler
	BeforeHandle() error
}

// An AfterHandler is a controller type that needs to perform some
// operation after every request.  It is passed the response that was
// generated by the request method, so that it can act based on the
// response's fields.
type AfterHandler interface {
	Handler
	AfterHandle(*Response) error
}

// A Getter is a controller type that can handle GET requests for a
// single instance of a resource.
//
// Note: HEAD requests will automatically map to
type Getter interface {
	Handler
	Get(identifier string) *Response
}

// A Querier is a controller type that can handle GET requests that
// query for multiple instances of a resource.
type Querier interface {
	Handler
	Query() *Response
}

// A Poster is a controller type that can handle POST requests.
type Poster interface {
	Handler
	Post() *Response
}

// A Putter is a controller type that can handle PUT requests.
type Putter interface {
	Handler
	Put(identifier string) *Response
}

// A Patcher is a controller type that can handle PATCH requests.
type Patcher interface {
	Handler
	Patch(identifier string) *Response
}

// A Deleter is a controller type that can handle DELETE requests.
type Deleter interface {
	Handler
	Delete(identifier string) *Response
}
<commit_msg>Make Handler.New return a Handler<commit_after>package silverback

import "net/http"

// A Handler is expected to be able to take a request and return a
// copy of itself based on that request.
type Handler interface {
	New(*http.Request) Handler
	Path() string
}

// A BeforeHandler is a controller type that needs to perform some
// operation before every request.
type BeforeHandler interface {
	Handler
	BeforeHandle() error
}

// An AfterHandler is a controller type that needs to perform some
// operation after every request.  It is passed the response that was
// generated by the request method, so that it can act based on the
// response's fields.
type AfterHandler interface {
	Handler
	AfterHandle(*Response) error
}

// A Getter is a controller type that can handle GET requests for a
// single instance of a resource.
//
// Note: HEAD requests will automatically map to
type Getter interface {
	Handler
	Get(identifier string) *Response
}

// A Querier is a controller type that can handle GET requests that
// query for multiple instances of a resource.
type Querier interface {
	Handler
	Query() *Response
}

// A Poster is a controller type that can handle POST requests.
type Poster interface {
	Handler
	Post() *Response
}

// A Putter is a controller type that can handle PUT requests.
type Putter interface {
	Handler
	Put(identifier string) *Response
}

// A Patcher is a controller type that can handle PATCH requests.
type Patcher interface {
	Handler
	Patch(identifier string) *Response
}

// A Deleter is a controller type that can handle DELETE requests.
type Deleter interface {
	Handler
	Delete(identifier string) *Response
}
<|endoftext|>


<commit_before>package ioc

import (
	"encoding/csv"
	"io"
	"log"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"
)

var (
	configFile string
	IOCMapping IOMap
)

func init() {
	configFile = os.Getenv("IOC_FILE")
	if configFile != "" {
		f, err := os.Open(configFile)
		if err != nil {
			log.Fatalf("Failed to open configuration file %s with error: %s", configFile, err)
		}
		defer f.Close()
		IOCMapping = loadIOCConfig(f)
	}
}

func loadIOCConfig(f io.Reader) IOMap {
	reader := csv.NewReader(f)
	mapping := IOMap{Map: make(map[string]*IOC), Mutex: sync.RWMutex{}}

	for {
		record, err := reader.Read()
		if err == io.EOF {
			break
		}
		if err != nil {
			log.Fatalf("Error parsing csv file %s with error: %s", configFile, err)
		}

		path := strings.TrimSpace(record[0])
		durationConf := record[1]
		readConf := record[2]
		writeConf := record[3]

		duration, err := strconv.Atoi(durationConf)
		if err != nil {
			log.Fatalf("Error parsing duration %s", durationConf)
		}
		read, err := strconv.ParseUint(readConf, 10, 64)
		if err != nil {
			log.Fatalf("Error parsing read limit %s", readConf)
		}
		write, err := strconv.ParseUint(writeConf, 10, 64)
		if err != nil {
			log.Fatalf("Error parsing write limit %s", writeConf)
		}

		mapping.Add(path, time.Duration(duration)*time.Microsecond, read, write)
	}
	return mapping

}

type IOMap struct {
	Map   map[string]*IOC
	Mutex sync.RWMutex
}

func (iom *IOMap) Add(key string, duration time.Duration, read, write uint64) {
	iom.Mutex.Lock()
	defer iom.Mutex.Unlock()

	iom.Map[key] = NewIOC(duration, read, write)
}

func (iom *IOMap) Remove(key string) {
	iom.Mutex.Lock()
	defer iom.Mutex.Unlock()

	delete(iom.Map, key)
}

func (iom *IOMap) Update(key string, duration time.Duration, read, write uint64) {
	iom.Mutex.Lock()
	defer iom.Mutex.Unlock()

	c := iom.Map[key]
	c.Update(duration, read, write)
}

func (iom *IOMap) Get(key string) (*IOC, bool) {
	iom.Mutex.RLock()
	defer iom.Mutex.RUnlock()

	c, exists := iom.Map[key]
	return c, exists
}

func (iom *IOMap) FindPath(p string) *IOC {
	iom.Mutex.RLock()
	defer iom.Mutex.RUnlock()

	for k := range iom.Map {

		if strings.HasPrefix(p, k) {
			return iom.Map[k]
		}
	}
	return nil
}
<commit_msg>Start and stop ioc when added or removed<commit_after>package ioc

import (
	"encoding/csv"
	"io"
	"log"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"
)

var (
	configFile string
	IOCMapping IOMap
)

func init() {
	configFile = os.Getenv("IOC_FILE")
	if configFile != "" {
		f, err := os.Open(configFile)
		if err != nil {
			log.Fatalf("Failed to open configuration file %s with error: %s", configFile, err)
		}
		defer f.Close()
		IOCMapping = loadIOCConfig(f)
	}
}

func loadIOCConfig(f io.Reader) IOMap {
	reader := csv.NewReader(f)
	mapping := IOMap{Map: make(map[string]*IOC), Mutex: sync.RWMutex{}}

	for {
		record, err := reader.Read()
		if err == io.EOF {
			break
		}
		if err != nil {
			log.Fatalf("Error parsing csv file %s with error: %s", configFile, err)
		}

		path := strings.TrimSpace(record[0])
		durationConf := record[1]
		readConf := record[2]
		writeConf := record[3]

		duration, err := strconv.Atoi(durationConf)
		if err != nil {
			log.Fatalf("Error parsing duration %s", durationConf)
		}
		read, err := strconv.ParseUint(readConf, 10, 64)
		if err != nil {
			log.Fatalf("Error parsing read limit %s", readConf)
		}
		write, err := strconv.ParseUint(writeConf, 10, 64)
		if err != nil {
			log.Fatalf("Error parsing write limit %s", writeConf)
		}

		mapping.Add(path, time.Duration(duration)*time.Microsecond, read, write)
	}
	return mapping

}

type IOMap struct {
	Map   map[string]*IOC
	Mutex sync.RWMutex
}

func (iom *IOMap) Add(key string, duration time.Duration, read, write uint64) {
	c := NewIOC(duration, read, write)
	// Clock only around the map modification
	iom.Mutex.Lock()
	iom.Map[key] = c
	iom.Mutex.Unlock()
	go c.Start()
}

func (iom *IOMap) Remove(key string) {
	// Locking only around map modification
	iom.Mutex.Lock()
	c := iom.Map[key]
	delete(iom.Map, key)
	iom.Mutex.Unlock()
	// Stop the ioc
	c.Stop()
}

func (iom *IOMap) Update(key string, duration time.Duration, read, write uint64) {
	iom.Mutex.Lock()
	defer iom.Mutex.Unlock()

	c := iom.Map[key]
	c.Update(duration, read, write)
}

func (iom *IOMap) Get(key string) (*IOC, bool) {
	iom.Mutex.RLock()
	defer iom.Mutex.RUnlock()

	c, exists := iom.Map[key]
	return c, exists
}

func (iom *IOMap) FindPath(p string) *IOC {
	iom.Mutex.RLock()
	defer iom.Mutex.RUnlock()

	for k := range iom.Map {

		if strings.HasPrefix(p, k) {
			return iom.Map[k]
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package set

import (
	"testing"
)

// BenchmarkAdd checks the performance of the set.Add() method
func BenchmarkAdd(b *testing.B) {
	// Create a new set
	set := New()

	// Run set.Add() b.N times
	for i := 0; i < b.N; i++ {
		set.Add(i)
	}
}

// benchmarkCartesianProduct checks the performance of the set.CartesianProduct() method
func benchmarkCartesianProduct(n int, s *Set, t *Set) {
	// Run set.CartesianProduct() n times
	for i := 0; i < n; i++ {
		s.CartesianProduct(t)
	}
}

// BenchmarkCartesianProductSmall checks the performance of the set.CartesianProduct() method
// over a small data set
func BenchmarkCartesianProductSmall(b *testing.B) {
	benchmarkCartesianProduct(b.N, New(1, 2), New(2, 1))
}

// BenchmarkCartesianProductLarge checks the performance of the set.CartesianProduct() method
// over a large data set
func BenchmarkCartesianProductLarge(b *testing.B) {
	benchmarkCartesianProduct(b.N, New(1, 2, 3, 4, 5, 6, 7, 8, 9), New(9, 8, 7, 6, 5, 4, 3, 2, 1))
}

// benchmarkClone checks the performance of the set.Clone() method
func benchmarkClone(n int, s *Set) {
	// Run set.Clone() n times
	for i := 0; i < n; i++ {
		s.Clone()
	}
}

// BenchmarkCloneSmall checks the performance of the set.Clone() method
// over a small data set
func BenchmarkCloneSmall(b *testing.B) {
	benchmarkClone(b.N, New(1, 2))
}

// BenchmarkCloneLarge checks the performance of the set.Clone() method
// over a large data set
func BenchmarkCloneLarge(b *testing.B) {
	benchmarkClone(b.N, New(1, 2, 3, 4, 5, 6, 7, 8, 9))
}

// benchmarkDifference checks the performance of the set.Difference() method
func benchmarkDifference(n int, s *Set, t *Set) {
	// Run set.Difference() n times
	for i := 0; i < n; i++ {
		s.Difference(t)
	}
}

// BenchmarkDifferenceSmall checks the performance of the set.Difference() method
// over a small data set
func BenchmarkDifferenceSmall(b *testing.B) {
	benchmarkDifference(b.N, New(1, 2), New(2, 1))
}

// BenchmarkDifferenceLarge checks the performance of the set.Difference() method
// over a large data set
func BenchmarkDifferenceLarge(b *testing.B) {
	benchmarkDifference(b.N, New(1, 2, 3, 4, 5, 6, 7, 8, 9), New(9, 8, 7, 6, 5, 4, 3, 2, 1))
}

// benchmarkEnumerate checks the performance of the set.Enumerate() method
func benchmarkEnumerate(n int, s *Set) {
	// Run set.Enumerate() n times
	for i := 0; i < n; i++ {
		s.Enumerate()
	}
}

// BenchmarkEnumerateSmall checks the performance of the set.Enumerate() method
// over a small data set
func BenchmarkEnumerateSmall(b *testing.B) {
	benchmarkEnumerate(b.N, New(1, 2))
}

// BenchmarkEnumerateLarge checks the performance of the set.Enumerate() method
// over a large data set
func BenchmarkEnumerateLarge(b *testing.B) {
	benchmarkEnumerate(b.N, New(1, 2, 3, 4, 5, 6, 7, 8, 9))
}

// benchmarkEqual checks the performance of the set.Equal() method
func benchmarkEqual(n int, s *Set, t *Set) {
	// Run set.Equal() n times
	for i := 0; i < n; i++ {
		s.Equal(t)
	}
}

// BenchmarkEqualSmall checks the performance of the set.Equal() method
// over a small data set
func BenchmarkEqualSmall(b *testing.B) {
	benchmarkEqual(b.N, New(1, 2), New(2, 1))
}

// BenchmarkEqualLarge checks the performance of the set.Equal() method
// over a large data set
func BenchmarkEqualLarge(b *testing.B) {
	benchmarkEqual(b.N, New(1, 2, 3, 4, 5, 6, 7, 8, 9), New(9, 8, 7, 6, 5, 4, 3, 2, 1))
}

// benchmarkFilter checks the performance of the set.Filter() method
func benchmarkFilter(n int, s *Set, fn func(interface{}) bool) {
	// Run set.Filter() n times
	for i := 0; i < n; i++ {
		s.Filter(fn)
	}
}

// BenchmarkFilterSmall checks the performance of the set.Filter() method
// over a small data set
func BenchmarkFilterSmall(b *testing.B) {
	benchmarkFilter(b.N, New(1, 2), func(v interface{}) bool {
		return v.(int)%2 == 0
	})
}

// BenchmarkFilterLarge checks the performance of the set.Filter() method
// over a large data set
func BenchmarkFilterLarge(b *testing.B) {
	benchmarkFilter(b.N, New(1, 2, 3, 4, 5, 6, 7, 8, 9), func(v interface{}) bool {
		return v.(int)%2 == 0
	})
}

// BenchmarkHas checks the performance of the set.Has() method
func BenchmarkHas(b *testing.B) {
	// Create a new set
	set := New()

	// Run set.Has() b.N times
	for i := 0; i < b.N; i++ {
		set.Has(i)
	}
}
<commit_msg>Add BenchmarkIntersection(), small and large variants<commit_after>package set

import (
	"testing"
)

// BenchmarkAdd checks the performance of the set.Add() method
func BenchmarkAdd(b *testing.B) {
	// Create a new set
	set := New()

	// Run set.Add() b.N times
	for i := 0; i < b.N; i++ {
		set.Add(i)
	}
}

// benchmarkCartesianProduct checks the performance of the set.CartesianProduct() method
func benchmarkCartesianProduct(n int, s *Set, t *Set) {
	// Run set.CartesianProduct() n times
	for i := 0; i < n; i++ {
		s.CartesianProduct(t)
	}
}

// BenchmarkCartesianProductSmall checks the performance of the set.CartesianProduct() method
// over a small data set
func BenchmarkCartesianProductSmall(b *testing.B) {
	benchmarkCartesianProduct(b.N, New(1, 2), New(2, 1))
}

// BenchmarkCartesianProductLarge checks the performance of the set.CartesianProduct() method
// over a large data set
func BenchmarkCartesianProductLarge(b *testing.B) {
	benchmarkCartesianProduct(b.N, New(1, 2, 3, 4, 5, 6, 7, 8, 9), New(9, 8, 7, 6, 5, 4, 3, 2, 1))
}

// benchmarkClone checks the performance of the set.Clone() method
func benchmarkClone(n int, s *Set) {
	// Run set.Clone() n times
	for i := 0; i < n; i++ {
		s.Clone()
	}
}

// BenchmarkCloneSmall checks the performance of the set.Clone() method
// over a small data set
func BenchmarkCloneSmall(b *testing.B) {
	benchmarkClone(b.N, New(1, 2))
}

// BenchmarkCloneLarge checks the performance of the set.Clone() method
// over a large data set
func BenchmarkCloneLarge(b *testing.B) {
	benchmarkClone(b.N, New(1, 2, 3, 4, 5, 6, 7, 8, 9))
}

// benchmarkDifference checks the performance of the set.Difference() method
func benchmarkDifference(n int, s *Set, t *Set) {
	// Run set.Difference() n times
	for i := 0; i < n; i++ {
		s.Difference(t)
	}
}

// BenchmarkDifferenceSmall checks the performance of the set.Difference() method
// over a small data set
func BenchmarkDifferenceSmall(b *testing.B) {
	benchmarkDifference(b.N, New(1, 2), New(2, 1))
}

// BenchmarkDifferenceLarge checks the performance of the set.Difference() method
// over a large data set
func BenchmarkDifferenceLarge(b *testing.B) {
	benchmarkDifference(b.N, New(1, 2, 3, 4, 5, 6, 7, 8, 9), New(9, 8, 7, 6, 5, 4, 3, 2, 1))
}

// benchmarkEnumerate checks the performance of the set.Enumerate() method
func benchmarkEnumerate(n int, s *Set) {
	// Run set.Enumerate() n times
	for i := 0; i < n; i++ {
		s.Enumerate()
	}
}

// BenchmarkEnumerateSmall checks the performance of the set.Enumerate() method
// over a small data set
func BenchmarkEnumerateSmall(b *testing.B) {
	benchmarkEnumerate(b.N, New(1, 2))
}

// BenchmarkEnumerateLarge checks the performance of the set.Enumerate() method
// over a large data set
func BenchmarkEnumerateLarge(b *testing.B) {
	benchmarkEnumerate(b.N, New(1, 2, 3, 4, 5, 6, 7, 8, 9))
}

// benchmarkEqual checks the performance of the set.Equal() method
func benchmarkEqual(n int, s *Set, t *Set) {
	// Run set.Equal() n times
	for i := 0; i < n; i++ {
		s.Equal(t)
	}
}

// BenchmarkEqualSmall checks the performance of the set.Equal() method
// over a small data set
func BenchmarkEqualSmall(b *testing.B) {
	benchmarkEqual(b.N, New(1, 2), New(2, 1))
}

// BenchmarkEqualLarge checks the performance of the set.Equal() method
// over a large data set
func BenchmarkEqualLarge(b *testing.B) {
	benchmarkEqual(b.N, New(1, 2, 3, 4, 5, 6, 7, 8, 9), New(9, 8, 7, 6, 5, 4, 3, 2, 1))
}

// benchmarkFilter checks the performance of the set.Filter() method
func benchmarkFilter(n int, s *Set, fn func(interface{}) bool) {
	// Run set.Filter() n times
	for i := 0; i < n; i++ {
		s.Filter(fn)
	}
}

// BenchmarkFilterSmall checks the performance of the set.Filter() method
// over a small data set
func BenchmarkFilterSmall(b *testing.B) {
	benchmarkFilter(b.N, New(1, 2), func(v interface{}) bool {
		return v.(int)%2 == 0
	})
}

// BenchmarkFilterLarge checks the performance of the set.Filter() method
// over a large data set
func BenchmarkFilterLarge(b *testing.B) {
	benchmarkFilter(b.N, New(1, 2, 3, 4, 5, 6, 7, 8, 9), func(v interface{}) bool {
		return v.(int)%2 == 0
	})
}

// BenchmarkHas checks the performance of the set.Has() method
func BenchmarkHas(b *testing.B) {
	// Create a new set
	set := New()

	// Run set.Has() b.N times
	for i := 0; i < b.N; i++ {
		set.Has(i)
	}
}

// benchmarkIntersection checks the performance of the set.Intersection() method
func benchmarkIntersection(n int, s *Set, t *Set) {
	// Run set.Intersection() n times
	for i := 0; i < n; i++ {
		s.Intersection(t)
	}
}

// BenchmarkIntersectionSmall checks the performance of the set.Intersection() method
// over a small data set
func BenchmarkIntersectionSmall(b *testing.B) {
	benchmarkIntersection(b.N, New(1, 2), New(2, 1))
}

// BenchmarkIntersectionLarge checks the performance of the set.Intersection() method
// over a large data set
func BenchmarkIntersectionLarge(b *testing.B) {
	benchmarkIntersection(b.N, New(1, 2, 3, 4, 5, 6, 7, 8, 9), New(9, 8, 7, 6, 5, 4, 3, 2, 1))
}
<|endoftext|>