<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.

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

package tchannel_test

// This file contains functions for tests to access internal tchannel state.
// Since it has a _test.go suffix, it is only compiled with tests in this package.

import (
	"bytes"
	"io"
	"math/rand"
	"sync"
	"testing"
	"time"

	. "github.com/uber/tchannel-go"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"github.com/uber/tchannel-go/raw"
	"github.com/uber/tchannel-go/testutils"
	"github.com/uber/tchannel-go/testutils/goroutines"
	"github.com/uber/tchannel-go/testutils/testreader"
	"golang.org/x/net/context"
)

type swapper struct {
	t *testing.T
}

func (s *swapper) OnError(ctx context.Context, err error) {
	s.t.Errorf("OnError: %v", err)
}

func (*swapper) Handle(ctx context.Context, args *raw.Args) (*raw.Res, error) {
	return &raw.Res{
		Arg2: args.Arg3,
		Arg3: args.Arg2,
	}, nil
}

func doPingAndCall(t *testing.T, clientCh *Channel, hostPort string) {
	ctx, cancel := NewContext(time.Second * 5)
	defer cancel()

	require.NoError(t, clientCh.Ping(ctx, hostPort))

	const maxRandArg = 512 * 1024

	arg2 := testutils.RandBytes(rand.Intn(maxRandArg))
	arg3 := testutils.RandBytes(rand.Intn(maxRandArg))
	resArg2, resArg3, _, err := raw.Call(ctx, clientCh, hostPort, "swap-server", "swap", arg2, arg3)
	if !assert.NoError(t, err, "error during sendRecv") {
		return
	}

	// We expect the arguments to be swapped.
	if bytes.Compare(arg3, resArg2) != 0 {
		t.Errorf("returned arg2 does not match expected:\n  got %v\n want %v", resArg2, arg3)
	}
	if bytes.Compare(arg2, resArg3) != 0 {
		t.Errorf("returned arg2 does not match expected:\n  got %v\n want %v", resArg3, arg2)
	}
}

func doErrorCall(t *testing.T, clientCh *Channel, hostPort string) {
	ctx, cancel := NewContext(time.Second * 5)
	defer cancel()

	_, _, _, err := raw.Call(ctx, clientCh, hostPort, "swap-server", "non-existent", nil, nil)
	assert.Error(t, err, "Call to non-existent endpoint should fail")
	assert.Equal(t, ErrCodeBadRequest, GetSystemErrorCode(err), "Error code mismatch")
}

func TestFramesReleased(t *testing.T) {
	CheckStress(t)

	defer testutils.SetTimeout(t, 10*time.Second)()
	const (
		requestsPerGoroutine = 10
		numGoroutines        = 10
	)

	pool := NewRecordingFramePool()
	opts := testutils.NewOpts().
		SetServiceName("swap-server").
		SetFramePool(pool).
		AddLogFilter("Couldn't find handler.", numGoroutines*requestsPerGoroutine)
	testutils.WithTestServer(t, opts, func(ts *testutils.TestServer) {
		ts.Register(raw.Wrap(&swapper{t}), "swap")

		clientOpts := testutils.NewOpts().SetFramePool(pool)
		clientCh := ts.NewClient(clientOpts)

		// Create an active connection that can be shared by the goroutines by calling Ping.
		ctx, cancel := NewContext(time.Second)
		defer cancel()
		require.NoError(t, clientCh.Ping(ctx, ts.HostPort()))

		var wg sync.WaitGroup
		for i := 0; i < numGoroutines; i++ {
			wg.Add(1)
			go func() {
				defer wg.Done()

				for i := 0; i < requestsPerGoroutine; i++ {
					doPingAndCall(t, clientCh, ts.HostPort())
					doErrorCall(t, clientCh, ts.HostPort())
				}
			}()
		}

		wg.Wait()
	})

	// TODO: The goroutines.GetAll is to debug test failures in Travis. Remove this once
	// we confirm that the test is not flaky.
	stacks := goroutines.GetAll()
	if unreleasedCount, isEmpty := pool.CheckEmpty(); isEmpty != "" || unreleasedCount > 0 {
		t.Errorf("Frame pool has %v unreleased frames, errors:\n%v\nStacks:%v",
			unreleasedCount, isEmpty, stacks)
	}
}

type dirtyFramePool struct{}

func (p dirtyFramePool) Get() *Frame {
	f := NewFrame(MaxFramePayloadSize)
	reader := testreader.Looper([]byte{^byte(0)})
	io.ReadFull(reader, f.Payload)
	return f
}

func (p dirtyFramePool) Release(f *Frame) {}

func TestDirtyFrameRequests(t *testing.T) {
	argSizes := []int{25000, 50000, 75000}

	// Create the largest required random cache.
	testutils.RandBytes(argSizes[len(argSizes)-1])

	opts := testutils.NewOpts().
		SetServiceName("swap-server").
		SetFramePool(dirtyFramePool{})
	testutils.WithTestServer(t, opts, func(ts *testutils.TestServer) {
		ts.Register(raw.Wrap(&swapper{t}), "swap")

		for _, argSize := range argSizes {
			ctx, cancel := NewContext(time.Second)
			defer cancel()

			arg2, arg3 := testutils.RandBytes(argSize), testutils.RandBytes(argSize)
			res2, res3, _, err := raw.Call(ctx, ts.Server(), ts.HostPort(), ts.Server().ServiceName(), "swap", arg2, arg3)
			if assert.NoError(t, err, "Call failed") {
				assert.Equal(t, arg2, res3, "Result arg3 wrong")
				assert.Equal(t, arg3, res2, "Result arg3 wrong")
			}
		}
	})
}
<commit_msg>Interpose a relay in frame pool tests<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.

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

package tchannel_test

// This file contains functions for tests to access internal tchannel state.
// Since it has a _test.go suffix, it is only compiled with tests in this package.

import (
	"bytes"
	"io"
	"math/rand"
	"sync"
	"testing"
	"time"

	. "github.com/uber/tchannel-go"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"github.com/uber/tchannel-go/raw"
	"github.com/uber/tchannel-go/testutils"
	"github.com/uber/tchannel-go/testutils/goroutines"
	"github.com/uber/tchannel-go/testutils/testreader"
	"golang.org/x/net/context"
)

type swapper struct {
	t *testing.T
}

func (s *swapper) OnError(ctx context.Context, err error) {
	s.t.Errorf("OnError: %v", err)
}

func (*swapper) Handle(ctx context.Context, args *raw.Args) (*raw.Res, error) {
	return &raw.Res{
		Arg2: args.Arg3,
		Arg3: args.Arg2,
	}, nil
}

func doPingAndCall(t *testing.T, clientCh *Channel, hostPort string) {
	ctx, cancel := NewContext(time.Second * 5)
	defer cancel()

	require.NoError(t, clientCh.Ping(ctx, hostPort))

	const maxRandArg = 512 * 1024

	arg2 := testutils.RandBytes(rand.Intn(maxRandArg))
	arg3 := testutils.RandBytes(rand.Intn(maxRandArg))
	resArg2, resArg3, _, err := raw.Call(ctx, clientCh, hostPort, "swap-server", "swap", arg2, arg3)
	if !assert.NoError(t, err, "error during sendRecv") {
		return
	}

	// We expect the arguments to be swapped.
	if bytes.Compare(arg3, resArg2) != 0 {
		t.Errorf("returned arg2 does not match expected:\n  got %v\n want %v", resArg2, arg3)
	}
	if bytes.Compare(arg2, resArg3) != 0 {
		t.Errorf("returned arg2 does not match expected:\n  got %v\n want %v", resArg3, arg2)
	}
}

func doErrorCall(t *testing.T, clientCh *Channel, hostPort string) {
	ctx, cancel := NewContext(time.Second * 5)
	defer cancel()

	_, _, _, err := raw.Call(ctx, clientCh, hostPort, "swap-server", "non-existent", nil, nil)
	assert.Error(t, err, "Call to non-existent endpoint should fail")
	assert.Equal(t, ErrCodeBadRequest, GetSystemErrorCode(err), "Error code mismatch")
}

func TestFramesReleased(t *testing.T) {
	CheckStress(t)

	defer testutils.SetTimeout(t, 10*time.Second)()
	const (
		requestsPerGoroutine = 10
		numGoroutines        = 10
	)

	pool := NewRecordingFramePool()
	opts := testutils.NewOpts().
		SetServiceName("swap-server").
		SetFramePool(pool).
		AddLogFilter("Couldn't find handler.", 2*numGoroutines*requestsPerGoroutine).
		SetRelay()

	testutils.WithTestServer(t, opts, func(ts *testutils.TestServer) {
		ts.Register(raw.Wrap(&swapper{t}), "swap")

		clientOpts := testutils.NewOpts().SetFramePool(pool)
		clientCh := ts.NewClient(clientOpts)

		// Create an active connection that can be shared by the goroutines by calling Ping.
		ctx, cancel := NewContext(time.Second)
		defer cancel()
		require.NoError(t, clientCh.Ping(ctx, ts.HostPort()))

		var wg sync.WaitGroup
		for i := 0; i < numGoroutines; i++ {
			wg.Add(1)
			go func() {
				defer wg.Done()

				for i := 0; i < requestsPerGoroutine; i++ {
					doPingAndCall(t, clientCh, ts.HostPort())
					doErrorCall(t, clientCh, ts.HostPort())
				}
			}()
		}

		wg.Wait()
	})

	// TODO: The goroutines.GetAll is to debug test failures in Travis. Remove this once
	// we confirm that the test is not flaky.
	stacks := goroutines.GetAll()
	if unreleasedCount, isEmpty := pool.CheckEmpty(); isEmpty != "" || unreleasedCount > 0 {
		t.Errorf("Frame pool has %v unreleased frames, errors:\n%v\nStacks:%v",
			unreleasedCount, isEmpty, stacks)
	}
}

type dirtyFramePool struct{}

func (p dirtyFramePool) Get() *Frame {
	f := NewFrame(MaxFramePayloadSize)
	reader := testreader.Looper([]byte{^byte(0)})
	io.ReadFull(reader, f.Payload)
	return f
}

func (p dirtyFramePool) Release(f *Frame) {}

func TestDirtyFrameRequests(t *testing.T) {
	argSizes := []int{25000, 50000, 75000}

	// Create the largest required random cache.
	testutils.RandBytes(argSizes[len(argSizes)-1])

	opts := testutils.NewOpts().
		SetServiceName("swap-server").
		SetFramePool(dirtyFramePool{}).
		SetRelay()

	testutils.WithTestServer(t, opts, func(ts *testutils.TestServer) {
		ts.Register(raw.Wrap(&swapper{t}), "swap")

		for _, argSize := range argSizes {
			ctx, cancel := NewContext(time.Second)
			defer cancel()

			arg2, arg3 := testutils.RandBytes(argSize), testutils.RandBytes(argSize)
			res2, res3, _, err := raw.Call(ctx, ts.Server(), ts.HostPort(), ts.Server().ServiceName(), "swap", arg2, arg3)
			if assert.NoError(t, err, "Call failed") {
				assert.Equal(t, arg2, res3, "Result arg3 wrong")
				assert.Equal(t, arg3, res2, "Result arg3 wrong")
			}
		}
	})
}
<|endoftext|>


<commit_before>package cache

import (
	"fmt"
	"sync"
	"time"

	"github.com/johnny-morrice/godless/api"
	"github.com/johnny-morrice/godless/crdt"
	"github.com/johnny-morrice/godless/log"
	"github.com/johnny-morrice/godless/query"
	"github.com/pkg/errors"
)

// Memcache style key value store.
// Will drop oldest.
type residentIndexCache struct {
	sync.RWMutex
	buff  []indexCacheItem
	assoc map[crdt.IPFSPath]*indexCacheItem
}

