<commit_before>package cache

import (
	"context"
	"sort"
	"sync"

	"github.com/grafana/metrictank/mdata/cache/accnt"
	"github.com/grafana/metrictank/mdata/chunk"
	opentracing "github.com/opentracing/opentracing-go"
	"github.com/raintank/worldping-api/pkg/log"
	"gopkg.in/raintank/schema.v1"
)

// CCacheMetric caches data chunks
type CCacheMetric struct {
	sync.RWMutex

	// cached data chunks by timestamp
	chunks map[uint32]*CCacheChunk

	// chunk time stamps in ascending order
	keys []uint32

	MKey schema.MKey
}

// NewCCacheMetric creates a CCacheMetric
func NewCCacheMetric() *CCacheMetric {
	return &CCacheMetric{
		chunks: make(map[uint32]*CCacheChunk),
	}
}

func (mc *CCacheMetric) Init(MKey schema.MKey, prev uint32, itergen chunk.IterGen) {
	mc.Add(prev, itergen)
	mc.MKey = MKey
}

// Del deletes chunks for the given timestamp
func (mc *CCacheMetric) Del(ts uint32) int {
	mc.Lock()
	defer mc.Unlock()

	if _, ok := mc.chunks[ts]; !ok {
		return len(mc.chunks)
	}

	prev := mc.chunks[ts].Prev
	next := mc.chunks[ts].Next

	if prev != 0 {
		if _, ok := mc.chunks[prev]; ok {
			mc.chunks[prev].Next = 0
		}
	}

	if next != 0 {
		if _, ok := mc.chunks[next]; ok {
			mc.chunks[next].Prev = 0
		}
	}

	delete(mc.chunks, ts)

	// regenerate the list of sorted keys after deleting a chunk
	mc.generateKeys()

	return len(mc.chunks)
}

// AddRange adds a range (sequence) of chunks.
// Note the following requirements:
// the sequence should be in ascending timestamp order
// the sequence should be complete (no gaps)
func (mc *CCacheMetric) AddRange(prev uint32, itergens []chunk.IterGen) {
	if len(itergens) == 0 {
		return
	}

	mc.Lock()
	defer mc.Unlock()

	ts := itergens[0].Ts

	// if previous chunk has not been passed we try to be smart and figure it out.
	// this is common in a scenario where a metric continuously gets queried
	// for a range that starts less than one chunkspan before now().
	if prev == 0 {
		res, ok := mc.seekDesc(ts - 1)
		if ok {
			prev = res
		}
	}

	for _, itergen := range itergens {
		ts = itergen.Ts

		if _, ok := mc.chunks[ts]; ok {
			// chunk is already present. no need to error on that, just ignore it
			continue
		}

		mc.chunks[ts] = &CCacheChunk{
			Ts:    ts,
			Prev:  0,
			Next:  0,
			Itgen: itergen,
		}

		// if the previous chunk is cached, link in both directions
		if _, ok := mc.chunks[prev]; ok {
			mc.chunks[prev].Next = ts
			mc.chunks[ts].Prev = prev
		}
		prev = ts
	}

	nextTs := mc.nextTs(ts)

	// if nextTs() can't figure out the end date it returns ts
	if nextTs > ts {
		// if the next chunk is cached, link in both directions
		if _, ok := mc.chunks[nextTs]; ok {
			mc.chunks[nextTs].Prev = ts
			mc.chunks[ts].Next = nextTs
		}
	}

	// regenerate the list of sorted keys after adding a chunk
	mc.generateKeys()

	return
}

func (mc *CCacheMetric) Add(prev uint32, itergen chunk.IterGen) {
	ts := itergen.Ts

	mc.Lock()
	defer mc.Unlock()

	if _, ok := mc.chunks[ts]; ok {
		// chunk is already present. no need to error on that, just ignore it
		return
	}

	mc.chunks[ts] = &CCacheChunk{
		Ts:    ts,
		Prev:  0,
		Next:  0,
		Itgen: itergen,
	}

	nextTs := mc.nextTs(ts)

	log.Debug("CCacheMetric Add: caching chunk ts %d, nextTs %d", ts, nextTs)

	// if previous chunk has not been passed we try to be smart and figure it out.
	// this is common in a scenario where a metric continuously gets queried
	// for a range that starts less than one chunkspan before now().
	if prev == 0 {
		res, ok := mc.seekDesc(ts - 1)
		if ok {
			prev = res
		}
	}

	// if the previous chunk is cached, link in both directions
	if _, ok := mc.chunks[prev]; ok {
		mc.chunks[prev].Next = ts
		mc.chunks[ts].Prev = prev
	}

	// if nextTs() can't figure out the end date it returns ts
	if nextTs > ts {
		// if the next chunk is cached, link in both directions
		if _, ok := mc.chunks[nextTs]; ok {
			mc.chunks[nextTs].Prev = ts
			mc.chunks[ts].Next = nextTs
		}
	}

	// regenerate the list of sorted keys after adding a chunk
	mc.generateKeys()

	return
}

// generateKeys generates sorted slice of all chunk timestamps
// assumes we have at least read lock
func (mc *CCacheMetric) generateKeys() {
	keys := make([]uint32, 0, len(mc.chunks))
	for k := range mc.chunks {
		keys = append(keys, k)
	}
	sort.Sort(accnt.Uint32Asc(keys))
	mc.keys = keys
}

// nextTs takes a chunk's ts and returns the ts of the next chunk. (guessing if necessary)
// assumes we already have at least a read lock
func (mc *CCacheMetric) nextTs(ts uint32) uint32 {
	chunk := mc.chunks[ts]
	span := chunk.Itgen.Span
	if span > 0 {
		// if the chunk is span-aware we don't need anything else
		return chunk.Ts + span
	}

	if chunk.Next == 0 {
		if chunk.Prev == 0 {
			// if a chunk has no next and no previous chunk we have to assume it's length is 0
			return chunk.Ts
		} else {
			// if chunk has no next chunk, but has a previous one, we assume the length of this one is same as the previous one
			return chunk.Ts + (chunk.Ts - chunk.Prev)
		}
	} else {
		// if chunk has a next chunk, then that's the ts we need
		return chunk.Next
	}
}

// lastTs returns the last Ts of this metric cache
// since ranges are exclusive at the end this is actually the first Ts that is not cached
func (mc *CCacheMetric) lastTs() uint32 {
	mc.RLock()
	defer mc.RUnlock()
	return mc.nextTs(mc.keys[len(mc.keys)-1])
}

// seekAsc finds the t0 of the chunk that contains ts, by searching from old to recent
// if not found or can't be sure returns 0, false
// assumes we already have at least a read lock
func (mc *CCacheMetric) seekAsc(ts uint32) (uint32, bool) {
	log.Debug("CCacheMetric seekAsc: seeking for %d in the keys %+d", ts, mc.keys)

	for i := 0; i < len(mc.keys) && mc.keys[i] <= ts; i++ {
		if mc.nextTs(mc.keys[i]) > ts {
			log.Debug("CCacheMetric seekAsc: seek found ts %d is between %d and %d", ts, mc.keys[i], mc.nextTs(mc.keys[i]))
			return mc.keys[i], true
		}
	}

	log.Debug("CCacheMetric seekAsc: seekAsc unsuccessful")
	return 0, false
}

// seekDesc finds the t0 of the chunk that contains ts, by searching from recent to old
// if not found or can't be sure returns 0, false
// assumes we already have at least a read lock
func (mc *CCacheMetric) seekDesc(ts uint32) (uint32, bool) {
	log.Debug("CCacheMetric seekDesc: seeking for %d in the keys %+d", ts, mc.keys)

	for i := len(mc.keys) - 1; i >= 0 && mc.nextTs(mc.keys[i]) > ts; i-- {
		if mc.keys[i] <= ts {
			log.Debug("CCacheMetric seekDesc: seek found ts %d is between %d and %d", ts, mc.keys[i], mc.nextTs(mc.keys[i]))
			return mc.keys[i], true
		}
	}

	log.Debug("CCacheMetric seekDesc: seekDesc unsuccessful")
	return 0, false
}

func (mc *CCacheMetric) searchForward(ctx context.Context, metric schema.AMKey, from, until uint32, res *CCSearchResult) {
	ts, ok := mc.seekAsc(from)
	if !ok {
		return
	}

	// add all consecutive chunks to search results, starting at the one containing "from"
	for ; ts != 0; ts = mc.chunks[ts].Next {
		log.Debug("CCacheMetric searchForward: forward search adds chunk ts %d to start", ts)
		res.Start = append(res.Start, mc.chunks[ts].Itgen)
		nextTs := mc.nextTs(ts)
		res.From = nextTs

		if nextTs >= until {
			res.Complete = true
			break
		}
		if mc.chunks[ts].Next != 0 && ts >= mc.chunks[ts].Next {
			log.Warn("CCacheMetric: suspected bug suppressed. searchForward(%q, %d, %d, res) ts is %d while Next is %d", metric, from, until, ts, mc.chunks[ts].Next)
			span := opentracing.SpanFromContext(ctx)
			span.SetTag("searchForwardBug", true)
			searchFwdBug.Inc()
			break
		}
	}
}

func (mc *CCacheMetric) searchBackward(from, until uint32, res *CCSearchResult) {
	ts, ok := mc.seekDesc(until - 1)
	if !ok {
		return
	}

	for ; ts != 0; ts = mc.chunks[ts].Prev {
		if ts < from {
			break
		}

		log.Debug("CCacheMetric searchBackward: backward search adds chunk ts %d to end", ts)
		res.End = append(res.End, mc.chunks[ts].Itgen)
		res.Until = ts
	}
}

// Search searches the CCacheMetric's data and returns a complete-as-possible CCSearchResult
//
// we first look for the chunks where the "from" and "until" ts are in.
// then we seek from the "from" towards "until"
// and add as many cunks as possible to the result, if this did not result
// in all chunks necessary to serve the request we do the same in the reverse
// order from "until" to "from"
// if the first seek in chronological direction already ends up with all the
// chunks we need to serve the request, the second one can be skipped.
//
// EXAMPLE:
// from ts:                    |
// until ts:                                                   |
// cache:            |---|---|---|   |   |   |   |   |---|---|---|---|---|---|
// chunks returned:          |---|                   |---|---|---|
func (mc *CCacheMetric) Search(ctx context.Context, metric schema.AMKey, res *CCSearchResult, from, until uint32) {
	mc.RLock()
	defer mc.RUnlock()

	if len(mc.chunks) < 1 {
		return
	}

	mc.searchForward(ctx, metric, from, until, res)
	if !res.Complete {
		mc.searchBackward(from, until, res)
	}

	if !res.Complete && res.From > res.Until {
		log.Debug("CCacheMetric Search: Found from > until (%d/%d), printing chunks\n", res.From, res.Until)
		mc.debugMetric()
	}
}

func (mc *CCacheMetric) debugMetric() {
	log.Debug("CCacheMetric debugMetric: --- debugging metric ---\n")
	for _, key := range mc.keys {
		log.Debug("CCacheMetric debugMetric: ts %d; prev %d; next %d\n", key, mc.chunks[key].Prev, mc.chunks[key].Next)
	}
	log.Debug("CCacheMetric debugMetric: ------------------------\n")
}
<commit_msg>optimize AddRange<commit_after>package cache

import (
	"context"
	"sort"
	"sync"

	"github.com/grafana/metrictank/mdata/cache/accnt"
	"github.com/grafana/metrictank/mdata/chunk"
	opentracing "github.com/opentracing/opentracing-go"
	"github.com/raintank/worldping-api/pkg/log"
	"gopkg.in/raintank/schema.v1"
)

// CCacheMetric caches data chunks
type CCacheMetric struct {
	sync.RWMutex

	// cached data chunks by timestamp
	chunks map[uint32]*CCacheChunk

	// chunk time stamps in ascending order
	keys []uint32

	MKey schema.MKey
}

// NewCCacheMetric creates a CCacheMetric
func NewCCacheMetric() *CCacheMetric {
	return &CCacheMetric{
		chunks: make(map[uint32]*CCacheChunk),
	}
}

func (mc *CCacheMetric) Init(MKey schema.MKey, prev uint32, itergen chunk.IterGen) {
	mc.Add(prev, itergen)
	mc.MKey = MKey
}

