<commit_before>package main

import (
	"encoding/binary"
	"io"
	"log"
	"net"
	"os"
	"path/filepath"
	"regexp"
	"syscall"
)

func handleConn(conn net.Conn) {
	var err error
	buf := make([]byte, 4096*1024) // 4MB
	openedFile := map[uintptr]*os.File{}
	reGetattr := regexp.MustCompile("^getattr(.*)")
	reReaddir := regexp.MustCompile("^readdir(.*)")
	reOpen := regexp.MustCompile("^open(.*)")
	reRead := regexp.MustCompile("^read(.*)")
	reWrite := regexp.MustCompile("^write(.*)")
	reTruncate := regexp.MustCompile("^truncate(.*)")
	reRelease := regexp.MustCompile("^release(.*)")
	reMkdir := regexp.MustCompile("^mkdir(.*)")
	reRmdir := regexp.MustCompile("^rmdir(.*)")
	reUnlink := regexp.MustCompile("^unlink(.*)")
	reCreate := regexp.MustCompile("^create(.*)")
	reUtime := regexp.MustCompile("^utime(.*)")
	rootdir := "/home/gle/code_repo/cloud_lib/tcfs-go/rootdir"
	for {
		_, err = io.ReadFull(conn, buf[:4])
		if err != nil {
			break
		}
		msglen := binary.BigEndian.Uint32(buf[:4])
		_, err = io.ReadFull(conn, buf[:msglen])
		// println(string(buf))
		if matched := reGetattr.FindStringSubmatch(string(buf[:msglen])); len(matched) > 1 {
			fixpath := rootdir + matched[1]
			var stat syscall.Stat_t
			err = syscall.Lstat(fixpath, &stat)
			if err != nil {
				binary.BigEndian.PutUint32(buf[0:4], 4)
				var ret int32 = -2
				binary.BigEndian.PutUint32(buf[4:8], uint32(ret))
				conn.Write(buf[:8])
				continue
			}
			binary.BigEndian.PutUint32(buf[0:4], 11*4)
			binary.BigEndian.PutUint32(buf[4:8], 0)
			binary.BigEndian.PutUint32(buf[8:12], uint32(stat.Dev))
			binary.BigEndian.PutUint32(buf[12:16], uint32(stat.Ino))
			binary.BigEndian.PutUint32(buf[16:20], stat.Mode)
			binary.BigEndian.PutUint32(buf[20:24], uint32(stat.Nlink))
			binary.BigEndian.PutUint32(buf[24:28], stat.Uid)
			binary.BigEndian.PutUint32(buf[28:32], stat.Gid)
			binary.BigEndian.PutUint32(buf[32:36], uint32(stat.Size))
			binary.BigEndian.PutUint32(buf[36:40], uint32(stat.Atim.Sec))
			binary.BigEndian.PutUint32(buf[40:44], uint32(stat.Mtim.Sec))
			binary.BigEndian.PutUint32(buf[44:48], uint32(stat.Ctim.Sec))
			conn.Write(buf[:48])

		} else if matched := reReaddir.FindStringSubmatch(string(buf[:msglen])); len(matched) > 1 {
			fixpath := rootdir + matched[1]
			fileList := []byte{}
			err = filepath.Walk(fixpath, func(path string, f os.FileInfo, err error) error {
				rp, _ := filepath.Rel(rootdir, path)
				fileList = append(fileList, rp...)
				fileList = append(fileList, 0)
				return nil
			})
			binary.BigEndian.PutUint32(buf[:4], uint32(len(fileList))+4)
			binary.BigEndian.PutUint32(buf[4:8], 0)
			copy(buf[8:], fileList)
			conn.Write(buf[:len(fileList)+8])
		} else if matched := reOpen.FindStringSubmatch(string(buf[:msglen])); len(matched) > 1 {
			flag := binary.BigEndian.Uint32([]byte(matched[1])[0:4])
			fixpath := rootdir + matched[1][4:]
			f, err := os.OpenFile(fixpath, int(flag), 0x666)
			if err != nil {
				binary.BigEndian.PutUint32(buf[0:4], 4)
				var ret int32 = -13
				binary.BigEndian.PutUint32(buf[4:8], uint32(ret))
				conn.Write(buf[:8])
				continue
			}
			fd := f.Fd()
			openedFile[fd] = f
			binary.BigEndian.PutUint32(buf[0:4], 8)
			binary.BigEndian.PutUint32(buf[4:8], 0)
			binary.BigEndian.PutUint32(buf[8:12], uint32(fd))
			conn.Write(buf[:12])
		} else if matched := reRead.FindStringSubmatch(string(buf[:msglen])); len(matched) > 1 {
			findex := binary.BigEndian.Uint32([]byte(matched[1])[:4])
			offset := binary.BigEndian.Uint32([]byte(matched[1])[4:8])
			size := binary.BigEndian.Uint32([]byte(matched[1])[8:12])
			// fixpath := rootdir + matched[1][12:]
			f := openedFile[uintptr(findex)]
			readbuf := make([]byte, size)
			readed, err := f.ReadAt(readbuf, int64(offset))
			if err != nil && err != io.EOF {
				binary.BigEndian.PutUint32(buf[0:4], 4)
				var ret int32 = -9
				binary.BigEndian.PutUint32(buf[4:8], uint32(ret))
				conn.Write(buf[:8])
				continue
			}
			if readed == 0 {
				binary.BigEndian.PutUint32(buf[0:4], 4)
				binary.BigEndian.PutUint32(buf[4:8], 0)
				conn.Write(buf[:8])
			} else if readed > 0 {
				binary.BigEndian.PutUint32(buf[0:4], 4+uint32(readed))
				binary.BigEndian.PutUint32(buf[4:8], uint32(readed))
				copy(buf[8:], readbuf)
				conn.Write(buf[:8+readed])
			}
		} else if matched := reWrite.FindStringSubmatch(string(buf[:msglen])); len(matched) > 1 {
		} else if matched := reTruncate.FindStringSubmatch(string(buf[:msglen])); len(matched) > 1 {
		} else if matched := reRelease.FindStringSubmatch(string(buf[:msglen])); len(matched) > 1 {
			findex := binary.BigEndian.Uint32([]byte(matched[1])[:4])
			f := openedFile[uintptr(findex)]
			err := f.Close()
			if err != nil {
				binary.BigEndian.PutUint32(buf[0:4], 4)
				ret := -9
				binary.BigEndian.PutUint32(buf[4:8], uint32(ret))
				conn.Write(buf[:8])
				continue
			}
			binary.BigEndian.PutUint32(buf[0:4], 4)
			binary.BigEndian.PutUint32(buf[4:8], 0)
			conn.Write(buf[:8])
		} else if matched := reMkdir.FindStringSubmatch(string(buf[:msglen])); len(matched) > 1 {
		} else if matched := reRmdir.FindStringSubmatch(string(buf[:msglen])); len(matched) > 1 {
		} else if matched := reUnlink.FindStringSubmatch(string(buf[:msglen])); len(matched) > 1 {
		} else if matched := reCreate.FindStringSubmatch(string(buf[:msglen])); len(matched) > 1 {
		} else if matched := reUtime.FindStringSubmatch(string(buf[:msglen])); len(matched) > 1 {
		} else {
		}
	}
}

func main() {
	l, e := net.Listen("tcp", ":9876")
	if e != nil {
		log.Fatal(e)
		return
	}
	for {
		conn, e := l.Accept()
		if e != nil {
			log.Fatal(e)
			continue
		}
		go handleConn(conn)
	}
}
<commit_msg>write<commit_after>package main

import (
	"encoding/binary"
	"flag"
	"io"
	"log"
	"net"
	"os"
	"path/filepath"
	"regexp"
	"syscall"
)

func handleConn(conn net.Conn) {
	var err error
	buf := make([]byte, 4096*1024) // 4MB
	openedFile := map[uintptr]*os.File{}
	reGetattr := regexp.MustCompile("^getattr(.*)")
	reReaddir := regexp.MustCompile("^readdir(.*)")
	reOpen := regexp.MustCompile("^open(.*)")
	reRead := regexp.MustCompile("^read(.*)")
	reWrite := regexp.MustCompile("^write(.*)")
	reTruncate := regexp.MustCompile("^truncate(.*)")
	reRelease := regexp.MustCompile("^release(.*)")
	reMkdir := regexp.MustCompile("^mkdir(.*)")
	reRmdir := regexp.MustCompile("^rmdir(.*)")
	reUnlink := regexp.MustCompile("^unlink(.*)")
	reCreate := regexp.MustCompile("^create(.*)")
	reUtime := regexp.MustCompile("^utime(.*)")
	rootdir := "/home/gle/code_repo/cloud_lib/tcfs-go/rootdir"
	for {
		_, err = io.ReadFull(conn, buf[:4])
		if err != nil {
			break
		}
		msglen := binary.BigEndian.Uint32(buf[:4])
		_, err = io.ReadFull(conn, buf[:msglen])
		// println(string(buf))
		if matched := reGetattr.FindStringSubmatch(string(buf[:msglen])); len(matched) > 1 {
			fixpath := rootdir + matched[1]
			var stat syscall.Stat_t
			err = syscall.Lstat(fixpath, &stat)
			if err != nil {
				binary.BigEndian.PutUint32(buf[0:4], 4)
				var ret int32 = -2
				binary.BigEndian.PutUint32(buf[4:8], uint32(ret))
				conn.Write(buf[:8])
				continue
			}
			binary.BigEndian.PutUint32(buf[0:4], 11*4)
			binary.BigEndian.PutUint32(buf[4:8], 0)
			binary.BigEndian.PutUint32(buf[8:12], uint32(stat.Dev))
			binary.BigEndian.PutUint32(buf[12:16], uint32(stat.Ino))
			binary.BigEndian.PutUint32(buf[16:20], stat.Mode)
			binary.BigEndian.PutUint32(buf[20:24], uint32(stat.Nlink))
			binary.BigEndian.PutUint32(buf[24:28], stat.Uid)
			binary.BigEndian.PutUint32(buf[28:32], stat.Gid)
			binary.BigEndian.PutUint32(buf[32:36], uint32(stat.Size))
			binary.BigEndian.PutUint32(buf[36:40], uint32(stat.Atim.Sec))
			binary.BigEndian.PutUint32(buf[40:44], uint32(stat.Mtim.Sec))
			binary.BigEndian.PutUint32(buf[44:48], uint32(stat.Ctim.Sec))
			conn.Write(buf[:48])

		} else if matched := reReaddir.FindStringSubmatch(string(buf[:msglen])); len(matched) > 1 {
			fixpath := rootdir + matched[1]
			fileList := []byte{}
			err = filepath.Walk(fixpath, func(path string, f os.FileInfo, err error) error {
				rp, _ := filepath.Rel(rootdir, path)
				fileList = append(fileList, rp...)
				fileList = append(fileList, 0)
				return nil
			})
			binary.BigEndian.PutUint32(buf[:4], uint32(len(fileList))+4)
			binary.BigEndian.PutUint32(buf[4:8], 0)
			copy(buf[8:], fileList)
			conn.Write(buf[:len(fileList)+8])
		} else if matched := reOpen.FindStringSubmatch(string(buf[:msglen])); len(matched) > 1 {
			flag := binary.BigEndian.Uint32([]byte(matched[1])[0:4])
			fixpath := rootdir + matched[1][4:]
			f, err := os.OpenFile(fixpath, int(flag), 0x666)
			if err != nil {
				binary.BigEndian.PutUint32(buf[0:4], 4)
				var ret int32 = -13
				binary.BigEndian.PutUint32(buf[4:8], uint32(ret))
				conn.Write(buf[:8])
				continue
			}
			fd := f.Fd()
			openedFile[fd] = f
			binary.BigEndian.PutUint32(buf[0:4], 8)
			binary.BigEndian.PutUint32(buf[4:8], 0)
			binary.BigEndian.PutUint32(buf[8:12], uint32(fd))
			conn.Write(buf[:12])
		} else if matched := reRead.FindStringSubmatch(string(buf[:msglen])); len(matched) > 1 {
			findex := binary.BigEndian.Uint32([]byte(matched[1])[:4])
			offset := binary.BigEndian.Uint32([]byte(matched[1])[4:8])
			size := binary.BigEndian.Uint32([]byte(matched[1])[8:12])
			// fixpath := rootdir + matched[1][12:]
			f := openedFile[uintptr(findex)]
			readbuf := make([]byte, size)
			readed, err := f.ReadAt(readbuf, int64(offset))
			if err != nil && err != io.EOF {
				binary.BigEndian.PutUint32(buf[0:4], 4)
				var ret int32 = -9
				binary.BigEndian.PutUint32(buf[4:8], uint32(ret))
				conn.Write(buf[:8])
				continue
			}
			if readed == 0 {
				binary.BigEndian.PutUint32(buf[0:4], 4)
				binary.BigEndian.PutUint32(buf[4:8], 0)
				conn.Write(buf[:8])
			} else if readed > 0 {
				binary.BigEndian.PutUint32(buf[0:4], 4+uint32(readed))
				binary.BigEndian.PutUint32(buf[4:8], uint32(readed))
				copy(buf[8:], readbuf)
				conn.Write(buf[:8+readed])
			}
		} else if matched := reWrite.FindStringSubmatch(string(buf[:msglen])); len(matched) > 1 {
			findex := binary.BigEndian.Uint32([]byte(matched[1])[:4])
			offset := binary.BigEndian.Uint32([]byte(matched[1])[4:8])
			size := binary.BigEndian.Uint32([]byte(matched[1])[8:12])
			wbuf := []byte(matched[1])[12 : 12+size]
			f := openedFile[uintptr(findex)]
			writed, _ := f.WriteAt(wbuf, int64(offset))
			binary.BigEndian.PutUint32(buf[0:4], 4)
			binary.BigEndian.PutUint32(buf[4:8], uint32(writed))
			conn.Write(buf[:8])
		} else if matched := reTruncate.FindStringSubmatch(string(buf[:msglen])); len(matched) > 1 {
		} else if matched := reRelease.FindStringSubmatch(string(buf[:msglen])); len(matched) > 1 {
			findex := binary.BigEndian.Uint32([]byte(matched[1])[:4])
			f := openedFile[uintptr(findex)]
			err := f.Close()
			if err != nil {
				binary.BigEndian.PutUint32(buf[0:4], 4)
				ret := -9
				binary.BigEndian.PutUint32(buf[4:8], uint32(ret))
				conn.Write(buf[:8])
				continue
			}
			binary.BigEndian.PutUint32(buf[0:4], 4)
			binary.BigEndian.PutUint32(buf[4:8], 0)
			conn.Write(buf[:8])
		} else if matched := reMkdir.FindStringSubmatch(string(buf[:msglen])); len(matched) > 1 {
		} else if matched := reRmdir.FindStringSubmatch(string(buf[:msglen])); len(matched) > 1 {
		} else if matched := reUnlink.FindStringSubmatch(string(buf[:msglen])); len(matched) > 1 {
		} else if matched := reCreate.FindStringSubmatch(string(buf[:msglen])); len(matched) > 1 {
		} else if matched := reUtime.FindStringSubmatch(string(buf[:msglen])); len(matched) > 1 {
		} else {
		}
	}
}