func MakeResidentIndexCache(buffSize int) api.IndexCache {
	if buffSize <= 0 {
		buffSize = __DEFAULT_BUFFER_SIZE
	}

	return &residentIndexCache{
		buff:  make([]indexCacheItem, buffSize),
		assoc: map[crdt.IPFSPath]*indexCacheItem{},
	}
}

type indexCacheItem struct {
	key       crdt.IPFSPath
	index     crdt.Index
	timestamp int
}

func (cache *residentIndexCache) GetIndex(indexAddr crdt.IPFSPath) (crdt.Index, error) {
	cache.RLock()
	defer cache.RUnlock()

	item, present := cache.assoc[indexAddr]

	if !present {
		return crdt.EmptyIndex(), fmt.Errorf("No cached index for: %v", indexAddr)
	}

	return item.index, nil
}

func (cache *residentIndexCache) SetIndex(indexAddr crdt.IPFSPath, index crdt.Index) error {
	cache.Lock()
	defer cache.Unlock()

	item, present := cache.assoc[indexAddr]

	if present {
		item.timestamp = makeTimestamp()
		return nil
	}

	return cache.addNewItem(indexAddr, index)
}

func (cache *residentIndexCache) addNewItem(indexAddr crdt.IPFSPath, index crdt.Index) error {
	newItem := indexCacheItem{
		timestamp: makeTimestamp(),
		key:       indexAddr,
		index:     index,
	}

	bufferedItem := cache.findOldest()
	*bufferedItem = newItem
	cache.assoc[indexAddr] = bufferedItem
	return nil
}

func (cache *residentIndexCache) findOldest() *indexCacheItem {
	var oldest *indexCacheItem

	for _, item := range cache.buff {
		if oldest == nil {
			oldest = &item
			continue
		}

		if item.timestamp < oldest.timestamp {
			oldest = &item
		}
	}

	if oldest == nil {
		panic("Corrupt buffer")
	}

	return oldest
}

func makeTimestamp() int {
	return time.Now().Nanosecond()
}

type residentHeadCache struct {
	sync.RWMutex
	writing  bool
	written  bool
	current  crdt.IPFSPath
	previous crdt.IPFSPath
}

func (cache *residentHeadCache) BeginReadTransaction() error {
	cache.RLock()
	return nil
}

func (cache *residentHeadCache) BeginWriteTransaction() error {
	cache.Lock()
	cache.writing = true
	return nil
}

func (cache *residentHeadCache) SetHead(head crdt.IPFSPath) error {
	cache.previous = cache.current
	cache.current = head
	cache.written = true
	return nil
}

func (cache *residentHeadCache) Commit() error {
	if cache.writing {
		cache.previous = ""
		cache.writing = false
		cache.written = false
		cache.Unlock()
	} else {
		cache.RUnlock()
	}

	return nil
}

func (cache *residentHeadCache) Rollback() error {
	if !cache.writing {
		return errors.New("Cannot rollback without write")
	}

	if cache.written {
		cache.current = cache.previous
	}

	return cache.Commit()
}

func (cache *residentHeadCache) GetHead() (crdt.IPFSPath, error) {
	head := cache.current
	return head, nil
}

func MakeResidentHeadCache() api.HeadCache {
	return &residentHeadCache{}
}

type residentPriorityQueue struct {
	sync.Mutex
	semaphore chan struct{}
	buff      []residentQueueItem
	datach    chan interface{}
}

func MakeResidentBufferQueue(buffSize int) api.RequestPriorityQueue {
	if buffSize <= 0 {
		buffSize = __DEFAULT_BUFFER_SIZE
	}

	queue := &residentPriorityQueue{
		semaphore: make(chan struct{}, buffSize),
		buff:      make([]residentQueueItem, buffSize),
		datach:    make(chan interface{}),
	}

	return queue
}

func (queue *residentPriorityQueue) Len() int {
	queue.Lock()
	defer queue.Unlock()
	count := 0
	for _, item := range queue.buff {
		if item.populated {
			count++
		}
	}

	return count
}

func (queue *residentPriorityQueue) Enqueue(request api.APIRequest, data interface{}) error {
	item, err := makeResidentQueueItem(request, data)

	if err != nil {
		return errors.Wrap(err, "residentPriorityQueue.Enqueue failed")
	}

	queue.Lock()
	defer queue.Unlock()
	queue.lockResource()

	for i := 0; i < len(queue.buff); i++ {
		spot := &queue.buff[i]
		if !spot.populated {
			*spot = item
			log.Debug("Enqueued item")
			return nil
		}
	}
	log.Debug("Queued request.")

	return corruptBuffer
}

func (queue *residentPriorityQueue) Drain() <-chan interface{} {
	go func() {
		for {
			data, err := queue.popFront()

			if err != nil {
				log.Error("Error draining residentPriorityQueue: %v", err)
				close(queue.datach)
				return
			}

			queue.datach <- data
		}
	}()

	return queue.datach
}

func (queue *residentPriorityQueue) Close() error {
	close(queue.datach)
	return nil
}

func (queue *residentPriorityQueue) popFront() (interface{}, error) {
	queue.unlockResource()
	queue.Lock()
	defer queue.Unlock()

	var best *residentQueueItem
	for i := 0; i < len(queue.buff); i++ {
		spot := &queue.buff[i]
		if !spot.populated {
			continue
		}

		if best == nil {
			best = spot
			continue
		}

		if spot.priority < best.priority {
			best = spot
		}
	}

	if best == nil {
		log.Error("Buffer is corrupt")
		return nil, corruptBuffer
	}

	best.populated = false

	return best.data, nil
}

func (queue *residentPriorityQueue) lockResource() {
	queue.semaphore <- struct{}{}
}

func (queue *residentPriorityQueue) unlockResource() {
	<-queue.semaphore
}

type residentQueueItem struct {
	populated bool
	data      interface{}
	priority  residentPriority
}

func makeResidentQueueItem(request api.APIRequest, data interface{}) (residentQueueItem, error) {
	priority, err := findRequestPriority(request)

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

	item := residentQueueItem{
		data:      data,
		priority:  priority,
		populated: true,
	}

	return item, nil
}

func findRequestPriority(request api.APIRequest) (residentPriority, error) {
	switch request.Type {
	case api.API_QUERY:
		if request.Query.OpCode == query.JOIN {
			return __QUERY_JOIN_PRIORITY, nil
		} else {
			return __QUERY_SELECT_PRIORITY, nil
		}
	case api.API_REFLECT:
		return __QUERY_REFLECT_PRIORITY, nil
	case api.API_REPLICATE:
		return __QUERY_REPLICATE_PRIORITY, nil
	default:
		return __UNKNOWN_PRIORITY, fmt.Errorf("Unknown request.Type: %v", request.Type)
	}
}

var corruptBuffer error = errors.New("Corrupt residentPriorityQueue buffer")

type residentPriority uint8

const (
	__QUERY_JOIN_PRIORITY = residentPriority(iota)
	__QUERY_REFLECT_PRIORITY
	__QUERY_SELECT_PRIORITY
	__QUERY_REPLICATE_PRIORITY
	__UNKNOWN_PRIORITY
)

const __DEFAULT_BUFFER_SIZE = 1024
<commit_msg>Remove superfluous logging<commit_after>package cache

import (
	"fmt"
	"sync"
	"time"

	"github.com/johnny-morrice/godless/api"
	"github.com/johnny-morrice/godless/crdt"
	"github.com/johnny-morrice/godless/log"
	"github.com/johnny-morrice/godless/query"
	"github.com/pkg/errors"
)

// Memcache style key value store.
// Will drop oldest.
type residentIndexCache struct {
	sync.RWMutex
	buff  []indexCacheItem
	assoc map[crdt.IPFSPath]*indexCacheItem
}

func MakeResidentIndexCache(buffSize int) api.IndexCache {
	if buffSize <= 0 {
		buffSize = __DEFAULT_BUFFER_SIZE
	}

	return &residentIndexCache{
		buff:  make([]indexCacheItem, buffSize),
		assoc: map[crdt.IPFSPath]*indexCacheItem{},
	}
}

type indexCacheItem struct {
	key       crdt.IPFSPath
	index     crdt.Index
	timestamp int
}

func (cache *residentIndexCache) GetIndex(indexAddr crdt.IPFSPath) (crdt.Index, error) {
	cache.RLock()
	defer cache.RUnlock()

	item, present := cache.assoc[indexAddr]

	if !present {
		return crdt.EmptyIndex(), fmt.Errorf("No cached index for: %v", indexAddr)
	}

	return item.index, nil
}

func (cache *residentIndexCache) SetIndex(indexAddr crdt.IPFSPath, index crdt.Index) error {
	cache.Lock()
	defer cache.Unlock()

	item, present := cache.assoc[indexAddr]

	if present {
		item.timestamp = makeTimestamp()
		return nil
	}

	return cache.addNewItem(indexAddr, index)
}

func (cache *residentIndexCache) addNewItem(indexAddr crdt.IPFSPath, index crdt.Index) error {
	newItem := indexCacheItem{
		timestamp: makeTimestamp(),
		key:       indexAddr,
		index:     index,
	}

	bufferedItem := cache.findOldest()
	*bufferedItem = newItem
	cache.assoc[indexAddr] = bufferedItem
	return nil
}

func (cache *residentIndexCache) findOldest() *indexCacheItem {
	var oldest *indexCacheItem

	for _, item := range cache.buff {
		if oldest == nil {
			oldest = &item
			continue
		}

		if item.timestamp < oldest.timestamp {
			oldest = &item
		}
	}

	if oldest == nil {
		panic("Corrupt buffer")
	}

	return oldest
}

func makeTimestamp() int {
	return time.Now().Nanosecond()
}

type residentHeadCache struct {
	sync.RWMutex
	writing  bool
	written  bool
	current  crdt.IPFSPath
	previous crdt.IPFSPath
}

func (cache *residentHeadCache) BeginReadTransaction() error {
	cache.RLock()
	return nil
}

func (cache *residentHeadCache) BeginWriteTransaction() error {
	cache.Lock()
	cache.writing = true
	return nil
}

func (cache *residentHeadCache) SetHead(head crdt.IPFSPath) error {
	cache.previous = cache.current
	cache.current = head
	cache.written = true
	return nil
}

func (cache *residentHeadCache) Commit() error {
	if cache.writing {
		cache.previous = ""
		cache.writing = false
		cache.written = false
		cache.Unlock()
	} else {
		cache.RUnlock()
	}

	return nil
}

func (cache *residentHeadCache) Rollback() error {
	if !cache.writing {
		return errors.New("Cannot rollback without write")
	}

	if cache.written {
		cache.current = cache.previous
	}

	return cache.Commit()
}

func (cache *residentHeadCache) GetHead() (crdt.IPFSPath, error) {
	head := cache.current
	return head, nil
}

func MakeResidentHeadCache() api.HeadCache {
	return &residentHeadCache{}
}

type residentPriorityQueue struct {
	sync.Mutex
	semaphore chan struct{}
	buff      []residentQueueItem
	datach    chan interface{}
}

func MakeResidentBufferQueue(buffSize int) api.RequestPriorityQueue {
	if buffSize <= 0 {
		buffSize = __DEFAULT_BUFFER_SIZE
	}

	queue := &residentPriorityQueue{
		semaphore: make(chan struct{}, buffSize),
		buff:      make([]residentQueueItem, buffSize),
		datach:    make(chan interface{}),
	}

	return queue
}

func (queue *residentPriorityQueue) Len() int {
	queue.Lock()
	defer queue.Unlock()
	count := 0
	for _, item := range queue.buff {
		if item.populated {
			count++
		}
	}

	return count
}