// Del deletes chunks for the given timestamp
func (mc *CCacheMetric) Del(ts uint32) int {
	mc.Lock()
	defer mc.Unlock()

	if _, ok := mc.chunks[ts]; !ok {
		return len(mc.chunks)
	}

	prev := mc.chunks[ts].Prev
	next := mc.chunks[ts].Next

	if prev != 0 {
		if _, ok := mc.chunks[prev]; ok {
			mc.chunks[prev].Next = 0
		}
	}

	if next != 0 {
		if _, ok := mc.chunks[next]; ok {
			mc.chunks[next].Prev = 0
		}
	}

	delete(mc.chunks, ts)

	// regenerate the list of sorted keys after deleting a chunk
	mc.generateKeys()

	return len(mc.chunks)
}

// AddRange adds a range (sequence) of chunks.
// Note the following requirements:
// the sequence should be in ascending timestamp order
// the sequence should be complete (no gaps)
func (mc *CCacheMetric) AddRange(prev uint32, itergens []chunk.IterGen) {
	if len(itergens) == 0 {
		return
	}

	if len(itergens) == 1 {
		mc.Add(prev, itergens[0])
		return
	}

	mc.Lock()
	defer mc.Unlock()

	// handle the first one
	itergen := itergens[0]
	ts := itergen.Ts

	// if previous chunk has not been passed we try to be smart and figure it out.
	// this is common in a scenario where a metric continuously gets queried
	// for a range that starts less than one chunkspan before now().
	if prev == 0 {
		res, ok := mc.seekDesc(ts - 1)
		if ok {
			prev = res
		}
	}

	// if the previous chunk is cached, link it
	if _, ok := mc.chunks[prev]; ok {
		mc.chunks[prev].Next = ts
	} else {
		prev = 0
	}

	// add chunk if we don't have it yet (most likely)
	if _, ok := mc.chunks[ts]; !ok {
		mc.chunks[ts] = &CCacheChunk{
			Ts:    ts,
			Prev:  prev,
			Next:  itergens[1].Ts,
			Itgen: itergen,
		}
	}

	prev = ts

	// handle the 2nd until the last-but-one
	for i := 1; i < len(itergens)-1; i++ {
		itergen := itergens[i]
		ts := itergen.Ts
		// add chunk if we don't have it yet (most likely)
		if _, ok := mc.chunks[ts]; !ok {
			mc.chunks[ts] = &CCacheChunk{
				Ts:    ts,
				Prev:  prev,
				Next:  itergens[i+1].Ts,
				Itgen: itergen,
			}
		}
		prev = ts
	}

	// handle the last one
	itergen = itergens[len(itergens)-1]
	ts = itergen.Ts

	// if nextTs() can't figure out the end date it returns ts
	next := mc.nextTsCore(itergen, ts, prev, 0)
	if next == ts {
		next = 0
	} else {
		// if the next chunk is cached, link in both directions
		if _, ok := mc.chunks[next]; ok {
			mc.chunks[next].Prev = ts
		} else {
			next = 0
		}
	}

	// add chunk if we don't have it yet (most likely)
	if _, ok := mc.chunks[ts]; !ok {
		mc.chunks[ts] = &CCacheChunk{
			Ts:    ts,
			Prev:  prev,
			Next:  next,
			Itgen: itergen,
		}
	}
	// regenerate the list of sorted keys after adding a chunk
	mc.generateKeys()

	return
}

// Add adds a chunk to the cache
func (mc *CCacheMetric) Add(prev uint32, itergen chunk.IterGen) {
	ts := itergen.Ts

	mc.Lock()
	defer mc.Unlock()

	if _, ok := mc.chunks[ts]; ok {
		// chunk is already present. no need to error on that, just ignore it
		return
	}

	mc.chunks[ts] = &CCacheChunk{
		Ts:    ts,
		Prev:  0,
		Next:  0,
		Itgen: itergen,
	}

	nextTs := mc.nextTs(ts)

	log.Debug("CCacheMetric Add: caching chunk ts %d, nextTs %d", ts, nextTs)

	// if previous chunk has not been passed we try to be smart and figure it out.
	// this is common in a scenario where a metric continuously gets queried
	// for a range that starts less than one chunkspan before now().
	if prev == 0 {
		res, ok := mc.seekDesc(ts - 1)
		if ok {
			prev = res
		}
	}

	// if the previous chunk is cached, link in both directions
	if _, ok := mc.chunks[prev]; ok {
		mc.chunks[prev].Next = ts
		mc.chunks[ts].Prev = prev
	}

	// if nextTs() can't figure out the end date it returns ts
	if nextTs > ts {
		// if the next chunk is cached, link in both directions
		if _, ok := mc.chunks[nextTs]; ok {
			mc.chunks[nextTs].Prev = ts
			mc.chunks[ts].Next = nextTs
		}
	}

	// regenerate the list of sorted keys after adding a chunk
	mc.generateKeys()

	return
}

// generateKeys generates sorted slice of all chunk timestamps
// assumes we have at least read lock
func (mc *CCacheMetric) generateKeys() {
	keys := make([]uint32, 0, len(mc.chunks))
	for k := range mc.chunks {
		keys = append(keys, k)
	}
	sort.Sort(accnt.Uint32Asc(keys))
	mc.keys = keys
}

// nextTs takes a chunk's ts and returns the ts of the next chunk. (guessing if necessary)
// assumes we already have at least a read lock
func (mc *CCacheMetric) nextTs(ts uint32) uint32 {
	chunk := mc.chunks[ts]
	return mc.nextTsCore(chunk.Itgen, chunk.Ts, chunk.Prev, chunk.Next)
}

// nextTsCore returns the ts of the next chunk, given a chunks key properties
// (to the extent we know them). It guesses if necessary.
// assumes we already have at least a read lock
func (mc *CCacheMetric) nextTsCore(itgen chunk.IterGen, ts, prev, next uint32) uint32 {
	span := itgen.Span
	if span > 0 {
		// if the chunk is span-aware we don't need anything else
		return ts + span
	}

	// if chunk has a next chunk, then that's the ts we need
	if next != 0 {
		return next
	}
	// if chunk has no next chunk, but has a previous one, we assume the length of this one is same as the previous one
	if prev != 0 {
		return ts + (ts - prev)
	}
	// if a chunk has no next and no previous chunk we have to assume it's length is 0
	return ts
}

// lastTs returns the last Ts of this metric cache
// since ranges are exclusive at the end this is actually the first Ts that is not cached
func (mc *CCacheMetric) lastTs() uint32 {
	mc.RLock()
	defer mc.RUnlock()
	return mc.nextTs(mc.keys[len(mc.keys)-1])
}

// seekAsc finds the t0 of the chunk that contains ts, by searching from old to recent
// if not found or can't be sure returns 0, false
// assumes we already have at least a read lock
func (mc *CCacheMetric) seekAsc(ts uint32) (uint32, bool) {
	log.Debug("CCacheMetric seekAsc: seeking for %d in the keys %+d", ts, mc.keys)

	for i := 0; i < len(mc.keys) && mc.keys[i] <= ts; i++ {
		if mc.nextTs(mc.keys[i]) > ts {
			log.Debug("CCacheMetric seekAsc: seek found ts %d is between %d and %d", ts, mc.keys[i], mc.nextTs(mc.keys[i]))
			return mc.keys[i], true
		}
	}

	log.Debug("CCacheMetric seekAsc: seekAsc unsuccessful")
	return 0, false
}

// seekDesc finds the t0 of the chunk that contains ts, by searching from recent to old
// if not found or can't be sure returns 0, false
// assumes we already have at least a read lock
func (mc *CCacheMetric) seekDesc(ts uint32) (uint32, bool) {
	log.Debug("CCacheMetric seekDesc: seeking for %d in the keys %+d", ts, mc.keys)

	for i := len(mc.keys) - 1; i >= 0 && mc.nextTs(mc.keys[i]) > ts; i-- {
		if mc.keys[i] <= ts {
			log.Debug("CCacheMetric seekDesc: seek found ts %d is between %d and %d", ts, mc.keys[i], mc.nextTs(mc.keys[i]))
			return mc.keys[i], true
		}
	}

	log.Debug("CCacheMetric seekDesc: seekDesc unsuccessful")
	return 0, false
}

func (mc *CCacheMetric) searchForward(ctx context.Context, metric schema.AMKey, from, until uint32, res *CCSearchResult) {
	ts, ok := mc.seekAsc(from)
	if !ok {
		return
	}

	// add all consecutive chunks to search results, starting at the one containing "from"
	for ; ts != 0; ts = mc.chunks[ts].Next {
		log.Debug("CCacheMetric searchForward: forward search adds chunk ts %d to start", ts)
		res.Start = append(res.Start, mc.chunks[ts].Itgen)
		nextTs := mc.nextTs(ts)
		res.From = nextTs

		if nextTs >= until {
			res.Complete = true
			break
		}
		if mc.chunks[ts].Next != 0 && ts >= mc.chunks[ts].Next {
			log.Warn("CCacheMetric: suspected bug suppressed. searchForward(%q, %d, %d, res) ts is %d while Next is %d", metric, from, until, ts, mc.chunks[ts].Next)
			span := opentracing.SpanFromContext(ctx)
			span.SetTag("searchForwardBug", true)
			searchFwdBug.Inc()
			break
		}
	}
}

func (mc *CCacheMetric) searchBackward(from, until uint32, res *CCSearchResult) {
	ts, ok := mc.seekDesc(until - 1)
	if !ok {
		return
	}

	for ; ts != 0; ts = mc.chunks[ts].Prev {
		if ts < from {
			break
		}

		log.Debug("CCacheMetric searchBackward: backward search adds chunk ts %d to end", ts)
		res.End = append(res.End, mc.chunks[ts].Itgen)
		res.Until = ts
	}
}

// Search searches the CCacheMetric's data and returns a complete-as-possible CCSearchResult
//
// we first look for the chunks where the "from" and "until" ts are in.
// then we seek from the "from" towards "until"
// and add as many cunks as possible to the result, if this did not result
// in all chunks necessary to serve the request we do the same in the reverse
// order from "until" to "from"
// if the first seek in chronological direction already ends up with all the
// chunks we need to serve the request, the second one can be skipped.
//
// EXAMPLE:
// from ts:                    |
// until ts:                                                   |
// cache:            |---|---|---|   |   |   |   |   |---|---|---|---|---|---|
// chunks returned:          |---|                   |---|---|---|
func (mc *CCacheMetric) Search(ctx context.Context, metric schema.AMKey, res *CCSearchResult, from, until uint32) {
	mc.RLock()
	defer mc.RUnlock()

	if len(mc.chunks) < 1 {
		return
	}

	mc.searchForward(ctx, metric, from, until, res)
	if !res.Complete {
		mc.searchBackward(from, until, res)
	}

	if !res.Complete && res.From > res.Until {
		log.Debug("CCacheMetric Search: Found from > until (%d/%d), printing chunks\n", res.From, res.Until)
		mc.debugMetric()
	}
}

func (mc *CCacheMetric) debugMetric() {
	log.Debug("CCacheMetric debugMetric: --- debugging metric ---\n")
	for _, key := range mc.keys {
		log.Debug("CCacheMetric debugMetric: ts %d; prev %d; next %d\n", key, mc.chunks[key].Prev, mc.chunks[key].Next)
	}
	log.Debug("CCacheMetric debugMetric: ------------------------\n")
}
<|endoftext|>


<commit_before>package workerpool

import (
	"sync"
	"time"
)

type WorkerPool struct {
	workerChannels []chan func ()
	indexProvider  chan chan int
	lock           *sync.RWMutex
	stopped        bool

	timeSpentWorking     time.Duration
	usageSampleStartTime time.Time
}

func NewWorkerPool(poolSize int) (pool *WorkerPool) {
	pool = &WorkerPool{
		workerChannels: make([]chan func (), poolSize),
		indexProvider:  make(chan chan int, 0),
		lock:           &sync.RWMutex{},
	}

	pool.resetUsageTracking()
	go pool.mux()

	for i := range pool.workerChannels {
		pool.workerChannels[i] = make(chan func (), 0)
		go pool.startWorker(pool.workerChannels[i])
	}

	return
}

func (pool *WorkerPool) mux() {
	index := 0
	for {
		select {
		case c := <-pool.indexProvider:
			go func(index int) {
				c <- index
			}(index)
			index = (index + 1)%len(pool.workerChannels)
		}
	}
}

func (pool *WorkerPool) getNextIndex() int {
	c := make(chan int, 1)
	pool.indexProvider <- c
	return <-c
}