var (
	port = flag.String("port", ":9876", "port to listen to")
)

func main() {
	flag.Parse()
	l, e := net.Listen("tcp", *port)
	if e != nil {
		log.Fatal(e)
		return
	}
	for {
		conn, e := l.Accept()
		if e != nil {
			log.Fatal(e)
			continue
		}
		go handleConn(conn)
	}
}
<|endoftext|>


<commit_before>package net_test

import (
	"bytes"
	"cred-alert/net"
	"cred-alert/net/netfakes"
	"errors"
	"io/ioutil"
	"net/http"
	"strings"
	"time"

	"code.cloudfoundry.org/clock/fakeclock"

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

var _ = Describe("RetryingClient", func() {
	var (
		client     net.Client
		fakeClient *netfakes.FakeClient
		clock      *fakeclock.FakeClock
	)

	BeforeEach(func() {
		fakeClient = &netfakes.FakeClient{}
		clock = fakeclock.NewFakeClock(time.Now())
		client = net.NewRetryingClient(fakeClient, clock)
	})

	It("proxies requests to the underlying client", func() {
		body := strings.NewReader("My Special Body")
		request, err := http.NewRequest("POST", "http://example.com", body)
		Expect(err).NotTo(HaveOccurred())
		request.Header.Add("My-Special", "Header")

		successfulResponse := &http.Response{}
		fakeClient.DoReturns(successfulResponse, nil)

		resp, err := client.Do(request)
		Expect(err).NotTo(HaveOccurred())
		Expect(resp).To(BeIdenticalTo(successfulResponse))

		Expect(fakeClient.DoCallCount()).To(Equal(1))

		actualRequest := fakeClient.DoArgsForCall(0)

		Expect(actualRequest.URL).To(Equal(request.URL))
		Expect(actualRequest.Header).To(Equal(request.Header))
		Expect(actualRequest.Method).To(Equal(request.Method))

		buf := bytes.NewBuffer([]byte{})
		buf.ReadFrom(actualRequest.Body)
		Expect(buf.Bytes()).To(Equal([]byte("My Special Body")))
	})

	Context("when the request fails three times, then succeeds", func() {
		var (
			successfulResponse *http.Response
			startTimes         []time.Time
		)

		BeforeEach(func() {
			successfulResponse = &http.Response{}
			fakeClient.DoStub = func(req *http.Request) (*http.Response, error) {
				startTimes = append(startTimes, clock.Now())

				if fakeClient.DoCallCount() < 4 {
					return nil, errors.New("My Special Error")
				}

				return successfulResponse, nil
			}
		})

		It("retries the request three times", func() {
			request, err := http.NewRequest("GET", "http://example.com", bytes.NewBufferString("body"))
			Expect(err).NotTo(HaveOccurred())

			go func() {
				GinkgoRecover()
				actualResponse, err := client.Do(request)
				Expect(err).ToNot(HaveOccurred())
				Expect(actualResponse).To(BeIdenticalTo(successfulResponse))
			}()

			// 1
			Eventually(fakeClient.DoCallCount).Should(Equal(1))
			actualRequest := fakeClient.DoArgsForCall(0)
			Expect(actualRequest.URL).To(Equal(request.URL))
			Expect(actualRequest.Header).To(Equal(request.Header))
			Expect(actualRequest.ContentLength).To(BeNumerically("==", 4))

			actualBody, err := ioutil.ReadAll(actualRequest.Body)
			Expect(err).ToNot(HaveOccurred())
			Expect(actualBody).To(Equal([]byte("body")))

			clock.Increment(750 * time.Millisecond)

			// 2
			Eventually(fakeClient.DoCallCount).Should(Equal(2))
			actualRequest = fakeClient.DoArgsForCall(1)
			Expect(actualRequest.URL).To(Equal(request.URL))
			Expect(actualRequest.Header).To(Equal(request.Header))
			Expect(actualRequest.ContentLength).To(BeNumerically("==", 4))

			actualBody, err = ioutil.ReadAll(actualRequest.Body)
			Expect(err).ToNot(HaveOccurred())
			Expect(actualBody).To(Equal([]byte("body")))

			clock.Increment(1125 * time.Millisecond)

			// 3
			Eventually(fakeClient.DoCallCount).Should(Equal(3))
			actualRequest = fakeClient.DoArgsForCall(2)
			Expect(actualRequest.URL).To(Equal(request.URL))
			Expect(actualRequest.Header).To(Equal(request.Header))
			Expect(actualRequest.ContentLength).To(BeNumerically("==", 4))

			actualBody, err = ioutil.ReadAll(actualRequest.Body)
			Expect(err).ToNot(HaveOccurred())
			Expect(actualBody).To(Equal([]byte("body")))

			clock.Increment(1687 * time.Millisecond)

			// 4
			Eventually(fakeClient.DoCallCount).Should(Equal(4))
			actualRequest = fakeClient.DoArgsForCall(3)
			Expect(actualRequest.URL).To(Equal(request.URL))
			Expect(actualRequest.Header).To(Equal(request.Header))
			Expect(actualRequest.ContentLength).To(BeNumerically("==", 4))

			actualBody, err = ioutil.ReadAll(actualRequest.Body)
			Expect(err).ToNot(HaveOccurred())
			Expect(actualBody).To(Equal([]byte("body")))
		})

		It("retries the request three times with random sleep intervals)", func() {
			request, err := http.NewRequest("GET", "http://example.com", bytes.NewBufferString("body"))
			Expect(err).NotTo(HaveOccurred())

			go func() {
				GinkgoRecover()
				_, err := client.Do(request)
				Expect(err).NotTo(HaveOccurred())
			}()

			Eventually(fakeClient.DoCallCount).Should(Equal(1))
			clock.Increment(750 * time.Millisecond)

			Eventually(fakeClient.DoCallCount).Should(Equal(2))
			clock.Increment(1125 * time.Millisecond)

			Eventually(fakeClient.DoCallCount).Should(Equal(3))
			clock.Increment(1687 * time.Millisecond)

			Eventually(fakeClient.DoCallCount).Should(Equal(4))
			Eventually(startTimes).Should(HaveLen(4))

			Expect(startTimes[1].Sub(startTimes[0])).Should(BeNumerically(">=", 250*time.Millisecond))
			Expect(startTimes[1].Sub(startTimes[0])).Should(BeNumerically("<=", 750*time.Millisecond))

			Expect(startTimes[2].Sub(startTimes[1])).Should(BeNumerically(">=", 375*time.Millisecond))
			Expect(startTimes[2].Sub(startTimes[1])).Should(BeNumerically("<=", 1125*time.Millisecond))

			Expect(startTimes[3].Sub(startTimes[2])).Should(BeNumerically(">=", 562*time.Millisecond))
			Expect(startTimes[3].Sub(startTimes[2])).Should(BeNumerically("<=", 1687*time.Millisecond))
		})

	})

	Context("when the request continually fails", func() {
		BeforeEach(func() {
			fakeClient.DoReturns(nil, errors.New("disaster"))
		})

		It("returns an error", func() {
			request, err := http.NewRequest("GET", "http://example.com", bytes.NewBufferString("body"))
			Expect(err).NotTo(HaveOccurred())

			go func() {
				GinkgoRecover()
				_, err := client.Do(request)
				Expect(err).To(MatchError("request failed after retry"))
			}()

			Eventually(fakeClient.DoCallCount).Should(Equal(1))
			clock.Increment(750 * time.Millisecond)

			Eventually(fakeClient.DoCallCount).Should(Equal(2))
			clock.Increment(1125 * time.Millisecond)

			Eventually(fakeClient.DoCallCount).Should(Equal(3))
			clock.Increment(1687 * time.Millisecond)

			Eventually(fakeClient.DoCallCount).Should(Equal(4))
		})
	})
})
<commit_msg>Wait for watchers before incrementing clock<commit_after>package net_test

import (
	"bytes"
	"cred-alert/net"
	"cred-alert/net/netfakes"
	"errors"
	"io/ioutil"
	"net/http"
	"strings"
	"time"

	"code.cloudfoundry.org/clock/fakeclock"

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

var _ = Describe("RetryingClient", func() {
	var (
		client     net.Client
		fakeClient *netfakes.FakeClient
		clock      *fakeclock.FakeClock
	)

	BeforeEach(func() {
		fakeClient = &netfakes.FakeClient{}
		clock = fakeclock.NewFakeClock(time.Now())
		client = net.NewRetryingClient(fakeClient, clock)
	})

	It("proxies requests to the underlying client", func() {
		body := strings.NewReader("My Special Body")
		request, err := http.NewRequest("POST", "http://example.com", body)
		Expect(err).NotTo(HaveOccurred())
		request.Header.Add("My-Special", "Header")

		successfulResponse := &http.Response{}
		fakeClient.DoReturns(successfulResponse, nil)

		resp, err := client.Do(request)
		Expect(err).NotTo(HaveOccurred())
		Expect(resp).To(BeIdenticalTo(successfulResponse))

		Expect(fakeClient.DoCallCount()).To(Equal(1))

		actualRequest := fakeClient.DoArgsForCall(0)

		Expect(actualRequest.URL).To(Equal(request.URL))
		Expect(actualRequest.Header).To(Equal(request.Header))
		Expect(actualRequest.Method).To(Equal(request.Method))

		buf := bytes.NewBuffer([]byte{})
		buf.ReadFrom(actualRequest.Body)
		Expect(buf.Bytes()).To(Equal([]byte("My Special Body")))
	})

	Context("when the request fails three times, then succeeds", func() {
		var (
			successfulResponse *http.Response
			startTimes         []time.Time
		)

		BeforeEach(func() {
			successfulResponse = &http.Response{}
			fakeClient.DoStub = func(req *http.Request) (*http.Response, error) {
				startTimes = append(startTimes, clock.Now())

				if fakeClient.DoCallCount() < 4 {
					return nil, errors.New("My Special Error")
				}

				return successfulResponse, nil
			}
		})

		It("retries the request three times", func() {
			request, err := http.NewRequest("GET", "http://example.com", bytes.NewBufferString("body"))
			Expect(err).NotTo(HaveOccurred())

			go func() {
				GinkgoRecover()
				actualResponse, err := client.Do(request)
				Expect(err).ToNot(HaveOccurred())
				Expect(actualResponse).To(BeIdenticalTo(successfulResponse))
			}()

			// 1
			Eventually(fakeClient.DoCallCount).Should(Equal(1))
			actualRequest := fakeClient.DoArgsForCall(0)
			Expect(actualRequest.URL).To(Equal(request.URL))
			Expect(actualRequest.Header).To(Equal(request.Header))
			Expect(actualRequest.ContentLength).To(BeNumerically("==", 4))

			actualBody, err := ioutil.ReadAll(actualRequest.Body)
			Expect(err).ToNot(HaveOccurred())
			Expect(actualBody).To(Equal([]byte("body")))

			clock.WaitForWatcherAndIncrement(750 * time.Millisecond)

			// 2
			Eventually(fakeClient.DoCallCount).Should(Equal(2))
			actualRequest = fakeClient.DoArgsForCall(1)
			Expect(actualRequest.URL).To(Equal(request.URL))
			Expect(actualRequest.Header).To(Equal(request.Header))
			Expect(actualRequest.ContentLength).To(BeNumerically("==", 4))

			actualBody, err = ioutil.ReadAll(actualRequest.Body)
			Expect(err).ToNot(HaveOccurred())
			Expect(actualBody).To(Equal([]byte("body")))

			clock.WaitForWatcherAndIncrement(1125 * time.Millisecond)

			// 3
			Eventually(fakeClient.DoCallCount).Should(Equal(3))
			actualRequest = fakeClient.DoArgsForCall(2)
			Expect(actualRequest.URL).To(Equal(request.URL))
			Expect(actualRequest.Header).To(Equal(request.Header))
			Expect(actualRequest.ContentLength).To(BeNumerically("==", 4))

			actualBody, err = ioutil.ReadAll(actualRequest.Body)
			Expect(err).ToNot(HaveOccurred())
			Expect(actualBody).To(Equal([]byte("body")))

			clock.WaitForWatcherAndIncrement(1687 * time.Millisecond)

			// 4
			Eventually(fakeClient.DoCallCount).Should(Equal(4))
			actualRequest = fakeClient.DoArgsForCall(3)
			Expect(actualRequest.URL).To(Equal(request.URL))
			Expect(actualRequest.Header).To(Equal(request.Header))
			Expect(actualRequest.ContentLength).To(BeNumerically("==", 4))

			actualBody, err = ioutil.ReadAll(actualRequest.Body)
			Expect(err).ToNot(HaveOccurred())
			Expect(actualBody).To(Equal([]byte("body")))
		})

		It("retries the request three times with random sleep intervals)", func() {
			request, err := http.NewRequest("GET", "http://example.com", bytes.NewBufferString("body"))
			Expect(err).NotTo(HaveOccurred())

			go func() {
				GinkgoRecover()
				_, err := client.Do(request)
				Expect(err).NotTo(HaveOccurred())
			}()

			Eventually(fakeClient.DoCallCount).Should(Equal(1))
			clock.WaitForWatcherAndIncrement(750 * time.Millisecond)

			Eventually(fakeClient.DoCallCount).Should(Equal(2))
			clock.WaitForWatcherAndIncrement(1125 * time.Millisecond)

			Eventually(fakeClient.DoCallCount).Should(Equal(3))
			clock.WaitForWatcherAndIncrement(1687 * time.Millisecond)

			Eventually(fakeClient.DoCallCount).Should(Equal(4))
			Eventually(startTimes).Should(HaveLen(4))

			Expect(startTimes[1].Sub(startTimes[0])).Should(BeNumerically(">=", 250*time.Millisecond))
			Expect(startTimes[1].Sub(startTimes[0])).Should(BeNumerically("<=", 750*time.Millisecond))

			Expect(startTimes[2].Sub(startTimes[1])).Should(BeNumerically(">=", 375*time.Millisecond))
			Expect(startTimes[2].Sub(startTimes[1])).Should(BeNumerically("<=", 1125*time.Millisecond))

			Expect(startTimes[3].Sub(startTimes[2])).Should(BeNumerically(">=", 562*time.Millisecond))
			Expect(startTimes[3].Sub(startTimes[2])).Should(BeNumerically("<=", 1687*time.Millisecond))
		})

	})

	Context("when the request continually fails", func() {
		BeforeEach(func() {
			fakeClient.DoReturns(nil, errors.New("disaster"))
		})

		It("returns an error", func() {
			request, err := http.NewRequest("GET", "http://example.com", bytes.NewBufferString("body"))
			Expect(err).NotTo(HaveOccurred())

			go func() {
				GinkgoRecover()
				_, err := client.Do(request)
				Expect(err).To(MatchError("request failed after retry"))
			}()

			Eventually(fakeClient.DoCallCount).Should(Equal(1))
			clock.WaitForWatcherAndIncrement(750 * time.Millisecond)

			Eventually(fakeClient.DoCallCount).Should(Equal(2))
			clock.WaitForWatcherAndIncrement(1125 * time.Millisecond)

			Eventually(fakeClient.DoCallCount).Should(Equal(3))
			clock.WaitForWatcherAndIncrement(1687 * time.Millisecond)

			Eventually(fakeClient.DoCallCount).Should(Equal(4))
		})
	})
})
<|endoftext|>


<commit_before>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package apiaddressupdater_test

import (
	stdtesting "testing"
	"time"

	gc "launchpad.net/gocheck"

	"launchpad.net/juju-core/instance"
	jujutesting "launchpad.net/juju-core/juju/testing"
	"launchpad.net/juju-core/state"
	coretesting "launchpad.net/juju-core/testing"
	"launchpad.net/juju-core/worker/apiaddressupdater"
)

func TestPackage(t *stdtesting.T) {
	coretesting.MgoTestPackage(t)
}

type APIAddressUpdaterSuite struct {
	jujutesting.JujuConnSuite
}

var _ = gc.Suite(&APIAddressUpdaterSuite{})

type apiAddressSetter struct {
	servers chan [][]instance.HostPort
	err     error
}

func (s *apiAddressSetter) SetAPIHostPorts(servers [][]instance.HostPort) error {
	s.servers <- servers
	return s.err
}

func (s *APIAddressUpdaterSuite) TestStartStop(c *gc.C) {
	st, _ := s.OpenAPIAsNewMachine(c, state.JobHostUnits)
	worker := apiaddressupdater.NewAPIAddressUpdater(st.Machiner(), &apiAddressSetter{})
	worker.Kill()
	c.Assert(worker.Wait(), gc.IsNil)
}

func (s *APIAddressUpdaterSuite) TestAddressInitialUpdate(c *gc.C) {
	updatedServers := [][]instance.HostPort{instance.AddressesWithPort(
		instance.NewAddresses("localhost", "127.0.0.1"),
		1234,
	)}
	err := s.State.SetAPIHostPorts(updatedServers)
	c.Assert(err, gc.IsNil)

	setter := &apiAddressSetter{servers: make(chan [][]instance.HostPort, 1)}
	st, _ := s.OpenAPIAsNewMachine(c, state.JobHostUnits)
	worker := apiaddressupdater.NewAPIAddressUpdater(st.Machiner(), setter)
	defer func() { c.Assert(worker.Wait(), gc.IsNil) }()
	defer worker.Kill()

	// SetAPIHostPorts should be called with the initial value.
	select {
	case <-time.After(coretesting.LongWait):
		c.Fatalf("timed out waiting for SetAPIHostPorts to be called")
	case servers := <-setter.servers:
		c.Assert(servers, gc.DeepEquals, updatedServers)
	}
}

func (s *APIAddressUpdaterSuite) TestAddressChange(c *gc.C) {
	setter := &apiAddressSetter{servers: make(chan [][]instance.HostPort, 1)}
	st, _ := s.OpenAPIAsNewMachine(c, state.JobHostUnits)
	worker := apiaddressupdater.NewAPIAddressUpdater(st.Machiner(), setter)
	defer func() { c.Assert(worker.Wait(), gc.IsNil) }()
	defer worker.Kill()

	updatedServers := [][]instance.HostPort{instance.AddressesWithPort(
		instance.NewAddresses("localhost", "127.0.0.1"),
		1234,
	)}
	err := s.State.SetAPIHostPorts(updatedServers)
	c.Assert(err, gc.IsNil)

	// SetAPIHostPorts should be called with the initial value (empty),
	// and then the updated value.
	n := 0
	select {
	case <-time.After(coretesting.LongWait):
		c.Fatalf("timed out waiting for SetAPIHostPorts to be called")
	case servers := <-setter.servers:
		if n == 0 {
			c.Assert(servers, gc.HasLen, 0)
		} else {
			c.Assert(servers, gc.DeepEquals, updatedServers)
		}
		n++
	}
}
<commit_msg>[r=rogpeppe] worker/apiaddressupdater: fix test<commit_after>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package apiaddressupdater_test

import (
	stdtesting "testing"
	"time"

	gc "launchpad.net/gocheck"

	"launchpad.net/juju-core/instance"
	jujutesting "launchpad.net/juju-core/juju/testing"
	"launchpad.net/juju-core/state"
	coretesting "launchpad.net/juju-core/testing"
	"launchpad.net/juju-core/worker/apiaddressupdater"
)

func TestPackage(t *stdtesting.T) {
	coretesting.MgoTestPackage(t)
}

type APIAddressUpdaterSuite struct {
	jujutesting.JujuConnSuite
}

var _ = gc.Suite(&APIAddressUpdaterSuite{})

type apiAddressSetter struct {
	servers chan [][]instance.HostPort
	err     error
}

func (s *apiAddressSetter) SetAPIHostPorts(servers [][]instance.HostPort) error {
	s.servers <- servers
	return s.err
}

func (s *APIAddressUpdaterSuite) TestStartStop(c *gc.C) {
	st, _ := s.OpenAPIAsNewMachine(c, state.JobHostUnits)
	worker := apiaddressupdater.NewAPIAddressUpdater(st.Machiner(), &apiAddressSetter{})
	worker.Kill()
	c.Assert(worker.Wait(), gc.IsNil)
}

func (s *APIAddressUpdaterSuite) TestAddressInitialUpdate(c *gc.C) {
	updatedServers := [][]instance.HostPort{instance.AddressesWithPort(
		instance.NewAddresses("localhost", "127.0.0.1"),
		1234,
	)}
	err := s.State.SetAPIHostPorts(updatedServers)
	c.Assert(err, gc.IsNil)

	setter := &apiAddressSetter{servers: make(chan [][]instance.HostPort, 1)}
	st, _ := s.OpenAPIAsNewMachine(c, state.JobHostUnits)
	worker := apiaddressupdater.NewAPIAddressUpdater(st.Machiner(), setter)
	defer func() { c.Assert(worker.Wait(), gc.IsNil) }()
	defer worker.Kill()

	// SetAPIHostPorts should be called with the initial value.
	select {
	case <-time.After(coretesting.LongWait):
		c.Fatalf("timed out waiting for SetAPIHostPorts to be called")
	case servers := <-setter.servers:
		c.Assert(servers, gc.DeepEquals, updatedServers)
	}
}

func (s *APIAddressUpdaterSuite) TestAddressChange(c *gc.C) {
	setter := &apiAddressSetter{servers: make(chan [][]instance.HostPort, 1)}
	st, _ := s.OpenAPIAsNewMachine(c, state.JobHostUnits)
	worker := apiaddressupdater.NewAPIAddressUpdater(st.Machiner(), setter)
	defer func() { c.Assert(worker.Wait(), gc.IsNil) }()
	defer worker.Kill()
	s.BackingState.StartSync()
	updatedServers := [][]instance.HostPort{instance.AddressesWithPort(
		instance.NewAddresses("localhost", "127.0.0.1"),
		1234,
	)}
	// SetAPIHostPorts should be called with the initial value (empty),
	// and then the updated value.
	select {
	case <-time.After(coretesting.LongWait):
		c.Fatalf("timed out waiting for SetAPIHostPorts to be called first")
	case servers := <-setter.servers:
		c.Assert(servers, gc.HasLen, 0)
	}
	err := s.State.SetAPIHostPorts(updatedServers)
	c.Assert(err, gc.IsNil)
	s.BackingState.StartSync()
	select {
	case <-time.After(coretesting.LongWait):
		c.Fatalf("timed out waiting for SetAPIHostPorts to be called second")
	case servers := <-setter.servers:
		c.Assert(servers, gc.DeepEquals, updatedServers)
	}
}
<|endoftext|>


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

// Unix cryptographically secure pseudorandom number
// generator.

package rand

import (
	"crypto/aes"
	"io"
	"os"
	"sync"
	"time"
)

// Easy implementation: read from /dev/urandom.
// This is sufficient on Linux, OS X, and FreeBSD.

func init() { Reader = &devReader{name: "/dev/urandom"} }

// A devReader satisfies reads by reading the file named name.
type devReader struct {
	name string
	f    *os.File
	mu   sync.Mutex
}

func (r *devReader) Read(b []byte) (n int, err os.Error) {
	r.mu.Lock()
	if r.f == nil {
		f, err := os.Open(r.name, os.O_RDONLY, 0)
		if f == nil {
			r.mu.Unlock()
			return 0, err
		}
		r.f = f
	}
	r.mu.Unlock()
	return r.f.Read(b)
}

// Alternate pseudo-random implementation for use on
// systems without a reliable /dev/urandom.  So far we
// haven't needed it.

// newReader returns a new pseudorandom generator that
// seeds itself by reading from entropy.  If entropy == nil,
// the generator seeds itself by reading from the system's
// random number generator, typically /dev/random.
// The Read method on the returned reader always returns
// the full amount asked for, or else it returns an error.
//
// The generator uses the X9.31 algorithm with AES-128,
// reseeding after every 1 MB of generated data.
func newReader(entropy io.Reader) io.Reader {
	if entropy == nil {
		entropy = &devReader{name: "/dev/random"}
	}
	return &reader{entropy: entropy}
}

type reader struct {
	mu                   sync.Mutex
	budget               int // number of bytes that can be generated
	cipher               *aes.Cipher
	entropy              io.Reader
	time, seed, dst, key [aes.BlockSize]byte
}

func (r *reader) Read(b []byte) (n int, err os.Error) {
	r.mu.Lock()
	defer r.mu.Unlock()
	n = len(b)

	for len(b) > 0 {
		if r.budget == 0 {
			_, err := io.ReadFull(r.entropy, r.seed[0:])
			if err != nil {
				return n - len(b), err
			}
			_, err = io.ReadFull(r.entropy, r.key[0:])
			if err != nil {
				return n - len(b), err
			}
			r.cipher, err = aes.NewCipher(r.key[0:])
			if err != nil {
				return n - len(b), err
			}
			r.budget = 1 << 20 // reseed after generating 1MB
		}
		r.budget -= aes.BlockSize

		// ANSI X9.31 (== X9.17) algorithm, but using AES in place of 3DES.
		//
		// single block:
		// t = encrypt(time)
		// dst = encrypt(t^seed)
		// seed = encrypt(t^dst)
		ns := time.Nanoseconds()
		r.time[0] = byte(ns >> 56)
		r.time[1] = byte(ns >> 48)
		r.time[2] = byte(ns >> 40)
		r.time[3] = byte(ns >> 32)
		r.time[4] = byte(ns >> 24)
		r.time[5] = byte(ns >> 16)
		r.time[6] = byte(ns >> 8)
		r.time[7] = byte(ns)
		r.cipher.Encrypt(r.time[0:], r.time[0:])
		for i := 0; i < aes.BlockSize; i++ {
			r.dst[i] = r.time[i] ^ r.seed[i]
		}
		r.cipher.Encrypt(r.dst[0:], r.dst[0:])
		for i := 0; i < aes.BlockSize; i++ {
			r.seed[i] = r.time[i] ^ r.dst[i]
		}
		r.cipher.Encrypt(r.seed[0:], r.seed[0:])

		m := copy(b, r.dst[0:])
		b = b[m:]
	}

	return n, nil
}
<commit_msg>Use defer to unlock mutex in crypto/rand.<commit_after>// Copyright 2010 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Unix cryptographically secure pseudorandom number
// generator.

package rand

import (
	"crypto/aes"
	"io"
	"os"
	"sync"
	"time"
)

// Easy implementation: read from /dev/urandom.
// This is sufficient on Linux, OS X, and FreeBSD.

func init() { Reader = &devReader{name: "/dev/urandom"} }

// A devReader satisfies reads by reading the file named name.
type devReader struct {
	name string
	f    *os.File
	mu   sync.Mutex
}

func (r *devReader) Read(b []byte) (n int, err os.Error) {
	r.mu.Lock()
	defer r.mu.Unlock()
	if r.f == nil {
		f, err := os.Open(r.name, os.O_RDONLY, 0)
		if f == nil {
			return 0, err
		}
		r.f = f
	}
	return r.f.Read(b)
}

// Alternate pseudo-random implementation for use on
// systems without a reliable /dev/urandom.  So far we
// haven't needed it.

// newReader returns a new pseudorandom generator that
// seeds itself by reading from entropy.  If entropy == nil,
// the generator seeds itself by reading from the system's
// random number generator, typically /dev/random.
// The Read method on the returned reader always returns
// the full amount asked for, or else it returns an error.
//
// The generator uses the X9.31 algorithm with AES-128,
// reseeding after every 1 MB of generated data.
func newReader(entropy io.Reader) io.Reader {
	if entropy == nil {
		entropy = &devReader{name: "/dev/random"}
	}
	return &reader{entropy: entropy}
}

type reader struct {
	mu                   sync.Mutex
	budget               int // number of bytes that can be generated
	cipher               *aes.Cipher
	entropy              io.Reader
	time, seed, dst, key [aes.BlockSize]byte
}

func (r *reader) Read(b []byte) (n int, err os.Error) {
	r.mu.Lock()
	defer r.mu.Unlock()
	n = len(b)

	for len(b) > 0 {
		if r.budget == 0 {
			_, err := io.ReadFull(r.entropy, r.seed[0:])
			if err != nil {
				return n - len(b), err
			}
			_, err = io.ReadFull(r.entropy, r.key[0:])
			if err != nil {
				return n - len(b), err
			}
			r.cipher, err = aes.NewCipher(r.key[0:])
			if err != nil {
				return n - len(b), err
			}
			r.budget = 1 << 20 // reseed after generating 1MB
		}
		r.budget -= aes.BlockSize

		// ANSI X9.31 (== X9.17) algorithm, but using AES in place of 3DES.
		//
		// single block:
		// t = encrypt(time)
		// dst = encrypt(t^seed)
		// seed = encrypt(t^dst)
		ns := time.Nanoseconds()
		r.time[0] = byte(ns >> 56)
		r.time[1] = byte(ns >> 48)
		r.time[2] = byte(ns >> 40)
		r.time[3] = byte(ns >> 32)
		r.time[4] = byte(ns >> 24)
		r.time[5] = byte(ns >> 16)
		r.time[6] = byte(ns >> 8)
		r.time[7] = byte(ns)
		r.cipher.Encrypt(r.time[0:], r.time[0:])
		for i := 0; i < aes.BlockSize; i++ {
			r.dst[i] = r.time[i] ^ r.seed[i]
		}
		r.cipher.Encrypt(r.dst[0:], r.dst[0:])
		for i := 0; i < aes.BlockSize; i++ {
			r.seed[i] = r.time[i] ^ r.dst[i]
		}
		r.cipher.Encrypt(r.seed[0:], r.seed[0:])

		m := copy(b, r.dst[0:])
		b = b[m:]
	}

	return n, nil
}
<|endoftext|>


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

/*
A trivial example of wrapping a C library in Go.
For a more complex example and explanation,
see ../gmp/gmp.go.
*/

package stdio

/*
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <errno.h>

char* greeting = "hello, world";
*/
import "C"
import "unsafe"

type File C.FILE

var Stdout = (*File)(C.stdout)
var Stderr = (*File)(C.stderr)

// Test reference to library symbol.
// Stdout and stderr are too special to be a reliable test.
var myerr = C.sys_errlist

func (f *File) WriteString(s string) {
	p := C.CString(s)
	C.fputs(p, (*C.FILE)(f))
	C.free(unsafe.Pointer(p))
	f.Flush()
}

func (f *File) Flush() {
	C.fflush((*C.FILE)(f))
}

var Greeting = C.GoString(C.greeting)
<commit_msg>go/build: fix windows build by commenting out references to stdout and stderr in cgotest<commit_after>// Copyright 2009 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
A trivial example of wrapping a C library in Go.
For a more complex example and explanation,
see ../gmp/gmp.go.
*/

package stdio

/*
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <errno.h>

char* greeting = "hello, world";
*/
import "C"
import "unsafe"

type File C.FILE

// TODO(brainman): uncomment once stdout and stderr references are working on Windows.
//var Stdout = (*File)(C.stdout)
//var Stderr = (*File)(C.stderr)

// Test reference to library symbol.
// Stdout and stderr are too special to be a reliable test.
var myerr = C.sys_errlist

func (f *File) WriteString(s string) {
	p := C.CString(s)
	C.fputs(p, (*C.FILE)(f))
	C.free(unsafe.Pointer(p))
	f.Flush()
}

func (f *File) Flush() {
	C.fflush((*C.FILE)(f))
}

var Greeting = C.GoString(C.greeting)
<|endoftext|>


<commit_before>package memberlist

import (
	"net"
	"sync/atomic"
	"time"
)

const (
	StateAlive = iota
	StateSuspect
	StateDead
)

// Node is used to represent a known node
type Node struct {
	Name string // Remote node name
	Addr net.IP // Remote address
}

// NodeState is used to manage our state view of another node
type NodeState struct {
	Node
	Incarnation uint32    // Last known incarnation number
	State       int       // Current state
	StateChange time.Time // Time last state change happened
}

// ackHandler is used to register handlers for incoming acks
type ackHandler struct {
	handler func()
	timer   *time.Timer
}

// Schedule is used to ensure the Tick is performed periodically
func (m *Memberlist) schedule() {
	// Create a new ticker
	m.tickerLock.Lock()
	m.ticker = time.NewTicker(m.config.Interval)
	C := m.ticker.C
	m.tickerLock.Unlock()
	go func() {
		for {
			select {
			case <-C:
				m.tick()
			case <-m.stopTick:
				return
			}
		}
	}()
}

// Deschedule is used to stop the background maintenence
func (m *Memberlist) deschedule() {
	m.tickerLock.Lock()
	if m.ticker != nil {
		m.ticker.Stop()
		m.ticker = nil
	}
	m.tickerLock.Unlock()
	select {
	case m.stopTick <- struct{}{}:
	default:
	}
}

// Tick is used to perform a single round of failure detection and gossip
func (m *Memberlist) tick() {
	m.tickCount++

}

// nextSeqNo returns a usable sequence number in a thread safe way
func (m *Memberlist) nextSeqNo() uint32 {
	return atomic.AddUint32(&m.sequenceNum, 1)
}

// setAckHandler is used to attach a handler to be invoked when an
// ack with a given sequence number is received. If a timeout is reached,
// the handler is deleted
func (m *Memberlist) setAckHandler(seqNo uint32, handler func(), timeout time.Duration) {
	// Add the handler
	ah := &ackHandler{handler, nil}
	m.ackLock.Lock()
	m.ackHandlers[seqNo] = ah
	m.ackLock.Unlock()

	// Setup a reaping routing
	ah.timer = time.AfterFunc(timeout, func() {
		m.ackLock.Lock()
		delete(m.ackHandlers, seqNo)
		m.ackLock.Unlock()
	})
}

// Invokes an Ack handler if any is associated, and reaps the handler immediately
func (m *Memberlist) invokeAckHandler(seqNo uint32) {
	m.ackLock.Lock()
	ah, ok := m.ackHandlers[seqNo]
	delete(m.ackHandlers, seqNo)
	m.ackLock.Unlock()
	if !ok {
		return
	}
	ah.timer.Stop()
	ah.handler()
}

// aliveNode is invoked by the network layer when we get a message
// about a live node
func (m *Memberlist) aliveNode(a *alive) {
	// TODO: Ignore we are alive
	// TODO: Re-broadcast
	m.nodeLock.Lock()
	defer m.nodeLock.Unlock()
	state, ok := m.nodeMap[a.Node]

	// Check if we've never seen this node before
	if !ok {
		state = &NodeState{
			Node: Node{
				Name: a.Node,
				Addr: a.Addr,
			},
			State: StateDead,
		}

		// Add to map
		m.nodeMap[a.Node] = state

		// Get a random offset. This is important to ensure
		// the failure detection bound is low on average. If all
		// nodes did an append, failure detection bound would be
		// very high.
		n := len(m.nodes)
		offset := randomOffset(n)

		// Add at the end and swap with the node at the offset
		m.nodes = append(m.nodes, state)
		m.nodes[offset], m.nodes[n] = m.nodes[n], m.nodes[offset]
	}

	// Bail if the incarnation number is old
	if a.Incarnation <= state.Incarnation {
		return
	}

	// Update the state and incarnation number
	oldState := state.State
	state.Incarnation = a.Incarnation
	if state.State != StateAlive {
		state.State = StateAlive
		state.StateChange = time.Now()
	}

	// if Dead -> Alive, notify of join
	if oldState == StateDead {
		m.notifyLock.RLock()
		defer m.notifyLock.RUnlock()
		notifyAll(m.notifyJoin, &state.Node)
	}
}

// suspectNode is invoked by the network layer when we get a message
// about a suspect node
func (m *Memberlist) suspectNode(s *suspect) {
	// TODO: Refute if _we_ are suspected
	// TODO: Re-broadcast
	m.nodeLock.Lock()
	defer m.nodeLock.Unlock()
	state, ok := m.nodeMap[s.Node]

	// If we've never heard about this node before, ignore it
	if !ok {
		return
	}

	// Ignore old incarnation numbers
	if s.Incarnation < state.Incarnation {
		return
	}

	// Ignore non-alive nodes
	if state.State != StateAlive {
		return
	}

	// Update the state
	state.Incarnation = s.Incarnation
	state.State = StateSuspect
	state.StateChange = time.Now()

	// Setup a timeout for this
	timeout := suspicionTimeout(m.config.SuspicionMult, len(m.nodes), m.config.Interval)
	time.AfterFunc(timeout, func() {
		if state.Incarnation == s.Incarnation && state.State == StateSuspect {
			m.suspectTimeout(state)
		}
	})
}

// suspectTimeout is invoked when a suspect timeout has occurred
func (m *Memberlist) suspectTimeout(n *NodeState) {
	// Construct a dead message
	d := dead{Incarnation: n.Incarnation, Node: n.Name}
	m.deadNode(&d)
}

// deadNode is invoked by the network layer when we get a message
// about a dead node
func (m *Memberlist) deadNode(d *dead) {
	// TODO: Re-broadcast
	// TODO: Refute if us?
	m.nodeLock.Lock()
	defer m.nodeLock.Unlock()
	state, ok := m.nodeMap[d.Node]

	// If we've never heard about this node before, ignore it
	if !ok {
		return
	}

	// Check for new incarnation
	if d.Incarnation > state.Incarnation {
		state.Incarnation = d.Incarnation
	}

	// Ignore if node is already dead
	if state.State == StateDead {
		return
	}

	// Update the state
	state.State = StateDead
	state.StateChange = time.Now()

	// Notify of death
	m.notifyLock.RLock()
	defer m.notifyLock.RUnlock()
	notifyAll(m.notifyLeave, &state.Node)
}

// mergeState is invoked by the network layer when we get a Push/Pull
// state transfer
func (m *Memberlist) mergeState(remote []pushNodeState) {
}
<commit_msg>Check change time instead of incarnation<commit_after>package memberlist

import (
	"net"
	"sync/atomic"
	"time"
)

const (
	StateAlive = iota
	StateSuspect
	StateDead
)

// Node is used to represent a known node
type Node struct {
	Name string // Remote node name
	Addr net.IP // Remote address
}

// NodeState is used to manage our state view of another node
type NodeState struct {
	Node
	Incarnation uint32    // Last known incarnation number
	State       int       // Current state
	StateChange time.Time // Time last state change happened
}

// ackHandler is used to register handlers for incoming acks
type ackHandler struct {
	handler func()
	timer   *time.Timer
}

// Schedule is used to ensure the Tick is performed periodically
func (m *Memberlist) schedule() {
	// Create a new ticker
	m.tickerLock.Lock()
	m.ticker = time.NewTicker(m.config.Interval)
	C := m.ticker.C
	m.tickerLock.Unlock()
	go func() {
		for {
			select {
			case <-C:
				m.tick()
			case <-m.stopTick:
				return
			}
		}
	}()
}

// Deschedule is used to stop the background maintenence
func (m *Memberlist) deschedule() {
	m.tickerLock.Lock()
	if m.ticker != nil {
		m.ticker.Stop()
		m.ticker = nil
	}
	m.tickerLock.Unlock()
	select {
	case m.stopTick <- struct{}{}:
	default:
	}
}

// Tick is used to perform a single round of failure detection and gossip
func (m *Memberlist) tick() {
	m.tickCount++

}

// nextSeqNo returns a usable sequence number in a thread safe way
func (m *Memberlist) nextSeqNo() uint32 {
	return atomic.AddUint32(&m.sequenceNum, 1)
}

// setAckHandler is used to attach a handler to be invoked when an
// ack with a given sequence number is received. If a timeout is reached,
// the handler is deleted
func (m *Memberlist) setAckHandler(seqNo uint32, handler func(), timeout time.Duration) {
	// Add the handler
	ah := &ackHandler{handler, nil}
	m.ackLock.Lock()
	m.ackHandlers[seqNo] = ah
	m.ackLock.Unlock()

	// Setup a reaping routing
	ah.timer = time.AfterFunc(timeout, func() {
		m.ackLock.Lock()
		delete(m.ackHandlers, seqNo)
		m.ackLock.Unlock()
	})
}

// Invokes an Ack handler if any is associated, and reaps the handler immediately
func (m *Memberlist) invokeAckHandler(seqNo uint32) {
	m.ackLock.Lock()
	ah, ok := m.ackHandlers[seqNo]
	delete(m.ackHandlers, seqNo)
	m.ackLock.Unlock()
	if !ok {
		return
	}
	ah.timer.Stop()
	ah.handler()
}

// aliveNode is invoked by the network layer when we get a message
// about a live node
func (m *Memberlist) aliveNode(a *alive) {
	// TODO: Ignore we are alive
	// TODO: Re-broadcast
	m.nodeLock.Lock()
	defer m.nodeLock.Unlock()
	state, ok := m.nodeMap[a.Node]

	// Check if we've never seen this node before
	if !ok {
		state = &NodeState{
			Node: Node{
				Name: a.Node,
				Addr: a.Addr,
			},
			State: StateDead,
		}

		// Add to map
		m.nodeMap[a.Node] = state

		// Get a random offset. This is important to ensure
		// the failure detection bound is low on average. If all
		// nodes did an append, failure detection bound would be
		// very high.
		n := len(m.nodes)
		offset := randomOffset(n)

		// Add at the end and swap with the node at the offset
		m.nodes = append(m.nodes, state)
		m.nodes[offset], m.nodes[n] = m.nodes[n], m.nodes[offset]
	}

	// Bail if the incarnation number is old
	if a.Incarnation <= state.Incarnation {
		return
	}

	// Update the state and incarnation number
	oldState := state.State
	state.Incarnation = a.Incarnation
	if state.State != StateAlive {
		state.State = StateAlive
		state.StateChange = time.Now()
	}

	// if Dead -> Alive, notify of join
	if oldState == StateDead {
		m.notifyLock.RLock()
		defer m.notifyLock.RUnlock()
		notifyAll(m.notifyJoin, &state.Node)
	}
}

// suspectNode is invoked by the network layer when we get a message
// about a suspect node
func (m *Memberlist) suspectNode(s *suspect) {
	// TODO: Refute if _we_ are suspected
	// TODO: Re-broadcast
	m.nodeLock.Lock()
	defer m.nodeLock.Unlock()
	state, ok := m.nodeMap[s.Node]

	// If we've never heard about this node before, ignore it
	if !ok {
		return
	}

	// Ignore old incarnation numbers
	if s.Incarnation < state.Incarnation {
		return
	}

	// Ignore non-alive nodes
	if state.State != StateAlive {
		return
	}

	// Update the state
	state.Incarnation = s.Incarnation
	state.State = StateSuspect
	changeTime := time.Now()
	state.StateChange = changeTime

	// Setup a timeout for this
	timeout := suspicionTimeout(m.config.SuspicionMult, len(m.nodes), m.config.Interval)
	time.AfterFunc(timeout, func() {
		if state.State == StateSuspect && state.StateChange == changeTime {
			m.suspectTimeout(state)
		}
	})
}

// suspectTimeout is invoked when a suspect timeout has occurred
func (m *Memberlist) suspectTimeout(n *NodeState) {
	// Construct a dead message
	d := dead{Incarnation: n.Incarnation, Node: n.Name}
	m.deadNode(&d)
}

// deadNode is invoked by the network layer when we get a message
// about a dead node
func (m *Memberlist) deadNode(d *dead) {
	// TODO: Re-broadcast
	// TODO: Refute if us?
	m.nodeLock.Lock()
	defer m.nodeLock.Unlock()
	state, ok := m.nodeMap[d.Node]

	// If we've never heard about this node before, ignore it
	if !ok {
		return
	}

	// Check for new incarnation
	if d.Incarnation > state.Incarnation {
		state.Incarnation = d.Incarnation
	}

	// Ignore if node is already dead
	if state.State == StateDead {
		return
	}

	// Update the state
	state.State = StateDead
	state.StateChange = time.Now()

	// Notify of death
	m.notifyLock.RLock()
	defer m.notifyLock.RUnlock()
	notifyAll(m.notifyLeave, &state.Node)
}

// mergeState is invoked by the network layer when we get a Push/Pull
// state transfer
func (m *Memberlist) mergeState(remote []pushNodeState) {
}
<|endoftext|>


<commit_before>package kuiperbelt

import (
	"bufio"
	"encoding/json"
	"fmt"
	"io"
	"sync/atomic"
	"time"
)

type doNotCopy struct{}

func (*doNotCopy) Lock() {}

type Stats struct {
	connections      int64
	totalConnections int64
	totalMessages    int64
	connectErrors    int64
	messageErrors    int64
	doNotCopy        doNotCopy
}

func NewStats() *Stats {
	return &Stats{}
}

func (s *Stats) Connections() int64 {
	return atomic.LoadInt64(&s.connections)
}

func (s *Stats) TotalConnections() int64 {
	return atomic.LoadInt64(&s.totalConnections)
}

func (s *Stats) TotalMessages() int64 {
	return atomic.LoadInt64(&s.totalMessages)
}

func (s *Stats) ConnectErrors() int64 {
	return atomic.LoadInt64(&s.connectErrors)
}

func (s *Stats) MessageErrors() int64 {
	return atomic.LoadInt64(&s.messageErrors)
}

func (s *Stats) Dump(w io.Writer) error {
	return json.NewEncoder(w).Encode(struct {
		Connections      int64 `json:"connections"`
		TotalConnections int64 `json:"total_connections"`
		TotalMessages    int64 `json:"total_messages"`
		ConnectErrors    int64 `json:"connect_errors"`
		MessageErrors    int64 `json:"message_errors"`
	}{
		Connections:      s.Connections(),
		TotalConnections: s.TotalConnections(),
		TotalMessages:    s.TotalMessages(),
		ConnectErrors:    s.ConnectErrors(),
		MessageErrors:    s.MessageErrors(),
	})
}

func (s *Stats) DumpText(w io.Writer) error {
	now := time.Now().Unix()
	_w := bufio.NewWriter(w)
	fmt.Fprintf(_w, "kuiperbelt.connections       %19d %19d\n", s.Connections(), now)
	fmt.Fprintf(_w, "kuiperbelt.total_connections %19d %19d\n", s.TotalConnections(), now)
	fmt.Fprintf(_w, "kuiperbelt.total_messages    %19d %19d\n", s.TotalMessages(), now)
	fmt.Fprintf(_w, "kuiperbelt.connect_errors    %19d %19d\n", s.ConnectErrors(), now)
	fmt.Fprintf(_w, "kuiperbelt.message_errors    %19d %19d\n", s.MessageErrors(), now)
	return _w.Flush()
}

func (s *Stats) ConnectEvent() {
	atomic.AddInt64(&s.totalConnections, 1)
	atomic.AddInt64(&s.connections, 1)
}

func (s *Stats) ConnectErrorEvent() {
	atomic.AddInt64(&s.connectErrors, 1)
}

func (s *Stats) DisconnectEvent() {
	atomic.AddInt64(&s.connections, -1)
}

func (s *Stats) MessageEvent() {
	atomic.AddInt64(&s.totalMessages, 1)
}

func (s *Stats) MessageErrorEvent() {
	atomic.AddInt64(&s.messageErrors, 1)
}
<commit_msg>add some comments for noCopy<commit_after>package kuiperbelt

import (
	"bufio"
	"encoding/json"
	"fmt"
	"io"
	"sync/atomic"
	"time"
)

// macopy may be embedded into structs which must not be copied
// after the first use.
// See https://github.com/golang/go/issues/8005#issuecomment-190753527
// for details.
type macopy struct{}

func (*macopy) Lock() {}

type Stats struct {
	connections      int64
	totalConnections int64
	totalMessages    int64
	connectErrors    int64
	messageErrors    int64
	noCopy           macopy
}

func NewStats() *Stats {
	return &Stats{}
}

func (s *Stats) Connections() int64 {
	return atomic.LoadInt64(&s.connections)
}

func (s *Stats) TotalConnections() int64 {
	return atomic.LoadInt64(&s.totalConnections)
}

func (s *Stats) TotalMessages() int64 {
	return atomic.LoadInt64(&s.totalMessages)
}

func (s *Stats) ConnectErrors() int64 {
	return atomic.LoadInt64(&s.connectErrors)
}

func (s *Stats) MessageErrors() int64 {
	return atomic.LoadInt64(&s.messageErrors)
}

func (s *Stats) Dump(w io.Writer) error {
	return json.NewEncoder(w).Encode(struct {
		Connections      int64 `json:"connections"`
		TotalConnections int64 `json:"total_connections"`
		TotalMessages    int64 `json:"total_messages"`
		ConnectErrors    int64 `json:"connect_errors"`
		MessageErrors    int64 `json:"message_errors"`
	}{
		Connections:      s.Connections(),
		TotalConnections: s.TotalConnections(),
		TotalMessages:    s.TotalMessages(),
		ConnectErrors:    s.ConnectErrors(),
		MessageErrors:    s.MessageErrors(),
	})
}

func (s *Stats) DumpText(w io.Writer) error {
	now := time.Now().Unix()
	_w := bufio.NewWriter(w)
	fmt.Fprintf(_w, "kuiperbelt.connections       %19d %19d\n", s.Connections(), now)
	fmt.Fprintf(_w, "kuiperbelt.total_connections %19d %19d\n", s.TotalConnections(), now)
	fmt.Fprintf(_w, "kuiperbelt.total_messages    %19d %19d\n", s.TotalMessages(), now)
	fmt.Fprintf(_w, "kuiperbelt.connect_errors    %19d %19d\n", s.ConnectErrors(), now)
	fmt.Fprintf(_w, "kuiperbelt.message_errors    %19d %19d\n", s.MessageErrors(), now)
	return _w.Flush()
}

func (s *Stats) ConnectEvent() {
	atomic.AddInt64(&s.totalConnections, 1)
	atomic.AddInt64(&s.connections, 1)
}

func (s *Stats) ConnectErrorEvent() {
	atomic.AddInt64(&s.connectErrors, 1)
}

func (s *Stats) DisconnectEvent() {
	atomic.AddInt64(&s.connections, -1)
}

func (s *Stats) MessageEvent() {
	atomic.AddInt64(&s.totalMessages, 1)
}

func (s *Stats) MessageErrorEvent() {
	atomic.AddInt64(&s.messageErrors, 1)
}
<|endoftext|>


<commit_before>package stats

import (
	"runtime"

	"github.com/shirou/gopsutil/host"
	"github.com/shirou/gopsutil/mem"
)

const (
	udp        = "udp"
	bufferSize = 1024 * 10
)

// GoMemory contains go specific memory metrics
type GoMemory struct {
	NumGC               uint32           `json:"numgc"`
	LastGC              uint64           `json:"lastgc"`
	LastGCPauseDuration uint64           `json:"lastgcpause"`
	Allocated           uint64           `json:"alloc"`
	HeapAlloc           uint64           `json:"heap"`
	HeapSys             uint64           `json:"sys"`
	lastNumGC           uint32           `json:"-"`
	mem                 runtime.MemStats `json:"-"`
}

// GoInfo contains go specific metrics and stats
type GoInfo struct {
	Version    string   `json:"gover"`
	Memory     GoMemory `json:"gomem"`
	GoRoutines int      `json:"goroutines"`
}

// MemInfo contains memory info including swap information
type MemInfo struct {
	Memory *mem.VirtualMemoryStat `json:"mem"`
	Swap   *mem.SwapMemoryStat    `json:"swap"`
	// GoMemstats *runtime.MemStats      `json:"gomem"`
}

// Stats contains all of the statistics to be passed and Encoded/Decoded on the Client and Server sides
type Stats struct {
	HostInfo *host.HostInfoStat `json:"hostInfo"`
	MemInfo  *MemInfo           `json:"memInfo"`
	GoInfo   *GoInfo            `json:"goInfo"`
}

// GetHostInfo populates Stats with host system information
func (s *Stats) GetHostInfo() {

	if s.GoInfo == nil {
		s.GoInfo = new(GoInfo)
	}

	info, _ := host.HostInfo()

	s.HostInfo = info
	s.GoInfo.Version = runtime.Version()
}

// GetMemoryInfo populates Stats with host and go process memory information
func (s *Stats) GetMemoryInfo() {

	if s.GoInfo == nil {
		s.GetHostInfo()
	}

	if s.MemInfo == nil {
		s.MemInfo = new(MemInfo)
	}

	runtime.ReadMemStats(&s.GoInfo.Memory.mem)
	s.GoInfo.GoRoutines = runtime.NumGoroutine()
	s.GoInfo.Memory.NumGC = s.GoInfo.Memory.mem.NumGC
	s.GoInfo.Memory.Allocated = s.GoInfo.Memory.mem.Alloc
	s.GoInfo.Memory.HeapAlloc = s.GoInfo.Memory.mem.HeapAlloc
	s.GoInfo.Memory.HeapSys = s.GoInfo.Memory.mem.HeapSys

	if s.GoInfo.Memory.LastGC != s.GoInfo.Memory.mem.LastGC {
		s.GoInfo.Memory.LastGC = s.GoInfo.Memory.mem.LastGC
		s.GoInfo.Memory.NumGC = s.GoInfo.Memory.mem.NumGC - s.GoInfo.Memory.lastNumGC
		s.GoInfo.Memory.lastNumGC = s.GoInfo.Memory.mem.NumGC
		s.GoInfo.Memory.LastGCPauseDuration = s.GoInfo.Memory.mem.PauseNs[(s.GoInfo.Memory.mem.NumGC+255)%256]
	} else {
		s.GoInfo.Memory.NumGC = 0
		s.GoInfo.Memory.LastGCPauseDuration = 0
	}

	s.MemInfo.Memory, _ = mem.VirtualMemory()
	s.MemInfo.Swap, _ = mem.SwapMemory()
}
<commit_msg>update memstats  def for efficiency<commit_after>package stats

import (
	"runtime"

	"github.com/shirou/gopsutil/host"
	"github.com/shirou/gopsutil/mem"
)

const (
	udp        = "udp"
	bufferSize = 1024 * 10
)

// GoMemory contains go specific memory metrics
type GoMemory struct {
	NumGC               uint32            `json:"numgc"`
	LastGC              uint64            `json:"lastgc"`
	LastGCPauseDuration uint64            `json:"lastgcpause"`
	Allocated           uint64            `json:"alloc"`
	HeapAlloc           uint64            `json:"heap"`
	HeapSys             uint64            `json:"sys"`
	lastNumGC           uint32            `json:"-"`
	mem                 *runtime.MemStats `json:"-"`
}

// GoInfo contains go specific metrics and stats
type GoInfo struct {
	Version    string   `json:"gover"`
	Memory     GoMemory `json:"gomem"`
	GoRoutines int      `json:"goroutines"`
}

// MemInfo contains memory info including swap information
type MemInfo struct {
	Memory *mem.VirtualMemoryStat `json:"mem"`
	Swap   *mem.SwapMemoryStat    `json:"swap"`
}

// Stats contains all of the statistics to be passed and Encoded/Decoded on the Client and Server sides
type Stats struct {
	HostInfo *host.HostInfoStat `json:"hostInfo"`
	MemInfo  *MemInfo           `json:"memInfo"`
	GoInfo   *GoInfo            `json:"goInfo"`
}

// GetHostInfo populates Stats with host system information
func (s *Stats) GetHostInfo() {

	if s.GoInfo == nil {
		s.GoInfo = new(GoInfo)
		s.GoInfo.Memory.mem = new(runtime.MemStats)
	}

	info, _ := host.HostInfo()

	s.HostInfo = info
	s.GoInfo.Version = runtime.Version()
}

// GetMemoryInfo populates Stats with host and go process memory information
func (s *Stats) GetMemoryInfo() {

	if s.GoInfo == nil {
		s.GetHostInfo()
	}

	if s.MemInfo == nil {
		s.MemInfo = new(MemInfo)
	}

	runtime.ReadMemStats(s.GoInfo.Memory.mem)
	s.GoInfo.GoRoutines = runtime.NumGoroutine()
	s.GoInfo.Memory.NumGC = s.GoInfo.Memory.mem.NumGC
	s.GoInfo.Memory.Allocated = s.GoInfo.Memory.mem.Alloc
	s.GoInfo.Memory.HeapAlloc = s.GoInfo.Memory.mem.HeapAlloc
	s.GoInfo.Memory.HeapSys = s.GoInfo.Memory.mem.HeapSys

	if s.GoInfo.Memory.LastGC != s.GoInfo.Memory.mem.LastGC {
		s.GoInfo.Memory.LastGC = s.GoInfo.Memory.mem.LastGC
		s.GoInfo.Memory.NumGC = s.GoInfo.Memory.mem.NumGC - s.GoInfo.Memory.lastNumGC
		s.GoInfo.Memory.lastNumGC = s.GoInfo.Memory.mem.NumGC
		s.GoInfo.Memory.LastGCPauseDuration = s.GoInfo.Memory.mem.PauseNs[(s.GoInfo.Memory.mem.NumGC+255)%256]
	} else {
		s.GoInfo.Memory.NumGC = 0
		s.GoInfo.Memory.LastGCPauseDuration = 0
	}

	s.MemInfo.Memory, _ = mem.VirtualMemory()
	s.MemInfo.Swap, _ = mem.SwapMemory()
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"path/filepath"

	"time"

	. "github.com/claudetech/loggo/default"
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/sqlite"
	"golang.org/x/oauth2"
)

// Cache is the cache
type Cache struct {
	db        *gorm.DB
	dbAction  chan cacheAction
	tokenPath string
}

const (
	// StoreAction stores an object in cache
	StoreAction = iota
	// DeleteAction deletes an object in cache
	DeleteAction = iota
)

type cacheAction struct {
	action int
	object *APIObject
}

// APIObject is a Google Drive file object
type APIObject struct {
	ObjectID     string `gorm:"primary_key"`
	Name         string `gorm:"index"`
	IsDir        bool
	Size         uint64
	LastModified time.Time
	DownloadURL  string
	Parents      string `gorm:"index"`
	CreatedAt    time.Time
}

// PageToken is the last change id
type PageToken struct {
	gorm.Model
	Token string
}

// NewCache creates a new cache instance
func NewCache(cacheBasePath string, sqlDebug bool) (*Cache, error) {
	Log.Debugf("Opening cache connection")
	db, err := gorm.Open("sqlite3", filepath.Join(cacheBasePath, "cache"))
	if nil != err {
		Log.Debugf("%v", err)
		return nil, fmt.Errorf("Could not open cache database")
	}

	Log.Debugf("Migrating cache schema")
	db.AutoMigrate(&APIObject{})
	db.AutoMigrate(&PageToken{})
	db.LogMode(sqlDebug)

	cache := Cache{
		db:        db,
		dbAction:  make(chan cacheAction),
		tokenPath: filepath.Join(cacheBasePath, "token.json"),
	}

	go cache.startStoringQueue()

	return &cache, nil
}

func (c *Cache) startStoringQueue() {
	for {
		action := <-c.dbAction

		if nil != action.object {
			if action.action == DeleteAction || action.action == StoreAction {
				Log.Debugf("Deleting object %v", action.object.ObjectID)
				c.db.Delete(action.object)
			}
			if action.action == StoreAction {
				Log.Debugf("Storing object %v in cache", action.object.ObjectID)
				c.db.Create(action.object)
			}
		}
	}
}

// Close closes all handles
func (c *Cache) Close() error {
	Log.Debugf("Closing cache connection")

	close(c.dbAction)
	if err := c.db.Close(); nil != err {
		Log.Debugf("%v", err)
		return fmt.Errorf("Could not close cache connection")
	}

	return nil
}

// LoadToken loads a token from cache
func (c *Cache) LoadToken() (*oauth2.Token, error) {
	Log.Debugf("Loading token from cache")

	tokenFile, err := ioutil.ReadFile(c.tokenPath)
	if nil != err {
		Log.Debugf("%v", err)
		return nil, fmt.Errorf("Could not read token file in %v", c.tokenPath)
	}

	var token oauth2.Token
	json.Unmarshal(tokenFile, &token)

	Log.Tracef("Got token from cache %v", token)

	return &token, nil
}

// StoreToken stores a token in the cache or updates the existing token element
func (c *Cache) StoreToken(token *oauth2.Token) error {
	Log.Debugf("Storing token to cache")

	tokenJSON, err := json.Marshal(token)
	if nil != err {
		Log.Debugf("%v", err)
		return fmt.Errorf("Could not generate token.json content")
	}

	if err := ioutil.WriteFile(c.tokenPath, tokenJSON, 0644); nil != err {
		Log.Debugf("%v", err)
		return fmt.Errorf("Could not generate token.json file")
	}

	return nil
}

// GetObject gets an object by id
func (c *Cache) GetObject(id string) (*APIObject, error) {
	Log.Tracef("Getting object %v", id)

	var object APIObject
	c.db.Where(&APIObject{ObjectID: id}).First(&object)

	Log.Tracef("Got object from cache %v", object)

	if "" != object.ObjectID {
		return &object, nil
	}

	return nil, fmt.Errorf("Could not find object %v in cache", id)
}

// GetObjectsByParent get all objects under parent id
func (c *Cache) GetObjectsByParent(parent string) ([]*APIObject, error) {
	Log.Debugf("Getting children for %v", parent)

	var objects []*APIObject
	c.db.Where("parents LIKE ?", fmt.Sprintf("%%|%v|%%", parent)).Find(&objects)

	Log.Tracef("Got objects from cache %v", objects)

	if 0 != len(objects) {
		return objects, nil
	}

	return nil, fmt.Errorf("Could not find children for parent %v in cache", parent)
}

// GetObjectByParentAndName finds a child element by name and its parent id
func (c *Cache) GetObjectByParentAndName(parent, name string) (*APIObject, error) {
	Log.Tracef("Getting object %v in parent %v", name, parent)

	var object APIObject
	c.db.Where("parents LIKE ? AND name = ?", fmt.Sprintf("%%|%v|%%", parent), name).First(&object)

	Log.Tracef("Got object from cache %v", object)

	if "" != object.ObjectID {
		return &object, nil
	}

	return nil, fmt.Errorf("Could not find object with name %v in parent %v", name, parent)
}

// DeleteObject deletes an object by id
func (c *Cache) DeleteObject(id string) error {
	c.dbAction <- cacheAction{
		action: DeleteAction,
		object: &APIObject{ObjectID: id},
	}
	return nil
}

// UpdateObject updates an object
func (c *Cache) UpdateObject(object *APIObject) error {
	c.dbAction <- cacheAction{
		action: StoreAction,
		object: object,
	}
	return nil
}

// StoreStartPageToken stores the page token for changes
func (c *Cache) StoreStartPageToken(token string) error {
	Log.Debugf("Storing page token %v in cache", token)

	c.db.Delete(&PageToken{})
	c.db.Create(&PageToken{
		Token: token,
	})

	return nil
}

// GetStartPageToken gets the start page token
func (c *Cache) GetStartPageToken() (string, error) {
	Log.Debugf("Getting start page token from cache")

	var pageToken PageToken
	c.db.First(&pageToken)

	Log.Tracef("Got start page token %v", pageToken.Token)

	if "" == pageToken.Token {
		return "", fmt.Errorf("Token not found in cache")
	}

	return pageToken.Token, nil
}
<commit_msg>disabled unnecessary debug output<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"path/filepath"

	"time"

	. "github.com/claudetech/loggo/default"
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/sqlite"
	"golang.org/x/oauth2"
)

// Cache is the cache
type Cache struct {
	db        *gorm.DB
	dbAction  chan cacheAction
	tokenPath string
}

const (
	// StoreAction stores an object in cache
	StoreAction = iota
	// DeleteAction deletes an object in cache
	DeleteAction = iota
)

type cacheAction struct {
	action int
	object *APIObject
}

// APIObject is a Google Drive file object
type APIObject struct {
	ObjectID     string `gorm:"primary_key"`
	Name         string `gorm:"index"`
	IsDir        bool
	Size         uint64
	LastModified time.Time
	DownloadURL  string
	Parents      string `gorm:"index"`
	CreatedAt    time.Time
}

// PageToken is the last change id
type PageToken struct {
	gorm.Model
	Token string
}

// NewCache creates a new cache instance
func NewCache(cacheBasePath string, sqlDebug bool) (*Cache, error) {
	Log.Debugf("Opening cache connection")
	db, err := gorm.Open("sqlite3", filepath.Join(cacheBasePath, "cache"))
	if nil != err {
		Log.Debugf("%v", err)
		return nil, fmt.Errorf("Could not open cache database")
	}

	Log.Debugf("Migrating cache schema")
	db.AutoMigrate(&APIObject{})
	db.AutoMigrate(&PageToken{})
	db.LogMode(sqlDebug)

	cache := Cache{
		db:        db,
		dbAction:  make(chan cacheAction),
		tokenPath: filepath.Join(cacheBasePath, "token.json"),
	}

	go cache.startStoringQueue()

	return &cache, nil
}

func (c *Cache) startStoringQueue() {
	for {
		action := <-c.dbAction

		if nil != action.object {
			if action.action == DeleteAction || action.action == StoreAction {
				Log.Debugf("Deleting object %v", action.object.ObjectID)
				c.db.Delete(action.object)
			}
			if action.action == StoreAction {
				Log.Debugf("Storing object %v in cache", action.object.ObjectID)
				c.db.Create(action.object)
			}
		}
	}
}

// Close closes all handles
func (c *Cache) Close() error {
	Log.Debugf("Closing cache connection")

	close(c.dbAction)
	if err := c.db.Close(); nil != err {
		Log.Debugf("%v", err)
		return fmt.Errorf("Could not close cache connection")
	}

	return nil
}

// LoadToken loads a token from cache
func (c *Cache) LoadToken() (*oauth2.Token, error) {
	Log.Debugf("Loading token from cache")

	tokenFile, err := ioutil.ReadFile(c.tokenPath)
	if nil != err {
		Log.Debugf("%v", err)
		return nil, fmt.Errorf("Could not read token file in %v", c.tokenPath)
	}

	var token oauth2.Token
	json.Unmarshal(tokenFile, &token)

	Log.Tracef("Got token from cache %v", token)

	return &token, nil
}

// StoreToken stores a token in the cache or updates the existing token element
func (c *Cache) StoreToken(token *oauth2.Token) error {
	Log.Debugf("Storing token to cache")

	tokenJSON, err := json.Marshal(token)
	if nil != err {
		Log.Debugf("%v", err)
		return fmt.Errorf("Could not generate token.json content")
	}

	if err := ioutil.WriteFile(c.tokenPath, tokenJSON, 0644); nil != err {
		Log.Debugf("%v", err)
		return fmt.Errorf("Could not generate token.json file")
	}

	return nil
}

// GetObject gets an object by id
func (c *Cache) GetObject(id string) (*APIObject, error) {
	Log.Tracef("Getting object %v", id)

	var object APIObject
	c.db.Where(&APIObject{ObjectID: id}).First(&object)

	Log.Tracef("Got object from cache %v", object)

	if "" != object.ObjectID {
		return &object, nil
	}

	return nil, fmt.Errorf("Could not find object %v in cache", id)
}

// GetObjectsByParent get all objects under parent id
func (c *Cache) GetObjectsByParent(parent string) ([]*APIObject, error) {
	Log.Tracef("Getting children for %v", parent)

	var objects []*APIObject
	c.db.Where("parents LIKE ?", fmt.Sprintf("%%|%v|%%", parent)).Find(&objects)

	Log.Tracef("Got objects from cache %v", objects)

	if 0 != len(objects) {
		return objects, nil
	}

	return nil, fmt.Errorf("Could not find children for parent %v in cache", parent)
}

// GetObjectByParentAndName finds a child element by name and its parent id
func (c *Cache) GetObjectByParentAndName(parent, name string) (*APIObject, error) {
	Log.Tracef("Getting object %v in parent %v", name, parent)

	var object APIObject
	c.db.Where("parents LIKE ? AND name = ?", fmt.Sprintf("%%|%v|%%", parent), name).First(&object)

	Log.Tracef("Got object from cache %v", object)

	if "" != object.ObjectID {
		return &object, nil
	}

	return nil, fmt.Errorf("Could not find object with name %v in parent %v", name, parent)
}

// DeleteObject deletes an object by id
func (c *Cache) DeleteObject(id string) error {
	c.dbAction <- cacheAction{
		action: DeleteAction,
		object: &APIObject{ObjectID: id},
	}
	return nil
}

// UpdateObject updates an object
func (c *Cache) UpdateObject(object *APIObject) error {
	c.dbAction <- cacheAction{
		action: StoreAction,
		object: object,
	}
	return nil
}

// StoreStartPageToken stores the page token for changes
func (c *Cache) StoreStartPageToken(token string) error {
	Log.Debugf("Storing page token %v in cache", token)

	c.db.Delete(&PageToken{})
	c.db.Create(&PageToken{
		Token: token,
	})

	return nil
}

// GetStartPageToken gets the start page token
func (c *Cache) GetStartPageToken() (string, error) {
	Log.Debugf("Getting start page token from cache")

	var pageToken PageToken
	c.db.First(&pageToken)

	Log.Tracef("Got start page token %v", pageToken.Token)

	if "" == pageToken.Token {
		return "", fmt.Errorf("Token not found in cache")
	}

	return pageToken.Token, nil
}
<|endoftext|>


<commit_before>package gocaffe

/*

#cgo CXXFLAGS: -I/usr/local/include/ -I/usr/local/opt/openblas/include/ -I./deps/ -O3 -Wall
#cgo LDFLAGS: -lcaffe -lboost_system -lstdc++ -lopencv_core -lopencv_highgui -lopencv_imgproc -lboost_filesystem -lopencv_imgcodecs
#include <stdlib.h>
#include "caffe.h"

*/
import "C"

import (
	"sort"
	"sync"
	"time"
	"unsafe"

	"github.com/xlvector/dlog"
)

type CaffePredictor struct {
	predictor C.CaffePredictor
}

func NewCaffePredictor(model, trained string) *CaffePredictor {
	modelpath := C.CString(model)
	defer C.free(unsafe.Pointer(modelpath))

	trainedpath := C.CString(trained)
	defer C.free(unsafe.Pointer(trainedpath))

	return &CaffePredictor{
		predictor: C.NewCaffePredictor(modelpath, trainedpath),
	}
}

func doubleToFloats(in *C.double, size int) []float64 {
	defer C.free(unsafe.Pointer(in))
	out := (*[1 << 30]float64)(unsafe.Pointer(in))[:size:size]
	out2 := make([]float64, size)
	for i, v := range out {
		out2[i] = v
	}
	return out2
}

func (p *CaffePredictor) NClass() int {
	return int(C.NClass(p.predictor))
}

func (p *CaffePredictor) Predict(imgfile string) []float64 {
	imgpath := C.CString(imgfile)
	defer C.free(unsafe.Pointer(imgpath))

	ret := C.Predict(p.predictor, imgpath)
	if ret == nil {
		return nil
	}
	return doubleToFloats(ret, p.NClass())
}

type Triple struct {
	index, label int
	prob         float64
}

type TripleSlice []Triple

func (c TripleSlice) Len() int {
	return len(c)
}
func (c TripleSlice) Swap(i, j int) {
	c[i], c[j] = c[j], c[i]
}
func (c TripleSlice) Less(i, j int) bool {
	return c[i].prob > c[j].prob
}

func (p *CaffePredictor) GreedyMatch(probs [][]float64) []int {
	trs := make(TripleSlice, 0, len(probs)*len(probs[0]))
	for i, ps := range probs {
		for l, v := range ps {
			trs = append(trs, Triple{i, l, v})
		}
	}
	sort.Sort(trs)
	ul := make([]byte, len(probs))
	ur := make([]byte, len(probs[0]))
	ret := make([]int, len(probs))
	for i := 0; i < len(ret); i++ {
		ret[i] = -1
	}
	for _, t := range trs {
		if ul[t.index] > 0 || ur[t.label] > 0 {
			continue
		}
		ul[t.index] = 1
		ur[t.label] = 1
		ret[t.index] = t.label
	}
	return ret
}

type PredictResult struct {
	index int
	prob  []float64
}

func (p *CaffePredictor) PredictBatch(imgs []string) [][]float64 {
	start := time.Now().UnixNano()
	ret := make([][]float64, len(imgs))
	wg := &sync.WaitGroup{}
	ch := make(chan PredictResult, len(imgs)+10)
	for i, img := range imgs {
		wg.Add(1)
		go func(index int, imgSrc string) {
			out := p.Predict(img)
			//ret = append(ret, out)
			ch <- PredictResult{i, out}
			wg.Done()
		}(i, img)
	}
	wg.Wait()
	close(ch)
	for pr := range ch {
		ret[pr.index] = pr.prob
	}
	dlog.Println("predict all used(ms) : ", (time.Now().UnixNano()-start)/1000000)
	return ret
}
<commit_msg>single thread<commit_after>package gocaffe

/*

#cgo CXXFLAGS: -I/usr/local/include/ -I/usr/local/opt/openblas/include/ -I./deps/ -O3 -Wall
#cgo LDFLAGS: -lcaffe -lboost_system -lstdc++ -lopencv_core -lopencv_highgui -lopencv_imgproc -lboost_filesystem -lopencv_imgcodecs
#include <stdlib.h>
#include "caffe.h"

*/
import "C"

import (
	"sort"
	"time"
	"unsafe"

	"github.com/xlvector/dlog"
)

type CaffePredictor struct {
	predictor C.CaffePredictor
}

func NewCaffePredictor(model, trained string) *CaffePredictor {
	modelpath := C.CString(model)
	defer C.free(unsafe.Pointer(modelpath))

	trainedpath := C.CString(trained)
	defer C.free(unsafe.Pointer(trainedpath))

	return &CaffePredictor{
		predictor: C.NewCaffePredictor(modelpath, trainedpath),
	}
}

func doubleToFloats(in *C.double, size int) []float64 {
	defer C.free(unsafe.Pointer(in))
	out := (*[1 << 30]float64)(unsafe.Pointer(in))[:size:size]
	out2 := make([]float64, size)
	for i, v := range out {
		out2[i] = v
	}
	return out2
}

func (p *CaffePredictor) NClass() int {
	return int(C.NClass(p.predictor))
}

func (p *CaffePredictor) Predict(imgfile string) []float64 {
	imgpath := C.CString(imgfile)
	defer C.free(unsafe.Pointer(imgpath))

	ret := C.Predict(p.predictor, imgpath)
	if ret == nil {
		return nil
	}
	return doubleToFloats(ret, p.NClass())
}

type Triple struct {
	index, label int
	prob         float64
}

type TripleSlice []Triple

func (c TripleSlice) Len() int {
	return len(c)
}
func (c TripleSlice) Swap(i, j int) {
	c[i], c[j] = c[j], c[i]
}
func (c TripleSlice) Less(i, j int) bool {
	return c[i].prob > c[j].prob
}

func (p *CaffePredictor) GreedyMatch(probs [][]float64) []int {
	trs := make(TripleSlice, 0, len(probs)*len(probs[0]))
	for i, ps := range probs {
		for l, v := range ps {
			trs = append(trs, Triple{i, l, v})
		}
	}
	sort.Sort(trs)
	ul := make([]byte, len(probs))
	ur := make([]byte, len(probs[0]))
	ret := make([]int, len(probs))
	for i := 0; i < len(ret); i++ {
		ret[i] = -1
	}
	for _, t := range trs {
		if ul[t.index] > 0 || ur[t.label] > 0 {
			continue
		}
		ul[t.index] = 1
		ur[t.label] = 1
		ret[t.index] = t.label
	}
	return ret
}

func (p *CaffePredictor) PredictBatch(imgs []string) [][]float64 {
	start := time.Now().UnixNano()
	ret := make([][]float64, 0, len(imgs))
	for i, img := range imgs {
		out := p.Predict(img)
		ret = append(ret, out)
	}
	dlog.Println("predict all used(ms) : ", (time.Now().UnixNano()-start)/1000000)
	return ret
}

/*
func (p *CaffePredictor) PredictBatch(imgs []string) [][]float64 {
	start := time.Now().UnixNano()
	ret := make([][]float64, len(imgs))
	wg := &sync.WaitGroup{}
	ch := make(chan PredictResult, len(imgs)+10)
	for i, img := range imgs {
		wg.Add(1)
		go func(index int, imgSrc string) {
			out := p.Predict(img)
			//ret = append(ret, out)
			ch <- PredictResult{i, out}
			wg.Done()
		}(i, img)
	}
	wg.Wait()
	close(ch)
	for pr := range ch {
		ret[pr.index] = pr.prob
	}
	dlog.Println("predict all used(ms) : ", (time.Now().UnixNano()-start)/1000000)
	return ret
}
*/
<|endoftext|>


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

package os

import syscall "syscall"
import os "os"

// FDs are wrappers for file descriptors
export type FD struct {
	fd int64
}

export func NewFD(fd int64) *FD {
	if fd < 0 {
		return nil
	}
	return &FD{fd}
}

export var (
	Stdin = NewFD(0);
	Stdout = NewFD(1);
	Stderr = NewFD(2);
)

export const (
	O_RDONLY = syscall.O_RDONLY;
	O_WRONLY = syscall.O_WRONLY;
	O_RDWR = syscall.O_RDWR;
	O_APPEND = syscall.O_APPEND;
	O_ASYNC = syscall.O_ASYNC;
	O_CREAT = syscall.O_CREAT;
	O_NOCTTY = syscall.O_NOCTTY;
	O_NONBLOCK = syscall.O_NONBLOCK;
	O_NDELAY = O_NONBLOCK;
	O_SYNC = syscall.O_SYNC;
	O_TRUNC = syscall.O_TRUNC;
)

export func Open(name string, mode int, flags int) (fd *FD, err *Error) {
	r, e := syscall.open(name, int64(mode), int64(flags));
	return NewFD(r), ErrnoToError(e)
}

func (fd *FD) Close() *Error {
	if fd == nil {
		return EINVAL
	}
	r, e := syscall.close(fd.fd);
	fd.fd = -1;  // so it can't be closed again
	return ErrnoToError(e)
}

func (fd *FD) Read(b *[]byte) (ret int, err *Error) {
	if fd == nil {
		return -1, EINVAL
	}
	var r, e int64;
	if len(b) > 0 {  // because we access b[0]
		r, e = syscall.read(fd.fd, &b[0], int64(len(b)));
	}
	return int(r), ErrnoToError(e)
}

func (fd *FD) Write(b *[]byte) (ret int, err *Error) {
	if fd == nil {
		return -1, EINVAL
	}
	var r, e int64;
	if len(b) > 0 {  // because we access b[0]
		r, e = syscall.write(fd.fd, &b[0], int64(len(b)));
	}
	return int(r), ErrnoToError(e)
}

func (fd *FD) WriteString(s string) (ret int, err *Error) {
	if fd == nil {
		return -1, EINVAL
	}
	b := new([]byte, len(s)+1);
	if !syscall.StringToBytes(b, s) {
		return -1, EINVAL
	}
	r, e := syscall.write(fd.fd, &b[0], int64(len(s)));
	return int(r), ErrnoToError(e)
}

export func Pipe() (fd1 *FD, fd2 *FD, err *Error) {
	var p [2]int64;
	r, e := syscall.pipe(&p);
	if e != 0 {
		return nil, nil, ErrnoToError(e)
	}
	return NewFD(p[0]), NewFD(p[1]), nil
}

export func Mkdir(name string, perm int) *Error {
	r, e := syscall.mkdir(name, int64(perm));
	return ErrnoToError(e)
}
<commit_msg>read and write never return -1 now: error return is through the error variable only<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package os

import syscall "syscall"
import os "os"

// FDs are wrappers for file descriptors
export type FD struct {
	fd int64
}

export func NewFD(fd int64) *FD {
	if fd < 0 {
		return nil
	}
	return &FD{fd}
}

export var (
	Stdin = NewFD(0);
	Stdout = NewFD(1);
	Stderr = NewFD(2);
)

export const (
	O_RDONLY = syscall.O_RDONLY;
	O_WRONLY = syscall.O_WRONLY;
	O_RDWR = syscall.O_RDWR;
	O_APPEND = syscall.O_APPEND;
	O_ASYNC = syscall.O_ASYNC;
	O_CREAT = syscall.O_CREAT;
	O_NOCTTY = syscall.O_NOCTTY;
	O_NONBLOCK = syscall.O_NONBLOCK;
	O_NDELAY = O_NONBLOCK;
	O_SYNC = syscall.O_SYNC;
	O_TRUNC = syscall.O_TRUNC;
)

export func Open(name string, mode int, flags int) (fd *FD, err *Error) {
	r, e := syscall.open(name, int64(mode), int64(flags));
	return NewFD(r), ErrnoToError(e)
}

func (fd *FD) Close() *Error {
	if fd == nil {
		return EINVAL
	}
	r, e := syscall.close(fd.fd);
	fd.fd = -1;  // so it can't be closed again
	return ErrnoToError(e)
}

func (fd *FD) Read(b *[]byte) (ret int, err *Error) {
	if fd == nil {
		return 0, EINVAL
	}
	var r, e int64;
	if len(b) > 0 {  // because we access b[0]
		r, e = syscall.read(fd.fd, &b[0], int64(len(b)));
		if r < 0 {
			r = 0
		}
	}
	return int(r), ErrnoToError(e)
}

func (fd *FD) Write(b *[]byte) (ret int, err *Error) {
	if fd == nil {
		return 0, EINVAL
	}
	var r, e int64;
	if len(b) > 0 {  // because we access b[0]
		r, e = syscall.write(fd.fd, &b[0], int64(len(b)));
		if r < 0 {
			r = 0
		}
	}
	return int(r), ErrnoToError(e)
}

func (fd *FD) WriteString(s string) (ret int, err *Error) {
	if fd == nil {
		return 0, EINVAL
	}
	b := new([]byte, len(s)+1);
	if !syscall.StringToBytes(b, s) {
		return 0, EINVAL
	}
	r, e := syscall.write(fd.fd, &b[0], int64(len(s)));
	if r < 0 {
		r = 0
	}
	return int(r), ErrnoToError(e)
}

export func Pipe() (fd1 *FD, fd2 *FD, err *Error) {
	var p [2]int64;
	r, e := syscall.pipe(&p);
	if e != 0 {
		return nil, nil, ErrnoToError(e)
	}
	return NewFD(p[0]), NewFD(p[1]), nil
}

export func Mkdir(name string, perm int) *Error {
	r, e := syscall.mkdir(name, int64(perm));
	return ErrnoToError(e)
}
<|endoftext|>


<commit_before>// Package cards provides methods for common operations on a deck of cards
package cards

import (
	"fmt"
	"math/rand"
	"time"
)

// The possible suits to use. By default this is "Spades", "Hearts", "Diamonds", "Clubs"
var Suits = []string{"Spades", "Hearts", "Diamonds", "Clubs"}

// The number of ranks (values) per suit. By default this is 13
var Ranks = 13

// Deck represents a deck of cards
type Deck []Card

// NewDeck returns a new deck of cards, in order
//
// One card will be included of each suit and rank, for a total of Ranks*len(Suits) cards
func NewDeck() Deck {
	nCards := len(Suits) * Ranks
	d := make([]Card, nCards)
	for i := 0; i < nCards; i++ {
		d[i] = Card(i)
	}
	return d
}

// Shuffle randomizes the order of the cards in the deck
func (d Deck) Shuffle() {
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	for i := range d {
		j := r.Intn(i + 1)
		d[i], d[j] = d[j], d[i]
	}
}

// Cut splits the deck into two decks of equal size
func (d Deck) Cut() (Deck, Deck) {
	// TODO: Support cutting into >2 decks
	h := len(d) / 2
	return d[:h], d[h:]
}

// Top deals the top card from the deck, removing it from the deck
func (dp *Deck) Top() Card {
	d := *dp
	c := d[0]
	if len(d) == 1 {
		d = nil
	} else {
		d = d[1:]
	}
	*dp = d
	return c
}

// TopN deals the top n cards from the deck
//
// If the deck does not have n cards, it will return all its cards and become empty
func (dp *Deck) TopN(n int) []Card {
	c := []Card{}
	for i := 0; i < n && !dp.Empty(); i++ {
		c = append(c, dp.Top())
	}
	return c
}

// Add adds card(s) to the bottom of the deck
func (dp *Deck) Add(cards ...Card) {
	d := *dp
	d = append(d, cards...)
	*dp = d
}

// Empty returns whether the deck is empty
func (d Deck) Empty() bool {
	return len(d) == 0
}

// Card represents a Card in a Deck
type Card int

// Suit returns the suit of the card
func (c Card) Suit() Suit {
	return Suit(int(c) / Ranks)
}

// Rank returns the value of the card, for comparison with the rank of other cards.
func (c Card) Rank() int {
	return int(c) % Ranks
}

// String returns a string representation of the card, e.g., "4 of Hearts", "Ace of Spades"
//
// With the default value of Ranks, the rank of the card will be returned starting at 2 until 10, then Jack, Queen, King, Ace.
//
// If Ranks has been modified from its default, the zero-indexed rank will be returned instead.
func (c Card) String() string {
	v := c.Rank()
	s := ""
	if Ranks != 13 {
		return fmt.Sprintf("%d", v)
	}
	if v < 9 {
		s = fmt.Sprintf("%d", v+2)
	} else {
		switch v {
		case 9:
			s = "Jack"
		case 10:
			s = "Queen"
		case 11:
			s = "King"
		case 12:
			s = "Ace"
		default:
			panic("bad value")
		}
	}
	return fmt.Sprintf("%s of %s", s, c.Suit())
}

// Suit represents the Suit of the card, one of Suits
type Suit int

// String returns the string representation of the card, e.g., "Hearts"
func (s Suit) String() string {
	return Suits[s]
}
<commit_msg>structify types for forward compatibility<commit_after>// Package cards provides methods for common operations on a deck of cards
package cards

import (
	"fmt"
	"math/rand"
	"time"
)

// The possible suits to use. By default this is "Spades", "Hearts", "Diamonds", "Clubs"
var Suits = []string{"Spades", "Hearts", "Diamonds", "Clubs"}

// The number of ranks (values) per suit. By default this is 13
var Ranks = 13

// Deck represents a deck of cards
type Deck []Card

// NewDeck returns a new deck of cards, in order
//
// One card will be included of each suit and rank, for a total of Ranks*len(Suits) cards
func NewDeck() Deck {
	nCards := len(Suits) * Ranks
	d := make([]Card, nCards)
	for i := 0; i < nCards; i++ {
		d[i] = Card{i}
	}
	return d
}

// Shuffle randomizes the order of the cards in the deck
func (d Deck) Shuffle() {
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	for i := range d {
		j := r.Intn(i + 1)
		d[i], d[j] = d[j], d[i]
	}
}

// Cut splits the deck into two decks of equal size
func (d Deck) Cut() (Deck, Deck) {
	// TODO: Support cutting into >2 decks
	h := len(d) / 2
	return d[:h], d[h:]
}

// Top deals the top card from the deck, removing it from the deck
func (dp *Deck) Top() Card {
	d := *dp
	c := d[0]
	if len(d) == 1 {
		d = nil
	} else {
		d = d[1:]
	}
	*dp = d
	return c
}

// TopN deals the top n cards from the deck
//
// If the deck does not have n cards, it will return all its cards and become empty
func (dp *Deck) TopN(n int) []Card {
	c := []Card{}
	for i := 0; i < n && !dp.Empty(); i++ {
		c = append(c, dp.Top())
	}
	return c
}

// Add adds card(s) to the bottom of the deck
func (dp *Deck) Add(cards ...Card) {
	d := *dp
	d = append(d, cards...)
	*dp = d
}

// Empty returns whether the deck is empty
func (d Deck) Empty() bool {
	return len(d) == 0
}

// Card represents a Card in a Deck
type Card struct {
	int
}

// Suit returns the suit of the card
func (c Card) Suit() Suit {
	return Suit{c.int / Ranks}
}

// Rank returns the value of the card, for comparison with the rank of other cards.
func (c Card) Rank() int {
	return c.int % Ranks
}

var faces = []string{"Jack", "Queen", "King", "Ace"}

// String returns a string representation of the card, e.g., "4 of Hearts", "Ace of Spades"
//
// With the default value of Ranks, the rank of the card will be returned starting at 2 until 10, then Jack, Queen, King, Ace.
//
// If Ranks has been modified from its default, the zero-indexed rank will be returned instead.
func (c Card) String() string {
	v := c.Rank()
	s := ""
	if Ranks != 13 {
		return fmt.Sprintf("%d", v)
	}
	if v < 9 {
		s = fmt.Sprintf("%d", v+2)
	} else {
		s = faces[v-9]
	}
	return fmt.Sprintf("%s of %s", s, c.Suit())
}

// Suit represents the Suit of the card, one of Suits
type Suit struct {
	int
}

// String returns the string representation of the card, e.g., "Hearts"
func (s Suit) String() string {
	return Suits[s.int]
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/http"
	"net/http/httputil"
	"net/url"
	"io/ioutil"
	"log"
	"time"
	"github.com/BurntSushi/toml"
)

type Config struct {
	Upstream string
	ReqFanFactor int
	TimeoutMS int
}

func snd (c chan string, s string) {
	go func () { c <- s }()
}

// start starts Charm up and returns a done channel for the done message
func start(confPath string) (chan string) {
	done := make(chan string)

	// print a welcome message
	log.Print("Charm is starting up.")
	// read the config file
	log.Printf(".   . Reading %s", confPath)
	tomlData, err := ioutil.ReadFile(confPath)
	if err != nil {
		snd(done, fmt.Sprintf("Could not read file at %s", confPath))
		return done
	}
	// populate the config struct
	log.Print(".   . Loading config")
	var conf Config
	_, err = toml.Decode(string(tomlData), &conf)
	if err != nil {
		snd(done, "Could not decode config")
		return done
	}
	// report on the configuration
	log.Print("Charm is configured!")
	log.Printf(".   . Stabilizing %v", conf.Upstream)
	log.Printf(".   . with %v duplicate requests", conf.ReqFanFactor)
	log.Printf(".   . and a %v milisecond timeout.", conf.TimeoutMS)
	go run(conf, done)
	return done
}

type stableTransport struct {
	wrappedTransport http.RoundTripper
	reqFanFactor int
}

// stableTransport.RoundTrip makes many round trips and returns the first
// response
func (t *stableTransport) RoundTrip(r *http.Request) (*http.Response, error) {
	c := make(chan *http.Response)
	if t.wrappedTransport == nil {
		t.wrappedTransport = http.DefaultTransport
	}
	// fan out requests, send responses to the channel, log errors
	for i := 0; i < t.reqFanFactor; i++ {
		time.Sleep(5)
		go func () {
			resp, err := t.wrappedTransport.RoundTrip(r)
			if err != nil {
				// TODO: figure out how much logging we want
			} else {
				c <- resp
			}
		}()
	}

	// return the first good response
	return <-c, nil
}

type Stabilizer struct {
	upstreamURL *url.URL
	reqFanFactor int
}

// Stabilizer.ServeHTTP proxies with a stable transport
func (st *Stabilizer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	proxy := httputil.NewSingleHostReverseProxy(st.upstreamURL)
	proxy.Transport = &stableTransport{proxy.Transport, st.reqFanFactor}
	proxy.ServeHTTP(w, r)
}

// run
func run(conf Config, done chan string) {
	// make a stabilizer
	upstreamURL, err := url.Parse(conf.Upstream)
	if err != nil {
		log.Fatal("error parsing Upstream URL", conf.Upstream)
	}
	stabilizer := &Stabilizer{upstreamURL, conf.ReqFanFactor}

	// serve that stabilizer under a timeout
	timeout := time.Duration(conf.TimeoutMS) * time.Millisecond
	log.Fatal(http.ListenAndServe(
		":8000",
		http.TimeoutHandler(stabilizer, timeout, "upstream timeout"),
	))
}

func main() {
	// start Charm,
	done := start("/secret/charm.conf")
	// when Charm is done, log the message and quit.
        log.Print(<-done)
}
<commit_msg>adds some error logging<commit_after>package main

import (
	"fmt"
	"net/http"
	"net/http/httputil"
	"net/url"
	"io/ioutil"
	"log"
	"time"
	"github.com/BurntSushi/toml"
)

type Config struct {
	Upstream string
	ReqFanFactor int
	TimeoutMS int
}

func snd (c chan string, s string) {
	go func () { c <- s }()
}

// start starts Charm up and returns a done channel for the done message
func start(confPath string) (chan string) {
	done := make(chan string)

	// print a welcome message
	log.Print("Charm is starting up.")
	// read the config file
	log.Printf(".   . Reading %s", confPath)
	tomlData, err := ioutil.ReadFile(confPath)
	if err != nil {
		snd(done, fmt.Sprintf("Could not read file at %s", confPath))
		return done
	}
	// populate the config struct
	log.Print(".   . Loading config")
	var conf Config
	_, err = toml.Decode(string(tomlData), &conf)
	if err != nil {
		snd(done, "Could not decode config")
		return done
	}
	// report on the configuration
	log.Print("Charm is configured!")
	log.Printf(".   . Stabilizing %v", conf.Upstream)
	log.Printf(".   . with %v duplicate requests", conf.ReqFanFactor)
	log.Printf(".   . and a %v milisecond timeout.", conf.TimeoutMS)
	go run(conf, done)
	return done
}

type stableTransport struct {
	wrappedTransport http.RoundTripper
	reqFanFactor int
}

// stableTransport.RoundTrip makes many round trips and returns the first
// response
func (t *stableTransport) RoundTrip(r *http.Request) (*http.Response, error) {
	c := make(chan *http.Response)
	if t.wrappedTransport == nil {
		t.wrappedTransport = http.DefaultTransport
	}
	// fan out requests, send responses to the channel, log errors
	for i := 0; i < t.reqFanFactor; i++ {
		time.Sleep(5)
		go func () {
			resp, err := t.wrappedTransport.RoundTrip(r)
			if err != nil {
				if i == 0 {
					log.Printf("transport-error: %v", err)
				}
			} else {
				c <- resp
			}
		}()
	}

	// return the first good response
	return <-c, nil
}

type Stabilizer struct {
	upstreamURL *url.URL
	reqFanFactor int
}

// Stabilizer.ServeHTTP proxies with a stable transport
func (st *Stabilizer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	proxy := httputil.NewSingleHostReverseProxy(st.upstreamURL)
	proxy.Transport = &stableTransport{proxy.Transport, st.reqFanFactor}
	proxy.ServeHTTP(w, r)
}

// run
func run(conf Config, done chan string) {
	// make a stabilizer
	upstreamURL, err := url.Parse(conf.Upstream)
	if err != nil {
		log.Fatal("error parsing Upstream URL", conf.Upstream)
	}
	stabilizer := &Stabilizer{upstreamURL, conf.ReqFanFactor}

	// serve that stabilizer under a timeout
	timeout := time.Duration(conf.TimeoutMS) * time.Millisecond
	log.Fatal(http.ListenAndServe(
		":8000",
		http.TimeoutHandler(stabilizer, timeout, "upstream timeout"),
	))
}

func main() {
	// start Charm,
	done := start("/secret/charm.conf")
	// when Charm is done, log the message and quit.
        log.Print(<-done)
}
<|endoftext|>


<commit_before>/*
   Copyright 2014 Maciej Chałapuk

   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.
*/

// vim: sw=2 ts=2 expandtab

package precond

import "fmt"

/*
  Returns nil if given predicate is true, otherwise returns error
*/
func CheckTrue(predicate bool, message string, args ...interface{}) error {
  if !predicate {
    return fmt.Errorf(message, args)
  }
  return nil
}

/*
  Returns nil if given predicate is false, otherwise returns error
*/
func CheckFalse(antiPredicate bool, message string, args ...interface{}) error {
  return CheckTrue(!antiPredicate, message, args);
}

/*
  Returns nil if given value is nil, otherwise returns error
*/
func CheckNil(value interface{}, message string, args ...interface{}) error {
  return CheckTrue(value == nil, message, args)
}

/*
  Returns nil if given value is not nil, otherwise returns error
*/
func CheckNotNil(value interface{}, message string, args ...interface{}) error {
  return CheckTrue(value != nil, message, args)
}

/*
  Returns nil if given value is contained in given range <lower, upper>,
  otherwise returns error. Uses given epsilon for float comparison.
*/
func CheckInRangeEpsilon(value float64, lower float64, upper float64,
        epsilon float64, message string, args ...interface{}) error {
  predicate := value - lower + epsilon > 0 && upper - value + epsilon > 0
  return CheckTrue(predicate, message, args)
}

/*
  Returns nil if given value is contained in given range <lower, upper>,
  otherwise returns error. Uses epsilon value of 0.00001.
*/
func CheckInRange(value float64, lower float64, upper float64,
                  message string, args ...interface{}) error {
  return CheckInRangeEpsilon(value, lower, upper, .00001, message, args)
}

<commit_msg>~ unfolding argument lists<commit_after>/*
   Copyright 2014 Maciej Chałapuk

   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.
*/

// vim: sw=2 ts=2 expandtab

package precond

import "fmt"

/*
  Returns nil if given predicate is true, otherwise returns error
*/
func CheckTrue(predicate bool, message string, args ...interface{}) error {
  if !predicate {
    return fmt.Errorf(message, args...)
  }
  return nil
}

/*
  Returns nil if given predicate is false, otherwise returns error
*/
func CheckFalse(antiPredicate bool, message string, args ...interface{}) error {
  return CheckTrue(!antiPredicate, message, args...);
}

/*
  Returns nil if given value is nil, otherwise returns error
*/
func CheckNil(value interface{}, message string, args ...interface{}) error {
  return CheckTrue(value == nil, message, args...)
}

/*
  Returns nil if given value is not nil, otherwise returns error
*/
func CheckNotNil(value interface{}, message string, args ...interface{}) error {
  return CheckTrue(value != nil, message, args...)
}

/*
  Returns nil if given value is contained in given range <lower, upper>,
  otherwise returns error. Uses given epsilon for float comparison.
*/
func CheckInRangeEpsilon(value float64, lower float64, upper float64,
        epsilon float64, message string, args ...interface{}) error {
  predicate := value - lower + epsilon > 0 && upper - value + epsilon > 0
  return CheckTrue(predicate, message, args...)
}

/*
  Returns nil if given value is contained in given range <lower, upper>,
  otherwise returns error. Uses epsilon value of 0.00001.
*/
func CheckInRange(value float64, lower float64, upper float64,
                  message string, args ...interface{}) error {
  return CheckInRangeEpsilon(value, lower, upper, .00001, message, args...)
}

<|endoftext|>