func (queue *residentPriorityQueue) Enqueue(request api.APIRequest, data interface{}) error {
	item, err := makeResidentQueueItem(request, data)

	if err != nil {
		return errors.Wrap(err, "residentPriorityQueue.Enqueue failed")
	}

	queue.Lock()
	defer queue.Unlock()
	queue.lockResource()

	for i := 0; i < len(queue.buff); i++ {
		spot := &queue.buff[i]
		if !spot.populated {
			*spot = item
			return nil
		}
	}
	log.Debug("Queued request.")

	return corruptBuffer
}

func (queue *residentPriorityQueue) Drain() <-chan interface{} {
	go func() {
		for {
			data, err := queue.popFront()

			if err != nil {
				log.Error("Error draining residentPriorityQueue: %v", err)
				close(queue.datach)
				return
			}

			queue.datach <- data
		}
	}()

	return queue.datach
}

func (queue *residentPriorityQueue) Close() error {
	close(queue.datach)
	return nil
}

func (queue *residentPriorityQueue) popFront() (interface{}, error) {
	queue.unlockResource()
	queue.Lock()
	defer queue.Unlock()

	var best *residentQueueItem
	for i := 0; i < len(queue.buff); i++ {
		spot := &queue.buff[i]
		if !spot.populated {
			continue
		}

		if best == nil {
			best = spot
			continue
		}

		if spot.priority < best.priority {
			best = spot
		}
	}

	if best == nil {
		log.Error("Buffer is corrupt")
		return nil, corruptBuffer
	}

	best.populated = false

	return best.data, nil
}

func (queue *residentPriorityQueue) lockResource() {
	queue.semaphore <- struct{}{}
}

func (queue *residentPriorityQueue) unlockResource() {
	<-queue.semaphore
}

type residentQueueItem struct {
	populated bool
	data      interface{}
	priority  residentPriority
}

func makeResidentQueueItem(request api.APIRequest, data interface{}) (residentQueueItem, error) {
	priority, err := findRequestPriority(request)

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

	item := residentQueueItem{
		data:      data,
		priority:  priority,
		populated: true,
	}

	return item, nil
}

func findRequestPriority(request api.APIRequest) (residentPriority, error) {
	switch request.Type {
	case api.API_QUERY:
		if request.Query.OpCode == query.JOIN {
			return __QUERY_JOIN_PRIORITY, nil
		} else {
			return __QUERY_SELECT_PRIORITY, nil
		}
	case api.API_REFLECT:
		return __QUERY_REFLECT_PRIORITY, nil
	case api.API_REPLICATE:
		return __QUERY_REPLICATE_PRIORITY, nil
	default:
		return __UNKNOWN_PRIORITY, fmt.Errorf("Unknown request.Type: %v", request.Type)
	}
}

var corruptBuffer error = errors.New("Corrupt residentPriorityQueue buffer")

type residentPriority uint8

const (
	__QUERY_JOIN_PRIORITY = residentPriority(iota)
	__QUERY_REFLECT_PRIORITY
	__QUERY_SELECT_PRIORITY
	__QUERY_REPLICATE_PRIORITY
	__UNKNOWN_PRIORITY
)

const __DEFAULT_BUFFER_SIZE = 1024
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package announced

import (
	"fmt"

	"github.com/golang/glog"

	"k8s.io/apimachinery/pkg/api/meta"
	"k8s.io/apimachinery/pkg/apimachinery"
	"k8s.io/apimachinery/pkg/apimachinery/registered"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/util/sets"
)

type SchemeFunc func(*runtime.Scheme) error
type VersionToSchemeFunc map[string]SchemeFunc

// GroupVersionFactoryArgs contains all the per-version parts of a GroupMetaFactory.
type GroupVersionFactoryArgs struct {
	GroupName   string
	VersionName string

	AddToScheme SchemeFunc
}

// GroupMetaFactoryArgs contains the group-level args of a GroupMetaFactory.
type GroupMetaFactoryArgs struct {
	GroupName              string
	VersionPreferenceOrder []string
	ImportPrefix           string

	RootScopedKinds sets.String // nil is allowed
	IgnoredKinds    sets.String // nil is allowed

	// May be nil if there are no internal objects.
	AddInternalObjectsToScheme SchemeFunc
}

// NewGroupMetaFactory builds the args for you. This is for if you're
// constructing a factory all at once and not using the registry.
func NewGroupMetaFactory(groupArgs *GroupMetaFactoryArgs, versions VersionToSchemeFunc) *GroupMetaFactory {
	gmf := &GroupMetaFactory{
		GroupArgs:   groupArgs,
		VersionArgs: map[string]*GroupVersionFactoryArgs{},
	}
	for v, f := range versions {
		gmf.VersionArgs[v] = &GroupVersionFactoryArgs{
			GroupName:   groupArgs.GroupName,
			VersionName: v,
			AddToScheme: f,
		}
	}
	return gmf
}

// Announce adds this Group factory to the global factory registry. It should
// only be called if you constructed the GroupMetaFactory yourself via
// NewGroupMetadFactory.
// Note that this will panic on an error, since it's expected that you'll be
// calling this at initialization time and any error is a result of a
// programmer importing the wrong set of packages. If this assumption doesn't
// work for you, just call DefaultGroupFactoryRegistry.AnnouncePreconstructedFactory
// yourself.
func (gmf *GroupMetaFactory) Announce(groupFactoryRegistry APIGroupFactoryRegistry) *GroupMetaFactory {
	if err := groupFactoryRegistry.AnnouncePreconstructedFactory(gmf); err != nil {
		panic(err)
	}
	return gmf
}

// GroupMetaFactory has the logic for actually assembling and registering a group.
//
// There are two ways of obtaining one of these.
// 1. You can announce your group and versions separately, and then let the
//    GroupFactoryRegistry assemble this object for you. (This allows group and
//    versions to be imported separately, without referencing each other, to
//    keep import trees small.)
// 2. You can call NewGroupMetaFactory(), which is mostly a drop-in replacement
//    for the old, bad way of doing things. You can then call .Announce() to
//    announce your constructed factory to any code that would like to do
//    things the new, better way.
//
// Note that GroupMetaFactory actually does construct GroupMeta objects, but
// currently it does so in a way that's very entangled with an
// APIRegistrationManager. It's a TODO item to cleanly separate that interface.
type GroupMetaFactory struct {
	GroupArgs *GroupMetaFactoryArgs
	// map of version name to version factory
	VersionArgs map[string]*GroupVersionFactoryArgs

	// assembled by Register()
	prioritizedVersionList []schema.GroupVersion
}

// Register constructs the finalized prioritized version list and sanity checks
// the announced group & versions. Then it calls register.
func (gmf *GroupMetaFactory) Register(m *registered.APIRegistrationManager) error {
	if gmf.GroupArgs == nil {
		return fmt.Errorf("partially announced groups are not allowed, only got versions: %#v", gmf.VersionArgs)
	}
	if len(gmf.VersionArgs) == 0 {
		return fmt.Errorf("group %v announced but no versions announced", gmf.GroupArgs.GroupName)
	}

	pvSet := sets.NewString(gmf.GroupArgs.VersionPreferenceOrder...)
	if pvSet.Len() != len(gmf.GroupArgs.VersionPreferenceOrder) {
		return fmt.Errorf("preference order for group %v has duplicates: %v", gmf.GroupArgs.GroupName, gmf.GroupArgs.VersionPreferenceOrder)
	}
	prioritizedVersions := []schema.GroupVersion{}
	for _, v := range gmf.GroupArgs.VersionPreferenceOrder {
		prioritizedVersions = append(
			prioritizedVersions,
			schema.GroupVersion{
				Group:   gmf.GroupArgs.GroupName,
				Version: v,
			},
		)
	}

	// Go through versions that weren't explicitly prioritized.
	unprioritizedVersions := []schema.GroupVersion{}
	for _, v := range gmf.VersionArgs {
		if v.GroupName != gmf.GroupArgs.GroupName {
			return fmt.Errorf("found %v/%v in group %v?", v.GroupName, v.VersionName, gmf.GroupArgs.GroupName)
		}
		if pvSet.Has(v.VersionName) {
			pvSet.Delete(v.VersionName)
			continue
		}
		unprioritizedVersions = append(unprioritizedVersions, schema.GroupVersion{Group: v.GroupName, Version: v.VersionName})
	}
	if len(unprioritizedVersions) > 1 {
		glog.Warningf("group %v has multiple unprioritized versions: %#v. They will have an arbitrary preference order!", gmf.GroupArgs.GroupName, unprioritizedVersions)
	}
	if pvSet.Len() != 0 {
		return fmt.Errorf("group %v has versions in the priority list that were never announced: %s", gmf.GroupArgs.GroupName, pvSet)
	}
	prioritizedVersions = append(prioritizedVersions, unprioritizedVersions...)
	m.RegisterVersions(prioritizedVersions)
	gmf.prioritizedVersionList = prioritizedVersions
	return nil
}

func (gmf *GroupMetaFactory) newRESTMapper(scheme *runtime.Scheme, externalVersions []schema.GroupVersion, groupMeta *apimachinery.GroupMeta) meta.RESTMapper {
	// the list of kinds that are scoped at the root of the api hierarchy
	// if a kind is not enumerated here, it is assumed to have a namespace scope
	rootScoped := sets.NewString()
	if gmf.GroupArgs.RootScopedKinds != nil {
		rootScoped = gmf.GroupArgs.RootScopedKinds
	}
	ignoredKinds := sets.NewString()
	if gmf.GroupArgs.IgnoredKinds != nil {
		ignoredKinds = gmf.GroupArgs.IgnoredKinds
	}

	return meta.NewDefaultRESTMapperFromScheme(
		externalVersions,
		groupMeta.InterfacesFor,
		gmf.GroupArgs.ImportPrefix,
		ignoredKinds,
		rootScoped,
		scheme,
	)
}

// Enable enables group versions that are allowed, adds methods to the scheme, etc.
func (gmf *GroupMetaFactory) Enable(m *registered.APIRegistrationManager, scheme *runtime.Scheme) error {
	externalVersions := []schema.GroupVersion{}
	for _, v := range gmf.prioritizedVersionList {
		if !m.IsAllowedVersion(v) {
			continue
		}
		externalVersions = append(externalVersions, v)
		if err := m.EnableVersions(v); err != nil {
			return err
		}
		gmf.VersionArgs[v.Version].AddToScheme(scheme)
	}
	if len(externalVersions) == 0 {
		glog.V(4).Infof("No version is registered for group %v", gmf.GroupArgs.GroupName)
		return nil
	}

	if gmf.GroupArgs.AddInternalObjectsToScheme != nil {
		gmf.GroupArgs.AddInternalObjectsToScheme(scheme)
	}

	preferredExternalVersion := externalVersions[0]
	accessor := meta.NewAccessor()

	groupMeta := &apimachinery.GroupMeta{
		GroupVersion:  preferredExternalVersion,
		GroupVersions: externalVersions,
		SelfLinker:    runtime.SelfLinker(accessor),
	}
	for _, v := range externalVersions {
		gvf := gmf.VersionArgs[v.Version]
		if err := groupMeta.AddVersionInterfaces(
			schema.GroupVersion{Group: gvf.GroupName, Version: gvf.VersionName},
			&meta.VersionInterfaces{
				ObjectConvertor:  scheme,
				MetadataAccessor: accessor,
			},
		); err != nil {
			return err
		}
	}
	groupMeta.InterfacesFor = groupMeta.DefaultInterfacesFor
	groupMeta.RESTMapper = gmf.newRESTMapper(scheme, externalVersions, groupMeta)

	if err := m.RegisterGroup(*groupMeta); err != nil {
		return err
	}
	return nil
}