func (pool *WorkerPool) ScheduleWork(work func ()) {
	pool.lock.RLock()
	defer pool.lock.RUnlock()
	if pool.stopped {
		return
	}

	go func() {
		for {
			pool.lock.RLock()
			index := pool.getNextIndex()
			if !pool.stopped {
				select {
				case pool.workerChannels[index] <- work:
					pool.lock.RUnlock()
					return
				default:
					pool.lock.RUnlock()
					continue
				}
			}
		}
	}()
}

func (pool *WorkerPool) StopWorkers() {
	pool.lock.Lock()
	defer pool.lock.Unlock()
	if pool.stopped {
		return
	}
	pool.stopped = true
	for _, workerChannel := range pool.workerChannels {
		close(workerChannel)
	}
}

func (pool *WorkerPool) startWorker(workerChannel chan func ()) {
	for {
		f, ok := <-workerChannel
		if ok {
			tWork := time.Now()
			f()
			dtWork := time.Since(tWork)

			pool.lock.Lock()
			pool.timeSpentWorking += dtWork
			pool.lock.Unlock()
		} else {
			return
		}
	}
}

func (pool *WorkerPool) StartTrackingUsage() {
	pool.resetUsageTracking()
}

func (pool *WorkerPool) MeasureUsage() (usage float64, measurementDuration time.Duration) {
	pool.lock.Lock()
	timeSpentWorking := pool.timeSpentWorking
	measurementDuration = time.Since(pool.usageSampleStartTime)
	pool.lock.Unlock()

	usage = timeSpentWorking.Seconds()/(measurementDuration.Seconds()*float64(len(pool.workerChannels)))

	pool.resetUsageTracking()
	return usage, measurementDuration
}

func (pool *WorkerPool) resetUsageTracking() {
	pool.lock.Lock()
	pool.usageSampleStartTime = time.Now()
	pool.timeSpentWorking = 0
	pool.lock.Unlock()
}
<commit_msg>like, so much better workerpool<commit_after>package workerpool

import (
	"sync"
	"time"
)

type WorkerPool struct {
	workQueue chan func ()
	workerCloseChannels []chan bool

	lock           *sync.RWMutex
	stopped        bool

	timeSpentWorking     time.Duration
	usageSampleStartTime time.Time
}

func NewWorkerPool(poolSize int) (pool *WorkerPool) {
	pool = &WorkerPool{
		workQueue: make(chan func (), 0),
		workerCloseChannels: make([]chan bool, poolSize),
		lock:           &sync.RWMutex{},
	}

	pool.resetUsageTracking()

	for i := range pool.workerCloseChannels {
		pool.workerCloseChannels[i] = make(chan bool, 0)
		go pool.startWorker(pool.workQueue, pool.workerCloseChannels[i])
	}

	return
}

func (pool *WorkerPool) ScheduleWork(work func ()) {
	pool.lock.RLock()
	defer pool.lock.RUnlock()
	if pool.stopped {
		return
	}

	go func() {
		pool.workQueue <- work
	}()
}

func (pool *WorkerPool) StopWorkers() {
	pool.lock.Lock()
	defer pool.lock.Unlock()
	if pool.stopped {
		return
	}
	pool.stopped = true

	for _, closeChan := range pool.workerCloseChannels {
		closeChan <- true
	}
}

func (pool *WorkerPool) startWorker(workChannel chan func (), closeChannel chan bool) {
	for {
		select {
		case f := <-workChannel:
			tWork := time.Now()
			f()
			dtWork := time.Since(tWork)

			pool.lock.Lock()
			pool.timeSpentWorking += dtWork
			pool.lock.Unlock()
		case <-closeChannel:
			return
		}
	}
}

func (pool *WorkerPool) StartTrackingUsage() {
	pool.resetUsageTracking()
}

func (pool *WorkerPool) MeasureUsage() (usage float64, measurementDuration time.Duration) {
	pool.lock.Lock()
	timeSpentWorking := pool.timeSpentWorking
	measurementDuration = time.Since(pool.usageSampleStartTime)
	pool.lock.Unlock()

	usage = timeSpentWorking.Seconds()/(measurementDuration.Seconds()*float64(len(pool.workerCloseChannels)))

	pool.resetUsageTracking()
	return usage, measurementDuration
}

func (pool *WorkerPool) resetUsageTracking() {
	pool.lock.Lock()
	pool.usageSampleStartTime = time.Now()
	pool.timeSpentWorking = 0
	pool.lock.Unlock()
}
<|endoftext|>


<commit_before>package prometheusbackend

import (
	"expvar"
	"net/http"
	"strings"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"vitess.io/vitess/go/stats"
	"vitess.io/vitess/go/vt/log"
)

// PromBackend implements PullBackend using Prometheus as the backing metrics storage.
type PromBackend struct {
	namespace string
}

var (
	be PromBackend
)

// Init initializes the Prometheus be with the given namespace.
func Init(namespace string) {
	http.Handle("/metrics", promhttp.Handler())
	be.namespace = namespace
	stats.Register(be.publishPrometheusMetric)
}

// PublishPromMetric is used to publish the metric to Prometheus.
func (be PromBackend) publishPrometheusMetric(name string, v expvar.Var) {
	switch st := v.(type) {
	case *stats.Counter:
		newMetricFuncCollector(st, be.buildPromName(name), prometheus.CounterValue, func() float64 { return float64(st.Get()) })
	case *stats.CounterFunc:
		newMetricFuncCollector(st, be.buildPromName(name), prometheus.CounterValue, func() float64 { return float64(st.F()) })
	case *stats.Gauge:
		newMetricFuncCollector(st, be.buildPromName(name), prometheus.GaugeValue, func() float64 { return float64(st.Get()) })
	case *stats.GaugeFunc:
		newMetricFuncCollector(st, be.buildPromName(name), prometheus.GaugeValue, func() float64 { return float64(st.F()) })
	case *stats.CountersWithSingleLabel:
		newCountersWithSingleLabelCollector(st, be.buildPromName(name), st.Label(), prometheus.CounterValue)
	case *stats.CountersWithMultiLabels:
		newMetricWithMultiLabelsCollector(st, be.buildPromName(name))
	case *stats.CountersFuncWithMultiLabels:
		newMetricsFuncWithMultiLabelsCollector(st, be.buildPromName(name), prometheus.CounterValue)
	case *stats.GaugesFuncWithMultiLabels:
		newMetricsFuncWithMultiLabelsCollector(&st.CountersFuncWithMultiLabels, be.buildPromName(name), prometheus.GaugeValue)
	case *stats.GaugesWithSingleLabel:
		newGaugesWithSingleLabelCollector(st, be.buildPromName(name), st.Label(), prometheus.GaugeValue)
	case *stats.GaugesWithMultiLabels:
		newGaugesWithMultiLabelsCollector(st, be.buildPromName(name))
	case *stats.CounterDuration:
		newMetricFuncCollector(st, be.buildPromName(name), prometheus.CounterValue, func() float64 { return st.Get().Seconds() })
	case *stats.CounterDurationFunc:
		newMetricFuncCollector(st, be.buildPromName(name), prometheus.CounterValue, func() float64 { return st.F().Seconds() })
	case *stats.GaugeDuration:
		newMetricFuncCollector(st, be.buildPromName(name), prometheus.GaugeValue, func() float64 { return st.Get().Seconds() })
	case *stats.GaugeDurationFunc:
		newMetricFuncCollector(st, be.buildPromName(name), prometheus.GaugeValue, func() float64 { return st.F().Seconds() })
	case *stats.Timings:
		newTimingsCollector(st, be.buildPromName(name))
	case *stats.MultiTimings:
		newMultiTimingsCollector(st, be.buildPromName(name))
	case *stats.Histogram:
		newHistogramCollector(st, be.buildPromName(name))
	case *stats.String, stats.StringFunc, stats.StringMapFunc, *stats.Rates:
		// silently ignore these types since they don't make sense to
		// export to prometheus' data model
	default:
		log.Warningf("Not exporting to Prometheus an unsupported metric type of %T: %s", st, name)
	}
}

// buildPromName specifies the namespace as a prefix to the metric name
func (be PromBackend) buildPromName(name string) string {
	s := strings.TrimPrefix(normalizeMetric(name), be.namespace+"_")
	return prometheus.BuildFQName("", be.namespace, s)
}

func labelsToSnake(labels []string) []string {
	output := make([]string, len(labels))
	for i, l := range labels {
		output[i] = normalizeMetric(l)
	}
	return output
}

// normalizeMetricForPrometheus produces a compliant name by applying
// special case conversions and then applying a camel case to snake case converter.
func normalizeMetric(name string) string {
	// Special cases
	r := strings.NewReplacer("VSchema", "vschema", "VtGate", "vtgate")
	name = r.Replace(name)

	return stats.GetSnakeName(name)
}
<commit_msg>change the unsupported metric type case to log.Fatalf<commit_after>package prometheusbackend

import (
	"expvar"
	"net/http"
	"strings"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"vitess.io/vitess/go/stats"
	"vitess.io/vitess/go/vt/log"
)

// PromBackend implements PullBackend using Prometheus as the backing metrics storage.
type PromBackend struct {
	namespace string
}

var (
	be PromBackend
)

// Init initializes the Prometheus be with the given namespace.
func Init(namespace string) {
	http.Handle("/metrics", promhttp.Handler())
	be.namespace = namespace
	stats.Register(be.publishPrometheusMetric)
}

// PublishPromMetric is used to publish the metric to Prometheus.
func (be PromBackend) publishPrometheusMetric(name string, v expvar.Var) {
	switch st := v.(type) {
	case *stats.Counter:
		newMetricFuncCollector(st, be.buildPromName(name), prometheus.CounterValue, func() float64 { return float64(st.Get()) })
	case *stats.CounterFunc:
		newMetricFuncCollector(st, be.buildPromName(name), prometheus.CounterValue, func() float64 { return float64(st.F()) })
	case *stats.Gauge:
		newMetricFuncCollector(st, be.buildPromName(name), prometheus.GaugeValue, func() float64 { return float64(st.Get()) })
	case *stats.GaugeFunc:
		newMetricFuncCollector(st, be.buildPromName(name), prometheus.GaugeValue, func() float64 { return float64(st.F()) })
	case *stats.CountersWithSingleLabel:
		newCountersWithSingleLabelCollector(st, be.buildPromName(name), st.Label(), prometheus.CounterValue)
	case *stats.CountersWithMultiLabels:
		newMetricWithMultiLabelsCollector(st, be.buildPromName(name))
	case *stats.CountersFuncWithMultiLabels:
		newMetricsFuncWithMultiLabelsCollector(st, be.buildPromName(name), prometheus.CounterValue)
	case *stats.GaugesFuncWithMultiLabels:
		newMetricsFuncWithMultiLabelsCollector(&st.CountersFuncWithMultiLabels, be.buildPromName(name), prometheus.GaugeValue)
	case *stats.GaugesWithSingleLabel:
		newGaugesWithSingleLabelCollector(st, be.buildPromName(name), st.Label(), prometheus.GaugeValue)
	case *stats.GaugesWithMultiLabels:
		newGaugesWithMultiLabelsCollector(st, be.buildPromName(name))
	case *stats.CounterDuration:
		newMetricFuncCollector(st, be.buildPromName(name), prometheus.CounterValue, func() float64 { return st.Get().Seconds() })
	case *stats.CounterDurationFunc:
		newMetricFuncCollector(st, be.buildPromName(name), prometheus.CounterValue, func() float64 { return st.F().Seconds() })
	case *stats.GaugeDuration:
		newMetricFuncCollector(st, be.buildPromName(name), prometheus.GaugeValue, func() float64 { return st.Get().Seconds() })
	case *stats.GaugeDurationFunc:
		newMetricFuncCollector(st, be.buildPromName(name), prometheus.GaugeValue, func() float64 { return st.F().Seconds() })
	case *stats.Timings:
		newTimingsCollector(st, be.buildPromName(name))
	case *stats.MultiTimings:
		newMultiTimingsCollector(st, be.buildPromName(name))
	case *stats.Histogram:
		newHistogramCollector(st, be.buildPromName(name))
	case *stats.String, stats.StringFunc, stats.StringMapFunc, *stats.Rates:
		// Silently ignore these types since they don't make sense to
		// export to Prometheus' data model.
	default:
		log.Fatalf("prometheus: not exporting unsupported metric type %T: %s", st, name)
	}
}

// buildPromName specifies the namespace as a prefix to the metric name
func (be PromBackend) buildPromName(name string) string {
	s := strings.TrimPrefix(normalizeMetric(name), be.namespace+"_")
	return prometheus.BuildFQName("", be.namespace, s)
}

func labelsToSnake(labels []string) []string {
	output := make([]string, len(labels))
	for i, l := range labels {
		output[i] = normalizeMetric(l)
	}
	return output
}

// normalizeMetricForPrometheus produces a compliant name by applying
// special case conversions and then applying a camel case to snake case converter.
func normalizeMetric(name string) string {
	// Special cases
	r := strings.NewReplacer("VSchema", "vschema", "VtGate", "vtgate")
	name = r.Replace(name)

	return stats.GetSnakeName(name)
}
<|endoftext|>


<commit_before>//go:build linux
// +build linux

package macvlan

import (
	"net"
	"sync"

	"github.com/docker/docker/libnetwork/datastore"
	"github.com/docker/docker/libnetwork/discoverapi"
	"github.com/docker/docker/libnetwork/driverapi"
	"github.com/docker/docker/libnetwork/types"
)

const (
	vethLen             = 7
	containerVethPrefix = "eth"
	vethPrefix          = "veth"
	macvlanType         = "macvlan"  // driver type name
	modePrivate         = "private"  // macvlan mode private
	modeVepa            = "vepa"     // macvlan mode vepa
	modeBridge          = "bridge"   // macvlan mode bridge
	modePassthru        = "passthru" // macvlan mode passthrough
	parentOpt           = "parent"   // parent interface -o parent
	modeOpt             = "_mode"    // macvlan mode ux opt suffix
)

var driverModeOpt = macvlanType + modeOpt // mode --option macvlan_mode

type endpointTable map[string]*endpoint

type networkTable map[string]*network

type driver struct {
	networks networkTable
	sync.Once
	sync.Mutex
	store datastore.DataStore
}

type endpoint struct {
	id       string
	nid      string
	mac      net.HardwareAddr
	addr     *net.IPNet
	addrv6   *net.IPNet
	srcName  string
	dbIndex  uint64
	dbExists bool
}

type network struct {
	id        string
	endpoints endpointTable
	driver    *driver
	config    *configuration
	sync.Mutex
}

// Init initializes and registers the libnetwork macvlan driver
func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
	c := driverapi.Capability{
		DataScope:         datastore.LocalScope,
		ConnectivityScope: datastore.GlobalScope,
	}
	d := &driver{
		networks: networkTable{},
	}
	if err := d.initStore(config); err != nil {
		return err
	}

	return dc.RegisterDriver(macvlanType, d, c)
}

func (d *driver) NetworkAllocate(id string, option map[string]string, ipV4Data, ipV6Data []driverapi.IPAMData) (map[string]string, error) {
	return nil, types.NotImplementedErrorf("not implemented")
}

func (d *driver) NetworkFree(id string) error {
	return types.NotImplementedErrorf("not implemented")
}

func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) {
	return make(map[string]interface{}), nil
}

func (d *driver) Type() string {
	return macvlanType
}

func (d *driver) IsBuiltIn() bool {
	return true
}

func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error {
	return nil
}

func (d *driver) RevokeExternalConnectivity(nid, eid string) error {
	return nil
}

// DiscoverNew is a notification for a new discovery event
func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
	return nil
}

// DiscoverDelete is a notification for a discovery delete event
func (d *driver) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error {
	return nil
}

func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
}

func (d *driver) DecodeTableEntry(tablename string, key string, value []byte) (string, map[string]string) {
	return "", nil
}
<commit_msg>libnetwork: macvlan: clean up some consts<commit_after>//go:build linux
// +build linux

package macvlan

import (
	"net"
	"sync"

	"github.com/docker/docker/libnetwork/datastore"
	"github.com/docker/docker/libnetwork/discoverapi"
	"github.com/docker/docker/libnetwork/driverapi"
	"github.com/docker/docker/libnetwork/types"
)

const (
	vethLen             = 7
	containerVethPrefix = "eth"
	vethPrefix          = "veth"
	macvlanType         = "macvlan"      // driver type name
	modePrivate         = "private"      // macvlan mode private
	modeVepa            = "vepa"         // macvlan mode vepa
	modeBridge          = "bridge"       // macvlan mode bridge
	modePassthru        = "passthru"     // macvlan mode passthrough
	parentOpt           = "parent"       // parent interface -o parent
	driverModeOpt       = "macvlan_mode" // macvlan mode ux opt suffix
)

type endpointTable map[string]*endpoint

type networkTable map[string]*network

type driver struct {
	networks networkTable
	sync.Once
	sync.Mutex
	store datastore.DataStore
}

type endpoint struct {
	id       string
	nid      string
	mac      net.HardwareAddr
	addr     *net.IPNet
	addrv6   *net.IPNet
	srcName  string
	dbIndex  uint64
	dbExists bool
}

type network struct {
	id        string
	endpoints endpointTable
	driver    *driver
	config    *configuration
	sync.Mutex
}

// Init initializes and registers the libnetwork macvlan driver
func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
	c := driverapi.Capability{
		DataScope:         datastore.LocalScope,
		ConnectivityScope: datastore.GlobalScope,
	}
	d := &driver{
		networks: networkTable{},
	}
	if err := d.initStore(config); err != nil {
		return err
	}

	return dc.RegisterDriver(macvlanType, d, c)
}

func (d *driver) NetworkAllocate(id string, option map[string]string, ipV4Data, ipV6Data []driverapi.IPAMData) (map[string]string, error) {
	return nil, types.NotImplementedErrorf("not implemented")
}

func (d *driver) NetworkFree(id string) error {
	return types.NotImplementedErrorf("not implemented")
}

func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) {
	return make(map[string]interface{}), nil
}

func (d *driver) Type() string {
	return macvlanType
}

func (d *driver) IsBuiltIn() bool {
	return true
}

func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error {
	return nil
}

func (d *driver) RevokeExternalConnectivity(nid, eid string) error {
	return nil
}

// DiscoverNew is a notification for a new discovery event
func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
	return nil
}

// DiscoverDelete is a notification for a discovery delete event
func (d *driver) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error {
	return nil
}

func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
}

func (d *driver) DecodeTableEntry(tablename string, key string, value []byte) (string, map[string]string) {
	return "", nil
}
<|endoftext|>


<commit_before>package terraform

import (
	"log"

	"github.com/hashicorp/terraform/addrs"
	"github.com/hashicorp/terraform/dag"
	"github.com/hashicorp/terraform/states"
	"github.com/zclconf/go-cty/cty"
)

// OrphanResourceCountTransformer is a GraphTransformer that adds orphans
// for an expanded count to the graph. The determination of this depends
// on the count argument given.
//
// Orphans are found by comparing the count to what is found in the state.
// This transform assumes that if an element in the state is within the count
// bounds given, that it is not an orphan.
type OrphanResourceCountTransformer struct {
	Concrete ConcreteResourceInstanceNodeFunc

	Count   int                  // Actual count of the resource, or -1 if count is not set at all
	ForEach map[string]cty.Value // The ForEach map on the resource
	Addr    addrs.AbsResource    // Addr of the resource to look for orphans
	State   *states.State        // Full global state
}

func (t *OrphanResourceCountTransformer) Transform(g *Graph) error {
	rs := t.State.Resource(t.Addr)
	if rs == nil {
		return nil // Resource doesn't exist in state, so nothing to do!
	}

	haveKeys := make(map[addrs.InstanceKey]struct{})
	for key := range rs.Instances {
		haveKeys[key] = struct{}{}
	}

	// if for_each is set, use that transformer
	if t.ForEach != nil {
		return t.transformForEach(haveKeys, g)
	}
	if t.Count < 0 {
		return t.transformNoCount(haveKeys, g)
	}
	if t.Count == 0 {
		return t.transformZeroCount(haveKeys, g)
	}
	return t.transformCount(haveKeys, g)
}

func (t *OrphanResourceCountTransformer) transformForEach(haveKeys map[addrs.InstanceKey]struct{}, g *Graph) error {
	// If there is a no-key node, add this to the graph first,
	// so that we can create edges to it in subsequent (StringKey) nodes.
	// This is because the last item determines the resource mode for the whole resource,
	// so if this (non-deterministically) happens to end up as the last one,
	// that will change the resource's EachMode and our addressing for our instances
	// will not work as expected
	noKeyNode, hasNoKeyNode := haveKeys[addrs.NoKey]
	if hasNoKeyNode {
		g.Add(noKeyNode)
	}

	for key := range haveKeys {
		s, _ := key.(addrs.StringKey)
		// If the key is present in our current for_each, carry on
		if _, ok := t.ForEach[string(s)]; ok {
			continue
		}

		// If the key is no-key, we have already added it, so skip
		if key == addrs.NoKey {
			continue
		}

		abstract := NewNodeAbstractResourceInstance(t.Addr.Instance(key))
		var node dag.Vertex = abstract
		if f := t.Concrete; f != nil {
			node = f(abstract)
		}
		log.Printf("[TRACE] OrphanResourceCount(non-zero): adding %s as %T", t.Addr, node)
		g.Add(node)

		// Add edge to noKeyNode if it exists
		if hasNoKeyNode {
			g.Connect(dag.BasicEdge(node, noKeyNode))
		}
	}
	return nil
}

func (t *OrphanResourceCountTransformer) transformCount(haveKeys map[addrs.InstanceKey]struct{}, g *Graph) error {
	// Due to the logic in Transform, we only get in here if our count is
	// at least one.

	_, have0Key := haveKeys[addrs.IntKey(0)]

	for key := range haveKeys {
		if key == addrs.NoKey && !have0Key {
			// If we have no 0-key then we will accept a no-key instance
			// as an alias for it.
			continue
		}

		i, isInt := key.(addrs.IntKey)
		if isInt && int(i) < t.Count {
			continue
		}

		abstract := NewNodeAbstractResourceInstance(t.Addr.Instance(key))
		var node dag.Vertex = abstract
		if f := t.Concrete; f != nil {
			node = f(abstract)
		}
		log.Printf("[TRACE] OrphanResourceCount(non-zero): adding %s as %T", t.Addr, node)
		g.Add(node)
	}

	return nil
}

func (t *OrphanResourceCountTransformer) transformZeroCount(haveKeys map[addrs.InstanceKey]struct{}, g *Graph) error {
	// This case is easy: we need to orphan any keys we have at all.

	for key := range haveKeys {
		abstract := NewNodeAbstractResourceInstance(t.Addr.Instance(key))
		var node dag.Vertex = abstract
		if f := t.Concrete; f != nil {
			node = f(abstract)
		}
		log.Printf("[TRACE] OrphanResourceCount(zero): adding %s as %T", t.Addr, node)
		g.Add(node)
	}

	return nil
}

func (t *OrphanResourceCountTransformer) transformNoCount(haveKeys map[addrs.InstanceKey]struct{}, g *Graph) error {
	// Negative count indicates that count is not set at all, in which
	// case we expect to have a single instance with no key set at all.
	// However, we'll also accept an instance with key 0 set as an alias
	// for it, in case the user has just deleted the "count" argument and
	// so wants to keep the first instance in the set.

	_, haveNoKey := haveKeys[addrs.NoKey]
	_, have0Key := haveKeys[addrs.IntKey(0)]
	keepKey := addrs.NoKey
	if have0Key && !haveNoKey {
		// If we don't have a no-key instance then we can use the 0-key instance
		// instead.
		keepKey = addrs.IntKey(0)
	}

	for key := range haveKeys {
		if key == keepKey {
			continue
		}

		abstract := NewNodeAbstractResourceInstance(t.Addr.Instance(key))
		var node dag.Vertex = abstract
		if f := t.Concrete; f != nil {
			node = f(abstract)
		}
		log.Printf("[TRACE] OrphanResourceCount(no-count): adding %s as %T", t.Addr, node)
		g.Add(node)
	}

	return nil
}
<commit_msg>Creating the node would be nice<commit_after>package terraform

import (
	"log"

	"github.com/hashicorp/terraform/addrs"
	"github.com/hashicorp/terraform/dag"
	"github.com/hashicorp/terraform/states"
	"github.com/zclconf/go-cty/cty"
)

// OrphanResourceCountTransformer is a GraphTransformer that adds orphans
// for an expanded count to the graph. The determination of this depends
// on the count argument given.
//
// Orphans are found by comparing the count to what is found in the state.
// This transform assumes that if an element in the state is within the count
// bounds given, that it is not an orphan.
type OrphanResourceCountTransformer struct {
	Concrete ConcreteResourceInstanceNodeFunc

	Count   int                  // Actual count of the resource, or -1 if count is not set at all
	ForEach map[string]cty.Value // The ForEach map on the resource
	Addr    addrs.AbsResource    // Addr of the resource to look for orphans
	State   *states.State        // Full global state
}