// RegisterAndEnable is provided only to allow this code to get added in multiple steps.
// It's really bad that this is called in init() methods, but supporting this
// temporarily lets us do the change incrementally.
func (gmf *GroupMetaFactory) RegisterAndEnable(registry *registered.APIRegistrationManager, scheme *runtime.Scheme) error {
	if err := gmf.Register(registry); err != nil {
		return err
	}
	if err := gmf.Enable(registry, scheme); err != nil {
		return err
	}

	return nil
}
<commit_msg>GroupMetaFactoryArgs documentation<commit_after>/*
Copyright 2016 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package announced

import (
	"fmt"

	"github.com/golang/glog"

	"k8s.io/apimachinery/pkg/api/meta"
	"k8s.io/apimachinery/pkg/apimachinery"
	"k8s.io/apimachinery/pkg/apimachinery/registered"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/util/sets"
)

type SchemeFunc func(*runtime.Scheme) error
type VersionToSchemeFunc map[string]SchemeFunc

// GroupVersionFactoryArgs contains all the per-version parts of a GroupMetaFactory.
type GroupVersionFactoryArgs struct {
	GroupName   string
	VersionName string

	AddToScheme SchemeFunc
}

// GroupMetaFactoryArgs contains the group-level args of a GroupMetaFactory.
type GroupMetaFactoryArgs struct {
	// GroupName is the name of the API-Group
	//
	// example: 'servicecatalog.k8s.io'
	GroupName              string
	VersionPreferenceOrder []string
	// ImportPrefix is the base go package of the API-Group
	//
	// example: 'k8s.io/kubernetes/pkg/apis/autoscaling'
	ImportPrefix string
	// RootScopedKinds are resources that are not namespaced.
	RootScopedKinds sets.String // nil is allowed
	IgnoredKinds    sets.String // nil is allowed

	// May be nil if there are no internal objects.
	AddInternalObjectsToScheme SchemeFunc
}

// NewGroupMetaFactory builds the args for you. This is for if you're
// constructing a factory all at once and not using the registry.
func NewGroupMetaFactory(groupArgs *GroupMetaFactoryArgs, versions VersionToSchemeFunc) *GroupMetaFactory {
	gmf := &GroupMetaFactory{
		GroupArgs:   groupArgs,
		VersionArgs: map[string]*GroupVersionFactoryArgs{},
	}
	for v, f := range versions {
		gmf.VersionArgs[v] = &GroupVersionFactoryArgs{
			GroupName:   groupArgs.GroupName,
			VersionName: v,
			AddToScheme: f,
		}
	}
	return gmf
}

// Announce adds this Group factory to the global factory registry. It should
// only be called if you constructed the GroupMetaFactory yourself via
// NewGroupMetadFactory.
// Note that this will panic on an error, since it's expected that you'll be
// calling this at initialization time and any error is a result of a
// programmer importing the wrong set of packages. If this assumption doesn't
// work for you, just call DefaultGroupFactoryRegistry.AnnouncePreconstructedFactory
// yourself.
func (gmf *GroupMetaFactory) Announce(groupFactoryRegistry APIGroupFactoryRegistry) *GroupMetaFactory {
	if err := groupFactoryRegistry.AnnouncePreconstructedFactory(gmf); err != nil {
		panic(err)
	}
	return gmf
}

// GroupMetaFactory has the logic for actually assembling and registering a group.
//
// There are two ways of obtaining one of these.
// 1. You can announce your group and versions separately, and then let the
//    GroupFactoryRegistry assemble this object for you. (This allows group and
//    versions to be imported separately, without referencing each other, to
//    keep import trees small.)
// 2. You can call NewGroupMetaFactory(), which is mostly a drop-in replacement
//    for the old, bad way of doing things. You can then call .Announce() to
//    announce your constructed factory to any code that would like to do
//    things the new, better way.
//
// Note that GroupMetaFactory actually does construct GroupMeta objects, but
// currently it does so in a way that's very entangled with an
// APIRegistrationManager. It's a TODO item to cleanly separate that interface.
type GroupMetaFactory struct {
	GroupArgs *GroupMetaFactoryArgs
	// map of version name to version factory
	VersionArgs map[string]*GroupVersionFactoryArgs

	// assembled by Register()
	prioritizedVersionList []schema.GroupVersion
}

// Register constructs the finalized prioritized version list and sanity checks
// the announced group & versions. Then it calls register.
func (gmf *GroupMetaFactory) Register(m *registered.APIRegistrationManager) error {
	if gmf.GroupArgs == nil {
		return fmt.Errorf("partially announced groups are not allowed, only got versions: %#v", gmf.VersionArgs)
	}
	if len(gmf.VersionArgs) == 0 {
		return fmt.Errorf("group %v announced but no versions announced", gmf.GroupArgs.GroupName)
	}

	pvSet := sets.NewString(gmf.GroupArgs.VersionPreferenceOrder...)
	if pvSet.Len() != len(gmf.GroupArgs.VersionPreferenceOrder) {
		return fmt.Errorf("preference order for group %v has duplicates: %v", gmf.GroupArgs.GroupName, gmf.GroupArgs.VersionPreferenceOrder)
	}
	prioritizedVersions := []schema.GroupVersion{}
	for _, v := range gmf.GroupArgs.VersionPreferenceOrder {
		prioritizedVersions = append(
			prioritizedVersions,
			schema.GroupVersion{
				Group:   gmf.GroupArgs.GroupName,
				Version: v,
			},
		)
	}

	// Go through versions that weren't explicitly prioritized.
	unprioritizedVersions := []schema.GroupVersion{}
	for _, v := range gmf.VersionArgs {
		if v.GroupName != gmf.GroupArgs.GroupName {
			return fmt.Errorf("found %v/%v in group %v?", v.GroupName, v.VersionName, gmf.GroupArgs.GroupName)
		}
		if pvSet.Has(v.VersionName) {
			pvSet.Delete(v.VersionName)
			continue
		}
		unprioritizedVersions = append(unprioritizedVersions, schema.GroupVersion{Group: v.GroupName, Version: v.VersionName})
	}
	if len(unprioritizedVersions) > 1 {
		glog.Warningf("group %v has multiple unprioritized versions: %#v. They will have an arbitrary preference order!", gmf.GroupArgs.GroupName, unprioritizedVersions)
	}
	if pvSet.Len() != 0 {
		return fmt.Errorf("group %v has versions in the priority list that were never announced: %s", gmf.GroupArgs.GroupName, pvSet)
	}
	prioritizedVersions = append(prioritizedVersions, unprioritizedVersions...)
	m.RegisterVersions(prioritizedVersions)
	gmf.prioritizedVersionList = prioritizedVersions
	return nil
}

func (gmf *GroupMetaFactory) newRESTMapper(scheme *runtime.Scheme, externalVersions []schema.GroupVersion, groupMeta *apimachinery.GroupMeta) meta.RESTMapper {
	// the list of kinds that are scoped at the root of the api hierarchy
	// if a kind is not enumerated here, it is assumed to have a namespace scope
	rootScoped := sets.NewString()
	if gmf.GroupArgs.RootScopedKinds != nil {
		rootScoped = gmf.GroupArgs.RootScopedKinds
	}
	ignoredKinds := sets.NewString()
	if gmf.GroupArgs.IgnoredKinds != nil {
		ignoredKinds = gmf.GroupArgs.IgnoredKinds
	}

	return meta.NewDefaultRESTMapperFromScheme(
		externalVersions,
		groupMeta.InterfacesFor,
		gmf.GroupArgs.ImportPrefix,
		ignoredKinds,
		rootScoped,
		scheme,
	)
}

// Enable enables group versions that are allowed, adds methods to the scheme, etc.
func (gmf *GroupMetaFactory) Enable(m *registered.APIRegistrationManager, scheme *runtime.Scheme) error {
	externalVersions := []schema.GroupVersion{}
	for _, v := range gmf.prioritizedVersionList {
		if !m.IsAllowedVersion(v) {
			continue
		}
		externalVersions = append(externalVersions, v)
		if err := m.EnableVersions(v); err != nil {
			return err
		}
		gmf.VersionArgs[v.Version].AddToScheme(scheme)
	}
	if len(externalVersions) == 0 {
		glog.V(4).Infof("No version is registered for group %v", gmf.GroupArgs.GroupName)
		return nil
	}

	if gmf.GroupArgs.AddInternalObjectsToScheme != nil {
		gmf.GroupArgs.AddInternalObjectsToScheme(scheme)
	}

	preferredExternalVersion := externalVersions[0]
	accessor := meta.NewAccessor()

	groupMeta := &apimachinery.GroupMeta{
		GroupVersion:  preferredExternalVersion,
		GroupVersions: externalVersions,
		SelfLinker:    runtime.SelfLinker(accessor),
	}
	for _, v := range externalVersions {
		gvf := gmf.VersionArgs[v.Version]
		if err := groupMeta.AddVersionInterfaces(
			schema.GroupVersion{Group: gvf.GroupName, Version: gvf.VersionName},
			&meta.VersionInterfaces{
				ObjectConvertor:  scheme,
				MetadataAccessor: accessor,
			},
		); err != nil {
			return err
		}
	}
	groupMeta.InterfacesFor = groupMeta.DefaultInterfacesFor
	groupMeta.RESTMapper = gmf.newRESTMapper(scheme, externalVersions, groupMeta)

	if err := m.RegisterGroup(*groupMeta); err != nil {
		return err
	}
	return nil
}

// RegisterAndEnable is provided only to allow this code to get added in multiple steps.
// It's really bad that this is called in init() methods, but supporting this
// temporarily lets us do the change incrementally.
func (gmf *GroupMetaFactory) RegisterAndEnable(registry *registered.APIRegistrationManager, scheme *runtime.Scheme) error {
	if err := gmf.Register(registry); err != nil {
		return err
	}
	if err := gmf.Enable(registry, scheme); err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package integration

import (
	"errors"
	"io/ioutil"
	"log"
	"time"

	dfakes "github.com/concourse/blackbox/datadog/fakes"
	efakes "github.com/concourse/blackbox/expvar/fakes"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/ginkgomon"

	"github.com/concourse/blackbox"
	"github.com/concourse/blackbox/expvar"
)

var _ = Describe("Emitter", func() {
	var (
		process ifrit.Process

		fakeFetcher *efakes.FakeFetcher
		fakeDatadog *dfakes.FakeClient
	)

	BeforeEach(func() {
		fakeFetcher = &efakes.FakeFetcher{}
		fakeDatadog = &dfakes.FakeClient{}
	})

	JustBeforeEach(func() {
		process = ginkgomon.Invoke(blackbox.NewEmitter(
			fakeDatadog,
			fakeFetcher,
			time.Second,
			"an-amazing-host.local",
			[]string{"some", "great", "tags"},
		))
	})

	AfterEach(func() {
		ginkgomon.Interrupt(process)
	})

	Context("when everything is great", func() {
		BeforeEach(func() {
			expvars := expvar.Expvars{
				"memory": map[string]float32{
					"limit": 3.23,
				},
			}
			fakeFetcher.FetchReturns(expvars, nil)
		})

		It("sends the things to datadog", func() {
			Eventually(fakeDatadog.PublishSeriesCallCount).Should(Equal(1))

			emittedSeries := fakeDatadog.PublishSeriesArgsForCall(0)
			metric := emittedSeries[0]

			Ω(metric.Name).Should(Equal("memory.limit"))
			Ω(metric.Host).Should(Equal("an-amazing-host.local"))
			Ω(metric.Tags).Should(ConsistOf("some", "great", "tags"))

			point := metric.Points[0]
			Ω(point.Timestamp).Should(BeTemporally("~", time.Now()))
			Ω(point.Value).Should(BeNumerically("~", 3.23, 0.0001))
		})
	})

	Context("when fetching expvars fails", func() {
		BeforeEach(func() {
			log.SetOutput(ioutil.Discard)

			error := errors.New("disaster")
			fakeFetcher.FetchReturns(expvar.Expvars{}, error)
		})

		It("does not send anything to datadog", func() {
			Consistently(fakeDatadog.PublishSeriesCallCount).Should(Equal(0))
		})
	})
})
<commit_msg>we do not care about nanoseconds<commit_after>package integration

import (
	"errors"
	"io/ioutil"
	"log"
	"time"

	dfakes "github.com/concourse/blackbox/datadog/fakes"
	efakes "github.com/concourse/blackbox/expvar/fakes"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/ginkgomon"

	"github.com/concourse/blackbox"
	"github.com/concourse/blackbox/expvar"
)

var _ = Describe("Emitter", func() {
	var (
		process ifrit.Process

		fakeFetcher *efakes.FakeFetcher
		fakeDatadog *dfakes.FakeClient
	)

	BeforeEach(func() {
		fakeFetcher = &efakes.FakeFetcher{}
		fakeDatadog = &dfakes.FakeClient{}
	})

	JustBeforeEach(func() {
		process = ginkgomon.Invoke(blackbox.NewEmitter(
			fakeDatadog,
			fakeFetcher,
			time.Second,
			"an-amazing-host.local",
			[]string{"some", "great", "tags"},
		))
	})

	AfterEach(func() {
		ginkgomon.Interrupt(process)
	})

	Context("when everything is great", func() {
		BeforeEach(func() {
			expvars := expvar.Expvars{
				"memory": map[string]float32{
					"limit": 3.23,
				},
			}
			fakeFetcher.FetchReturns(expvars, nil)
		})

		It("sends the things to datadog", func() {
			Eventually(fakeDatadog.PublishSeriesCallCount).Should(Equal(1))

			emittedSeries := fakeDatadog.PublishSeriesArgsForCall(0)
			metric := emittedSeries[0]

			Ω(metric.Name).Should(Equal("memory.limit"))
			Ω(metric.Host).Should(Equal("an-amazing-host.local"))
			Ω(metric.Tags).Should(ConsistOf("some", "great", "tags"))

			point := metric.Points[0]
			Ω(point.Timestamp).Should(BeTemporally("~", time.Now(), 1*time.Second))
			Ω(point.Value).Should(BeNumerically("~", 3.23, 0.0001))
		})
	})

	Context("when fetching expvars fails", func() {
		BeforeEach(func() {
			log.SetOutput(ioutil.Discard)

			error := errors.New("disaster")
			fakeFetcher.FetchReturns(expvar.Expvars{}, error)
		})

		It("does not send anything to datadog", func() {
			Consistently(fakeDatadog.PublishSeriesCallCount).Should(Equal(0))
		})
	})
})
<|endoftext|>


<commit_before>/*
   Nging is a toolbox for webmasters
   Copyright (C) 2018-present  Wenhui Shen <swh@admpub.com>

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published
   by the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

package perm

import (
	"github.com/admpub/nging/application/registry/navigate"
	"github.com/webx-top/echo"
)

var navTreeCached *Map

func NavTreeCached() *Map {
	if navTreeCached != nil {
		return navTreeCached
	}
	navTreeCached = NewMap()
	for _, project := range navigate.ProjectListAll() {
		if project == nil {
			continue
		}
		navTreeCached.Import(project.NavList)
	}
	navTreeCached.Import(navigate.TopNavigate)
	return navTreeCached
}

func init() {
	echo.On(`beforeRun`, func(_ echo.H) error {
		NavTreeCached()
		return nil
	})
}
<commit_msg>update<commit_after>/*
   Nging is a toolbox for webmasters
   Copyright (C) 2018-present  Wenhui Shen <swh@admpub.com>

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published
   by the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

package perm

import (
	"sync"

	"github.com/admpub/nging/application/registry/navigate"
	"github.com/webx-top/echo"
)

var (
	navTreeCached *Map
	navTreeOnce   sync.Once
)

func initNavTreeCached() {
	if navTreeCached != nil {
		return
	}
	navTreeCached = NewMap()
	for _, project := range navigate.ProjectListAll() {
		if project == nil {
			continue
		}
		navTreeCached.Import(project.NavList)
	}
	navTreeCached.Import(navigate.TopNavigate)
}

func NavTreeCached() *Map {
	navTreeOnce.Do(initNavTreeCached)
	return navTreeCached
}

func init() {
	echo.On(`beforeRun`, func(_ echo.H) error {
		NavTreeCached()
		return nil
	})
}
<|endoftext|>


<commit_before>/*
Copyright 2020 The Ceph-CSI Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package cephfs

import (
	"context"
	"strings"

	"github.com/ceph/ceph-csi/internal/util"

	"github.com/golang/protobuf/ptypes/timestamp"
	klog "k8s.io/klog/v2"
)

// cephfsSnapshot represents a CSI snapshot and its cluster information.
type cephfsSnapshot struct {
	NamePrefix string
	Monitors   string
	// MetadataPool & Pool fields are not used atm. But its definitely good to have it in this struct
	// so keeping it here
	MetadataPool string
	Pool         string
	ClusterID    string
	RequestName  string
}

func createSnapshot(ctx context.Context, volOptions *volumeOptions, cr *util.Credentials, snapID, volID volumeID) error {
	args := []string{
		"fs",
		"subvolume",
		"snapshot",
		"create",
		volOptions.FsName,
		string(volID),
		string(snapID),
		"--group_name",
		volOptions.SubvolumeGroup,
		"-m", volOptions.Monitors,
		"-c", util.CephConfigPath,
		"-n", cephEntityClientPrefix + cr.ID,
		"--keyfile=" + cr.KeyFile,
	}

	err := execCommandErr(
		ctx,
		"ceph",
		args[:]...)
	if err != nil {
		util.ErrorLog(ctx, "failed to create subvolume snapshot %s %s(%s) in fs %s", string(snapID), string(volID), err, volOptions.FsName)
		return err
	}
	return nil
}

func deleteSnapshot(ctx context.Context, volOptions *volumeOptions, cr *util.Credentials, snapID, volID volumeID) error {
	args := []string{
		"fs",
		"subvolume",
		"snapshot",
		"rm",
		volOptions.FsName,
		string(volID),
		string(snapID),
		"--group_name",
		volOptions.SubvolumeGroup,
		"-m", volOptions.Monitors,
		"-c", util.CephConfigPath,
		"-n", cephEntityClientPrefix + cr.ID,
		"--keyfile=" + cr.KeyFile,
		"--force",
	}

	err := execCommandErr(
		ctx,
		"ceph",
		args[:]...)
	if err != nil {
		util.ErrorLog(ctx, "failed to delete subvolume snapshot %s %s(%s) in fs %s", string(snapID), string(volID), err, volOptions.FsName)
		return err
	}
	return nil
}

type snapshotInfo struct {
	CreatedAt        string `json:"created_at"`
	CreationTime     *timestamp.Timestamp
	DataPool         string `json:"data_pool"`
	HasPendingClones string `json:"has_pending_clones"`
	Protected        string `json:"protected"`
	Size             int    `json:"size"`
}

func getSnapshotInfo(ctx context.Context, volOptions *volumeOptions, cr *util.Credentials, snapID, volID volumeID) (snapshotInfo, error) {
	snap := snapshotInfo{}
	args := []string{
		"fs",
		"subvolume",
		"snapshot",
		"info",
		volOptions.FsName,
		string(volID),
		string(snapID),
		"--group_name",
		volOptions.SubvolumeGroup,
		"-m", volOptions.Monitors,
		"-c", util.CephConfigPath,
		"-n", cephEntityClientPrefix + cr.ID,
		"--keyfile=" + cr.KeyFile,
		"--format=json",
	}
	err := execCommandJSON(
		ctx,
		&snap,
		"ceph",
		args[:]...)
	if err != nil {
		if strings.Contains(err.Error(), ErrSnapNotFound.Error()) {
			return snapshotInfo{}, err
		}
		util.ErrorLog(ctx, "failed to get subvolume snapshot info %s %s(%s) in fs %s", string(snapID), string(volID), err, volOptions.FsName)
		return snapshotInfo{}, err
	}
	return snap, nil
}

func protectSnapshot(ctx context.Context, volOptions *volumeOptions, cr *util.Credentials, snapID, volID volumeID) error {
	args := []string{
		"fs",
		"subvolume",
		"snapshot",
		"protect",
		volOptions.FsName,
		string(volID),
		string(snapID),
		"--group_name",
		volOptions.SubvolumeGroup,
		"-m", volOptions.Monitors,
		"-c", util.CephConfigPath,
		"-n", cephEntityClientPrefix + cr.ID,
		"--keyfile=" + cr.KeyFile,
	}

	err := execCommandErr(
		ctx,
		"ceph",
		args[:]...)
	if err != nil {
		if strings.Contains(err.Error(), ErrSnapProtectionExist.Error()) {
			return nil
		}
		util.ErrorLog(ctx, "failed to protect subvolume snapshot %s %s(%s) in fs %s", string(snapID), string(volID), err, volOptions.FsName)
		return err
	}
	return nil
}

func unprotectSnapshot(ctx context.Context, volOptions *volumeOptions, cr *util.Credentials, snapID, volID volumeID) error {
	args := []string{
		"fs",
		"subvolume",
		"snapshot",
		"unprotect",
		volOptions.FsName,
		string(volID),
		string(snapID),
		"--group_name",
		volOptions.SubvolumeGroup,
		"-m", volOptions.Monitors,
		"-c", util.CephConfigPath,
		"-n", cephEntityClientPrefix + cr.ID,
		"--keyfile=" + cr.KeyFile,
	}

	err := execCommandErr(
		ctx,
		"ceph",
		args[:]...)
	if err != nil {
		// Incase the snap is already unprotected we get ErrSnapProtectionExist error code
		// in that case we are safe and we could discard this error.
		if strings.Contains(err.Error(), ErrSnapProtectionExist.Error()) {
			return nil
		}
		klog.Errorf(util.Log(ctx, "failed to unprotect subvolume snapshot %s %s(%s) in fs %s"), string(snapID), string(volID), err, volOptions.FsName)
		return err
	}
	return nil
}

func cloneSnapshot(ctx context.Context, parentVolOptions *volumeOptions, cr *util.Credentials, volID, snapID, cloneID volumeID, cloneVolOptions *volumeOptions) error {
	args := []string{
		"fs",
		"subvolume",
		"snapshot",
		"clone",
		parentVolOptions.FsName,
		string(volID),
		string(snapID),
		string(cloneID),
		"--group_name",
		parentVolOptions.SubvolumeGroup,
		"--target_group_name",
		cloneVolOptions.SubvolumeGroup,
		"-m", parentVolOptions.Monitors,
		"-c", util.CephConfigPath,
		"-n", cephEntityClientPrefix + cr.ID,
		"--keyfile=" + cr.KeyFile,
	}
	if cloneVolOptions.Pool != "" {
		args = append(args, "--pool_layout", cloneVolOptions.Pool)
	}

	err := execCommandErr(
		ctx,
		"ceph",
		args[:]...)

	if err != nil {
		klog.Errorf(util.Log(ctx, "failed to clone subvolume snapshot %s %s(%s) in fs %s"), string(cloneID), string(volID), err, parentVolOptions.FsName)
		if strings.HasPrefix(err.Error(), ErrVolumeNotFound.Error()) {
			return ErrVolumeNotFound
		}
		return err
	}
	return nil
}
<commit_msg>cephfs: replace Errorf with ErrorLog in unprotectSnapshot<commit_after>/*
Copyright 2020 The Ceph-CSI Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package cephfs

import (
	"context"
	"strings"

	"github.com/ceph/ceph-csi/internal/util"

	"github.com/golang/protobuf/ptypes/timestamp"
	klog "k8s.io/klog/v2"
)

// cephfsSnapshot represents a CSI snapshot and its cluster information.
type cephfsSnapshot struct {
	NamePrefix string
	Monitors   string
	// MetadataPool & Pool fields are not used atm. But its definitely good to have it in this struct
	// so keeping it here
	MetadataPool string
	Pool         string
	ClusterID    string
	RequestName  string
}

func createSnapshot(ctx context.Context, volOptions *volumeOptions, cr *util.Credentials, snapID, volID volumeID) error {
	args := []string{
		"fs",
		"subvolume",
		"snapshot",
		"create",
		volOptions.FsName,
		string(volID),
		string(snapID),
		"--group_name",
		volOptions.SubvolumeGroup,
		"-m", volOptions.Monitors,
		"-c", util.CephConfigPath,
		"-n", cephEntityClientPrefix + cr.ID,
		"--keyfile=" + cr.KeyFile,
	}

	err := execCommandErr(
		ctx,
		"ceph",
		args[:]...)
	if err != nil {
		util.ErrorLog(ctx, "failed to create subvolume snapshot %s %s(%s) in fs %s", string(snapID), string(volID), err, volOptions.FsName)
		return err
	}
	return nil
}

func deleteSnapshot(ctx context.Context, volOptions *volumeOptions, cr *util.Credentials, snapID, volID volumeID) error {
	args := []string{
		"fs",
		"subvolume",
		"snapshot",
		"rm",
		volOptions.FsName,
		string(volID),
		string(snapID),
		"--group_name",
		volOptions.SubvolumeGroup,
		"-m", volOptions.Monitors,
		"-c", util.CephConfigPath,
		"-n", cephEntityClientPrefix + cr.ID,
		"--keyfile=" + cr.KeyFile,
		"--force",
	}

	err := execCommandErr(
		ctx,
		"ceph",
		args[:]...)
	if err != nil {
		util.ErrorLog(ctx, "failed to delete subvolume snapshot %s %s(%s) in fs %s", string(snapID), string(volID), err, volOptions.FsName)
		return err
	}
	return nil
}

type snapshotInfo struct {
	CreatedAt        string `json:"created_at"`
	CreationTime     *timestamp.Timestamp
	DataPool         string `json:"data_pool"`
	HasPendingClones string `json:"has_pending_clones"`
	Protected        string `json:"protected"`
	Size             int    `json:"size"`
}

func getSnapshotInfo(ctx context.Context, volOptions *volumeOptions, cr *util.Credentials, snapID, volID volumeID) (snapshotInfo, error) {
	snap := snapshotInfo{}
	args := []string{
		"fs",
		"subvolume",
		"snapshot",
		"info",
		volOptions.FsName,
		string(volID),
		string(snapID),
		"--group_name",
		volOptions.SubvolumeGroup,
		"-m", volOptions.Monitors,
		"-c", util.CephConfigPath,
		"-n", cephEntityClientPrefix + cr.ID,
		"--keyfile=" + cr.KeyFile,
		"--format=json",
	}
	err := execCommandJSON(
		ctx,
		&snap,
		"ceph",
		args[:]...)
	if err != nil {
		if strings.Contains(err.Error(), ErrSnapNotFound.Error()) {
			return snapshotInfo{}, err
		}
		util.ErrorLog(ctx, "failed to get subvolume snapshot info %s %s(%s) in fs %s", string(snapID), string(volID), err, volOptions.FsName)
		return snapshotInfo{}, err
	}
	return snap, nil
}

func protectSnapshot(ctx context.Context, volOptions *volumeOptions, cr *util.Credentials, snapID, volID volumeID) error {
	args := []string{
		"fs",
		"subvolume",
		"snapshot",
		"protect",
		volOptions.FsName,
		string(volID),
		string(snapID),
		"--group_name",
		volOptions.SubvolumeGroup,
		"-m", volOptions.Monitors,
		"-c", util.CephConfigPath,
		"-n", cephEntityClientPrefix + cr.ID,
		"--keyfile=" + cr.KeyFile,
	}

	err := execCommandErr(
		ctx,
		"ceph",
		args[:]...)
	if err != nil {
		if strings.Contains(err.Error(), ErrSnapProtectionExist.Error()) {
			return nil
		}
		util.ErrorLog(ctx, "failed to protect subvolume snapshot %s %s(%s) in fs %s", string(snapID), string(volID), err, volOptions.FsName)
		return err
	}
	return nil
}

func unprotectSnapshot(ctx context.Context, volOptions *volumeOptions, cr *util.Credentials, snapID, volID volumeID) error {
	args := []string{
		"fs",
		"subvolume",
		"snapshot",
		"unprotect",
		volOptions.FsName,
		string(volID),
		string(snapID),
		"--group_name",
		volOptions.SubvolumeGroup,
		"-m", volOptions.Monitors,
		"-c", util.CephConfigPath,
		"-n", cephEntityClientPrefix + cr.ID,
		"--keyfile=" + cr.KeyFile,
	}

	err := execCommandErr(
		ctx,
		"ceph",
		args[:]...)
	if err != nil {
		// Incase the snap is already unprotected we get ErrSnapProtectionExist error code
		// in that case we are safe and we could discard this error.
		if strings.Contains(err.Error(), ErrSnapProtectionExist.Error()) {
			return nil
		}
		util.ErrorLog(ctx, "failed to unprotect subvolume snapshot %s %s(%s) in fs %s", string(snapID), string(volID), err, volOptions.FsName)
		return err
	}
	return nil
}

func cloneSnapshot(ctx context.Context, parentVolOptions *volumeOptions, cr *util.Credentials, volID, snapID, cloneID volumeID, cloneVolOptions *volumeOptions) error {
	args := []string{
		"fs",
		"subvolume",
		"snapshot",
		"clone",
		parentVolOptions.FsName,
		string(volID),
		string(snapID),
		string(cloneID),
		"--group_name",
		parentVolOptions.SubvolumeGroup,
		"--target_group_name",
		cloneVolOptions.SubvolumeGroup,
		"-m", parentVolOptions.Monitors,
		"-c", util.CephConfigPath,
		"-n", cephEntityClientPrefix + cr.ID,
		"--keyfile=" + cr.KeyFile,
	}
	if cloneVolOptions.Pool != "" {
		args = append(args, "--pool_layout", cloneVolOptions.Pool)
	}

	err := execCommandErr(
		ctx,
		"ceph",
		args[:]...)

	if err != nil {
		klog.Errorf(util.Log(ctx, "failed to clone subvolume snapshot %s %s(%s) in fs %s"), string(cloneID), string(volID), err, parentVolOptions.FsName)
		if strings.HasPrefix(err.Error(), ErrVolumeNotFound.Error()) {
			return ErrVolumeNotFound
		}
		return err
	}
	return nil
}
<|endoftext|>


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

package cache

import (
	"sort"

	"golang.org/x/tools/internal/lsp/debug"
	"golang.org/x/tools/internal/span"
)

type debugView struct{ *view }

func (v debugView) ID() string             { return v.id }
func (v debugView) Session() debug.Session { return debugSession{v.session} }

type debugSession struct{ *session }

func (s debugSession) ID() string         { return s.id }
func (s debugSession) Cache() debug.Cache { return debugCache{s.cache} }
func (s debugSession) Files() []*debug.File {
	var files []*debug.File
	seen := make(map[span.URI]*debug.File)
	s.overlayMu.Lock()
	defer s.overlayMu.Unlock()
	for _, overlay := range s.overlays {
		f, ok := seen[overlay.uri]
		if !ok {
			f = &debug.File{Session: s, URI: overlay.uri}
			seen[overlay.uri] = f
			files = append(files, f)
		}
		f.Data = string(overlay.text)
		f.Error = nil
		f.Hash = overlay.hash
	}
	sort.Slice(files, func(i int, j int) bool {
		return files[i].URI < files[j].URI
	})
	return files
}

func (s debugSession) File(hash string) *debug.File {
	s.overlayMu.Lock()
	defer s.overlayMu.Unlock()
	for _, overlay := range s.overlays {
		if overlay.hash == hash {
			return &debug.File{
				Session: s,
				URI:     overlay.uri,
				Data:    string(overlay.text),
				Error:   nil,
				Hash:    overlay.hash,
			}
		}
	}
	return &debug.File{
		Session: s,
		Hash:    hash,
	}
}
<commit_msg>internal/lsp/cache: add Env to debugView<commit_after>// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package cache

import (
	"sort"

	"golang.org/x/tools/internal/lsp/debug"
	"golang.org/x/tools/internal/span"
)

type debugView struct{ *view }

func (v debugView) ID() string             { return v.id }
func (v debugView) Session() debug.Session { return debugSession{v.session} }
func (v debugView) Env() []string          { return v.Options().Env }

type debugSession struct{ *session }

func (s debugSession) ID() string         { return s.id }
func (s debugSession) Cache() debug.Cache { return debugCache{s.cache} }
func (s debugSession) Files() []*debug.File {
	var files []*debug.File
	seen := make(map[span.URI]*debug.File)
	s.overlayMu.Lock()
	defer s.overlayMu.Unlock()
	for _, overlay := range s.overlays {
		f, ok := seen[overlay.uri]
		if !ok {
			f = &debug.File{Session: s, URI: overlay.uri}
			seen[overlay.uri] = f
			files = append(files, f)
		}
		f.Data = string(overlay.text)
		f.Error = nil
		f.Hash = overlay.hash
	}
	sort.Slice(files, func(i int, j int) bool {
		return files[i].URI < files[j].URI
	})
	return files
}

func (s debugSession) File(hash string) *debug.File {
	s.overlayMu.Lock()
	defer s.overlayMu.Unlock()
	for _, overlay := range s.overlays {
		if overlay.hash == hash {
			return &debug.File{
				Session: s,
				URI:     overlay.uri,
				Data:    string(overlay.text),
				Error:   nil,
				Hash:    overlay.hash,
			}
		}
	}
	return &debug.File{
		Session: s,
		Hash:    hash,
	}
}
<|endoftext|>


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

// Package mapsort provides sorted access to maps.
package mapsort

import (
	"sort"

	"google.golang.org/protobuf/reflect/protoreflect"
)

// Range iterates over every map entry in sorted key order,
// calling f for each key and value encountered.
func Range(mapv protoreflect.Map, keyKind protoreflect.Kind, f func(protoreflect.MapKey, protoreflect.Value) bool) {
	var keys []protoreflect.MapKey
	mapv.Range(func(key protoreflect.MapKey, _ protoreflect.Value) bool {
		keys = append(keys, key)
		return true
	})
	sort.Slice(keys, func(i, j int) bool {
		switch keyKind {
		case protoreflect.BoolKind:
			return !keys[i].Bool() && keys[j].Bool()
		case protoreflect.Int32Kind,
			protoreflect.Sint32Kind,
			protoreflect.Sfixed32Kind,
			protoreflect.Int64Kind,
			protoreflect.Sint64Kind,
			protoreflect.Sfixed64Kind:
			return keys[i].Int() < keys[j].Int()
		case protoreflect.Uint32Kind,
			protoreflect.Fixed32Kind,
			protoreflect.Uint64Kind,
			protoreflect.Fixed64Kind:
			return keys[i].Uint() < keys[j].Uint()
		default:
			return keys[i].String() < keys[j].String()
		}
	})
	for _, key := range keys {
		if !f(key, mapv.Get(key)) {
			break
		}
	}
}
<commit_msg>internal/mapsort: use explicit kind for strings<commit_after>// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package mapsort provides sorted access to maps.
package mapsort

import (
	"sort"

	"google.golang.org/protobuf/reflect/protoreflect"
)

// Range iterates over every map entry in sorted key order,
// calling f for each key and value encountered.
func Range(mapv protoreflect.Map, keyKind protoreflect.Kind, f func(protoreflect.MapKey, protoreflect.Value) bool) {
	var keys []protoreflect.MapKey
	mapv.Range(func(key protoreflect.MapKey, _ protoreflect.Value) bool {
		keys = append(keys, key)
		return true
	})
	sort.Slice(keys, func(i, j int) bool {
		switch keyKind {
		case protoreflect.BoolKind:
			return !keys[i].Bool() && keys[j].Bool()
		case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind,
			protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
			return keys[i].Int() < keys[j].Int()
		case protoreflect.Uint32Kind, protoreflect.Fixed32Kind,
			protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
			return keys[i].Uint() < keys[j].Uint()
		case protoreflect.StringKind:
			return keys[i].String() < keys[j].String()
		default:
			panic("invalid kind: " + keyKind.String())
		}
	})
	for _, key := range keys {
		if !f(key, mapv.Get(key)) {
			break
		}
	}
}
<|endoftext|>


<commit_before>package cartogram

import (
	"fmt"
	"io/ioutil"
	"path"
	"regexp"

	"github.com/akerl/voyager/prompt"
)

const (
	accountRegexString = `(\d+)(/(\w+))?`
)

// AccountRegex matches an account number with an optional role name
var AccountRegex = regexp.MustCompile(accountRegexString)

// Pack defines a group of Cartograms
type Pack map[string]Cartogram

// Find checks both Lookup and Search for an account
func (cp Pack) Find(args []string) (Account, error) {
	var targetAccount Account
	var err error
	var found bool

	found, targetAccount, err = cp.findDirectAccount(args)
	if err != nil || found {
		return targetAccount, err
	}

	found, targetAccount, err = cp.findMatchAccount(args)
	if err != nil || found {
		return targetAccount, err
	}

	return targetAccount, fmt.Errorf("Unable to locate an account with provided info")
}

func (cp Pack) findDirectAccount(args []string) (bool, Account, error) {
	var account Account
	if len(args) != 1 {
		return false, account, nil
	}
	accountMatch := AccountRegex.FindStringSubmatch(args[0])
	if len(accountMatch) == 0 {
		return false, account, nil
	}
	var accountID string
	accountID = accountMatch[1]
	found, account := cp.Lookup(accountID)
	if !found {
		return false, account, fmt.Errorf("Account not found: %s", accountID)
	}
	return true, account, nil
}

func (cp Pack) findMatchAccount(args []string) (bool, Account, error) {
	var account Account
	tfs := TagFilterSet{}
	if err := tfs.LoadFromArgs(args); err != nil {
		return false, account, err
	}
	accounts := cp.Search(tfs)

	switch len(accounts) {
	case 0:
		return false, account, nil
	case 1:
		return true, accounts[0], nil
	default:
		mapOfAccounts := map[string]Account{}
		sliceOfNames := []string{}
		for _, a := range accounts {
			name := fmt.Sprintf("%s (%s)", a.Account, a.Tags)
			mapOfAccounts[name] = a
			sliceOfNames = append(sliceOfNames, name)
		}
		chosen, err := prompt.PickFromList("Desired account:", sliceOfNames, "")
		if err != nil {
			return false, account, err
		}
		return true, mapOfAccounts[chosen], nil
	}
}

// Lookup finds an account in a Pack based on its ID
func (cp Pack) Lookup(accountID string) (bool, Account) {
	for _, c := range cp {
		found, account := c.Lookup(accountID)
		if found {
			return true, account
		}
	}
	return false, Account{}
}

// Search finds accounts based on their tags
func (cp Pack) Search(tfs TagFilterSet) AccountSet {
	results := AccountSet{}
	for _, c := range cp {
		results = append(results, c.Search(tfs)...)
	}
	return results
}

// Load populates the Cartograms from disk
func (cp Pack) Load() error {
	config, err := configDir()
	if err != nil {
		return err
	}
	fileObjs, err := ioutil.ReadDir(config)
	if err != nil {
		return nil
	}
	var files []string
	for _, fileObj := range fileObjs {
		files = append(files, path.Join(config, fileObj.Name()))
	}
	err = cp.loadFromFiles(files)
	return err
}

func (cp Pack) loadFromFiles(filePaths []string) error {
	for _, filePath := range filePaths {
		name := path.Base(filePath)
		newC := Cartogram{}
		if err := newC.loadFromFile(filePath); err != nil {
			return err
		}
		fmt.Printf("Adding cartogram to pack: %s\n", name)
		cp[name] = newC
	}
	return nil
}

// Write dumps the Cartograms to disk
func (cp Pack) Write() error {
	config, err := configDir()
	if err != nil {
		return err
	}

	for name, c := range cp {
		filePath := path.Join(config, name)
		if err := c.writeToFile(filePath); err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>remove debug line<commit_after>package cartogram

import (
	"fmt"
	"io/ioutil"
	"path"
	"regexp"

	"github.com/akerl/voyager/prompt"
)

const (
	accountRegexString = `(\d+)(/(\w+))?`
)

// AccountRegex matches an account number with an optional role name
var AccountRegex = regexp.MustCompile(accountRegexString)

// Pack defines a group of Cartograms
type Pack map[string]Cartogram

// Find checks both Lookup and Search for an account
func (cp Pack) Find(args []string) (Account, error) {
	var targetAccount Account
	var err error
	var found bool

	found, targetAccount, err = cp.findDirectAccount(args)
	if err != nil || found {
		return targetAccount, err
	}

	found, targetAccount, err = cp.findMatchAccount(args)
	if err != nil || found {
		return targetAccount, err
	}

	return targetAccount, fmt.Errorf("Unable to locate an account with provided info")
}

func (cp Pack) findDirectAccount(args []string) (bool, Account, error) {
	var account Account
	if len(args) != 1 {
		return false, account, nil
	}
	accountMatch := AccountRegex.FindStringSubmatch(args[0])
	if len(accountMatch) == 0 {
		return false, account, nil
	}
	var accountID string
	accountID = accountMatch[1]
	found, account := cp.Lookup(accountID)
	if !found {
		return false, account, fmt.Errorf("Account not found: %s", accountID)
	}
	return true, account, nil
}

func (cp Pack) findMatchAccount(args []string) (bool, Account, error) {
	var account Account
	tfs := TagFilterSet{}
	if err := tfs.LoadFromArgs(args); err != nil {
		return false, account, err
	}
	accounts := cp.Search(tfs)

	switch len(accounts) {
	case 0:
		return false, account, nil
	case 1:
		return true, accounts[0], nil
	default:
		mapOfAccounts := map[string]Account{}
		sliceOfNames := []string{}
		for _, a := range accounts {
			name := fmt.Sprintf("%s (%s)", a.Account, a.Tags)
			mapOfAccounts[name] = a
			sliceOfNames = append(sliceOfNames, name)
		}
		chosen, err := prompt.PickFromList("Desired account:", sliceOfNames, "")
		if err != nil {
			return false, account, err
		}
		return true, mapOfAccounts[chosen], nil
	}
}

// Lookup finds an account in a Pack based on its ID
func (cp Pack) Lookup(accountID string) (bool, Account) {
	for _, c := range cp {
		found, account := c.Lookup(accountID)
		if found {
			return true, account
		}
	}
	return false, Account{}
}

// Search finds accounts based on their tags
func (cp Pack) Search(tfs TagFilterSet) AccountSet {
	results := AccountSet{}
	for _, c := range cp {
		results = append(results, c.Search(tfs)...)
	}
	return results
}

// Load populates the Cartograms from disk
func (cp Pack) Load() error {
	config, err := configDir()
	if err != nil {
		return err
	}
	fileObjs, err := ioutil.ReadDir(config)
	if err != nil {
		return nil
	}
	var files []string
	for _, fileObj := range fileObjs {
		files = append(files, path.Join(config, fileObj.Name()))
	}
	err = cp.loadFromFiles(files)
	return err
}

func (cp Pack) loadFromFiles(filePaths []string) error {
	for _, filePath := range filePaths {
		name := path.Base(filePath)
		newC := Cartogram{}
		if err := newC.loadFromFile(filePath); err != nil {
			return err
		}
		cp[name] = newC
	}
	return nil
}

// Write dumps the Cartograms to disk
func (cp Pack) Write() error {
	config, err := configDir()
	if err != nil {
		return err
	}

	for name, c := range cp {
		filePath := path.Join(config, name)
		if err := c.writeToFile(filePath); err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"strconv"
	"encoding/json"
	"github.com/hyperledger/fabric/core/chaincode/shim"
)

type Chaincode struct { }

type ChaincodeFunctions struct {
	stub shim.ChaincodeStubInterface
}

func main() {
	err := shim.Start(new(Chaincode))
	if err != nil {
		fmt.Printf("Error starting Simple chaincode: %s", err)
	}
}

// Init resets all the things
func (t Chaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	if len(args) > 0 {
		return nil, errors.New("Incorrect number of arguments. Expecting 0")
	}
	_ = stub.PutState("orderbook", []byte("{}"))
	return nil, nil
}

func (t Chaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Println("invoke is running " + function)
	fns := ChaincodeFunctions{stub}
	if function == "addOrder" {
		investor := args[0]
		ioi, err := strconv.ParseFloat(args[1], 64)
		if err != nil {
	        return nil, errors.New("Failed to parse " + args[1] + " as a float64")
    	}
		return fns.AddOrder(investor, ioi)
	} else if function == "allocateOrder" {
		investor := args[0]
		alloc, err := strconv.ParseFloat(args[1], 64)
		if err != nil {
	        return nil, errors.New("Failed to parse " + args[1] + " as a float64")
    	}
		return fns.AllocateOrder(investor, alloc)
	}
	fmt.Println("invoke did not find func: " + function)

	return nil, errors.New("Received unknown function invocation: " + function)
}

func (t Chaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Println("query is running " + function)
	fns := ChaincodeFunctions{stub}
	if function == "getOrder" {
		investor := args[0]
		return fns.GetOrder(investor)
	} else if function == "getOrderbook" {
		return fns.GetOrderbook()
	}
	fmt.Println("query did not find func: " + function)

	return nil, errors.New("Received unknown function query: " + function)
}

type Order struct {
	Investor	string 		`json:"investor"`
	Ioi 		float64 	`json:"ioi"`
	Alloc 		float64		`json:"alloc"`
}

// Public Functions

func (c ChaincodeFunctions) AddOrder(investor string, ioi float64) ([]byte, error)  {
	order := Order{Investor: investor, Ioi: ioi, Alloc: 0.0}
	c.saveOrderToBlockChain(order)
	return nil, nil
}

func (c ChaincodeFunctions) GetOrder(investor string) ([]byte, error) {
	orderJson := c.getOrderAsJsonFromBlockchain(investor)
	return []byte(orderJson), nil
}

func (c ChaincodeFunctions) GetOrderbook() ([]byte, error) {
	orderbookJson, _ := c.stub.GetState("orderbook")
	return []byte(orderbookJson), nil
}

func (c ChaincodeFunctions) AllocateOrder(investor string, alloc float64) ([]byte, error) {
	order := c.getOrderFromBlockChain(investor)
	order.Alloc = alloc
	c.saveOrderToBlockChain(order)
	return nil, nil
}

// Private Functions

func (c ChaincodeFunctions) getOrderAsJsonFromBlockchain(investor string) string {
	order := c.getOrderFromBlockChain(investor)
	orderJson, _ := json.Marshal(order)
	return string(orderJson)
}

func (c ChaincodeFunctions) getOrderFromBlockChain(investor string) Order {
	orderbook := c.getOrderbookFromBlockChain()
	return orderbook[investor]
}

func (c ChaincodeFunctions) saveOrderToBlockChain(order Order) {
	orderbook := c.getOrderbookFromBlockChain()
	orderbook[order.Investor] = order
	c.saveOrderbookToBlockChain(orderbook)
}

func (c ChaincodeFunctions) getOrderbookFromBlockChain() map[string]Order {
	orderbookJson, _ := c.stub.GetState("orderbook")
	var orderbook map[string]Order
	_ = json.Unmarshal(orderbookJson, &orderbook)
	return orderbook
}

func (c ChaincodeFunctions) saveOrderbookToBlockChain(orderbook map[string]Order) {
	orderbookJson, _ := json.Marshal(orderbook)
	_ = c.stub.PutState("orderbook", []byte(orderbookJson))
}<commit_msg>batch check-in<commit_after>package main

import (
	"errors"
	"fmt"
	"strconv"
	"encoding/json"
	"github.com/hyperledger/fabric/core/chaincode/shim"
)

type Chaincode struct { }

type ChaincodeFunctions struct {
	stub shim.ChaincodeStubInterface
}

// Adding a comment
func main() {
	err := shim.Start(new(Chaincode))
	if err != nil {
		fmt.Printf("Error starting Simple chaincode: %s", err)
	}
}

// Init resets all the things
func (t Chaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	if len(args) > 0 {
		return nil, errors.New("Incorrect number of arguments. Expecting 0")
	}
	_ = stub.PutState("orderbook", []byte("{}"))
	return nil, nil
}

func (t Chaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Println("invoke is running " + function)
	fns := ChaincodeFunctions{stub}
	if function == "addOrder" {
		investor := args[0]
		ioi, err := strconv.ParseFloat(args[1], 64)
		if err != nil {
	        return nil, errors.New("Failed to parse " + args[1] + " as a float64")
    	}
		return fns.AddOrder(investor, ioi)
	} else if function == "allocateOrder" {
		investor := args[0]
		alloc, err := strconv.ParseFloat(args[1], 64)
		if err != nil {
	        return nil, errors.New("Failed to parse " + args[1] + " as a float64")
    	}
		return fns.AllocateOrder(investor, alloc)
	}
	fmt.Println("invoke did not find func: " + function)

	return nil, errors.New("Received unknown function invocation: " + function)
}

func (t Chaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Println("query is running " + function)
	fns := ChaincodeFunctions{stub}
	if function == "getOrder" {
		investor := args[0]
		return fns.GetOrder(investor)
	} else if function == "getOrderbook" {
		return fns.GetOrderbook()
	}
	fmt.Println("query did not find func: " + function)

	return nil, errors.New("Received unknown function query: " + function)
}

type Order struct {
	Investor	string 		`json:"investor"`
	Ioi 		float64 	`json:"ioi"`
	Alloc 		float64		`json:"alloc"`
}

// Public Functions

func (c ChaincodeFunctions) AddOrder(investor string, ioi float64) ([]byte, error)  {
	order := Order{Investor: investor, Ioi: ioi, Alloc: 0.0}
	c.saveOrderToBlockChain(order)
	return nil, nil
}

func (c ChaincodeFunctions) GetOrder(investor string) ([]byte, error) {
	orderJson := c.getOrderAsJsonFromBlockchain(investor)
	return []byte(orderJson), nil
}

func (c ChaincodeFunctions) GetOrderbook() ([]byte, error) {
	orderbookJson, _ := c.stub.GetState("orderbook")
	return []byte(orderbookJson), nil
}

func (c ChaincodeFunctions) AllocateOrder(investor string, alloc float64) ([]byte, error) {
	order := c.getOrderFromBlockChain(investor)
	order.Alloc = alloc
	c.saveOrderToBlockChain(order)
	return nil, nil
}

// Private Functions

func (c ChaincodeFunctions) getOrderAsJsonFromBlockchain(investor string) string {
	order := c.getOrderFromBlockChain(investor)
	orderJson, _ := json.Marshal(order)
	return string(orderJson)
}

func (c ChaincodeFunctions) getOrderFromBlockChain(investor string) Order {
	orderbook := c.getOrderbookFromBlockChain()
	return orderbook[investor]
}

func (c ChaincodeFunctions) saveOrderToBlockChain(order Order) {
	orderbook := c.getOrderbookFromBlockChain()
	orderbook[order.Investor] = order
	c.saveOrderbookToBlockChain(orderbook)
}

func (c ChaincodeFunctions) getOrderbookFromBlockChain() map[string]Order {
	orderbookJson, _ := c.stub.GetState("orderbook")
	var orderbook map[string]Order
	_ = json.Unmarshal(orderbookJson, &orderbook)
	return orderbook
}

func (c ChaincodeFunctions) saveOrderbookToBlockChain(orderbook map[string]Order) {
	orderbookJson, _ := json.Marshal(orderbook)
	_ = c.stub.PutState("orderbook", []byte(orderbookJson))
}<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"strconv"
	"encoding/json"
	"github.com/hyperledger/fabric/core/chaincode/shim"
)

type SimpleChaincode struct { }

func main() {
	err := shim.Start(new(SimpleChaincode))
	if err != nil {
		fmt.Printf("Error starting Simple chaincode: %s", err)
	}
}

// Init resets all the things
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	if len(args) > 0 {
		return nil, errors.New("Incorrect number of arguments. Expecting 0")
	}
	_ = stub.PutState("orderbook", []byte("{}"))
	return nil, nil
}

// Invoke is our entry point to invoke a chaincode function
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Println("invoke is running " + function)

	// Handle different functions
	if function == "addOrder" {
		investor := args[0]
		ioi, err := strconv.ParseFloat(args[1], 64)
		if err != nil {
	        return nil, errors.New("Failed to parse " + args[1] + " as a float64")
    	}
		return t.addOrder(stub, investor, ioi)
	} else if function == "allocateOrder" {
		investor := args[0]
		alloc, err := strconv.ParseFloat(args[1], 64)
		if err != nil {
	        return nil, errors.New("Failed to parse " + args[1] + " as a float64")
    	}
		return t.allocateOrder(stub, investor, alloc)
	}
	fmt.Println("invoke did not find func: " + function)

	return nil, errors.New("Received unknown function invocation: " + function)
}

// Query is our entry point for queries
func (t *SimpleChaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Println("query is running " + function)

	// Handle different functions
	if function == "init" {
		t.Init(stub, function, args)
	} else if function == "getOrder" { //read a variable
		investor := args[0]
		return t.getOrder(stub, investor)
	}
	fmt.Println("query did not find func: " + function)

	return nil, errors.New("Received unknown function query: " + function)
}

type Order struct {
	Investor	string 		`json:"investor"`
	Ioi 		float64 	`json:"ioi"`
	Alloc 		float64		`json:"alloc"`
}

func (t *SimpleChaincode) addOrder(stub shim.ChaincodeStubInterface, investor string, ioi float64) ([]byte, error)  {
	order := Order{
		Investor: investor,
		Ioi: ioi,
		Alloc: 0.0,
	}
	orderbookJson, _ := stub.GetState("orderbook")
	var orderbook map[string]Order
	_ = json.Unmarshal(orderbookJson, &orderbook)
	orderbook[investor] = order
	orderbookJson, _ = json.Marshal(orderbookJson)
	_ = stub.PutState("orderbook", []byte(orderbookJson))
	return nil, nil
}

func (t *SimpleChaincode) getOrder(stub shim.ChaincodeStubInterface, investor string) ([]byte, error) {
	orderbookJson, _ := stub.GetState("orderbook")
	var orderbook map[string]Order
	_ = json.Unmarshal(orderbookJson, &orderbook)
	order := orderbook[investor]
	orderJson, _ := json.Marshal(order)
	return orderJson, nil
}

func (t *SimpleChaincode) allocateOrder(stub shim.ChaincodeStubInterface, investor string, alloc float64) ([]byte, error) {
	orderbookJson, _ := stub.GetState("orderbook")
	var orderbook map[string]Order
	_ = json.Unmarshal(orderbookJson, &orderbook)
	order := orderbook[investor]
	order.Alloc = alloc
	orderbook[investor] = order
	orderbookJson, _ = json.Marshal(orderbookJson)
	_ = stub.PutState("orderbook", []byte(orderbookJson))
	return nil, nil
}<commit_msg>'new'<commit_after>package main

import (
	"errors"
	"fmt"
	"strconv"
	"encoding/json"
	"github.com/hyperledger/fabric/core/chaincode/shim"
)

type SimpleChaincode struct { }

func main() {
	err := shim.Start(new(SimpleChaincode))
	if err != nil {
		fmt.Printf("Error starting Simple chaincode: %s", err)
	}
}

// Init resets all the things
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	if len(args) > 0 {
		return nil, errors.New("Incorrect number of arguments. Expecting 0")
	}
	_ = stub.PutState("orderbook", []byte("{}"))
	return nil, nil
}

// Invoke is our entry point to invoke a chaincode function
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Println("invoke is running " + function)

	// Handle different functions
	if function == "addOrder" {
		investor := args[0]
		ioi, err := strconv.ParseFloat(args[1], 64)
		if err != nil {
	        return nil, errors.New("Failed to parse " + args[1] + " as a float64")
    	}
		return t.addOrder(stub, investor, ioi)
	} else if function == "allocateOrder" {
		investor := args[0]
		alloc, err := strconv.ParseFloat(args[1], 64)
		if err != nil {
	        return nil, errors.New("Failed to parse " + args[1] + " as a float64")
    	}
		return t.allocateOrder(stub, investor, alloc)
	}
	fmt.Println("invoke did not find func: " + function)

	return nil, errors.New("Received unknown function invocation: " + function)
}

// Query is our entry point for queries
func (t *SimpleChaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Println("query is running " + function)

	// Handle different functions
	if function == "init" {
		t.Init(stub, function, args)
	} else if function == "getOrder" { //read a variable
		investor := args[0]
		return t.getOrder(stub, investor)
	}
	fmt.Println("query did not find func: " + function)

	return nil, errors.New("Received unknown function query: " + function)
}

type Order struct {
	Investor	string 		`json:"investor"`
	Ioi 		float64 	`json:"ioi"`
	Alloc 		float64		`json:"alloc"`
}

func (t *SimpleChaincode) addOrder(stub shim.ChaincodeStubInterface, investor string, ioi float64) ([]byte, error)  {
	order := Order{
		Investor: investor,
		Ioi: ioi,
		Alloc: 0.0,
	}
	orderbookJson, _ := stub.GetState("orderbook")
	var orderbook map[string]Order
	_ = json.Unmarshal(orderbookJson, &orderbook)
	orderbook[investor] = order
	orderbookJson, _ = json.Marshal(orderbook)
	_ = stub.PutState("orderbook", []byte(orderbookJson))
	return nil, nil
}

func (t *SimpleChaincode) getOrder(stub shim.ChaincodeStubInterface, investor string) ([]byte, error) {
	orderbookJson, _ := stub.GetState("orderbook")
	var orderbook map[string]Order
	_ = json.Unmarshal(orderbookJson, &orderbook)
	order := orderbook[investor]
	orderJson, _ := json.Marshal(order)
	return orderJson, nil
}

func (t *SimpleChaincode) allocateOrder(stub shim.ChaincodeStubInterface, investor string, alloc float64) ([]byte, error) {
	orderbookJson, _ := stub.GetState("orderbook")
	var orderbook map[string]Order
	_ = json.Unmarshal(orderbookJson, &orderbook)
	order := orderbook[investor]
	order.Alloc = alloc
	orderbook[investor] = order
	orderbookJson, _ = json.Marshal(orderbookJson)
	_ = stub.PutState("orderbook", []byte(orderbook))
	return nil, nil
}<|endoftext|>