func (t *OrphanResourceCountTransformer) Transform(g *Graph) error {
	rs := t.State.Resource(t.Addr)
	if rs == nil {
		return nil // Resource doesn't exist in state, so nothing to do!
	}

	haveKeys := make(map[addrs.InstanceKey]struct{})
	for key := range rs.Instances {
		haveKeys[key] = struct{}{}
	}

	// if for_each is set, use that transformer
	if t.ForEach != nil {
		return t.transformForEach(haveKeys, g)
	}
	if t.Count < 0 {
		return t.transformNoCount(haveKeys, g)
	}
	if t.Count == 0 {
		return t.transformZeroCount(haveKeys, g)
	}
	return t.transformCount(haveKeys, g)
}

func (t *OrphanResourceCountTransformer) transformForEach(haveKeys map[addrs.InstanceKey]struct{}, g *Graph) error {
	// If there is a no-key node, add this to the graph first,
	// so that we can create edges to it in subsequent (StringKey) nodes.
	// This is because the last item determines the resource mode for the whole resource,
	// so if this (non-deterministically) happens to end up as the last one,
	// that will change the resource's EachMode and our addressing for our instances
	// will not work as expected
	_, hasNoKeyNode := haveKeys[addrs.NoKey]
	var noKeyNode dag.Vertex
	if hasNoKeyNode {
		abstract := NewNodeAbstractResourceInstance(t.Addr.Instance(addrs.NoKey))
		noKeyNode = abstract
		if f := t.Concrete; f != nil {
			noKeyNode = f(abstract)
		}
		g.Add(noKeyNode)
	}

	for key := range haveKeys {
		s, _ := key.(addrs.StringKey)
		// If the key is present in our current for_each, carry on
		if _, ok := t.ForEach[string(s)]; ok {
			continue
		}

		// If the key is no-key, we have already added it, so skip
		if key == addrs.NoKey {
			continue
		}

		abstract := NewNodeAbstractResourceInstance(t.Addr.Instance(key))
		var node dag.Vertex = abstract
		if f := t.Concrete; f != nil {
			node = f(abstract)
		}
		log.Printf("[TRACE] OrphanResourceCount(non-zero): adding %s as %T", t.Addr, node)
		g.Add(node)

		// Add edge to noKeyNode if it exists
		if hasNoKeyNode {
			g.Connect(dag.BasicEdge(node, noKeyNode))
		}
	}
	return nil
}

func (t *OrphanResourceCountTransformer) transformCount(haveKeys map[addrs.InstanceKey]struct{}, g *Graph) error {
	// Due to the logic in Transform, we only get in here if our count is
	// at least one.

	_, have0Key := haveKeys[addrs.IntKey(0)]

	for key := range haveKeys {
		if key == addrs.NoKey && !have0Key {
			// If we have no 0-key then we will accept a no-key instance
			// as an alias for it.
			continue
		}

		i, isInt := key.(addrs.IntKey)
		if isInt && int(i) < t.Count {
			continue
		}

		abstract := NewNodeAbstractResourceInstance(t.Addr.Instance(key))
		var node dag.Vertex = abstract
		if f := t.Concrete; f != nil {
			node = f(abstract)
		}
		log.Printf("[TRACE] OrphanResourceCount(non-zero): adding %s as %T", t.Addr, node)
		g.Add(node)
	}

	return nil
}

func (t *OrphanResourceCountTransformer) transformZeroCount(haveKeys map[addrs.InstanceKey]struct{}, g *Graph) error {
	// This case is easy: we need to orphan any keys we have at all.

	for key := range haveKeys {
		abstract := NewNodeAbstractResourceInstance(t.Addr.Instance(key))
		var node dag.Vertex = abstract
		if f := t.Concrete; f != nil {
			node = f(abstract)
		}
		log.Printf("[TRACE] OrphanResourceCount(zero): adding %s as %T", t.Addr, node)
		g.Add(node)
	}

	return nil
}

func (t *OrphanResourceCountTransformer) transformNoCount(haveKeys map[addrs.InstanceKey]struct{}, g *Graph) error {
	// Negative count indicates that count is not set at all, in which
	// case we expect to have a single instance with no key set at all.
	// However, we'll also accept an instance with key 0 set as an alias
	// for it, in case the user has just deleted the "count" argument and
	// so wants to keep the first instance in the set.

	_, haveNoKey := haveKeys[addrs.NoKey]
	_, have0Key := haveKeys[addrs.IntKey(0)]
	keepKey := addrs.NoKey
	if have0Key && !haveNoKey {
		// If we don't have a no-key instance then we can use the 0-key instance
		// instead.
		keepKey = addrs.IntKey(0)
	}

	for key := range haveKeys {
		if key == keepKey {
			continue
		}

		abstract := NewNodeAbstractResourceInstance(t.Addr.Instance(key))
		var node dag.Vertex = abstract
		if f := t.Concrete; f != nil {
			node = f(abstract)
		}
		log.Printf("[TRACE] OrphanResourceCount(no-count): adding %s as %T", t.Addr, node)
		g.Add(node)
	}

	return nil
}
<|endoftext|>


<commit_before>package zcash

import (
	"encoding/binary"
	"encoding/hex"
	"errors"
	"log"
	"strings"
	"sync"

	"github.com/robvanmieghem/gominer/clients"
	"github.com/robvanmieghem/gominer/clients/stratum"
)

// zcash stratum as defined on https://github.com/str4d/zips/blob/23d74b0373c824dd51c7854c0e3ea22489ba1b76/drafts/str4d-stratum/draft1.rst

type stratumJob struct {
	JobID      string
	Version    uint32
	PrevHash   []byte
	MerkleRoot []byte
	Reserved   []byte
	Time       []byte
	Bits       []byte
	CleanJobs  bool

	ExtraNonce2 stratum.ExtraNonce2
}

//StratumClient is a zcash client using the stratum protocol
type StratumClient struct {
	connectionstring string
	User             string

	mutex           sync.Mutex // protects following
	stratumclient   *stratum.Client
	extranonce1     []byte
	extranonce2Size uint
	target          []byte
	currentJob      stratumJob
	clients.BaseClient
}

// NewClient creates a new StratumClient given a '[stratum+tcp://]host:port' connectionstring
func NewClient(connectionstring, pooluser string) (sc clients.Client) {
	if strings.HasPrefix(connectionstring, "stratum+tcp://") {
		connectionstring = strings.TrimPrefix(connectionstring, "stratum+tcp://")
	}
	sc = &StratumClient{connectionstring: connectionstring, User: pooluser}
	return
}

//Start connects to the stratumserver and processes the notifications
func (sc *StratumClient) Start() {
	sc.mutex.Lock()
	defer func() {
		sc.mutex.Unlock()
	}()

	sc.DeprecateOutstandingJobs()

	sc.stratumclient = &stratum.Client{}
	//In case of an error, drop the current stratumclient and restart
	sc.stratumclient.ErrorCallback = func(err error) {
		log.Println("Error in connection to stratumserver:", err)
		sc.stratumclient.Close()
		sc.Start()
	}

	sc.subscribeToStratumTargetChanges()
	sc.subscribeToStratumJobNotifications()

	//Connect to the stratum server
	log.Println("Connecting to", sc.connectionstring)
	sc.stratumclient.Dial(sc.connectionstring)

	//Subscribe for mining
	//Close the connection on an error will cause the client to generate an error, resulting in te errorhandler to be triggered
	result, err := sc.stratumclient.Call("mining.subscribe", []string{"gominer"})
	if err != nil {
		log.Println("ERROR Error in response from stratum", err)
		sc.stratumclient.Close()
		return
	}
	reply, ok := result.([]interface{})
	if !ok || len(reply) < 2 {
		log.Println("ERROR Invalid response from stratum", result)
		sc.stratumclient.Close()
		return
	}

	//Keep the extranonce1 and extranonce2_size from the reply
	if sc.extranonce1, err = stratum.HexStringToBytes(reply[1]); err != nil {
		log.Println("ERROR Invalid extrannonce1 from startum")
		sc.stratumclient.Close()
		return
	}

	sc.extranonce2Size = uint(32 - len(sc.extranonce1))

	//Authorize the miner
	_, err = sc.stratumclient.Call("mining.authorize", []string{sc.User, ""})
	if err != nil {
		log.Println("Unable to authorize:", err)
		sc.stratumclient.Close()
		return
	}

}

func (sc *StratumClient) subscribeToStratumTargetChanges() {
	sc.stratumclient.SetNotificationHandler("mining.set_target", func(params []interface{}) {

		if params == nil || len(params) < 1 {
			log.Println("ERROR No target parameter supplied by stratum server")
			return
		}
		var err error
		sc.target, err = stratum.HexStringToBytes(params[0])
		if err != nil {
			log.Println("ERROR Invalid target supplied by stratum server:", params[0])
		}

		log.Println("Stratum server changed target to", params[0])
	})
}

func (sc *StratumClient) subscribeToStratumJobNotifications() {
	sc.stratumclient.SetNotificationHandler("mining.notify", func(params []interface{}) {
		log.Println("New job received from stratum server")
		if params == nil || len(params) < 8 {
			log.Println("ERROR Wrong number of parameters supplied by stratum server")
			return
		}

		sj := stratumJob{}

		sj.ExtraNonce2.Size = sc.extranonce2Size

		var ok bool
		var err error
		if sj.JobID, ok = params[0].(string); !ok {
			log.Println("ERROR Wrong job_id parameter supplied by stratum server")
			return
		}
		versionBytes, err := stratum.HexStringToBytes(params[1])
		if err != nil {
			log.Println("ERROR Wrong version parameter supplied by stratum server:", params[1])
			return
		}
		sj.Version = binary.LittleEndian.Uint32(versionBytes)
		if sj.Version != 4 {
			log.Println("ERROR Wrong version supplied by stratum server:", sj.Version)
			return
		}
		if sj.PrevHash, err = stratum.HexStringToBytes(params[2]); err != nil {
			log.Println("ERROR Wrong prevhash parameter supplied by stratum server")
			return
		}
		if sj.MerkleRoot, err = stratum.HexStringToBytes(params[3]); err != nil {
			log.Println("ERROR Wrong merkleroot parameter supplied by stratum server")
			return
		}
		if sj.Reserved, err = stratum.HexStringToBytes(params[5]); err != nil {
			log.Println("ERROR Wrong reserved parameter supplied by stratum server")
			return
		}
		if sj.Time, err = stratum.HexStringToBytes(params[5]); err != nil {
			log.Println("ERROR Wrong time parameter supplied by stratum server")
			return
		}

		if sj.Bits, err = stratum.HexStringToBytes(params[6]); err != nil {
			log.Println("ERROR Wrong bits parameter supplied by stratum server")
			return
		}
		if sj.CleanJobs, ok = params[7].(bool); !ok {
			log.Println("ERROR Wrong clean_jobs parameter supplied by stratum server")
			return
		}
		sc.addNewStratumJob(sj)
	})
}

func (sc *StratumClient) addNewStratumJob(sj stratumJob) {
	sc.mutex.Lock()
	defer sc.mutex.Unlock()
	sc.currentJob = sj
	if sj.CleanJobs {
		sc.DeprecateOutstandingJobs()
	}
	sc.AddJobToDeprecate(sj.JobID)
}

//GetHeaderForWork fetches new work from the SIA daemon
func (sc *StratumClient) GetHeaderForWork() (target, header []byte, deprecationChannel chan bool, job interface{}, err error) {
	err = errors.New("GetHeaderForWork not implemented for zcash stratum yet")
	return
}

//SubmitHeader reports a solved header
func (sc *StratumClient) SubmitHeader(header []byte, job interface{}) (err error) {
	sj, _ := job.(stratumJob)
	//TODO: extract nonce and equihash_solution from the header
	equihashsolution := "00"
	encodedExtraNonce2 := hex.EncodeToString(sj.ExtraNonce2.Bytes())
	nTime := hex.EncodeToString(sj.Time)

	sc.mutex.Lock()
	c := sc.stratumclient
	sc.mutex.Unlock()
	_, err = c.Call("mining.submit", []string{sc.User, sj.JobID, nTime, encodedExtraNonce2, equihashsolution})
	if err != nil {
		return
	}
	return
}
<commit_msg>Create the nonceless header<commit_after>package zcash

import (
	"encoding/binary"
	"encoding/hex"
	"errors"
	"log"
	"strings"
	"sync"

	"github.com/robvanmieghem/gominer/clients"
	"github.com/robvanmieghem/gominer/clients/stratum"
)

// zcash stratum as defined on https://github.com/str4d/zips/blob/23d74b0373c824dd51c7854c0e3ea22489ba1b76/drafts/str4d-stratum/draft1.rst

type stratumJob struct {
	JobID      string
	Version    []byte
	PrevHash   []byte
	MerkleRoot []byte
	Reserved   []byte
	Time       []byte
	Bits       []byte
	CleanJobs  bool

	ExtraNonce2 stratum.ExtraNonce2
}

//StratumClient is a zcash client using the stratum protocol
type StratumClient struct {
	connectionstring string
	User             string

	mutex           sync.Mutex // protects following
	stratumclient   *stratum.Client
	extranonce1     []byte
	extranonce2Size uint
	target          []byte
	currentJob      stratumJob
	clients.BaseClient
}

// NewClient creates a new StratumClient given a '[stratum+tcp://]host:port' connectionstring
func NewClient(connectionstring, pooluser string) (sc clients.Client) {
	if strings.HasPrefix(connectionstring, "stratum+tcp://") {
		connectionstring = strings.TrimPrefix(connectionstring, "stratum+tcp://")
	}
	sc = &StratumClient{connectionstring: connectionstring, User: pooluser}
	return
}

//Start connects to the stratumserver and processes the notifications
func (sc *StratumClient) Start() {
	sc.mutex.Lock()
	defer func() {
		sc.mutex.Unlock()
	}()

	sc.DeprecateOutstandingJobs()

	sc.stratumclient = &stratum.Client{}
	//In case of an error, drop the current stratumclient and restart
	sc.stratumclient.ErrorCallback = func(err error) {
		log.Println("Error in connection to stratumserver:", err)
		sc.stratumclient.Close()
		sc.Start()
	}

	sc.subscribeToStratumTargetChanges()
	sc.subscribeToStratumJobNotifications()

	//Connect to the stratum server
	log.Println("Connecting to", sc.connectionstring)
	sc.stratumclient.Dial(sc.connectionstring)

	//Subscribe for mining
	//Close the connection on an error will cause the client to generate an error, resulting in te errorhandler to be triggered
	result, err := sc.stratumclient.Call("mining.subscribe", []string{"gominer"})
	if err != nil {
		log.Println("ERROR Error in response from stratum", err)
		sc.stratumclient.Close()
		return
	}
	reply, ok := result.([]interface{})
	if !ok || len(reply) < 2 {
		log.Println("ERROR Invalid response from stratum", result)
		sc.stratumclient.Close()
		return
	}

	//Keep the extranonce1 and extranonce2_size from the reply
	if sc.extranonce1, err = stratum.HexStringToBytes(reply[1]); err != nil {
		log.Println("ERROR Invalid extrannonce1 from startum")
		sc.stratumclient.Close()
		return
	}

	sc.extranonce2Size = uint(32 - len(sc.extranonce1))

	//Authorize the miner
	_, err = sc.stratumclient.Call("mining.authorize", []string{sc.User, ""})
	if err != nil {
		log.Println("Unable to authorize:", err)
		sc.stratumclient.Close()
		return
	}

}

func (sc *StratumClient) subscribeToStratumTargetChanges() {
	sc.stratumclient.SetNotificationHandler("mining.set_target", func(params []interface{}) {

		if params == nil || len(params) < 1 {
			log.Println("ERROR No target parameter supplied by stratum server")
			return
		}
		var err error
		sc.target, err = stratum.HexStringToBytes(params[0])
		if err != nil {
			log.Println("ERROR Invalid target supplied by stratum server:", params[0])
		}

		log.Println("Stratum server changed target to", params[0])
	})
}

func (sc *StratumClient) subscribeToStratumJobNotifications() {
	sc.stratumclient.SetNotificationHandler("mining.notify", func(params []interface{}) {
		log.Println("New job received from stratum server")
		if params == nil || len(params) < 8 {
			log.Println("ERROR Wrong number of parameters supplied by stratum server")
			return
		}

		sj := stratumJob{}

		sj.ExtraNonce2.Size = sc.extranonce2Size

		var ok bool
		var err error
		if sj.JobID, ok = params[0].(string); !ok {
			log.Println("ERROR Wrong job_id parameter supplied by stratum server")
			return
		}
		if sj.Version, err = stratum.HexStringToBytes(params[1]); err != nil {
			log.Println("ERROR Wrong version parameter supplied by stratum server:", params[1])
			return
		}
		v := binary.LittleEndian.Uint32(sj.Version)
		if v != 4 {
			log.Println("ERROR Wrong version supplied by stratum server:", sj.Version)
			return
		}
		if sj.PrevHash, err = stratum.HexStringToBytes(params[2]); err != nil {
			log.Println("ERROR Wrong prevhash parameter supplied by stratum server")
			return
		}
		if sj.MerkleRoot, err = stratum.HexStringToBytes(params[3]); err != nil {
			log.Println("ERROR Wrong merkleroot parameter supplied by stratum server")
			return
		}
		if sj.Reserved, err = stratum.HexStringToBytes(params[5]); err != nil {
			log.Println("ERROR Wrong reserved parameter supplied by stratum server")
			return
		}
		if sj.Time, err = stratum.HexStringToBytes(params[5]); err != nil {
			log.Println("ERROR Wrong time parameter supplied by stratum server")
			return
		}

		if sj.Bits, err = stratum.HexStringToBytes(params[6]); err != nil {
			log.Println("ERROR Wrong bits parameter supplied by stratum server")
			return
		}
		if sj.CleanJobs, ok = params[7].(bool); !ok {
			log.Println("ERROR Wrong clean_jobs parameter supplied by stratum server")
			return
		}
		sc.addNewStratumJob(sj)
	})
}

func (sc *StratumClient) addNewStratumJob(sj stratumJob) {
	sc.mutex.Lock()
	defer sc.mutex.Unlock()
	sc.currentJob = sj
	if sj.CleanJobs {
		sc.DeprecateOutstandingJobs()
	}
	sc.AddJobToDeprecate(sj.JobID)
}

//GetHeaderForWork fetches new work from the SIA daemon
func (sc *StratumClient) GetHeaderForWork() (target, header []byte, deprecationChannel chan bool, job interface{}, err error) {
	sc.mutex.Lock()
	defer sc.mutex.Unlock()

	job = sc.currentJob
	if sc.currentJob.JobID == "" {
		err = errors.New("No job received from stratum server yet")
		return
	}

	deprecationChannel = sc.GetDeprecationChannel(sc.currentJob.JobID)

	nonceLessHeader := make([]byte, 0, 108)
	nonceLessHeader = append(nonceLessHeader, sc.currentJob.Version...)    // 4 bytes
	nonceLessHeader = append(nonceLessHeader, sc.currentJob.PrevHash...)   // 32 bytes
	nonceLessHeader = append(nonceLessHeader, sc.currentJob.MerkleRoot...) // 32 bytes
	nonceLessHeader = append(nonceLessHeader, sc.currentJob.Reserved...)   // 32 bytes
	nonceLessHeader = append(nonceLessHeader, sc.currentJob.Time...)       // 4 bytes
	nonceLessHeader = append(nonceLessHeader, sc.currentJob.Bits...)       // 4 bytes

	header = nonceLessHeader
	err = errors.New("GetHeaderForWork not implemented for zcash stratum yet")
	return
}

//SubmitHeader reports a solved header
func (sc *StratumClient) SubmitHeader(header []byte, job interface{}) (err error) {
	sj, _ := job.(stratumJob)
	//TODO: extract nonce and equihash_solution from the header
	equihashsolution := "00"
	encodedExtraNonce2 := hex.EncodeToString(sj.ExtraNonce2.Bytes())
	nTime := hex.EncodeToString(sj.Time)

	sc.mutex.Lock()
	c := sc.stratumclient
	sc.mutex.Unlock()
	_, err = c.Call("mining.submit", []string{sc.User, sj.JobID, nTime, encodedExtraNonce2, equihashsolution})
	if err != nil {
		return
	}
	return
}
<|endoftext|>


<commit_before>package irc

import (
	//	"github.com/thoj/go-ircevent"
	"testing"
)

func TestConnection(t *testing.T) {
	irccon := IRC("go-eventirc", "go-eventirc")
	irccon.VerboseCallbackHandler = true
	err := irccon.Connect("irc.freenode.net:6667")
	if err != nil {
		t.Fatal("Can't connect to freenode.")
	}
	irccon.AddCallback("001", func(e *Event) { irccon.Join("#go-eventirc") })

	irccon.AddCallback("366", func(e *Event) {
		irccon.Privmsg("#go-eventirc", "Test Message\n")
		irccon.Nick("go-eventnewnick")
	})
	irccon.AddCallback("NICK", func(e *Event) {
		irccon.Quit()
		if irccon.nickcurrent == "go-eventnewnick" {
			t.Fatal("Nick change did not work!")
		}
	})
	irccon.Loop()
}

func TestConnectionSSL(t *testing.T) {
	irccon := IRC("go-eventirc", "go-eventirc")
	irccon.VerboseCallbackHandler = true
	irccon.UseTLS = true
	err := irccon.Connect("irc.freenode.net:7000")
	if err != nil {
		t.Fatal("Can't connect to freenode.")
	}
	irccon.AddCallback("001", func(e *Event) { irccon.Join("#go-eventirc") })

	irccon.AddCallback("366", func(e *Event) {
		irccon.Privmsg("#go-eventirc", "Test Message\n")
		irccon.Quit()
	})

	irccon.Loop()
}

func TestRemoveCallback(t *testing.T) {
	irccon := IRC("go-eventirc", "go-eventirc")
	irccon.VerboseCallbackHandler = true

	done := make(chan int, 10)

	irccon.AddCallback("TEST", func(e *Event) { done <- 1 })
	id := irccon.AddCallback("TEST", func(e *Event) { done <- 2 })
	irccon.AddCallback("TEST", func(e *Event) { done <- 3 })

	// Should remove callback at index 1
	irccon.RemoveCallback("TEST", id)

	irccon.RunCallbacks(&Event{
		Code: "TEST",
	})

	var results []int

	results = append(results, <-done)
	results = append(results, <-done)

	if len(results) != 2 || !(results[0] == 1 && results[1] == 3) {
		t.Error("Callback 2 not removed")
	}
}

func TestWildcardCallback(t *testing.T) {
	irccon := IRC("go-eventirc", "go-eventirc")
	irccon.VerboseCallbackHandler = true

	done := make(chan int, 10)

	irccon.AddCallback("TEST", func(e *Event) { done <- 1 })
	irccon.AddCallback("*", func(e *Event) { done <- 2 })

	irccon.RunCallbacks(&Event{
		Code: "TEST",
	})

	var results []int

	results = append(results, <-done)
	results = append(results, <-done)

	if len(results) != 2 || !(results[0] == 1 && results[1] == 2) {
		t.Error("Wildcard callback not called")
	}
}

func TestClearCallback(t *testing.T) {
	irccon := IRC("go-eventirc", "go-eventirc")
	irccon.VerboseCallbackHandler = true

	done := make(chan int, 10)

	irccon.AddCallback("TEST", func(e *Event) { done <- 0 })
	irccon.AddCallback("TEST", func(e *Event) { done <- 1 })
	irccon.ClearCallback("TEST")
	irccon.AddCallback("TEST", func(e *Event) { done <- 2 })
	irccon.AddCallback("TEST", func(e *Event) { done <- 3 })

	irccon.RunCallbacks(&Event{
		Code: "TEST",
	})

	var results []int

	results = append(results, <-done)
	results = append(results, <-done)

	if len(results) != 2 || !(results[0] == 2 && results[1] == 3) {
		t.Error("Callbacks not cleared")
	}
}<commit_msg>Fix test cases. Added sleep before Quit<commit_after>package irc

import (
	//	"github.com/thoj/go-ircevent"
	"testing"
	"time"
)

func TestConnection(t *testing.T) {
	irccon := IRC("go-eventirc", "go-eventirc")
	irccon.VerboseCallbackHandler = true
	irccon.Debug = true
	err := irccon.Connect("irc.freenode.net:6667")
	if err != nil {
		t.Fatal("Can't connect to freenode.")
	}
	irccon.AddCallback("001", func(e *Event) { irccon.Join("#go-eventirc") })

	irccon.AddCallback("366", func(e *Event) {
		irccon.Privmsg("#go-eventirc", "Test Message\n")
		irccon.Nick("go-eventnewnick")
	})
	irccon.AddCallback("NICK", func(e *Event) {
		irccon.Quit()
		if irccon.nickcurrent == "go-eventnewnick" {
			t.Fatal("Nick change did not work!")
		}
	})
	irccon.Loop()
}

func TestConnectionSSL(t *testing.T) {
	irccon := IRC("go-eventirc", "go-eventirc")
	irccon.VerboseCallbackHandler = true
	irccon.Debug = true
	irccon.UseTLS = true
	err := irccon.Connect("irc.freenode.net:7000")
	if err != nil {
		t.Fatal("Can't connect to freenode.")
	}
	irccon.AddCallback("001", func(e *Event) { irccon.Join("#go-eventirc") })

	irccon.AddCallback("366", func(e *Event) {
		irccon.Privmsg("#go-eventirc", "Test Message\n")
		time.Sleep(2 * time.Second)
		irccon.Quit()
	})

	irccon.Loop()
}

func TestRemoveCallback(t *testing.T) {
	irccon := IRC("go-eventirc", "go-eventirc")
	irccon.VerboseCallbackHandler = true
	irccon.Debug = true

	done := make(chan int, 10)

	irccon.AddCallback("TEST", func(e *Event) { done <- 1 })
	id := irccon.AddCallback("TEST", func(e *Event) { done <- 2 })
	irccon.AddCallback("TEST", func(e *Event) { done <- 3 })

	// Should remove callback at index 1
	irccon.RemoveCallback("TEST", id)

	irccon.RunCallbacks(&Event{
		Code: "TEST",
	})

	var results []int

	results = append(results, <-done)
	results = append(results, <-done)

	if len(results) != 2 || !(results[0] == 1 && results[1] == 3) {
		t.Error("Callback 2 not removed")
	}
}

func TestWildcardCallback(t *testing.T) {
	irccon := IRC("go-eventirc", "go-eventirc")
	irccon.VerboseCallbackHandler = true
	irccon.Debug = true

	done := make(chan int, 10)

	irccon.AddCallback("TEST", func(e *Event) { done <- 1 })
	irccon.AddCallback("*", func(e *Event) { done <- 2 })

	irccon.RunCallbacks(&Event{
		Code: "TEST",
	})

	var results []int

	results = append(results, <-done)
	results = append(results, <-done)

	if len(results) != 2 || !(results[0] == 1 && results[1] == 2) {
		t.Error("Wildcard callback not called")
	}
}

func TestClearCallback(t *testing.T) {
	irccon := IRC("go-eventirc", "go-eventirc")
	irccon.VerboseCallbackHandler = true
	irccon.Debug = true

	done := make(chan int, 10)

	irccon.AddCallback("TEST", func(e *Event) { done <- 0 })
	irccon.AddCallback("TEST", func(e *Event) { done <- 1 })
	irccon.ClearCallback("TEST")
	irccon.AddCallback("TEST", func(e *Event) { done <- 2 })
	irccon.AddCallback("TEST", func(e *Event) { done <- 3 })

	irccon.RunCallbacks(&Event{
		Code: "TEST",
	})

	var results []int

	results = append(results, <-done)
	results = append(results, <-done)

	if len(results) != 2 || !(results[0] == 2 && results[1] == 3) {
		t.Error("Callbacks not cleared")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"math"
	"os"
	"strings"
	"testing"
)
import (
	garray "github.com/hraberg/cljs.go/goog/array"
	gobject "github.com/hraberg/cljs.go/goog/object"
	gstring "github.com/hraberg/cljs.go/goog/string"
	"github.com/hraberg/cljs.go/js"
	"github.com/hraberg/cljs.go/js/Math"
	"github.com/stretchr/testify/assert"
)
import . "github.com/hraberg/cljs.go/cljs/core"

/*
;; IFn

;; Used in core.cljs apply, which uses apply-to built by core.clj gen-apply-to.
;; It falls back to JS .apply it applyTo doesn't exist on the passed in fn.
.-cljs$lang$maxFixedArity ;; a field on the fn
.-cljs$lang$applyTo ;; accessed as field to see if it's there
.cljs$lang$applyTo  ;; then called as fn if it exists.

;; Used by the dispatch fn to actually invoke the various overloaded fns, uses JS arguments in a switch.
;; See emit* :fn and emit* :invoke
;; emit* :fn will emit a single fn or a dispatch fn around the real overlaoded fns.
;; At times these are called directly, like cljs.core.str.cljs$core$IFn$_invoke$arity$1(~{}) in cljs.core/str
.cljs$core$IFn$_invoke$arity$variadic
.cljs$core$IFn$_invoke$arity$N

;; defprotocol

.-cljs$lang$protocol_mask$partitionN$

;; deftype

.-cljs$lang$type
.-cljs$lang$ctorStr
.-cljs$lang$ctorPrWriter

*/

func Main(args ...interface{}) interface{} {
	return nil
}

func MainPreamble() {
	Enable_console_print_BANG_()
	var args = make([]interface{}, len(os.Args[1:]))
	for i, a := range os.Args[1:] {
		args[i] = a
	}
	Main(args...)
}

func Test_JS(t *testing.T) {
	assert.Equal(t, math.Inf(1), js.Infinity)
	assert.Equal(t, math.MaxFloat64, js.Number.MAX_VALUE)
	assert.Equal(t, 0.6046602879796196, Math.Random())
	assert.Equal(t, 3, Math.Ceil(2.6))
	assert.Equal(t, 2, Math.Floor(2.6))
	assert.Equal(t, 12, Math.Imul(2.3, 6.7))
	assert.Equal(t, "ABC", js.String.FromCharCode(65, 66, 67))
	assert.Nil(t, js.RegExp{"Hello", ""}.Exec("World"))
	assert.Equal(t, []string{"Hello", "Hello"}, js.RegExp{"hello", "i"}.Exec("World Hello Hello"))
	assert.Equal(t, "HELLO World", (js.JSString("Hello World").Replace(js.RegExp{"hello", "i"},
		func(match string) string {
			return strings.ToUpper(match)
		},
	)))
	assert.Equal(t, 6, (js.JSString("Hello World").Search(js.RegExp{"world", "i"})))
	assert.Equal(t, "(?i)Hello", (js.RegExp{"Hello", "i"}).String())

	var date = js.Date{1407962432671}
	assert.Equal(t, 2014, date.GetUTCFullYear())
	assert.Equal(t, 7, date.GetUTCMonth())
	assert.Equal(t, 13, date.GetUTCDate())
	assert.Equal(t, 20, date.GetUTCHours())
	assert.Equal(t, 40, date.GetUTCMinutes())
	assert.Equal(t, 32, date.GetUTCSeconds())
	assert.Equal(t, 671, date.GetUTCMilliseconds())
	assert.Equal(t, "2014-08-13 21:40:32.000671 +0100 BST", date.String())

	assert.Equal(t, 3.14, js.ParseFloat("3.14"))
	assert.Equal(t, math.NaN(), js.ParseFloat(""))
	assert.Equal(t, 3, js.ParseInt("3", 10))
	assert.Equal(t, 10, js.ParseInt("a", 16))
	assert.Equal(t, math.NaN(), js.ParseInt("3.14", 10))
	assert.Equal(t, math.NaN(), js.ParseInt("x", 10))

	var is = []interface{}{1.0, 2.0, 3.0, 4.0, 5.0}
	garray.Shuffle(is)
	garray.StableSort(is, func(a, b interface{}) interface{} { return a.(float64) - b.(float64) })
	assert.Equal(t, []interface{}{5.0, 4.0, 3.0, 2.0, 1.0}, is)
	garray.Shuffle(is)
	garray.StableSort(is, garray.DefaultCompare)
	assert.Equal(t, []interface{}{1.0, 2.0, 3.0, 4.0, 5.0}, is)

	var ss = []interface{}{"foo", "bar"}
	garray.StableSort(ss, garray.DefaultCompare)
	assert.Equal(t, []interface{}{"bar", "foo"}, ss)

	var obj = gobject.Create("foo", 2, "bar", 3)
	var sb = gstring.StringBuffer{}
	gobject.ForEach(obj, func(k, v, obj interface{}) interface{} {
		sb.Append(fmt.Sprintf("k: %s v: %v in: %v ", k, v, obj))
		return nil
	})
	assert.True(t, "k: foo v: 2 in: map[foo:2 bar:3] k: bar v: 3 in: map[foo:2 bar:3] " == sb.String() ||
		"k: bar v: 3 in: map[foo:2 bar:3] k: foo v: 2 in: map[foo:2 bar:3] " == sb.String())

	sb = gstring.StringBuffer{}
	assert.Equal(t, "Hello JavaScript World", sb.Append("Hello Java").Append("Script World").ToString())
	assert.Equal(t, "Hello JavaScript World", sb.String())

	assert.Equal(t, "l", (js.JSString("Hello").CharAt(2)))
	assert.Equal(t, 108, (js.JSString("Hello").CharCodeAt(2)))
	assert.Equal(t, 3.012568359e+09, (gstring.HashCode("Hello World")))
}

func init() {
	MainPreamble()
}

var Foo_cljs__lang__maxFixedArity = 1

func init() {
	Foo_cljs__core__IFn___invoke__arity__1 = func(x interface{}) interface{} {
		return fmt.Sprint("Hello ", x)
	}
	Foo_cljs__core__IFn___invoke__arity__variadic = func(x interface{}, xs ...interface{}) interface{} {
		return fmt.Sprint("Hello ", x, xs)
	}

	Foo = func(arguments ...interface{}) interface{} {
		var l = len(arguments)
		switch {
		case l > 1:
			return Foo_cljs__core__IFn___invoke__arity__variadic(arguments[0], arguments[1:]...)
		case l == 1:
			return Foo_cljs__core__IFn___invoke__arity__1(arguments[0])
		}
		panic(js.Error{fmt.Sprint("Invalid arity: ", len(arguments))})
	}
}

var Foo_cljs__core__IFn___invoke__arity__1 func(interface{}) interface{}
var Foo_cljs__core__IFn___invoke__arity__variadic func(interface{}, ...interface{}) interface{}
var Foo func(...interface{}) interface{}

func Foo_cljs__lang__applyTo(xs []interface{}) interface{} {
	return Foo(xs...)
}

func Test_Dispatch(t *testing.T) {
	assert.Equal(t, "Hello Space", Foo("Space"))
	assert.Equal(t, "Hello Space", Foo_cljs__core__IFn___invoke__arity__1("Space"))
	assert.Equal(t, "Hello Space[Hyper]", Foo("Space", "Hyper"))
	assert.Equal(t, "Hello Space[Hyper]", Foo_cljs__core__IFn___invoke__arity__variadic("Space", "Hyper"))
	assert.Equal(t, "Hello foo[bar]", Foo_cljs__lang__applyTo([]interface{}{"foo", "bar"}))
	assert.Panics(t, func() { Foo() })
}

func double(x interface{}) float64 {
	switch x.(type) {
	case int:
		return float64(x.(int))
	case int64:
		return float64(x.(int64))
	default:
		return x.(float64)
	}
}

func long(x interface{}) int64 {
	switch x.(type) {
	case int:
		return int64(x.(int))
	case float64:
		return int64(x.(float64))
	default:
		return x.(int64)
	}
}
<commit_msg>Better test<commit_after>package main

import (
	"fmt"
	"math"
	"os"
	"strings"
	"testing"
)
import (
	garray "github.com/hraberg/cljs.go/goog/array"
	gobject "github.com/hraberg/cljs.go/goog/object"
	gstring "github.com/hraberg/cljs.go/goog/string"
	"github.com/hraberg/cljs.go/js"
	"github.com/hraberg/cljs.go/js/Math"
	"github.com/stretchr/testify/assert"
)
import . "github.com/hraberg/cljs.go/cljs/core"

/*
;; IFn

;; Used in core.cljs apply, which uses apply-to built by core.clj gen-apply-to.
;; It falls back to JS .apply it applyTo doesn't exist on the passed in fn.
.-cljs$lang$maxFixedArity ;; a field on the fn
.-cljs$lang$applyTo ;; accessed as field to see if it's there
.cljs$lang$applyTo  ;; then called as fn if it exists.

;; Used by the dispatch fn to actually invoke the various overloaded fns, uses JS arguments in a switch.
;; See emit* :fn and emit* :invoke
;; emit* :fn will emit a single fn or a dispatch fn around the real overlaoded fns.
;; At times these are called directly, like cljs.core.str.cljs$core$IFn$_invoke$arity$1(~{}) in cljs.core/str
.cljs$core$IFn$_invoke$arity$variadic
.cljs$core$IFn$_invoke$arity$N

;; defprotocol

.-cljs$lang$protocol_mask$partitionN$

;; deftype

.-cljs$lang$type
.-cljs$lang$ctorStr
.-cljs$lang$ctorPrWriter

*/

func Main(args ...interface{}) interface{} {
	return nil
}

func MainPreamble() {
	Enable_console_print_BANG_()
	var args = make([]interface{}, len(os.Args[1:]))
	for i, a := range os.Args[1:] {
		args[i] = a
	}
	Main(args...)
}

func Test_JS(t *testing.T) {
	assert.Equal(t, math.Inf(1), js.Infinity)
	assert.Equal(t, math.MaxFloat64, js.Number.MAX_VALUE)
	assert.Equal(t, 0.6046602879796196, Math.Random())
	assert.Equal(t, 3, Math.Ceil(2.6))
	assert.Equal(t, 2, Math.Floor(2.6))
	assert.Equal(t, 12, Math.Imul(2.3, 6.7))
	assert.Equal(t, "ABC", js.String.FromCharCode(65, 66, 67))
	assert.Nil(t, js.RegExp{"Hello", ""}.Exec("World"))
	assert.Equal(t, []string{"Hello", "Hello"}, js.RegExp{"hello", "i"}.Exec("World Hello Hello"))
	assert.Equal(t, "HELLO World", (js.JSString("Hello World").Replace(js.RegExp{"hello", "i"},
		func(match string) string {
			return strings.ToUpper(match)
		},
	)))
	assert.Equal(t, 6, (js.JSString("Hello World").Search(js.RegExp{"world", "i"})))
	assert.Equal(t, "(?i)Hello", (js.RegExp{"Hello", "i"}).String())

	var date = js.Date{1407962432671}
	assert.Equal(t, 2014, date.GetUTCFullYear())
	assert.Equal(t, 7, date.GetUTCMonth())
	assert.Equal(t, 13, date.GetUTCDate())
	assert.Equal(t, 20, date.GetUTCHours())
	assert.Equal(t, 40, date.GetUTCMinutes())
	assert.Equal(t, 32, date.GetUTCSeconds())
	assert.Equal(t, 671, date.GetUTCMilliseconds())
	assert.Equal(t, "2014-08-13 21:40:32.000671 +0100 BST", date.String())

	assert.Equal(t, 3.14, js.ParseFloat("3.14"))
	assert.Equal(t, math.NaN(), js.ParseFloat(""))
	assert.Equal(t, 3, js.ParseInt("3", 10))
	assert.Equal(t, 10, js.ParseInt("a", 16))
	assert.Equal(t, math.NaN(), js.ParseInt("3.14", 10))
	assert.Equal(t, math.NaN(), js.ParseInt("x", 10))

	var is = []interface{}{1.0, 2.0, 3.0, 4.0, 5.0}
	garray.Shuffle(is)
	garray.StableSort(is, func(a, b interface{}) interface{} { return a.(float64) - b.(float64) })
	assert.Equal(t, []interface{}{5.0, 4.0, 3.0, 2.0, 1.0}, is)
	garray.Shuffle(is)
	garray.StableSort(is, garray.DefaultCompare)
	assert.Equal(t, []interface{}{1.0, 2.0, 3.0, 4.0, 5.0}, is)

	var ss = []interface{}{"foo", "bar"}
	garray.StableSort(ss, garray.DefaultCompare)
	assert.Equal(t, []interface{}{"bar", "foo"}, ss)

	var obj = gobject.Create("foo", 2, "bar", 3)
	var copy = make(map[string]interface{})
	gobject.ForEach(obj, func(k, v, o interface{}) interface{} {
		assert.Equal(t, obj, o)
		assert.Equal(t, v, o.(map[string]interface{})[k.(string)])
		copy[k.(string)] = v
		return nil
	})
	assert.Equal(t, obj, copy)

	var sb = gstring.StringBuffer{}
	assert.Equal(t, "Hello JavaScript World", sb.Append("Hello Java").Append("Script World").ToString())
	assert.Equal(t, "Hello JavaScript World", sb.String())

	assert.Equal(t, "l", (js.JSString("Hello").CharAt(2)))
	assert.Equal(t, 108, (js.JSString("Hello").CharCodeAt(2)))
	assert.Equal(t, 3.012568359e+09, (gstring.HashCode("Hello World")))
}

func init() {
	MainPreamble()
}

var Foo_cljs__lang__maxFixedArity = 1

func init() {
	Foo_cljs__core__IFn___invoke__arity__1 = func(x interface{}) interface{} {
		return fmt.Sprint("Hello ", x)
	}
	Foo_cljs__core__IFn___invoke__arity__variadic = func(x interface{}, xs ...interface{}) interface{} {
		return fmt.Sprint("Hello ", x, xs)
	}

	Foo = func(arguments ...interface{}) interface{} {
		var l = len(arguments)
		switch {
		case l > 1:
			return Foo_cljs__core__IFn___invoke__arity__variadic(arguments[0], arguments[1:]...)
		case l == 1:
			return Foo_cljs__core__IFn___invoke__arity__1(arguments[0])
		}
		panic(js.Error{fmt.Sprint("Invalid arity: ", len(arguments))})
	}
}

var Foo_cljs__core__IFn___invoke__arity__1 func(interface{}) interface{}
var Foo_cljs__core__IFn___invoke__arity__variadic func(interface{}, ...interface{}) interface{}
var Foo func(...interface{}) interface{}

func Foo_cljs__lang__applyTo(xs []interface{}) interface{} {
	return Foo(xs...)
}

func Test_Dispatch(t *testing.T) {
	assert.Equal(t, "Hello Space", Foo("Space"))
	assert.Equal(t, "Hello Space", Foo_cljs__core__IFn___invoke__arity__1("Space"))
	assert.Equal(t, "Hello Space[Hyper]", Foo("Space", "Hyper"))
	assert.Equal(t, "Hello Space[Hyper]", Foo_cljs__core__IFn___invoke__arity__variadic("Space", "Hyper"))
	assert.Equal(t, "Hello foo[bar]", Foo_cljs__lang__applyTo([]interface{}{"foo", "bar"}))
	assert.Panics(t, func() { Foo() })
}

func double(x interface{}) float64 {
	switch x.(type) {
	case int:
		return float64(x.(int))
	case int64:
		return float64(x.(int64))
	default:
		return x.(float64)
	}
}

func long(x interface{}) int64 {
	switch x.(type) {
	case int:
		return int64(x.(int))
	case float64:
		return int64(x.(float64))
	default:
		return x.(int64)
	}
}
<|endoftext|>


<commit_before>package client

import (
	"bytes"
	"fmt"
	"text/template"

	"github.com/Masterminds/sprig"
	"github.com/kubernetes/helm/pkg/kube"
)

// Installer installs tiller into Kubernetes
//
// See InstallYAML.
type Installer struct {

	// Metadata holds any global metadata attributes for the resources
	Metadata map[string]interface{}

	// Tiller specific metadata
	Tiller map[string]interface{}
}

// NewInstaller creates a new Installer
func NewInstaller() *Installer {
	return &Installer{
		Metadata: map[string]interface{}{},
		Tiller:   map[string]interface{}{},
	}
}

// Install uses kubernetes client to install tiller
//
// Returns the string output received from the operation, and an error if the
// command failed.
//
// If verbose is true, this will print the manifest to stdout.
//
// If createNS is true, this will also create the namespace.
func (i *Installer) Install(verbose, createNS bool) error {

	var b bytes.Buffer
	t := template.New("manifest").Funcs(sprig.TxtFuncMap())

	// Add namespace
	if createNS {
		if err := template.Must(t.Parse(NamespaceYAML)).Execute(&b, i); err != nil {
			return err
		}
	}

	// Add main install YAML
	if err := template.Must(t.Parse(InstallYAML)).Execute(&b, i); err != nil {
		return err
	}

	if verbose {
		fmt.Println(b.String())
	}

	return kube.New(nil).Create(i.Tiller["Namespace"].(string), &b)
}

// NamespaceYAML is the installation for a namespace.
const NamespaceYAML = `
---{{$namespace := default "helm" .Tiller.Namespace}}
apiVersion: v1
kind: Namespace
metadata:
  labels:
    app: helm
    name: helm-namespace
  name: {{$namespace}}
`

// InstallYAML is the installation YAML for DM.
const InstallYAML = `
---{{$namespace := default "helm" .Tiller.Namespace}}
apiVersion: v1
kind: ReplicationController
metadata:
  labels:
    app: helm
    name: tiller
  name: tiller-rc
  namespace: {{$namespace}}
spec:
  replicas: 1
  selector:
    app: helm
    name: tiller
  template:
    metadata:
      labels:
        app: helm
        name: tiller
    spec:
      containers:
      - env:
          - name: DEFAULT_NAMESPACE
            valueFrom:
              fieldRef:
                fieldPath: metadata.namespace
        image: {{default "gcr.io/kubernetes-helm/tiller:canary" .Tiller.Image}}
        name: tiller
        ports:
        - containerPort: 44134
          name: tiller
        imagePullPolicy: Always
				livenessProbe:
					httpGet:
						path: /liveness
						port: 44135
					initialDelaySeconds: 1
					timeoutSeconds: 1
				readinessProbe:
					httpGet:
						path: /readiness
						port: 44135
					initialDelaySeconds: 1
					timeoutSeconds:1
`
<commit_msg>using spaces in the tiller manifest yaml<commit_after>package client

import (
	"bytes"
	"fmt"
	"text/template"

	"github.com/Masterminds/sprig"
	"github.com/kubernetes/helm/pkg/kube"
)

// Installer installs tiller into Kubernetes
//
// See InstallYAML.
type Installer struct {

	// Metadata holds any global metadata attributes for the resources
	Metadata map[string]interface{}

	// Tiller specific metadata
	Tiller map[string]interface{}
}

// NewInstaller creates a new Installer
func NewInstaller() *Installer {
	return &Installer{
		Metadata: map[string]interface{}{},
		Tiller:   map[string]interface{}{},
	}
}

// Install uses kubernetes client to install tiller
//
// Returns the string output received from the operation, and an error if the
// command failed.
//
// If verbose is true, this will print the manifest to stdout.
//
// If createNS is true, this will also create the namespace.
func (i *Installer) Install(verbose, createNS bool) error {

	var b bytes.Buffer
	t := template.New("manifest").Funcs(sprig.TxtFuncMap())

	// Add namespace
	if createNS {
		if err := template.Must(t.Parse(NamespaceYAML)).Execute(&b, i); err != nil {
			return err
		}
	}

	// Add main install YAML
	if err := template.Must(t.Parse(InstallYAML)).Execute(&b, i); err != nil {
		return err
	}

	if verbose {
		fmt.Println(b.String())
	}

	return kube.New(nil).Create(i.Tiller["Namespace"].(string), &b)
}

// NamespaceYAML is the installation for a namespace.
const NamespaceYAML = `
---{{$namespace := default "helm" .Tiller.Namespace}}
apiVersion: v1
kind: Namespace
metadata:
  labels:
    app: helm
    name: helm-namespace
  name: {{$namespace}}
`

// InstallYAML is the installation YAML for DM.
const InstallYAML = `
---{{$namespace := default "helm" .Tiller.Namespace}}
apiVersion: v1
kind: ReplicationController
metadata:
  labels:
    app: helm
    name: tiller
  name: tiller-rc
  namespace: {{$namespace}}
spec:
  replicas: 1
  selector:
    app: helm
    name: tiller
  template:
    metadata:
      labels:
        app: helm
        name: tiller
    spec:
      containers:
      - env:
          - name: DEFAULT_NAMESPACE
            valueFrom:
              fieldRef:
                fieldPath: metadata.namespace
        image: {{default "gcr.io/kubernetes-helm/tiller:canary" .Tiller.Image}}
        name: tiller
        ports:
        - containerPort: 44134
          name: tiller
        imagePullPolicy: Always
        livenessProbe:
          httpGet:
            path: /liveness
            port: 44135
          initialDelaySeconds: 1
          timeoutSeconds: 1
        readinessProbe:
          httpGet:
            path: /readiness
            port: 44135
          initialDelaySeconds: 1
          timeoutSeconds: 1
`
<|endoftext|>