<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"reflect"
	"regexp"
	"strconv"
	"strings"
	"sync"
	"unsafe"

	"github.com/gorilla/mux"

	"github.com/lxc/lxd/lxd/db"
	"github.com/lxc/lxd/lxd/util"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/logger"
	"github.com/lxc/lxd/shared/version"
)

// DevLxdServer creates an http.Server capable of handling requests against the
// /dev/lxd Unix socket endpoint created inside containers.
func DevLxdServer(d *Daemon) *http.Server {
	return &http.Server{
		Handler:   devLxdAPI(d),
		ConnState: pidMapper.ConnStateHandler,
	}
}

type devLxdResponse struct {
	content interface{}
	code    int
	ctype   string
}

func okResponse(ct interface{}, ctype string) *devLxdResponse {
	return &devLxdResponse{ct, http.StatusOK, ctype}
}

type devLxdHandler struct {
	path string

	/*
	 * This API will have to be changed slightly when we decide to support
	 * websocket events upgrading, but since we don't have events on the
	 * server side right now either, I went the simple route to avoid
	 * needless noise.
	 */
	f func(c container, r *http.Request) *devLxdResponse
}

var configGet = devLxdHandler{"/1.0/config", func(c container, r *http.Request) *devLxdResponse {
	filtered := []string{}
	for k := range c.ExpandedConfig() {
		if strings.HasPrefix(k, "user.") {
			filtered = append(filtered, fmt.Sprintf("/1.0/config/%s", k))
		}
	}
	return okResponse(filtered, "json")
}}

var configKeyGet = devLxdHandler{"/1.0/config/{key}", func(c container, r *http.Request) *devLxdResponse {
	key := mux.Vars(r)["key"]
	if !strings.HasPrefix(key, "user.") {
		return &devLxdResponse{"not authorized", http.StatusForbidden, "raw"}
	}

	value, ok := c.ExpandedConfig()[key]
	if !ok {
		return &devLxdResponse{"not found", http.StatusNotFound, "raw"}
	}

	return okResponse(value, "raw")
}}

var metadataGet = devLxdHandler{"/1.0/meta-data", func(c container, r *http.Request) *devLxdResponse {
	value := c.ExpandedConfig()["user.meta-data"]
	return okResponse(fmt.Sprintf("#cloud-config\ninstance-id: %s\nlocal-hostname: %s\n%s", c.Name(), c.Name(), value), "raw")
}}

var handlers = []devLxdHandler{
	{"/", func(c container, r *http.Request) *devLxdResponse {
		return okResponse([]string{"/1.0"}, "json")
	}},
	{"/1.0", func(c container, r *http.Request) *devLxdResponse {
		return okResponse(shared.Jmap{"api_version": version.APIVersion}, "json")
	}},
	configGet,
	configKeyGet,
	metadataGet,
	/* TODO: events */
}

func hoistReq(f func(container, *http.Request) *devLxdResponse, d *Daemon) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		conn := extractUnderlyingConn(w)
		cred, ok := pidMapper.m[conn]
		if !ok {
			http.Error(w, pidNotInContainerErr.Error(), 500)
			return
		}

		c, err := findContainerForPid(cred.pid, d)
		if err != nil {
			http.Error(w, err.Error(), 500)
			return
		}

		// Access control
		rootUid := int64(0)

		idmapset, err := c.LastIdmapSet()
		if err == nil && idmapset != nil {
			uid, _ := idmapset.ShiftIntoNs(0, 0)
			rootUid = int64(uid)
		}

		if rootUid != cred.uid {
			http.Error(w, "Access denied for non-root user", 401)
			return
		}

		resp := f(c, r)
		if resp.code != http.StatusOK {
			http.Error(w, fmt.Sprintf("%s", resp.content), resp.code)
		} else if resp.ctype == "json" {
			w.Header().Set("Content-Type", "application/json")
			util.WriteJSON(w, resp.content, debug)
		} else {
			w.Header().Set("Content-Type", "application/octet-stream")
			fmt.Fprintf(w, resp.content.(string))
		}
	}
}

func devLxdAPI(d *Daemon) http.Handler {
	m := mux.NewRouter()

	for _, handler := range handlers {
		m.HandleFunc(handler.path, hoistReq(handler.f, d))
	}

	return m
}

/*
 * Everything below here is the guts of the unix socket bits. Unfortunately,
 * golang's API does not make this easy. What happens is:
 *
 * 1. We install a ConnState listener on the http.Server, which does the
 *    initial unix socket credential exchange. When we get a connection started
 *    event, we use SO_PEERCRED to extract the creds for the socket.
 *
 * 2. We store a map from the connection pointer to the pid for that
 *    connection, so that once the HTTP negotiation occurrs and we get a
 *    ResponseWriter, we know (because we negotiated on the first byte) which
 *    pid the connection belogs to.
 *
 * 3. Regular HTTP negotiation and dispatch occurs via net/http.
 *
 * 4. When rendering the response via ResponseWriter, we match its underlying
 *    connection against what we stored in step (2) to figure out which container
 *    it came from.
 */

/*
 * We keep this in a global so that we can reference it from the server and
 * from our http handlers, since there appears to be no way to pass information
 * around here.
 */
var pidMapper = ConnPidMapper{m: map[*net.UnixConn]*ucred{}}

type ucred struct {
	pid int32
	uid int64
	gid int64
}

type ConnPidMapper struct {
	m     map[*net.UnixConn]*ucred
	mLock sync.Mutex
}

func (m *ConnPidMapper) ConnStateHandler(conn net.Conn, state http.ConnState) {
	unixConn := conn.(*net.UnixConn)
	switch state {
	case http.StateNew:
		cred, err := getCred(unixConn)
		if err != nil {
			logger.Debugf("Error getting ucred for conn %s", err)
		} else {
			m.mLock.Lock()
			m.m[unixConn] = cred
			m.mLock.Unlock()
		}
	case http.StateActive:
		return
	case http.StateIdle:
		return
	case http.StateHijacked:
		/*
		 * The "Hijacked" state indicates that the connection has been
		 * taken over from net/http. This is useful for things like
		 * developing websocket libraries, who want to upgrade the
		 * connection to a websocket one, and not use net/http any
		 * more. Whatever the case, we want to forget about it since we
		 * won't see it either.
		 */
		m.mLock.Lock()
		delete(m.m, unixConn)
		m.mLock.Unlock()
	case http.StateClosed:
		m.mLock.Lock()
		delete(m.m, unixConn)
		m.mLock.Unlock()
	default:
		logger.Debugf("Unknown state for connection %s", state)
	}
}

/*
 * I also don't see that golang exports an API to get at the underlying FD, but
 * we need it to get at SO_PEERCRED, so let's grab it.
 */
func extractUnderlyingFd(unixConnPtr *net.UnixConn) (int, error) {
	conn := reflect.Indirect(reflect.ValueOf(unixConnPtr))

	netFdPtr := conn.FieldByName("fd")
	if !netFdPtr.IsValid() {
		return -1, fmt.Errorf("Unable to extract fd from net.UnixConn")
	}
	netFd := reflect.Indirect(netFdPtr)

	fd := netFd.FieldByName("sysfd")
	if !fd.IsValid() {
		// Try under the new name
		pfdPtr := netFd.FieldByName("pfd")
		if !pfdPtr.IsValid() {
			return -1, fmt.Errorf("Unable to extract pfd from netFD")
		}
		pfd := reflect.Indirect(pfdPtr)

		fd = pfd.FieldByName("Sysfd")
		if !fd.IsValid() {
			return -1, fmt.Errorf("Unable to extract Sysfd from poll.FD")
		}
	}

	return int(fd.Int()), nil
}

func getCred(conn *net.UnixConn) (*ucred, error) {
	fd, err := extractUnderlyingFd(conn)
	if err != nil {
		return nil, err
	}

	uid, gid, pid, err := getUcred(fd)
	if err != nil {
		return nil, err
	}

	return &ucred{pid, int64(uid), int64(gid)}, nil
}

/*
 * As near as I can tell, there is no nice way of extracting an underlying
 * net.Conn (or in our case, net.UnixConn) from an http.Request or
 * ResponseWriter without hijacking it [1]. Since we want to send and receive
 * unix creds to figure out which container this request came from, we need to
 * do this.
 *
 * [1]: https://groups.google.com/forum/#!topic/golang-nuts/_FWdFXJa6QA
 */
func extractUnderlyingConn(w http.ResponseWriter) *net.UnixConn {
	v := reflect.Indirect(reflect.ValueOf(w))
	connPtr := v.FieldByName("conn")
	conn := reflect.Indirect(connPtr)
	rwc := conn.FieldByName("rwc")

	netConnPtr := (*net.Conn)(unsafe.Pointer(rwc.UnsafeAddr()))
	unixConnPtr := (*netConnPtr).(*net.UnixConn)

	return unixConnPtr
}

var pidNotInContainerErr = fmt.Errorf("pid not in container?")

func findContainerForPid(pid int32, d *Daemon) (container, error) {
	/*
	 * Try and figure out which container a pid is in. There is probably a
	 * better way to do this. Based on rharper's initial performance
	 * metrics, looping over every container and calling newLxdContainer is
	 * expensive, so I wanted to avoid that if possible, so this happens in
	 * a two step process:
	 *
	 * 1. Walk up the process tree until you see something that looks like
	 *    an lxc monitor process and extract its name from there.
	 *
	 * 2. If this fails, it may be that someone did an `lxc exec foo bash`,
	 *    so the process isn't actually a descendant of the container's
	 *    init. In this case we just look through all the containers until
	 *    we find an init with a matching pid namespace. This is probably
	 *    uncommon, so hopefully the slowness won't hurt us.
	 */

	origpid := pid

	for pid > 1 {
		cmdline, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/cmdline", pid))
		if err != nil {
			return nil, err
		}

		if strings.HasPrefix(string(cmdline), "[lxc monitor]") {
			// container names can't have spaces
			parts := strings.Split(string(cmdline), " ")
			name := strings.TrimSuffix(parts[len(parts)-1], "\x00")

			return containerLoadByName(d.State(), name)
		}

		status, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/status", pid))
		if err != nil {
			return nil, err
		}

		re := regexp.MustCompile("PPid:\\s*([0-9]*)")
		for _, line := range strings.Split(string(status), "\n") {
			m := re.FindStringSubmatch(line)
			if m != nil && len(m) > 1 {
				result, err := strconv.Atoi(m[1])
				if err != nil {
					return nil, err
				}

				pid = int32(result)
				break
			}
		}
	}

	origPidNs, err := os.Readlink(fmt.Sprintf("/proc/%d/ns/pid", origpid))
	if err != nil {
		return nil, err
	}

	containers, err := d.db.ContainersList(db.CTypeRegular)
	if err != nil {
		return nil, err
	}

	for _, container := range containers {
		c, err := containerLoadByName(d.State(), container)
		if err != nil {
			return nil, err
		}

		if !c.IsRunning() {
			continue
		}

		initpid := c.InitPID()
		pidNs, err := os.Readlink(fmt.Sprintf("/proc/%d/ns/pid", initpid))
		if err != nil {
			return nil, err
		}

		if origPidNs == pidNs {
			return c, nil
		}
	}

	return nil, pidNotInContainerErr
}
<commit_msg>devlxd: Cleanup in preparation for events<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"reflect"
	"regexp"
	"strconv"
	"strings"
	"sync"
	"unsafe"

	"github.com/gorilla/mux"

	"github.com/lxc/lxd/lxd/db"
	"github.com/lxc/lxd/lxd/util"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/logger"
	"github.com/lxc/lxd/shared/version"
)

// DevLxdServer creates an http.Server capable of handling requests against the
// /dev/lxd Unix socket endpoint created inside containers.
func DevLxdServer(d *Daemon) *http.Server {
	return &http.Server{
		Handler:   devLxdAPI(d),
		ConnState: pidMapper.ConnStateHandler,
	}
}

type devLxdResponse struct {
	content interface{}
	code    int
	ctype   string
}

func okResponse(ct interface{}, ctype string) *devLxdResponse {
	return &devLxdResponse{ct, http.StatusOK, ctype}
}

type devLxdHandler struct {
	path string

	/*
	 * This API will have to be changed slightly when we decide to support
	 * websocket events upgrading, but since we don't have events on the
	 * server side right now either, I went the simple route to avoid
	 * needless noise.
	 */
	f func(c container, w http.ResponseWriter, r *http.Request) *devLxdResponse
}

var devlxdConfigGet = devLxdHandler{"/1.0/config", func(c container, w http.ResponseWriter, r *http.Request) *devLxdResponse {
	filtered := []string{}
	for k := range c.ExpandedConfig() {
		if strings.HasPrefix(k, "user.") {
			filtered = append(filtered, fmt.Sprintf("/1.0/config/%s", k))
		}
	}
	return okResponse(filtered, "json")
}}

var devlxdConfigKeyGet = devLxdHandler{"/1.0/config/{key}", func(c container, w http.ResponseWriter, r *http.Request) *devLxdResponse {
	key := mux.Vars(r)["key"]
	if !strings.HasPrefix(key, "user.") {
		return &devLxdResponse{"not authorized", http.StatusForbidden, "raw"}
	}

	value, ok := c.ExpandedConfig()[key]
	if !ok {
		return &devLxdResponse{"not found", http.StatusNotFound, "raw"}
	}

	return okResponse(value, "raw")
}}

var devlxdMetadataGet = devLxdHandler{"/1.0/meta-data", func(c container, w http.ResponseWriter, r *http.Request) *devLxdResponse {
	value := c.ExpandedConfig()["user.meta-data"]
	return okResponse(fmt.Sprintf("#cloud-config\ninstance-id: %s\nlocal-hostname: %s\n%s", c.Name(), c.Name(), value), "raw")
}}

var handlers = []devLxdHandler{
	{"/", func(c container, w http.ResponseWriter, r *http.Request) *devLxdResponse {
		return okResponse([]string{"/1.0"}, "json")
	}},
	{"/1.0", func(c container, w http.ResponseWriter, r *http.Request) *devLxdResponse {
		return okResponse(shared.Jmap{"api_version": version.APIVersion}, "json")
	}},
	devlxdConfigGet,
	devlxdConfigKeyGet,
	devlxdMetadataGet,
}

func hoistReq(f func(container, http.ResponseWriter, *http.Request) *devLxdResponse, d *Daemon) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		conn := extractUnderlyingConn(w)
		cred, ok := pidMapper.m[conn]
		if !ok {
			http.Error(w, pidNotInContainerErr.Error(), 500)
			return
		}

		c, err := findContainerForPid(cred.pid, d)
		if err != nil {
			http.Error(w, err.Error(), 500)
			return
		}

		// Access control
		rootUid := int64(0)

		idmapset, err := c.LastIdmapSet()
		if err == nil && idmapset != nil {
			uid, _ := idmapset.ShiftIntoNs(0, 0)
			rootUid = int64(uid)
		}

		if rootUid != cred.uid {
			http.Error(w, "Access denied for non-root user", 401)
			return
		}

		resp := f(c, w, r)
		if resp.code != http.StatusOK {
			http.Error(w, fmt.Sprintf("%s", resp.content), resp.code)
		} else if resp.ctype == "json" {
			w.Header().Set("Content-Type", "application/json")
			util.WriteJSON(w, resp.content, debug)
		} else if resp.ctype != "websocket" {
			w.Header().Set("Content-Type", "application/octet-stream")
			fmt.Fprintf(w, resp.content.(string))
		}
	}
}

func devLxdAPI(d *Daemon) http.Handler {
	m := mux.NewRouter()

	for _, handler := range handlers {
		m.HandleFunc(handler.path, hoistReq(handler.f, d))
	}

	return m
}

/*
 * Everything below here is the guts of the unix socket bits. Unfortunately,
 * golang's API does not make this easy. What happens is:
 *
 * 1. We install a ConnState listener on the http.Server, which does the
 *    initial unix socket credential exchange. When we get a connection started
 *    event, we use SO_PEERCRED to extract the creds for the socket.
 *
 * 2. We store a map from the connection pointer to the pid for that
 *    connection, so that once the HTTP negotiation occurrs and we get a
 *    ResponseWriter, we know (because we negotiated on the first byte) which
 *    pid the connection belogs to.
 *
 * 3. Regular HTTP negotiation and dispatch occurs via net/http.
 *
 * 4. When rendering the response via ResponseWriter, we match its underlying
 *    connection against what we stored in step (2) to figure out which container
 *    it came from.
 */

/*
 * We keep this in a global so that we can reference it from the server and
 * from our http handlers, since there appears to be no way to pass information
 * around here.
 */
var pidMapper = ConnPidMapper{m: map[*net.UnixConn]*ucred{}}

type ucred struct {
	pid int32
	uid int64
	gid int64
}

type ConnPidMapper struct {
	m     map[*net.UnixConn]*ucred
	mLock sync.Mutex
}

func (m *ConnPidMapper) ConnStateHandler(conn net.Conn, state http.ConnState) {
	unixConn := conn.(*net.UnixConn)
	switch state {
	case http.StateNew:
		cred, err := getCred(unixConn)
		if err != nil {
			logger.Debugf("Error getting ucred for conn %s", err)
		} else {
			m.mLock.Lock()
			m.m[unixConn] = cred
			m.mLock.Unlock()
		}
	case http.StateActive:
		return
	case http.StateIdle:
		return
	case http.StateHijacked:
		/*
		 * The "Hijacked" state indicates that the connection has been
		 * taken over from net/http. This is useful for things like
		 * developing websocket libraries, who want to upgrade the
		 * connection to a websocket one, and not use net/http any
		 * more. Whatever the case, we want to forget about it since we
		 * won't see it either.
		 */
		m.mLock.Lock()
		delete(m.m, unixConn)
		m.mLock.Unlock()
	case http.StateClosed:
		m.mLock.Lock()
		delete(m.m, unixConn)
		m.mLock.Unlock()
	default:
		logger.Debugf("Unknown state for connection %s", state)
	}
}

/*
 * I also don't see that golang exports an API to get at the underlying FD, but
 * we need it to get at SO_PEERCRED, so let's grab it.
 */
func extractUnderlyingFd(unixConnPtr *net.UnixConn) (int, error) {
	conn := reflect.Indirect(reflect.ValueOf(unixConnPtr))

	netFdPtr := conn.FieldByName("fd")
	if !netFdPtr.IsValid() {
		return -1, fmt.Errorf("Unable to extract fd from net.UnixConn")
	}
	netFd := reflect.Indirect(netFdPtr)

	fd := netFd.FieldByName("sysfd")
	if !fd.IsValid() {
		// Try under the new name
		pfdPtr := netFd.FieldByName("pfd")
		if !pfdPtr.IsValid() {
			return -1, fmt.Errorf("Unable to extract pfd from netFD")
		}
		pfd := reflect.Indirect(pfdPtr)

		fd = pfd.FieldByName("Sysfd")
		if !fd.IsValid() {
			return -1, fmt.Errorf("Unable to extract Sysfd from poll.FD")
		}
	}

	return int(fd.Int()), nil
}

func getCred(conn *net.UnixConn) (*ucred, error) {
	fd, err := extractUnderlyingFd(conn)
	if err != nil {
		return nil, err
	}

	uid, gid, pid, err := getUcred(fd)
	if err != nil {
		return nil, err
	}

	return &ucred{pid, int64(uid), int64(gid)}, nil
}

/*
 * As near as I can tell, there is no nice way of extracting an underlying
 * net.Conn (or in our case, net.UnixConn) from an http.Request or
 * ResponseWriter without hijacking it [1]. Since we want to send and receive
 * unix creds to figure out which container this request came from, we need to
 * do this.
 *
 * [1]: https://groups.google.com/forum/#!topic/golang-nuts/_FWdFXJa6QA
 */
func extractUnderlyingConn(w http.ResponseWriter) *net.UnixConn {
	v := reflect.Indirect(reflect.ValueOf(w))
	connPtr := v.FieldByName("conn")
	conn := reflect.Indirect(connPtr)
	rwc := conn.FieldByName("rwc")

	netConnPtr := (*net.Conn)(unsafe.Pointer(rwc.UnsafeAddr()))
	unixConnPtr := (*netConnPtr).(*net.UnixConn)

	return unixConnPtr
}

var pidNotInContainerErr = fmt.Errorf("pid not in container?")

func findContainerForPid(pid int32, d *Daemon) (container, error) {
	/*
	 * Try and figure out which container a pid is in. There is probably a
	 * better way to do this. Based on rharper's initial performance
	 * metrics, looping over every container and calling newLxdContainer is
	 * expensive, so I wanted to avoid that if possible, so this happens in
	 * a two step process:
	 *
	 * 1. Walk up the process tree until you see something that looks like
	 *    an lxc monitor process and extract its name from there.
	 *
	 * 2. If this fails, it may be that someone did an `lxc exec foo bash`,
	 *    so the process isn't actually a descendant of the container's
	 *    init. In this case we just look through all the containers until
	 *    we find an init with a matching pid namespace. This is probably
	 *    uncommon, so hopefully the slowness won't hurt us.
	 */

	origpid := pid

	for pid > 1 {
		cmdline, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/cmdline", pid))
		if err != nil {
			return nil, err
		}

		if strings.HasPrefix(string(cmdline), "[lxc monitor]") {
			// container names can't have spaces
			parts := strings.Split(string(cmdline), " ")
			name := strings.TrimSuffix(parts[len(parts)-1], "\x00")

			return containerLoadByName(d.State(), name)
		}

		status, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/status", pid))
		if err != nil {
			return nil, err
		}

		re := regexp.MustCompile("PPid:\\s*([0-9]*)")
		for _, line := range strings.Split(string(status), "\n") {
			m := re.FindStringSubmatch(line)
			if m != nil && len(m) > 1 {
				result, err := strconv.Atoi(m[1])
				if err != nil {
					return nil, err
				}

				pid = int32(result)
				break
			}
		}
	}

	origPidNs, err := os.Readlink(fmt.Sprintf("/proc/%d/ns/pid", origpid))
	if err != nil {
		return nil, err
	}

	containers, err := d.db.ContainersList(db.CTypeRegular)
	if err != nil {
		return nil, err
	}

	for _, container := range containers {
		c, err := containerLoadByName(d.State(), container)
		if err != nil {
			return nil, err
		}

		if !c.IsRunning() {
			continue
		}

		initpid := c.InitPID()
		pidNs, err := os.Readlink(fmt.Sprintf("/proc/%d/ns/pid", initpid))
		if err != nil {
			return nil, err
		}

		if origPidNs == pidNs {
			return c, nil
		}
	}

	return nil, pidNotInContainerErr
}
<|endoftext|>


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

package view

import (
	"errors"
	"fmt"
	"strings"
	"time"

	"go.opencensus.io/stats"
	"go.opencensus.io/stats/internal"
	"go.opencensus.io/tag"
)

type command interface {
	handleCommand(w *worker)
}

// getViewByNameReq is the command to get a view given its name.
type getViewByNameReq struct {
	name string
	c    chan *getViewByNameResp
}

type getViewByNameResp struct {
	v *View
}

func (cmd *getViewByNameReq) handleCommand(w *worker) {
	v := w.views[cmd.name]
	if v == nil {
		cmd.c <- &getViewByNameResp{nil}
		return
	}
	cmd.c <- &getViewByNameResp{v.view}
}

// registerViewReq is the command to register a view.
type registerViewReq struct {
	views []*View
	err   chan error
}

func (cmd *registerViewReq) handleCommand(w *worker) {
	for _, v := range cmd.views {
		if err := v.canonicalize(); err != nil {
			cmd.err <- err
			return
		}
	}
	var errstr []string
	for _, view := range cmd.views {
		vi, err := w.tryRegisterView(view)
		if err != nil {
			errstr = append(errstr, fmt.Sprintf("%s: %v", view.Name, err))
			continue
		}
		internal.SubscriptionReporter(view.Measure.Name())
		vi.subscribe()
	}
	if len(errstr) > 0 {
		cmd.err <- errors.New(strings.Join(errstr, "\n"))
	} else {
		cmd.err <- nil
	}
}

// unregisterFromViewReq is the command to unregister to a view. Has no
// impact on the data collection for client that are pulling data from the
// library.
type unregisterFromViewReq struct {
	views []string
	done  chan struct{}
}

func (cmd *unregisterFromViewReq) handleCommand(w *worker) {
	for _, name := range cmd.views {
		vi, ok := w.views[name]
		if !ok {
			continue
		}

		// Report pending data for this view before removing it.
		w.reportView(vi, time.Now())

		vi.unsubscribe()
		if !vi.isSubscribed() {
			// this was the last subscription and view is not collecting anymore.
			// The collected data can be cleared.
			vi.clearRows()
		}
		w.unregisterView(name)
	}
	cmd.done <- struct{}{}
}

// retrieveDataReq is the command to retrieve data for a view.
type retrieveDataReq struct {
	now time.Time
	v   string
	c   chan *retrieveDataResp
}

type retrieveDataResp struct {
	rows []*Row
	err  error
}

func (cmd *retrieveDataReq) handleCommand(w *worker) {
	w.mu.Lock()
	defer w.mu.Unlock()
	vi, ok := w.views[cmd.v]
	if !ok {
		cmd.c <- &retrieveDataResp{
			nil,
			fmt.Errorf("cannot retrieve data; view %q is not registered", cmd.v),
		}
		return
	}

	if !vi.isSubscribed() {
		cmd.c <- &retrieveDataResp{
			nil,
			fmt.Errorf("cannot retrieve data; view %q has no subscriptions or collection is not forcibly started", cmd.v),
		}
		return
	}
	cmd.c <- &retrieveDataResp{
		vi.collectedRows(),
		nil,
	}
}

// recordReq is the command to record data related to multiple measures
// at once.
type recordReq struct {
	tm          *tag.Map
	ms          []stats.Measurement
	attachments map[string]interface{}
	t           time.Time
}

func (cmd *recordReq) handleCommand(w *worker) {
	w.mu.Lock()
	defer w.mu.Unlock()
	for _, m := range cmd.ms {
		if (m == stats.Measurement{}) { // not registered
			continue
		}
		ref := w.getMeasureRef(m.Measure().Name())
		for v := range ref.views {
			v.addSample(cmd.tm, m.Value(), cmd.attachments, time.Now())
		}
	}
}

// setReportingPeriodReq is the command to modify the duration between
// reporting the collected data to the registered clients.
type setReportingPeriodReq struct {
	d time.Duration
	c chan bool
}

func (cmd *setReportingPeriodReq) handleCommand(w *worker) {
	w.timer.Stop()
	if cmd.d <= 0 {
		w.timer = time.NewTicker(defaultReportingDuration)
	} else {
		w.timer = time.NewTicker(cmd.d)
	}
	cmd.c <- true
}
<commit_msg>Remove call to time.Now() on worker thread when handling record reqs (#1210)<commit_after>// Copyright 2017, OpenCensus Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

package view

import (
	"errors"
	"fmt"
	"strings"
	"time"

	"go.opencensus.io/stats"
	"go.opencensus.io/stats/internal"
	"go.opencensus.io/tag"
)

type command interface {
	handleCommand(w *worker)
}

// getViewByNameReq is the command to get a view given its name.
type getViewByNameReq struct {
	name string
	c    chan *getViewByNameResp
}

type getViewByNameResp struct {
	v *View
}

func (cmd *getViewByNameReq) handleCommand(w *worker) {
	v := w.views[cmd.name]
	if v == nil {
		cmd.c <- &getViewByNameResp{nil}
		return
	}
	cmd.c <- &getViewByNameResp{v.view}
}

// registerViewReq is the command to register a view.
type registerViewReq struct {
	views []*View
	err   chan error
}

func (cmd *registerViewReq) handleCommand(w *worker) {
	for _, v := range cmd.views {
		if err := v.canonicalize(); err != nil {
			cmd.err <- err
			return
		}
	}
	var errstr []string
	for _, view := range cmd.views {
		vi, err := w.tryRegisterView(view)
		if err != nil {
			errstr = append(errstr, fmt.Sprintf("%s: %v", view.Name, err))
			continue
		}
		internal.SubscriptionReporter(view.Measure.Name())
		vi.subscribe()
	}
	if len(errstr) > 0 {
		cmd.err <- errors.New(strings.Join(errstr, "\n"))
	} else {
		cmd.err <- nil
	}
}

// unregisterFromViewReq is the command to unregister to a view. Has no
// impact on the data collection for client that are pulling data from the
// library.
type unregisterFromViewReq struct {
	views []string
	done  chan struct{}
}

func (cmd *unregisterFromViewReq) handleCommand(w *worker) {
	for _, name := range cmd.views {
		vi, ok := w.views[name]
		if !ok {
			continue
		}

		// Report pending data for this view before removing it.
		w.reportView(vi, time.Now())

		vi.unsubscribe()
		if !vi.isSubscribed() {
			// this was the last subscription and view is not collecting anymore.
			// The collected data can be cleared.
			vi.clearRows()
		}
		w.unregisterView(name)
	}
	cmd.done <- struct{}{}
}

// retrieveDataReq is the command to retrieve data for a view.
type retrieveDataReq struct {
	now time.Time
	v   string
	c   chan *retrieveDataResp
}

type retrieveDataResp struct {
	rows []*Row
	err  error
}

func (cmd *retrieveDataReq) handleCommand(w *worker) {
	w.mu.Lock()
	defer w.mu.Unlock()
	vi, ok := w.views[cmd.v]
	if !ok {
		cmd.c <- &retrieveDataResp{
			nil,
			fmt.Errorf("cannot retrieve data; view %q is not registered", cmd.v),
		}
		return
	}

	if !vi.isSubscribed() {
		cmd.c <- &retrieveDataResp{
			nil,
			fmt.Errorf("cannot retrieve data; view %q has no subscriptions or collection is not forcibly started", cmd.v),
		}
		return
	}
	cmd.c <- &retrieveDataResp{
		vi.collectedRows(),
		nil,
	}
}

// recordReq is the command to record data related to multiple measures
// at once.
type recordReq struct {
	tm          *tag.Map
	ms          []stats.Measurement
	attachments map[string]interface{}
	t           time.Time
}

func (cmd *recordReq) handleCommand(w *worker) {
	w.mu.Lock()
	defer w.mu.Unlock()
	for _, m := range cmd.ms {
		if (m == stats.Measurement{}) { // not registered
			continue
		}
		ref := w.getMeasureRef(m.Measure().Name())
		for v := range ref.views {
			v.addSample(cmd.tm, m.Value(), cmd.attachments, cmd.t)
		}
	}
}

// setReportingPeriodReq is the command to modify the duration between
// reporting the collected data to the registered clients.
type setReportingPeriodReq struct {
	d time.Duration
	c chan bool
}

func (cmd *setReportingPeriodReq) handleCommand(w *worker) {
	w.timer.Stop()
	if cmd.d <= 0 {
		w.timer = time.NewTicker(defaultReportingDuration)
	} else {
		w.timer = time.NewTicker(cmd.d)
	}
	cmd.c <- true
}
<|endoftext|>


<commit_before>// +build linux

package nsinit

import (
	"fmt"
	"github.com/dotcloud/docker/pkg/system"
	"io/ioutil"
	"os"
	"path/filepath"
	"syscall"
)

// default mount point flags
const defaultMountFlags = syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NODEV

// setupNewMountNamespace is used to initialize a new mount namespace for an new
// container in the rootfs that is specified.
//
// There is no need to unmount the new mounts because as soon as the mount namespace
// is no longer in use, the mounts will be removed automatically
func setupNewMountNamespace(rootfs, console string, readonly, noPivotRoot bool) error {
	flag := syscall.MS_PRIVATE
	if noPivotRoot {
		flag = syscall.MS_SLAVE
	}
	if err := system.Mount("", "/", "", uintptr(flag|syscall.MS_REC), ""); err != nil {
		return fmt.Errorf("mounting / as slave %s", err)
	}
	if err := system.Mount(rootfs, rootfs, "bind", syscall.MS_BIND|syscall.MS_REC, ""); err != nil {
		return fmt.Errorf("mouting %s as bind %s", rootfs, err)
	}
	if readonly {
		if err := system.Mount(rootfs, rootfs, "bind", syscall.MS_BIND|syscall.MS_REMOUNT|syscall.MS_RDONLY|syscall.MS_REC, ""); err != nil {
			return fmt.Errorf("mounting %s as readonly %s", rootfs, err)
		}
	}
	if err := mountSystem(rootfs); err != nil {
		return fmt.Errorf("mount system %s", err)
	}
	if err := copyDevNodes(rootfs); err != nil {
		return fmt.Errorf("copy dev nodes %s", err)
	}
	// In non-privileged mode, this fails. Discard the error.
	setupLoopbackDevices(rootfs)
	if err := setupDev(rootfs); err != nil {
		return err
	}
	if console != "" {
		if err := setupPtmx(rootfs, console); err != nil {
			return err
		}
	}
	if err := system.Chdir(rootfs); err != nil {
		return fmt.Errorf("chdir into %s %s", rootfs, err)
	}

	if noPivotRoot {
		if err := rootMsMove(rootfs); err != nil {
			return err
		}
	} else {
		if err := rootPivot(rootfs); err != nil {
			return err
		}
	}

	system.Umask(0022)

	return nil
}

// use a pivot root to setup the rootfs
func rootPivot(rootfs string) error {
	pivotDir, err := ioutil.TempDir(rootfs, ".pivot_root")
	if err != nil {
		return fmt.Errorf("can't create pivot_root dir %s", pivotDir, err)
	}
	if err := system.Pivotroot(rootfs, pivotDir); err != nil {
		return fmt.Errorf("pivot_root %s", err)
	}
	if err := system.Chdir("/"); err != nil {
		return fmt.Errorf("chdir / %s", err)
	}
	// path to pivot dir now changed, update
	pivotDir = filepath.Join("/", filepath.Base(pivotDir))
	if err := system.Unmount(pivotDir, syscall.MNT_DETACH); err != nil {
		return fmt.Errorf("unmount pivot_root dir %s", err)
	}
	if err := os.Remove(pivotDir); err != nil {
		return fmt.Errorf("remove pivot_root dir %s", err)
	}
	return nil
}

// use MS_MOVE and chroot to setup the rootfs
func rootMsMove(rootfs string) error {
	if err := system.Mount(rootfs, "/", "", syscall.MS_MOVE, ""); err != nil {
		return fmt.Errorf("mount move %s into / %s", rootfs, err)
	}
	if err := system.Chroot("."); err != nil {
		return fmt.Errorf("chroot . %s", err)
	}
	if err := system.Chdir("/"); err != nil {
		return fmt.Errorf("chdir / %s", err)
	}
	return nil
}

// copyDevNodes mknods the hosts devices so the new container has access to them
func copyDevNodes(rootfs string) error {
	oldMask := system.Umask(0000)
	defer system.Umask(oldMask)

	for _, node := range []string{
		"null",
		"zero",
		"full",
		"random",
		"urandom",
		"tty",
	} {
		if err := copyDevNode(rootfs, node); err != nil {
			return err
		}
	}
	return nil
}

func setupLoopbackDevices(rootfs string) error {
	for i := 0; ; i++ {
		if err := copyDevNode(rootfs, fmt.Sprintf("loop%d", i)); err != nil {
			if !os.IsNotExist(err) {
				return err
			}
			break
		}

	}
	return nil
}

func copyDevNode(rootfs, node string) error {
	stat, err := os.Stat(filepath.Join("/dev", node))
	if err != nil {
		return err
	}
	var (
		dest = filepath.Join(rootfs, "dev", node)
		st   = stat.Sys().(*syscall.Stat_t)
	)
	if err := system.Mknod(dest, st.Mode, int(st.Rdev)); err != nil && !os.IsExist(err) {
		return fmt.Errorf("copy %s %s", node, err)
	}
	return nil
}

// setupDev symlinks the current processes pipes into the
// appropriate destination on the containers rootfs
func setupDev(rootfs string) error {
	for _, link := range []struct {
		from string
		to   string
	}{
		{"/proc/kcore", "/dev/core"},
		{"/proc/self/fd", "/dev/fd"},
		{"/proc/self/fd/0", "/dev/stdin"},
		{"/proc/self/fd/1", "/dev/stdout"},
		{"/proc/self/fd/2", "/dev/stderr"},
	} {
		dest := filepath.Join(rootfs, link.to)
		if err := os.Remove(dest); err != nil && !os.IsNotExist(err) {
			return fmt.Errorf("remove %s %s", dest, err)
		}
		if err := os.Symlink(link.from, dest); err != nil {
			return fmt.Errorf("symlink %s %s", dest, err)
		}
	}
	return nil
}

// setupConsole ensures that the container has a proper /dev/console setup
func setupConsole(rootfs, console string) error {
	oldMask := system.Umask(0000)
	defer system.Umask(oldMask)

	stat, err := os.Stat(console)
	if err != nil {
		return fmt.Errorf("stat console %s %s", console, err)
	}
	var (
		st   = stat.Sys().(*syscall.Stat_t)
		dest = filepath.Join(rootfs, "dev/console")
	)
	if err := os.Remove(dest); err != nil && !os.IsNotExist(err) {
		return fmt.Errorf("remove %s %s", dest, err)
	}
	if err := os.Chmod(console, 0600); err != nil {
		return err
	}
	if err := os.Chown(console, 0, 0); err != nil {
		return err
	}
	if err := system.Mknod(dest, (st.Mode&^07777)|0600, int(st.Rdev)); err != nil {
		return fmt.Errorf("mknod %s %s", dest, err)
	}
	if err := system.Mount(console, dest, "bind", syscall.MS_BIND, ""); err != nil {
		return fmt.Errorf("bind %s to %s %s", console, dest, err)
	}
	return nil
}

// mountSystem sets up linux specific system mounts like sys, proc, shm, and devpts
// inside the mount namespace
func mountSystem(rootfs string) error {
	for _, m := range []struct {
		source string
		path   string
		device string
		flags  int
		data   string
	}{
		{source: "proc", path: filepath.Join(rootfs, "proc"), device: "proc", flags: defaultMountFlags},
		{source: "sysfs", path: filepath.Join(rootfs, "sys"), device: "sysfs", flags: defaultMountFlags},
		{source: "shm", path: filepath.Join(rootfs, "dev", "shm"), device: "tmpfs", flags: defaultMountFlags, data: "mode=1777,size=65536k"},
		{source: "devpts", path: filepath.Join(rootfs, "dev", "pts"), device: "devpts", flags: syscall.MS_NOSUID | syscall.MS_NOEXEC, data: "newinstance,ptmxmode=0666,mode=620,gid=5"},
	} {
		if err := os.MkdirAll(m.path, 0755); err != nil && !os.IsExist(err) {
			return fmt.Errorf("mkdirall %s %s", m.path, err)
		}
		if err := system.Mount(m.source, m.path, m.device, uintptr(m.flags), m.data); err != nil {
			return fmt.Errorf("mounting %s into %s %s", m.source, m.path, err)
		}
	}
	return nil
}

// setupPtmx adds a symlink to pts/ptmx for /dev/ptmx and
// finishes setting up /dev/console
func setupPtmx(rootfs, console string) error {
	ptmx := filepath.Join(rootfs, "dev/ptmx")
	if err := os.Remove(ptmx); err != nil && !os.IsNotExist(err) {
		return err
	}
	if err := os.Symlink("pts/ptmx", ptmx); err != nil {
		return fmt.Errorf("symlink dev ptmx %s", err)
	}
	if err := setupConsole(rootfs, console); err != nil {
		return err
	}
	return nil
}

// remountProc is used to detach and remount the proc filesystem
// commonly needed with running a new process inside an existing container
func remountProc() error {
	if err := system.Unmount("/proc", syscall.MNT_DETACH); err != nil {
		return err
	}
	if err := system.Mount("proc", "/proc", "proc", uintptr(defaultMountFlags), ""); err != nil {
		return err
	}
	return nil
}

func remountSys() error {
	if err := system.Unmount("/sys", syscall.MNT_DETACH); err != nil {
		if err != syscall.EINVAL {
			return err
		}
	} else {
		if err := system.Mount("sysfs", "/sys", "sysfs", uintptr(defaultMountFlags), ""); err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>Always symlink /dev/ptmx for libcontainer Docker-DCO-1.1-Signed-off-by: Michael Crosby <michael@crosbymichael.com> (github: crosbymichael)<commit_after>// +build linux

package nsinit

import (
	"fmt"
	"github.com/dotcloud/docker/pkg/system"
	"io/ioutil"
	"os"
	"path/filepath"
	"syscall"
)

// default mount point flags
const defaultMountFlags = syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NODEV

// setupNewMountNamespace is used to initialize a new mount namespace for an new
// container in the rootfs that is specified.
//
// There is no need to unmount the new mounts because as soon as the mount namespace
// is no longer in use, the mounts will be removed automatically
func setupNewMountNamespace(rootfs, console string, readonly, noPivotRoot bool) error {
	flag := syscall.MS_PRIVATE
	if noPivotRoot {
		flag = syscall.MS_SLAVE
	}
	if err := system.Mount("", "/", "", uintptr(flag|syscall.MS_REC), ""); err != nil {
		return fmt.Errorf("mounting / as slave %s", err)
	}
	if err := system.Mount(rootfs, rootfs, "bind", syscall.MS_BIND|syscall.MS_REC, ""); err != nil {
		return fmt.Errorf("mouting %s as bind %s", rootfs, err)
	}
	if readonly {
		if err := system.Mount(rootfs, rootfs, "bind", syscall.MS_BIND|syscall.MS_REMOUNT|syscall.MS_RDONLY|syscall.MS_REC, ""); err != nil {
			return fmt.Errorf("mounting %s as readonly %s", rootfs, err)
		}
	}
	if err := mountSystem(rootfs); err != nil {
		return fmt.Errorf("mount system %s", err)
	}
	if err := copyDevNodes(rootfs); err != nil {
		return fmt.Errorf("copy dev nodes %s", err)
	}
	// In non-privileged mode, this fails. Discard the error.
	setupLoopbackDevices(rootfs)
	if err := setupDev(rootfs); err != nil {
		return err
	}
	if err := setupPtmx(rootfs, console); err != nil {
		return err
	}
	if err := system.Chdir(rootfs); err != nil {
		return fmt.Errorf("chdir into %s %s", rootfs, err)
	}

	if noPivotRoot {
		if err := rootMsMove(rootfs); err != nil {
			return err
		}
	} else {
		if err := rootPivot(rootfs); err != nil {
			return err
		}
	}

	system.Umask(0022)

	return nil
}

// use a pivot root to setup the rootfs
func rootPivot(rootfs string) error {
	pivotDir, err := ioutil.TempDir(rootfs, ".pivot_root")
	if err != nil {
		return fmt.Errorf("can't create pivot_root dir %s", pivotDir, err)
	}
	if err := system.Pivotroot(rootfs, pivotDir); err != nil {
		return fmt.Errorf("pivot_root %s", err)
	}
	if err := system.Chdir("/"); err != nil {
		return fmt.Errorf("chdir / %s", err)
	}
	// path to pivot dir now changed, update
	pivotDir = filepath.Join("/", filepath.Base(pivotDir))
	if err := system.Unmount(pivotDir, syscall.MNT_DETACH); err != nil {
		return fmt.Errorf("unmount pivot_root dir %s", err)
	}
	if err := os.Remove(pivotDir); err != nil {
		return fmt.Errorf("remove pivot_root dir %s", err)
	}
	return nil
}

// use MS_MOVE and chroot to setup the rootfs
func rootMsMove(rootfs string) error {
	if err := system.Mount(rootfs, "/", "", syscall.MS_MOVE, ""); err != nil {
		return fmt.Errorf("mount move %s into / %s", rootfs, err)
	}
	if err := system.Chroot("."); err != nil {
		return fmt.Errorf("chroot . %s", err)
	}
	if err := system.Chdir("/"); err != nil {
		return fmt.Errorf("chdir / %s", err)
	}
	return nil
}

// copyDevNodes mknods the hosts devices so the new container has access to them
func copyDevNodes(rootfs string) error {
	oldMask := system.Umask(0000)
	defer system.Umask(oldMask)

	for _, node := range []string{
		"null",
		"zero",
		"full",
		"random",
		"urandom",
		"tty",
	} {
		if err := copyDevNode(rootfs, node); err != nil {
			return err
		}
	}
	return nil
}

func setupLoopbackDevices(rootfs string) error {
	for i := 0; ; i++ {
		if err := copyDevNode(rootfs, fmt.Sprintf("loop%d", i)); err != nil {
			if !os.IsNotExist(err) {
				return err
			}
			break
		}

	}
	return nil
}

func copyDevNode(rootfs, node string) error {
	stat, err := os.Stat(filepath.Join("/dev", node))
	if err != nil {
		return err
	}
	var (
		dest = filepath.Join(rootfs, "dev", node)
		st   = stat.Sys().(*syscall.Stat_t)
	)
	if err := system.Mknod(dest, st.Mode, int(st.Rdev)); err != nil && !os.IsExist(err) {
		return fmt.Errorf("copy %s %s", node, err)
	}
	return nil
}

// setupDev symlinks the current processes pipes into the
// appropriate destination on the containers rootfs
func setupDev(rootfs string) error {
	for _, link := range []struct {
		from string
		to   string
	}{
		{"/proc/kcore", "/dev/core"},
		{"/proc/self/fd", "/dev/fd"},
		{"/proc/self/fd/0", "/dev/stdin"},
		{"/proc/self/fd/1", "/dev/stdout"},
		{"/proc/self/fd/2", "/dev/stderr"},
	} {
		dest := filepath.Join(rootfs, link.to)
		if err := os.Remove(dest); err != nil && !os.IsNotExist(err) {
			return fmt.Errorf("remove %s %s", dest, err)
		}
		if err := os.Symlink(link.from, dest); err != nil {
			return fmt.Errorf("symlink %s %s", dest, err)
		}
	}
	return nil
}

// setupConsole ensures that the container has a proper /dev/console setup
func setupConsole(rootfs, console string) error {
	oldMask := system.Umask(0000)
	defer system.Umask(oldMask)

	stat, err := os.Stat(console)
	if err != nil {
		return fmt.Errorf("stat console %s %s", console, err)
	}
	var (
		st   = stat.Sys().(*syscall.Stat_t)
		dest = filepath.Join(rootfs, "dev/console")
	)
	if err := os.Remove(dest); err != nil && !os.IsNotExist(err) {
		return fmt.Errorf("remove %s %s", dest, err)
	}
	if err := os.Chmod(console, 0600); err != nil {
		return err
	}
	if err := os.Chown(console, 0, 0); err != nil {
		return err
	}
	if err := system.Mknod(dest, (st.Mode&^07777)|0600, int(st.Rdev)); err != nil {
		return fmt.Errorf("mknod %s %s", dest, err)
	}
	if err := system.Mount(console, dest, "bind", syscall.MS_BIND, ""); err != nil {
		return fmt.Errorf("bind %s to %s %s", console, dest, err)
	}
	return nil
}

// mountSystem sets up linux specific system mounts like sys, proc, shm, and devpts
// inside the mount namespace
func mountSystem(rootfs string) error {
	for _, m := range []struct {
		source string
		path   string
		device string
		flags  int
		data   string
	}{
		{source: "proc", path: filepath.Join(rootfs, "proc"), device: "proc", flags: defaultMountFlags},
		{source: "sysfs", path: filepath.Join(rootfs, "sys"), device: "sysfs", flags: defaultMountFlags},
		{source: "shm", path: filepath.Join(rootfs, "dev", "shm"), device: "tmpfs", flags: defaultMountFlags, data: "mode=1777,size=65536k"},
		{source: "devpts", path: filepath.Join(rootfs, "dev", "pts"), device: "devpts", flags: syscall.MS_NOSUID | syscall.MS_NOEXEC, data: "newinstance,ptmxmode=0666,mode=620,gid=5"},
	} {
		if err := os.MkdirAll(m.path, 0755); err != nil && !os.IsExist(err) {
			return fmt.Errorf("mkdirall %s %s", m.path, err)
		}
		if err := system.Mount(m.source, m.path, m.device, uintptr(m.flags), m.data); err != nil {
			return fmt.Errorf("mounting %s into %s %s", m.source, m.path, err)
		}
	}
	return nil
}

// setupPtmx adds a symlink to pts/ptmx for /dev/ptmx and
// finishes setting up /dev/console
func setupPtmx(rootfs, console string) error {
	ptmx := filepath.Join(rootfs, "dev/ptmx")
	if err := os.Remove(ptmx); err != nil && !os.IsNotExist(err) {
		return err
	}
	if err := os.Symlink("pts/ptmx", ptmx); err != nil {
		return fmt.Errorf("symlink dev ptmx %s", err)
	}
	if console != "" {
		if err := setupConsole(rootfs, console); err != nil {
			return err
		}
	}
	return nil
}

// remountProc is used to detach and remount the proc filesystem
// commonly needed with running a new process inside an existing container
func remountProc() error {
	if err := system.Unmount("/proc", syscall.MNT_DETACH); err != nil {
		return err
	}
	if err := system.Mount("proc", "/proc", "proc", uintptr(defaultMountFlags), ""); err != nil {
		return err
	}
	return nil
}

func remountSys() error {
	if err := system.Unmount("/sys", syscall.MNT_DETACH); err != nil {
		if err != syscall.EINVAL {
			return err
		}
	} else {
		if err := system.Mount("sysfs", "/sys", "sysfs", uintptr(defaultMountFlags), ""); err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package numbers

import (
	"errors"
	"reflect"
	"testing"
)

// TestFactorsList unit test FactorsList function.
func TestFactorsList(t *testing.T) {
	testCases := []struct {
		input    int
		expected []int
		err      error
	}{
		{2, []int{2}, nil},
		{15, []int{3, 5}, nil},
		{26, []int{2, 13}, nil},
		{37, []int{37}, nil},
		{42, []int{2, 3, 7}, nil},
		{-1, []int(nil), errors.New("no prime factors for numbers below two. received '-1'")},
	}
	for _, test := range testCases {
		observed, err := FactorsList(test.input)
		if err != nil {
			if test.err.Error() != err.Error() {
				t.Error(err)
			}
		}
		if !reflect.DeepEqual(observed, test.expected) {
			t.Errorf("for input '%d', expected '%v', got '%v'",
				test.input, test.expected, observed)
		}
	}
}

// BenchmarkFactorList benchmark FactorsList function.
func BenchmarkFactorList(b *testing.B) {
	for i := 0; i <= b.N; i++ {
		_, err := FactorsList(1000)
		if err != nil {
			b.Error(err)
		}
	}
}

// TestIsPrime unit test IsPrime function.
func TestIsPrime(t *testing.T) {
	testCases := []struct {
		input    int
		expected bool
	}{
		{-5, false},
		{0, false},
		{2, true},
		{6, false},
		{13, true},
	}
	for _, test := range testCases {
		observed := IsPrime(test.input)
		if observed != test.expected {
			t.Errorf("for input '%d', expected '%t', got '%t'",
				test.input, test.expected, observed)
		}
	}
}

// BenchmarkIsPrime benchmark IsPrime function.
func BenchmarkIsPrime(b *testing.B) {
	for i := 0; i <= b.N; i++ {
		_ = IsPrime(1728459)
	}
}

// TestFibonacciGen unit test FibonacciGen function.
func TestFibonacciGen(t *testing.T) {
	testCases := []struct {
		input, expected int
	}{
		{1, 0},
		{2, 1},
		{3, 1},
		{4, 2},
		{5, 3},
		{8, 13},
		{10, 34},
		{12, 89},
	}
	for _, test := range testCases {
		var observed int
		c := FibonacciGen()
		for n := 0; n < test.input; n++ {
			observed = <-c
		}
		if observed != test.expected {
			t.Errorf("for input '%d', expected '%d', got '%d'", test.input, test.expected, observed)
		}
	}
}

// BenchmarkFibonacciGen benchmark FibonacciGen function.
func BenchmarkFibonacciGen(b *testing.B) {
	for i := 0; i <= b.N; i++ {
		c := FibonacciGen()
		for n := 0; n < 10000; n++ {
			_ = <-c
		}
	}
}

// TestNthFibonacci unit test NthFibonacci function.
func TestNthFibonacci(t *testing.T) {
	var testCases = []struct {
		input, expected int
	}{
		{1, 1},
		{5, 5},
		{7, 13},
		{10, 55},
		{19, 4181},
	}
	for _, test := range testCases {
		observed := NthFibonacci(test.input)
		if observed != test.expected {
			t.Errorf("for input '%d', expected '%d', got '%d'",
				test.input, test.expected, observed)
		}
	}
}

// BenchmarkNthFibonacci benchmark NthFibonacci function.
func BenchmarkNthFibonacci(b *testing.B) {
	for i := 0; i < b.N; i++ {
		_ = NthFibonacci(10000)
	}
}

// TestEvenNumbers unit test EvenNumbers function.
func TestEvenNumbers(t *testing.T) {
	testCases := []struct {
		inputA, inputB int
		expected       []int
		err            error
	}{
		{1, 1, []int(nil), nil},
		{1, 3, []int{2}, nil},
		{4, 8, []int{4, 6, 8}, nil},
		{-4, 8, []int{-4, -2, 0, 2, 4, 6, 8}, nil},
		{-1, -2, []int(nil), errors.New("a must be greater than b. received a '-1' and b '-2'")},
	}
	for _, test := range testCases {
		observed, err := EvenNumbers(test.inputA, test.inputB)
		if err != nil {
			if err.Error() != test.err.Error() {
				t.Error(err)
			}
		}
		if !reflect.DeepEqual(observed, test.expected) {
			t.Errorf("for a '%d' and b '%d', expected '%v', got '%v'",
				test.inputA, test.inputB, test.expected, observed)
		}
	}
}

// BenchmarkEvenNumbers benchmark EvenNumbers function.
func BenchmarkEvenNumbers(b *testing.B) {
	for i := 0; i <= b.N; i++ {
		_, err := EvenNumbers(1, 100000)
		if err != nil {
			b.Error(err)
		}
	}
}

// TestOddNumbers unit test OddNumbers function.
func TestOddNumbers(t *testing.T) {
	testCases := []struct {
		inputA, inputB int
		expected       []int
		err            error
	}{
		{1, 1, []int{1}, nil},
		{1, 3, []int{1, 3}, nil},
		{4, 8, []int{5, 7}, nil},
		{-4, 8, []int{-3, -1, 1, 3, 5, 7}, nil},
		{-1, -2, []int(nil), errors.New("a must be greater than b. received a '-1' and b '-2'")},
	}
	for _, test := range testCases {
		observed, err := OddNumbers(test.inputA, test.inputB)
		if err != nil {
			if err.Error() != test.err.Error() {
				t.Error(err)
			}
		}
		if !reflect.DeepEqual(observed, test.expected) {
			t.Errorf("for a '%d' and b '%d', expected '%v', got '%v'",
				test.inputA, test.inputB, test.expected, observed)
		}
	}
}

// BenchmarkOddNumbers benchmark OddNumbers function.
func BenchmarkOddNumbers(b *testing.B) {
	for i := 0; i <= b.N; i++ {
		_, err := OddNumbers(1, 100000)
		if err != nil {
			b.Error(err)
		}
	}
}

// TestNthEven unit test NthEven function.
func TestNthEven(t *testing.T) {
	testCases := []struct {
		input, expected int
		err             error
	}{
		{-1, 0, errors.New("input must be a positive number. received '-1'")},
		{-2, 0, errors.New("input must be a positive number. received '-2'")},
		{1, 0, nil},
		{2, 2, nil},
		{10, 18, nil},
	}
	for _, test := range testCases {
		observed, err := NthEven(test.input)
		if err != nil {
			if err.Error() != test.err.Error() {
				t.Errorf("for input '%d', expected '%s', got '%s'",
					test.input, test.err.Error(), err.Error())
			}
		}
		if !reflect.DeepEqual(observed, test.expected) {
			t.Errorf("for input '%d', expected '%v', got '%v'",
				test.input, test.expected, observed)
		}
	}
}
<commit_msg>Add benchmark test for NthEven function<commit_after>package numbers

import (
	"errors"
	"reflect"
	"testing"
)

// TestFactorsList unit test FactorsList function.
func TestFactorsList(t *testing.T) {
	testCases := []struct {
		input    int
		expected []int
		err      error
	}{
		{2, []int{2}, nil},
		{15, []int{3, 5}, nil},
		{26, []int{2, 13}, nil},
		{37, []int{37}, nil},
		{42, []int{2, 3, 7}, nil},
		{-1, []int(nil), errors.New("no prime factors for numbers below two. received '-1'")},
	}
	for _, test := range testCases {
		observed, err := FactorsList(test.input)
		if err != nil {
			if test.err.Error() != err.Error() {
				t.Error(err)
			}
		}
		if !reflect.DeepEqual(observed, test.expected) {
			t.Errorf("for input '%d', expected '%v', got '%v'",
				test.input, test.expected, observed)
		}
	}
}

// BenchmarkFactorList benchmark FactorsList function.
func BenchmarkFactorList(b *testing.B) {
	for i := 0; i <= b.N; i++ {
		_, err := FactorsList(1000)
		if err != nil {
			b.Error(err)
		}
	}
}

// TestIsPrime unit test IsPrime function.
func TestIsPrime(t *testing.T) {
	testCases := []struct {
		input    int
		expected bool
	}{
		{-5, false},
		{0, false},
		{2, true},
		{6, false},
		{13, true},
	}
	for _, test := range testCases {
		observed := IsPrime(test.input)
		if observed != test.expected {
			t.Errorf("for input '%d', expected '%t', got '%t'",
				test.input, test.expected, observed)
		}
	}
}

// BenchmarkIsPrime benchmark IsPrime function.
func BenchmarkIsPrime(b *testing.B) {
	for i := 0; i <= b.N; i++ {
		_ = IsPrime(1728459)
	}
}

// TestFibonacciGen unit test FibonacciGen function.
func TestFibonacciGen(t *testing.T) {
	testCases := []struct {
		input, expected int
	}{
		{1, 0},
		{2, 1},
		{3, 1},
		{4, 2},
		{5, 3},
		{8, 13},
		{10, 34},
		{12, 89},
	}
	for _, test := range testCases {
		var observed int
		c := FibonacciGen()
		for n := 0; n < test.input; n++ {
			observed = <-c
		}
		if observed != test.expected {
			t.Errorf("for input '%d', expected '%d', got '%d'", test.input, test.expected, observed)
		}
	}
}

// BenchmarkFibonacciGen benchmark FibonacciGen function.
func BenchmarkFibonacciGen(b *testing.B) {
	for i := 0; i <= b.N; i++ {
		c := FibonacciGen()
		for n := 0; n < 10000; n++ {
			_ = <-c
		}
	}
}

// TestNthFibonacci unit test NthFibonacci function.
func TestNthFibonacci(t *testing.T) {
	var testCases = []struct {
		input, expected int
	}{
		{1, 1},
		{5, 5},
		{7, 13},
		{10, 55},
		{19, 4181},
	}
	for _, test := range testCases {
		observed := NthFibonacci(test.input)
		if observed != test.expected {
			t.Errorf("for input '%d', expected '%d', got '%d'",
				test.input, test.expected, observed)
		}
	}
}

// BenchmarkNthFibonacci benchmark NthFibonacci function.
func BenchmarkNthFibonacci(b *testing.B) {
	for i := 0; i < b.N; i++ {
		_ = NthFibonacci(10000)
	}
}

// TestEvenNumbers unit test EvenNumbers function.
func TestEvenNumbers(t *testing.T) {
	testCases := []struct {
		inputA, inputB int
		expected       []int
		err            error
	}{
		{1, 1, []int(nil), nil},
		{1, 3, []int{2}, nil},
		{4, 8, []int{4, 6, 8}, nil},
		{-4, 8, []int{-4, -2, 0, 2, 4, 6, 8}, nil},
		{-1, -2, []int(nil), errors.New("a must be greater than b. received a '-1' and b '-2'")},
	}
	for _, test := range testCases {
		observed, err := EvenNumbers(test.inputA, test.inputB)
		if err != nil {
			if err.Error() != test.err.Error() {
				t.Error(err)
			}
		}
		if !reflect.DeepEqual(observed, test.expected) {
			t.Errorf("for a '%d' and b '%d', expected '%v', got '%v'",
				test.inputA, test.inputB, test.expected, observed)
		}
	}
}

// BenchmarkEvenNumbers benchmark EvenNumbers function.
func BenchmarkEvenNumbers(b *testing.B) {
	for i := 0; i <= b.N; i++ {
		_, err := EvenNumbers(1, 100000)
		if err != nil {
			b.Error(err)
		}
	}
}

// TestOddNumbers unit test OddNumbers function.
func TestOddNumbers(t *testing.T) {
	testCases := []struct {
		inputA, inputB int
		expected       []int
		err            error
	}{
		{1, 1, []int{1}, nil},
		{1, 3, []int{1, 3}, nil},
		{4, 8, []int{5, 7}, nil},
		{-4, 8, []int{-3, -1, 1, 3, 5, 7}, nil},
		{-1, -2, []int(nil), errors.New("a must be greater than b. received a '-1' and b '-2'")},
	}
	for _, test := range testCases {
		observed, err := OddNumbers(test.inputA, test.inputB)
		if err != nil {
			if err.Error() != test.err.Error() {
				t.Error(err)
			}
		}
		if !reflect.DeepEqual(observed, test.expected) {
			t.Errorf("for a '%d' and b '%d', expected '%v', got '%v'",
				test.inputA, test.inputB, test.expected, observed)
		}
	}
}

// BenchmarkOddNumbers benchmark OddNumbers function.
func BenchmarkOddNumbers(b *testing.B) {
	for i := 0; i <= b.N; i++ {
		_, err := OddNumbers(1, 100000)
		if err != nil {
			b.Error(err)
		}
	}
}

// TestNthEven unit test NthEven function.
func TestNthEven(t *testing.T) {
	testCases := []struct {
		input, expected int
		err             error
	}{
		{-1, 0, errors.New("input must be a positive number. received '-1'")},
		{-2, 0, errors.New("input must be a positive number. received '-2'")},
		{1, 0, nil},
		{2, 2, nil},
		{10, 18, nil},
	}
	for _, test := range testCases {
		observed, err := NthEven(test.input)
		if err != nil {
			if err.Error() != test.err.Error() {
				t.Errorf("for input '%d', expected '%s', got '%s'",
					test.input, test.err.Error(), err.Error())
			}
		}
		if !reflect.DeepEqual(observed, test.expected) {
			t.Errorf("for input '%d', expected '%v', got '%v'",
				test.input, test.expected, observed)
		}
	}
}

// BenchmarkNthEven benchmark NthEven function.
func BenchmarkNthEven(b *testing.B) {
	for i := 0; i <= b.N; i++ {
		_, err := NthEven(100000)
		if err != nil {
			b.Error(err)
		}
	}
}
<|endoftext|>


<commit_before>package config

import (
	"github.com/ponzu-cms/ponzu/management/editor"
	"github.com/ponzu-cms/ponzu/system/item"
)

// Config represents the confirgurable options of the system
type Config struct {
	item.Item

	Name            string   `json:"name"`
	Domain          string   `json:"domain"`
	HTTPPort        string   `json:"http_port"`
	HTTPSPort       string   `json:"https_port"`
	AdminEmail      string   `json:"admin_email"`
	ClientSecret    string   `json:"client_secret"`
	Etag            string   `json:"etag"`
	DisableCORS     bool     `json:"cors_disabled"`
	DisableGZIP     bool     `json:"gzip_disabled"`
	CacheInvalidate []string `json:"cache"`
}

// String partially implements item.Identifiable and overrides Item's String()
func (c *Config) String() string { return c.Name }

// MarshalEditor writes a buffer of html to edit a Post and partially implements editor.Editable
func (c *Config) MarshalEditor() ([]byte, error) {
	view, err := editor.Form(c,
		editor.Field{
			View: editor.Input("Name", c, map[string]string{
				"label":       "Site Name",
				"placeholder": "Add a name to this site (internal use only)",
			}),
		},
		editor.Field{
			View: editor.Input("Domain", c, map[string]string{
				"label":       "Domain Name (required for SSL certificate)",
				"placeholder": "e.g. www.example.com or example.com",
			}),
		},
		editor.Field{
			View: editor.Input("HTTPPort", c, map[string]string{
				"type": "hidden",
			}),
		},
		editor.Field{
			View: editor.Input("HTTPSPort", c, map[string]string{
				"type": "hidden",
			}),
		},
		editor.Field{
			View: editor.Input("AdminEmail", c, map[string]string{
				"label": "Adminstrator Email (notified of internal system information)",
			}),
		},
		editor.Field{
			View: editor.Input("ClientSecret", c, map[string]string{
				"label":    "Client Secret (used to validate requests, DO NOT SHARE)",
				"disabled": "true",
			}),
		},
		editor.Field{
			View: editor.Input("ClientSecret", c, map[string]string{
				"type": "hidden",
			}),
		},
		editor.Field{
			View: editor.Input("Etag", c, map[string]string{
				"label":    "Etag Header (used to cache resources)",
				"disabled": "true",
			}),
		},
		editor.Field{
			View: editor.Input("Etag", c, map[string]string{
				"type": "hidden",
			}),
		},
		editor.Field{
			View: editor.Checkbox("DisableCORS", c, map[string]string{
				"label": "Disable CORS (so only " + c.Domain + " can fetch your data)",
			}, map[string]string{
				"true": "Disable CORS",
			}),
		},
		editor.Field{
			View: editor.Checkbox("DisableGZIP", c, map[string]string{
				"label": "Disable GZIP (will increase server speed, but also bandwidth)",
			}, map[string]string{
				"true": "Disable GZIP",
			}),
		},
		editor.Field{
			View: editor.Checkbox("CacheInvalidate", c, map[string]string{
				"label": "Invalidate cache on save",
			}, map[string]string{
				"invalidate": "Invalidate Cache",
			}),
		},
	)
	if err != nil {
		return nil, err
	}

	open := []byte(`

System Configuration

		<form action="/admin/configure" method="post">
	`)
	close := []byte(`</form></div>`)
	script := []byte(`

	`)

	view = append(open, view...)
	view = append(view, close...)
	view = append(view, script...)

	return view, nil
}
<commit_msg>adding http basic auth fields for db backup via http<commit_after>package config

import (
	"github.com/ponzu-cms/ponzu/management/editor"
	"github.com/ponzu-cms/ponzu/system/item"
)

// Config represents the confirgurable options of the system
type Config struct {
	item.Item

	Name                    string   `json:"name"`
	Domain                  string   `json:"domain"`
	HTTPPort                string   `json:"http_port"`
	HTTPSPort               string   `json:"https_port"`
	AdminEmail              string   `json:"admin_email"`
	ClientSecret            string   `json:"client_secret"`
	Etag                    string   `json:"etag"`
	DisableCORS             bool     `json:"cors_disabled"`
	DisableGZIP             bool     `json:"gzip_disabled"`
	CacheInvalidate         []string `json:"cache"`
	BackupBasicAuthUser     string   `json:"backup_basic_auth_user"`
	BackupBasicAuthPassword string   `json:"backup_basic_auth_password"`
}

const (
	dbBackupInfo = `

Database Backup Credentials:

Add a user name and password to download a backup of your data via HTTP.

	`
)

// String partially implements item.Identifiable and overrides Item's String()
func (c *Config) String() string { return c.Name }

// MarshalEditor writes a buffer of html to edit a Post and partially implements editor.Editable
func (c *Config) MarshalEditor() ([]byte, error) {
	view, err := editor.Form(c,
		editor.Field{
			View: editor.Input("Name", c, map[string]string{
				"label":       "Site Name",
				"placeholder": "Add a name to this site (internal use only)",
			}),
		},
		editor.Field{
			View: editor.Input("Domain", c, map[string]string{
				"label":       "Domain Name (required for SSL certificate)",
				"placeholder": "e.g. www.example.com or example.com",
			}),
		},
		editor.Field{
			View: editor.Input("HTTPPort", c, map[string]string{
				"type": "hidden",
			}),
		},
		editor.Field{
			View: editor.Input("HTTPSPort", c, map[string]string{
				"type": "hidden",
			}),
		},
		editor.Field{
			View: editor.Input("AdminEmail", c, map[string]string{
				"label": "Adminstrator Email (notified of internal system information)",
			}),
		},
		editor.Field{
			View: editor.Input("ClientSecret", c, map[string]string{
				"label":    "Client Secret (used to validate requests, DO NOT SHARE)",
				"disabled": "true",
			}),
		},
		editor.Field{
			View: editor.Input("ClientSecret", c, map[string]string{
				"type": "hidden",
			}),
		},
		editor.Field{
			View: editor.Input("Etag", c, map[string]string{
				"label":    "Etag Header (used to cache resources)",
				"disabled": "true",
			}),
		},
		editor.Field{
			View: editor.Input("Etag", c, map[string]string{
				"type": "hidden",
			}),
		},
		editor.Field{
			View: editor.Checkbox("DisableCORS", c, map[string]string{
				"label": "Disable CORS (so only " + c.Domain + " can fetch your data)",
			}, map[string]string{
				"true": "Disable CORS",
			}),
		},
		editor.Field{
			View: editor.Checkbox("DisableGZIP", c, map[string]string{
				"label": "Disable GZIP (will increase server speed, but also bandwidth)",
			}, map[string]string{
				"true": "Disable GZIP",
			}),
		},
		editor.Field{
			View: editor.Checkbox("CacheInvalidate", c, map[string]string{
				"label": "Invalidate cache on save",
			}, map[string]string{
				"invalidate": "Invalidate Cache",
			}),
		},
		editor.Field{
			View: []byte(dbBackupInfo),
		},
		editor.Field{
			View: editor.Input("BackupBasicAuthUser", c, map[string]string{
				"label":       "HTTP Basic Auth User",
				"placeholder": "Enter a user name for Basic Auth access",
				"type":        "text",
			}),
		},
		editor.Field{
			View: editor.Input("BackupBasicAuthPassword", c, map[string]string{
				"label":       "HTTP Basic Auth Password",
				"placeholder": "Enter a password for Basic Auth access",
				"type":        "password",
			}),
		},
	)
	if err != nil {
		return nil, err
	}

	open := []byte(`

System Configuration

		<form action="/admin/configure" method="post">
	`)
	close := []byte(`</form></div>`)
	script := []byte(`

	`)

	view = append(open, view...)
	view = append(view, close...)
	view = append(view, script...)

	return view, nil
}
<|endoftext|>


<commit_before>package natty

import (
	"io"
	"net"
	"os"
	"sync"
	"testing"
	"time"

	"github.com/getlantern/golog"
	"github.com/getlantern/waddell"
)

const (
	MESSAGE_TEXT = "Hello World"

	WADDELL_ADDR = "localhost:19543"
)

var tlog = golog.LoggerFor("natty-test")

// TestDirect starts up two local Traversals that communicate with each other
// directly.  Once connected, one peer sends a UDP packet to the other to make
// sure that the connection works.
//
// Run test with -v flag to get debug output from natty.
func TestDirect(t *testing.T) {
	doTest(t, func(offer *Traversal, answer *Traversal) {
		go func() {
			for {
				msg, done := offer.NextMsgOut()
				if done {
					return
				}
				tlog.Debugf("offer -> answer: %s", msg)
				answer.MsgIn(msg)
			}
		}()

		go func() {
			for {
				msg, done := answer.NextMsgOut()
				if done {
					return
				}
				tlog.Debugf("answer -> offer: %s", msg)
				offer.MsgIn(msg)
			}
		}()
	})
}

// TestWaddell starts up two local Traversals that communicate with each other
// using a local waddell server.  Once connected, one peer sends a UDP packet to
// the other to make sure that the connection works.
//
// Run test with -v flag to get debug output from natty.
func TestWaddell(t *testing.T) {
	doTest(t, func(offer *Traversal, answer *Traversal) {
		// Start a waddell server
		server := &waddell.Server{}
		tlog.Debugf("Starting waddell at %s", WADDELL_ADDR)
		listener, err := net.Listen("tcp", WADDELL_ADDR)
		if err != nil {
			t.Fatalf("Unable to listen at %s: %s", WADDELL_ADDR, err)
		}
		go func() {
			err = server.Serve(listener)
			if err != nil {
				t.Fatalf("Unable to start waddell at %s: %s", WADDELL_ADDR, err)
			}
		}()

		offerClient := makeWaddellClient(t)
		answerClient := makeWaddellClient(t)

		// Send from offer -> answer
		go func() {
			for {
				msg, done := offer.NextMsgOut()
				if done {
					return
				}
				tlog.Debugf("offer -> answer: %s", msg)
				offerClient.Send(answerClient.ID(), []byte(msg))
			}
		}()

		// Receive to offer
		go func() {
			for {
				b := make([]byte, 4096+waddell.WADDELL_OVERHEAD)
				msg, err := offerClient.Receive(b)
				if err != nil {
					t.Fatalf("offer unable to receive message from waddell: %s", err)
				}
				offer.MsgIn(string(msg.Body))
			}
		}()

		// Send from answer -> offer
		go func() {
			for {
				msg, done := answer.NextMsgOut()
				if done {
					return
				}
				tlog.Debugf("answer -> offer: %s", msg)
				answerClient.Send(offerClient.ID(), []byte(msg))
			}
		}()

		// Receive to answer
		go func() {
			for {
				b := make([]byte, 4096+waddell.WADDELL_OVERHEAD)
				msg, err := answerClient.Receive(b)
				if err != nil {
					t.Fatalf("answer unable to receive message from waddell: %s", err)
				}
				answer.MsgIn(string(msg.Body))
			}
		}()

	})
}

func doTest(t *testing.T, signal func(*Traversal, *Traversal)) {
	var offer *Traversal
	var answer *Traversal

	var debug io.Writer
	if testing.Verbose() {
		debug = os.Stderr
	}

	offer = Offer(debug)
	defer offer.Close()

	answer = Answer(debug)
	defer answer.Close()

	var answerReady sync.WaitGroup
	answerReady.Add(1)

	var wg sync.WaitGroup
	wg.Add(2)

	// offer processing
	go func() {
		defer wg.Done()
		// Try it with a really short timeout (should error)
		fiveTuple, err := offer.FiveTupleTimeout(5 * time.Millisecond)
		if err == nil {
			errorf(t, "Really short timeout should have given error")
		}

		// Try it again without timeout
		fiveTuple, err = offer.FiveTuple()
		if err != nil {
			errorf(t, "offer had error: %s", err)
			return
		}

		// Call it again to make sure we're getting the same 5-tuple
		fiveTupleAgain, err := offer.FiveTuple()
		if fiveTupleAgain.Local != fiveTuple.Local ||
			fiveTupleAgain.Remote != fiveTuple.Remote ||
			fiveTupleAgain.Proto != fiveTuple.Proto {
			errorf(t, "2nd FiveTuple didn't match original")
		}

		tlog.Debugf("offer got FiveTuple: %s", fiveTuple)
		if fiveTuple.Proto != UDP {
			errorf(t, "Protocol was %s instead of udp", fiveTuple.Proto)
			return
		}
		local, remote, err := fiveTuple.UDPAddrs()
		if err != nil {
			errorf(t, "offer unable to resolve UDP addresses: %s", err)
			return
		}
		answerReady.Wait()
		log.Debug("Offer got answerReady")
		conn, err := net.DialUDP("udp", local, remote)
		if err != nil {
			errorf(t, "Unable to dial UDP: %s", err)
			return
		}
		for i := 0; i < 10; i++ {
			_, err := conn.Write([]byte(MESSAGE_TEXT))
			if err != nil {
				errorf(t, "offer unable to write to UDP: %s", err)
				return
			}
		}
	}()

	// answer processing
	go func() {
		defer wg.Done()
		fiveTuple, err := answer.FiveTupleTimeout(5 * time.Second)
		if err != nil {
			errorf(t, "answer had error: %s", err)
			return
		}
		if fiveTuple.Proto != UDP {
			errorf(t, "Protocol was %s instead of udp", fiveTuple.Proto)
			return
		}
		tlog.Debugf("answer got FiveTuple: %s", fiveTuple)
		local, _, err := fiveTuple.UDPAddrs()
		if err != nil {
			errorf(t, "Error in answer: %s", err)
			return
		}
		conn, err := net.ListenUDP("udp", local)
		if err != nil {
			errorf(t, "answer unable to listen on UDP: %s", err)
			return
		}
		tlog.Debugf("Answerer listining on UDP: %s", local)
		answerReady.Done()
		b := make([]byte, 1024)
		for {
			n, addr, err := conn.ReadFrom(b)
			if err != nil {
				errorf(t, "answer unable to read from UDP: %s", err)
				return
			}
			if addr.String() != fiveTuple.Remote {
				errorf(t, "UDP package had address %s, expected %s", addr, fiveTuple.Remote)
				return
			}
			msg := string(b[:n])
			if msg != MESSAGE_TEXT {
				tlog.Debugf("Got message '%s', expected '%s'", msg, MESSAGE_TEXT)
			}
			return
		}
	}()

	// "Signaling" - this would typically be done using a signaling server like
	// waddell when talking to a remote peer

	signal(offer, answer)

	doneCh := make(chan interface{})
	go func() {
		wg.Wait()
		doneCh <- nil
	}()

	select {
	case <-doneCh:
		return
	case <-time.After(1000 * time.Second):
		errorf(t, "Test timed out")
	}
}

func makeWaddellClient(t *testing.T) *waddell.Client {
	conn, err := net.Dial("tcp", WADDELL_ADDR)
	if err != nil {
		t.Fatalf("Unable to dial waddell: %s", err)
	}
	wc, err := waddell.Connect(conn)
	if err != nil {
		t.Fatalf("Unable to connect to waddell: %s", err)
	}
	return wc
}

func errorf(t *testing.T, msg string, args ...interface{}) {
	tlog.Errorf("error: "+msg, args...)
	t.Errorf(msg, args...)
}
<commit_msg>More test logging<commit_after>package natty

import (
	"io"
	"net"
	"os"
	"sync"
	"testing"
	"time"

	"github.com/getlantern/golog"
	"github.com/getlantern/waddell"
)

const (
	MESSAGE_TEXT = "Hello World"

	WADDELL_ADDR = "localhost:19543"
)

var tlog = golog.LoggerFor("natty-test")

// TestDirect starts up two local Traversals that communicate with each other
// directly.  Once connected, one peer sends a UDP packet to the other to make
// sure that the connection works.
//
// Run test with -v flag to get debug output from natty.
func TestDirect(t *testing.T) {
	doTest(t, func(offer *Traversal, answer *Traversal) {
		go func() {
			for {
				msg, done := offer.NextMsgOut()
				if done {
					return
				}
				tlog.Debugf("offer -> answer: %s", msg)
				answer.MsgIn(msg)
			}
		}()

		go func() {
			for {
				msg, done := answer.NextMsgOut()
				if done {
					return
				}
				tlog.Debugf("answer -> offer: %s", msg)
				offer.MsgIn(msg)
			}
		}()
	})
}

// TestWaddell starts up two local Traversals that communicate with each other
// using a local waddell server.  Once connected, one peer sends a UDP packet to
// the other to make sure that the connection works.
//
// Run test with -v flag to get debug output from natty.
func TestWaddell(t *testing.T) {
	doTest(t, func(offer *Traversal, answer *Traversal) {
		// Start a waddell server
		server := &waddell.Server{}
		tlog.Debugf("Starting waddell at %s", WADDELL_ADDR)
		listener, err := net.Listen("tcp", WADDELL_ADDR)
		if err != nil {
			t.Fatalf("Unable to listen at %s: %s", WADDELL_ADDR, err)
		}
		go func() {
			err = server.Serve(listener)
			if err != nil {
				t.Fatalf("Unable to start waddell at %s: %s", WADDELL_ADDR, err)
			}
		}()

		offerClient := makeWaddellClient(t)
		answerClient := makeWaddellClient(t)

		// Send from offer -> answer
		go func() {
			for {
				msg, done := offer.NextMsgOut()
				if done {
					return
				}
				tlog.Debugf("offer -> answer: %s", msg)
				offerClient.Send(answerClient.ID(), []byte(msg))
			}
		}()

		// Receive to offer
		go func() {
			for {
				b := make([]byte, 4096+waddell.WADDELL_OVERHEAD)
				msg, err := offerClient.Receive(b)
				if err != nil {
					t.Fatalf("offer unable to receive message from waddell: %s", err)
				}
				offer.MsgIn(string(msg.Body))
			}
		}()

		// Send from answer -> offer
		go func() {
			for {
				msg, done := answer.NextMsgOut()
				if done {
					return
				}
				tlog.Debugf("answer -> offer: %s", msg)
				answerClient.Send(offerClient.ID(), []byte(msg))
			}
		}()

		// Receive to answer
		go func() {
			for {
				b := make([]byte, 4096+waddell.WADDELL_OVERHEAD)
				msg, err := answerClient.Receive(b)
				if err != nil {
					t.Fatalf("answer unable to receive message from waddell: %s", err)
				}
				answer.MsgIn(string(msg.Body))
			}
		}()

	})
}

func doTest(t *testing.T, signal func(*Traversal, *Traversal)) {
	var offer *Traversal
	var answer *Traversal

	var debug io.Writer
	if testing.Verbose() {
		debug = os.Stderr
	}

	offer = Offer(debug)
	defer offer.Close()

	answer = Answer(debug)
	defer answer.Close()

	var answerReady sync.WaitGroup
	answerReady.Add(1)

	var wg sync.WaitGroup
	wg.Add(2)

	// offer processing
	go func() {
		defer wg.Done()
		// Try it with a really short timeout (should error)
		fiveTuple, err := offer.FiveTupleTimeout(5 * time.Millisecond)
		if err == nil {
			errorf(t, "Really short timeout should have given error")
		}

		// Try it again without timeout
		fiveTuple, err = offer.FiveTuple()
		if err != nil {
			errorf(t, "offer had error: %s", err)
			return
		}

		// Call it again to make sure we're getting the same 5-tuple
		fiveTupleAgain, err := offer.FiveTuple()
		if fiveTupleAgain.Local != fiveTuple.Local ||
			fiveTupleAgain.Remote != fiveTuple.Remote ||
			fiveTupleAgain.Proto != fiveTuple.Proto {
			errorf(t, "2nd FiveTuple didn't match original")
		}

		tlog.Debugf("offer got FiveTuple: %s", fiveTuple)
		if fiveTuple.Proto != UDP {
			errorf(t, "Protocol was %s instead of udp", fiveTuple.Proto)
			return
		}
		local, remote, err := fiveTuple.UDPAddrs()
		if err != nil {
			errorf(t, "offer unable to resolve UDP addresses: %s", err)
			return
		}
		answerReady.Wait()
		tlog.Debug("Offer got answerReady")
		conn, err := net.DialUDP("udp", local, remote)
		if err != nil {
			errorf(t, "Unable to dial UDP: %s", err)
			return
		}
		tlog.Debug("Offer connected to %s, sending data", local)
		for i := 0; i < 10; i++ {
			_, err := conn.Write([]byte(MESSAGE_TEXT))
			if err != nil {
				errorf(t, "offer unable to write to UDP: %s", err)
				return
			}
		}
	}()

	// answer processing
	go func() {
		defer wg.Done()
		fiveTuple, err := answer.FiveTupleTimeout(5 * time.Second)
		if err != nil {
			errorf(t, "answer had error: %s", err)
			return
		}
		if fiveTuple.Proto != UDP {
			errorf(t, "Protocol was %s instead of udp", fiveTuple.Proto)
			return
		}
		tlog.Debugf("answer got FiveTuple: %s", fiveTuple)
		local, _, err := fiveTuple.UDPAddrs()
		if err != nil {
			errorf(t, "Error in answer: %s", err)
			return
		}
		conn, err := net.ListenUDP("udp", local)
		if err != nil {
			errorf(t, "answer unable to listen on UDP: %s", err)
			return
		}
		tlog.Debugf("Answerer listining on UDP: %s", local)
		answerReady.Done()
		b := make([]byte, 1024)
		for {
			n, addr, err := conn.ReadFrom(b)
			if err != nil {
				errorf(t, "answer unable to read from UDP: %s", err)
				return
			}
			if addr.String() != fiveTuple.Remote {
				errorf(t, "UDP package had address %s, expected %s", addr, fiveTuple.Remote)
				return
			}
			msg := string(b[:n])
			if msg != MESSAGE_TEXT {
				tlog.Debugf("Got message '%s', expected '%s'", msg, MESSAGE_TEXT)
			}
			return
		}
	}()

	// "Signaling" - this would typically be done using a signaling server like
	// waddell when talking to a remote peer

	signal(offer, answer)

	doneCh := make(chan interface{})
	go func() {
		wg.Wait()
		doneCh <- nil
	}()

	select {
	case <-doneCh:
		return
	case <-time.After(1000 * time.Second):
		errorf(t, "Test timed out")
	}
}

func makeWaddellClient(t *testing.T) *waddell.Client {
	conn, err := net.Dial("tcp", WADDELL_ADDR)
	if err != nil {
		t.Fatalf("Unable to dial waddell: %s", err)
	}
	wc, err := waddell.Connect(conn)
	if err != nil {
		t.Fatalf("Unable to connect to waddell: %s", err)
	}
	return wc
}

func errorf(t *testing.T, msg string, args ...interface{}) {
	tlog.Errorf("error: "+msg, args...)
	t.Errorf(msg, args...)
}
<|endoftext|>


<commit_before>package fam100

import (
	"bytes"
	"encoding/gob"
	"fmt"
	"math/rand"
	"strconv"
	"strings"

	"github.com/boltdb/bolt"
)

var (
	// DB question database
	DefaultQuestionDB QuestionDB
	questionBucket    = []byte("questions")

	// Add to the existing seed
	ExtraQuestionSeed = int64(0)
)

func InitQuestion(dbPath string) (numQuestion int, err error) {
	if err := DefaultQuestionDB.Initialize(dbPath); err != nil {
		return 0, err
	}

	return DefaultQuestionDB.questionSize, nil
}

type QuestionDB struct {
	DB           *bolt.DB
	questionSize int
}

func (d *QuestionDB) Initialize(dbPath string) error {
	var err error
	d.DB, err = bolt.Open(dbPath, 0600, nil)
	if err != nil {
		return err
	}
	err = d.DB.Update(func(tx *bolt.Tx) error {
		_, err := tx.CreateBucketIfNotExists(questionBucket)
		if err != nil {
			return fmt.Errorf("create bucket: %s", err)
		}
		return nil
	})
	if err != nil {
		return err
	}

	err = d.DB.View(func(tx *bolt.Tx) error {
		b := tx.Bucket(questionBucket)
		stats := b.Stats()
		d.questionSize = stats.KeyN
		return nil
	})
	if err != nil {
		return err
	}

	if d.questionSize == 0 {
		return fmt.Errorf("Loaded 0 questions")
	}

	return nil
}

func (d *QuestionDB) Close() error {
	return d.DB.Close()
}

func (d *QuestionDB) AddQuestion(q Question) error {
	var buff bytes.Buffer
	enc := gob.NewEncoder(&buff)
	if err := enc.Encode(q); err != nil {
		return err
	}

	d.DB.Update(func(tx *bolt.Tx) error {
		b := tx.Bucket(questionBucket)
		id := strconv.FormatInt(int64(q.ID), 10)
		err := b.Put([]byte(id), buff.Bytes())
		return err
	})

	return nil
}

func AddQuestion(q Question) error {
	return DefaultQuestionDB.AddQuestion(q)
}

func (d *QuestionDB) GetQuestion(id string) (q Question, err error) {
	err = d.DB.View(func(tx *bolt.Tx) error {
		b := tx.Bucket(questionBucket)
		v := b.Get([]byte(id))

		buff := bytes.NewBuffer(v)
		dec := gob.NewDecoder(buff)
		if err := dec.Decode(&q); err != nil {
			return err
		}

		q.lookup = make(map[string]int)
		for i, ans := range q.Answers {
			for _, text := range ans.Text {
				text = strings.TrimSpace(strings.ToLower(text))
				q.lookup[text] = i
			}
		}

		return nil
	})
	return q, err
}
func GetQuestion(id string) (q Question, err error) {
	return DefaultQuestionDB.GetQuestion(id)
}

// NextQuestion generates next question randomly by taking into account
// numbers of game played for particular seed key
func NextQuestion(seed int64, played int, questionLimit int) (q Question, err error) {
	questionSize := DefaultQuestionDB.questionSize
	if questionLimit <= 0 || questionLimit > questionSize {
		questionLimit = questionSize
	}
	r := rand.New(rand.NewSource(seed + ExtraQuestionSeed))
	order := r.Perm(questionSize)
	id := order[played%questionLimit] + 1 // order is 0 based
	idStr := strconv.FormatInt(int64(id), 10)

	return GetQuestion(idStr)
}

// Question for a round
type Question struct {
	ID      int
	Text    string
	Answers []Answer
	lookup  map[string]int
}

// check answers gives the score for particular answer to a question
func (q Question) checkAnswer(text string) (correct bool, score, index int) {
	text = strings.TrimSpace(strings.ToLower(text))
	if i, ok := q.lookup[text]; ok {
		return true, q.Answers[i].Score, i
	}

	return false, 0, -1
}

type Answer struct {
	ID    int
	Text  []string
	Score int
}

func (a Answer) String() string {
	if len(a.Text) == 1 {
		return a.Text[0]
	}

	var b bytes.Buffer
	for i, text := range a.Text {
		if i != 0 {
			b.WriteString(" / ")
		}
		b.WriteString(text)
	}
	return b.String()
}
<commit_msg>export question bucket<commit_after>package fam100

import (
	"bytes"
	"encoding/gob"
	"fmt"
	"math/rand"
	"strconv"
	"strings"

	"github.com/boltdb/bolt"
)

var (
	// DB question database
	DefaultQuestionDB QuestionDB
	QuestionBucket    = []byte("questions")

	// Add to the existing seed
	ExtraQuestionSeed = int64(0)
)

func InitQuestion(dbPath string) (numQuestion int, err error) {
	if err := DefaultQuestionDB.Initialize(dbPath); err != nil {
		return 0, err
	}

	return DefaultQuestionDB.questionSize, nil
}

type QuestionDB struct {
	DB           *bolt.DB
	questionSize int
}

func (d *QuestionDB) Initialize(dbPath string) error {
	var err error
	d.DB, err = bolt.Open(dbPath, 0600, nil)
	if err != nil {
		return err
	}
	err = d.DB.Update(func(tx *bolt.Tx) error {
		_, err := tx.CreateBucketIfNotExists(QuestionBucket)
		if err != nil {
			return fmt.Errorf("create bucket: %s", err)
		}
		return nil
	})
	if err != nil {
		return err
	}

	err = d.DB.View(func(tx *bolt.Tx) error {
		b := tx.Bucket(QuestionBucket)
		stats := b.Stats()
		d.questionSize = stats.KeyN
		return nil
	})
	if err != nil {
		return err
	}

	if d.questionSize == 0 {
		return fmt.Errorf("Loaded 0 questions")
	}

	return nil
}

func (d *QuestionDB) Close() error {
	return d.DB.Close()
}

func (d *QuestionDB) AddQuestion(q Question) error {
	var buff bytes.Buffer
	enc := gob.NewEncoder(&buff)
	if err := enc.Encode(q); err != nil {
		return err
	}

	d.DB.Update(func(tx *bolt.Tx) error {
		b := tx.Bucket(QuestionBucket)
		id := strconv.FormatInt(int64(q.ID), 10)
		err := b.Put([]byte(id), buff.Bytes())
		return err
	})

	return nil
}

func AddQuestion(q Question) error {
	return DefaultQuestionDB.AddQuestion(q)
}

func (d *QuestionDB) GetQuestion(id string) (q Question, err error) {
	err = d.DB.View(func(tx *bolt.Tx) error {
		b := tx.Bucket(QuestionBucket)
		v := b.Get([]byte(id))

		buff := bytes.NewBuffer(v)
		dec := gob.NewDecoder(buff)
		if err := dec.Decode(&q); err != nil {
			return err
		}

		q.lookup = make(map[string]int)
		for i, ans := range q.Answers {
			for _, text := range ans.Text {
				text = strings.TrimSpace(strings.ToLower(text))
				q.lookup[text] = i
			}
		}

		return nil
	})
	return q, err
}
func GetQuestion(id string) (q Question, err error) {
	return DefaultQuestionDB.GetQuestion(id)
}

// NextQuestion generates next question randomly by taking into account
// numbers of game played for particular seed key
func NextQuestion(seed int64, played int, questionLimit int) (q Question, err error) {
	questionSize := DefaultQuestionDB.questionSize
	if questionLimit <= 0 || questionLimit > questionSize {
		questionLimit = questionSize
	}
	r := rand.New(rand.NewSource(seed + ExtraQuestionSeed))
	order := r.Perm(questionSize)
	id := order[played%questionLimit] + 1 // order is 0 based
	idStr := strconv.FormatInt(int64(id), 10)

	return GetQuestion(idStr)
}

// Question for a round
type Question struct {
	ID      int
	Text    string
	Answers []Answer
	lookup  map[string]int
}

// check answers gives the score for particular answer to a question
func (q Question) checkAnswer(text string) (correct bool, score, index int) {
	text = strings.TrimSpace(strings.ToLower(text))
	if i, ok := q.lookup[text]; ok {
		return true, q.Answers[i].Score, i
	}

	return false, 0, -1
}

type Answer struct {
	ID    int
	Text  []string
	Score int
}

func (a Answer) String() string {
	if len(a.Text) == 1 {
		return a.Text[0]
	}

	var b bytes.Buffer
	for i, text := range a.Text {
		if i != 0 {
			b.WriteString(" / ")
		}
		b.WriteString(text)
	}
	return b.String()
}
<|endoftext|>


<commit_before>package concurrentsort

import (
	"sync"
)

/*
	Interface and common types
*/

// QuickSortable is an interface which must be satisfied in order to call QuickSort()
type QuickSortable interface {
	Len() int
	LessOrEqual(i, j int) bool
	Swap(i, j int)
	GetSubSliceTo(i int) QuickSortable
	GetSubSliceFrom(j int) QuickSortable
}

// IntSlice attaches the methods of Interface to []int, sorting in increasing order.
type IntSlice []int

func (p IntSlice) Len() int {
	return len(p)
}
func (p IntSlice) LessOrEqual(i, j int) bool {
	return p[i] <= p[j]
}
func (p IntSlice) Swap(i, j int) {
	p[i], p[j] = p[j], p[i]
}
func (p IntSlice) GetSubSliceTo(i int) QuickSortable {
	return p[:i]
}
func (p IntSlice) GetSubSliceFrom(i int) QuickSortable {
	return p[i:]
}

/*
	Quick Sorting
*/

type quickSortConcurrentManager struct {
	availableWorkers int
	access           sync.Mutex
	rdvpoint         sync.WaitGroup
}

func (qscm *quickSortConcurrentManager) isAWorkerAvailable() bool {
	defer qscm.access.Unlock()
	qscm.access.Lock()
	if qscm.availableWorkers > 0 {
		qscm.availableWorkers--
		qscm.rdvpoint.Add(1)
		return true
	}
	return false
}

func (qscm *quickSortConcurrentManager) workerDone() {
	defer qscm.access.Unlock()
	qscm.access.Lock()
	qscm.availableWorkers++
	qscm.rdvpoint.Done()
}

// QuickSort sorts data using the quicksort algo distributed on nbWorkers goroutines
func QuickSort(data QuickSortable, nbWorkers int) {
	manager := quickSortConcurrentManager{availableWorkers: nbWorkers - 1}
	quickSort(data, &manager)
	manager.rdvpoint.Wait()
}

func quickSort(data QuickSortable, manager *quickSortConcurrentManager) {
	// Start sorting
	if data.Len() > 1 {
		// Select a pivot on the current slice
		pivotIndex := quickSortSelectPivot(data)
		// Partition it and recover new pivot index
		pivotIndex = quickSortPartition(data, pivotIndex)
		// Sort the first sub slice
		if manager.isAWorkerAvailable() {
			go func(d QuickSortable, pi int) {
				defer manager.workerDone()
				quickSort(d.GetSubSliceTo(pi), manager)
			}(data, pivotIndex)
		} else {
			// Run the recursive call within the same goroutine
			quickSort(data.GetSubSliceTo(pivotIndex), manager)
		}
		// Sort the second sub slice
		if manager.isAWorkerAvailable() {
			go func(d QuickSortable, pi int) {
				defer manager.workerDone()
				quickSort(d.GetSubSliceFrom(pi), manager)
			}(data, pivotIndex+1)
		} else {
			quickSort(data.GetSubSliceFrom(pivotIndex+1), manager)
		}
	}
}

func quickSortPartition(data QuickSortable, pivotIndex int) (newPivotIndex int) {
	// Swap the pivot to the end
	lastIndex := data.Len() - 1
	data.Swap(pivotIndex, lastIndex)
	pivotIndex = lastIndex
	// Launch the quicksort on this part of the slice
	var j int
	for i := 0; i < pivotIndex; i++ {
		if data.LessOrEqual(i, pivotIndex) {
			data.Swap(i, j)
			j++
		}
	}
	// Swap the pivot to the index where all data on the left are less of equals to him
	data.Swap(j, pivotIndex)
	// Return the new pivot index (now at index j)
	return j
}

func quickSortSelectPivot(data QuickSortable) (pivot int) {
	// Classical variant: take last index
	return data.Len() - 1
	// Check with median of medians ?
}
<commit_msg>quicksort - big boost thanks to concurrency limit for small slices<commit_after>package concurrentsort

import (
	"sync"
)

// Need proper benchmarking to compute the right value vs the cost of a goroutine
const QuickSortMinSizeForConcurrency = 10000

/*
	Interface and common types
*/

// QuickSortable is an interface which must be satisfied in order to call QuickSort()
type QuickSortable interface {
	Len() int
	LessOrEqual(i, j int) bool
	Swap(i, j int)
	GetSubSliceTo(i int) QuickSortable
	GetSubSliceFrom(j int) QuickSortable
}

// IntSlice attaches the methods of Interface to []int, sorting in increasing order.
type IntSlice []int

func (p IntSlice) Len() int {
	return len(p)
}
func (p IntSlice) LessOrEqual(i, j int) bool {
	return p[i] <= p[j]
}
func (p IntSlice) Swap(i, j int) {
	p[i], p[j] = p[j], p[i]
}
func (p IntSlice) GetSubSliceTo(i int) QuickSortable {
	return p[:i]
}
func (p IntSlice) GetSubSliceFrom(i int) QuickSortable {
	return p[i:]
}

/*
	Quick Sorting
*/

type quickSortConcurrentManager struct {
	availableWorkers int
	access           sync.Mutex
	rdvpoint         sync.WaitGroup
}

func (qscm *quickSortConcurrentManager) isAWorkerAvailable() bool {
	defer qscm.access.Unlock()
	qscm.access.Lock()
	if qscm.availableWorkers > 0 {
		qscm.availableWorkers--
		qscm.rdvpoint.Add(1)
		return true
	}
	return false
}

func (qscm *quickSortConcurrentManager) workerDone() {
	defer qscm.access.Unlock()
	qscm.access.Lock()
	qscm.availableWorkers++
	qscm.rdvpoint.Done()
}

// QuickSort sorts data using the quicksort algo distributed on nbWorkers goroutines
func QuickSort(data QuickSortable, nbWorkers int) {
	manager := quickSortConcurrentManager{availableWorkers: nbWorkers - 1}
	quickSort(data, &manager)
	manager.rdvpoint.Wait()
}

func quickSort(data QuickSortable, manager *quickSortConcurrentManager) {
	// Start sorting
	if data.Len() > 1 {
		// Select a pivot on the current slice
		pivotIndex := quickSortSelectPivot(data)
		// Partition it and recover new pivot index
		pivotIndex = quickSortPartition(data, pivotIndex)
		// Prepare the subslices
		firstSlice := data.GetSubSliceTo(pivotIndex)
		secondSlice := data.GetSubSliceFrom(pivotIndex + 1)
		// Are some of them eligible to concurrency ?
		firstSideLaunched := false
		secondSideLaunched := false
		// Try to side launch sub slices quicksort
		if firstSlice.Len() >= QuickSortMinSizeForConcurrency && manager.isAWorkerAvailable() {
			go func() {
				defer manager.workerDone()
				quickSort(firstSlice, manager)
			}()
			firstSideLaunched = true
		} else if secondSlice.Len() >= QuickSortMinSizeForConcurrency && manager.isAWorkerAvailable() {
			// If first did not make the side launch, maybe the second will ?
			go func() {
				defer manager.workerDone()
				quickSort(secondSlice, manager)
			}()
			secondSideLaunched = true
		}
		// Sort within the same goroutine
		if !firstSideLaunched {
			quickSort(firstSlice, manager)
		}
		if !secondSideLaunched {
			quickSort(secondSlice, manager)
		}
	}
}

func quickSortPartition(data QuickSortable, pivotIndex int) (newPivotIndex int) {
	// Swap the pivot to the end
	lastIndex := data.Len() - 1
	data.Swap(pivotIndex, lastIndex)
	pivotIndex = lastIndex
	// Launch the quicksort on this part of the slice
	var j int
	for i := 0; i < pivotIndex; i++ {
		if data.LessOrEqual(i, pivotIndex) {
			data.Swap(i, j)
			j++
		}
	}
	// Swap the pivot to the index where all data on the left are less of equals to him
	data.Swap(j, pivotIndex)
	// Return the new pivot index (now at index j)
	return j
}

func quickSortSelectPivot(data QuickSortable) (pivot int) {
	// Classical variant: take last index
	return data.Len() - 1
	// Check with median of medians ?
}
<|endoftext|>


<commit_before>package pg_test

import (
	"testing"
	"time"

	"github.com/go-pg/pg"

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

func concurrency() (int, int) {
	if testing.Short() {
		return 4, 100
	}
	return 10, 1000
}

var _ = Describe("DB timeout race", func() {
	var db *pg.DB
	var C, N int

	BeforeEach(func() {
		C, N = concurrency()
		N = 100
	})

	AfterEach(func() {
		pool := db.Pool()
		Expect(pool.Len()).To(Equal(0))
		Expect(pool.IdleLen()).To(Equal(0))

		err := db.Close()
		Expect(err).NotTo(HaveOccurred())

		// Give Postgres some time to recover.
		time.Sleep(time.Second)
	})

	test := func() {
		It("is race free", func() {
			perform(C, func(id int) {
				for i := 0; i < N; i++ {
					_, err := db.Exec("SELECT pg_sleep(1)")
					Expect(err).To(HaveOccurred())
				}
			})
		})
	}

	Describe("dial timeout", func() {
		BeforeEach(func() {
			opt := pgOptions()
			opt.DialTimeout = time.Nanosecond
			db = pg.Connect(opt)
		})

		test()
	})

	Describe("read timeout", func() {
		BeforeEach(func() {
			opt := pgOptions()
			opt.ReadTimeout = time.Nanosecond
			db = pg.Connect(opt)
		})

		test()
	})

	Describe("write timeout", func() {
		BeforeEach(func() {
			opt := pgOptions()
			opt.WriteTimeout = time.Nanosecond
			db = pg.Connect(opt)
		})

		test()
	})
})

var _ = Describe("DB race", func() {
	var db *pg.DB
	var C, N int

	BeforeEach(func() {
		db = pg.Connect(pgOptions())

		err := createTestSchema(db)
		Expect(err).NotTo(HaveOccurred())

		C, N = concurrency()
	})

	AfterEach(func() {
		err := db.Close()
		Expect(err).NotTo(HaveOccurred())
	})

	It("invalid Scan is race free", func() {
		perform(C, func(id int) {
			for i := 0; i < N; i++ {
				var n int
				if i%2 == 0 {
					_, err := db.QueryOne(pg.Scan(&n), "SELECT 1, 2")
					Expect(err).To(HaveOccurred())
				} else {
					_, err := db.QueryOne(pg.Scan(&n), "SELECT 123")
					Expect(err).NotTo(HaveOccurred())
					Expect(n).To(Equal(123))
				}
			}
		})
	})

	It("SelectOrInsert with OnConflict is race free", func() {
		perform(C, func(id int) {
			a := &Author{
				Name: "R. Scott Bakker",
			}
			for i := 0; i < N; i++ {
				a.ID = 0
				_, err := db.Model(a).
					Column("id").
					Where("name = ?name").
					OnConflict("DO NOTHING").
					Returning("id").
					SelectOrInsert(&a.ID)
				Expect(err).NotTo(HaveOccurred())
				Expect(a.ID).NotTo(BeZero())

				if i%(N/C) == 0 {
					err := db.Delete(a)
					if err != pg.ErrNoRows {
						Expect(err).NotTo(HaveOccurred())
					}
				}
			}
		})

		count, err := db.Model((*Author)(nil)).Count()
		Expect(err).NotTo(HaveOccurred())
		Expect(count).To(Equal(1))
	})

	It("SelectOrInsert without OnConflict is race free", func() {
		perform(C, func(id int) {
			a := &Author{
				Name: "R. Scott Bakker",
			}
			for i := 0; i < N; i++ {
				a.ID = 0
				_, err := db.Model(a).
					Column("id").
					Where("name = ?name").
					Returning("id").
					SelectOrInsert(&a.ID)
				Expect(err).NotTo(HaveOccurred())
				Expect(a.ID).NotTo(BeZero())

				if i%(N/C) == 0 {
					err := db.Delete(a)
					if err != pg.ErrNoRows {
						Expect(err).NotTo(HaveOccurred())
					}
				}
			}
		})

		count, err := db.Model((*Author)(nil)).Count()
		Expect(err).NotTo(HaveOccurred())
		Expect(count).To(Equal(1))
	})

	It("fully initializes model table", func() {
		type TestTable struct {
			tableName struct{} `sql:"'generate_series(0, 9)'"`
		}

		perform(C, func(id int) {
			n, err := db.Model((*TestTable)(nil)).Count()
			Expect(err).NotTo(HaveOccurred())
			Expect(n).To(Equal(10))
		})
	})
})
<commit_msg>add race tests for With[Context|Timeout]<commit_after>package pg_test

import (
	"context"
	"testing"
	"time"

	"github.com/go-pg/pg"

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

func concurrency() (int, int) {
	if testing.Short() {
		return 4, 100
	}
	return 10, 1000
}

var _ = Describe("DB timeout race", func() {
	var db *pg.DB
	var C, N int

	BeforeEach(func() {
		C, N = concurrency()
		N = 100
	})

	AfterEach(func() {
		pool := db.Pool()
		Expect(pool.Len()).To(Equal(0))
		Expect(pool.IdleLen()).To(Equal(0))

		err := db.Close()
		Expect(err).NotTo(HaveOccurred())

		// Give Postgres some time to recover.
		time.Sleep(time.Second)
	})

	test := func() {
		It("is race free", func() {
			perform(C, func(id int) {
				for i := 0; i < N; i++ {
					_, err := db.Exec("SELECT pg_sleep(1)")
					Expect(err).To(HaveOccurred())
				}
			})
		})
	}

	Describe("dial timeout", func() {
		BeforeEach(func() {
			opt := pgOptions()
			opt.DialTimeout = time.Nanosecond
			db = pg.Connect(opt)
		})

		test()
	})

	Describe("read timeout", func() {
		BeforeEach(func() {
			opt := pgOptions()
			opt.ReadTimeout = time.Nanosecond
			db = pg.Connect(opt)
		})

		test()
	})

	Describe("write timeout", func() {
		BeforeEach(func() {
			opt := pgOptions()
			opt.WriteTimeout = time.Nanosecond
			db = pg.Connect(opt)
		})

		test()
	})
})

var _ = Describe("DB race", func() {
	var db *pg.DB
	var C, N int

	BeforeEach(func() {
		db = pg.Connect(pgOptions())

		err := createTestSchema(db)
		Expect(err).NotTo(HaveOccurred())

		C, N = concurrency()
	})

	AfterEach(func() {
		err := db.Close()
		Expect(err).NotTo(HaveOccurred())
	})

	It("invalid Scan is race free", func() {
		perform(C, func(id int) {
			for i := 0; i < N; i++ {
				var n int
				if i%2 == 0 {
					_, err := db.QueryOne(pg.Scan(&n), "SELECT 1, 2")
					Expect(err).To(HaveOccurred())
				} else {
					_, err := db.QueryOne(pg.Scan(&n), "SELECT 123")
					Expect(err).NotTo(HaveOccurred())
					Expect(n).To(Equal(123))
				}
			}
		})
	})

	It("SelectOrInsert with OnConflict is race free", func() {
		perform(C, func(id int) {
			a := &Author{
				Name: "R. Scott Bakker",
			}
			for i := 0; i < N; i++ {
				a.ID = 0
				_, err := db.Model(a).
					Column("id").
					Where("name = ?name").
					OnConflict("DO NOTHING").
					Returning("id").
					SelectOrInsert(&a.ID)
				Expect(err).NotTo(HaveOccurred())
				Expect(a.ID).NotTo(BeZero())

				if i%(N/C) == 0 {
					err := db.Delete(a)
					if err != pg.ErrNoRows {
						Expect(err).NotTo(HaveOccurred())
					}
				}
			}
		})

		count, err := db.Model((*Author)(nil)).Count()
		Expect(err).NotTo(HaveOccurred())
		Expect(count).To(Equal(1))
	})

	It("SelectOrInsert without OnConflict is race free", func() {
		perform(C, func(id int) {
			a := &Author{
				Name: "R. Scott Bakker",
			}
			for i := 0; i < N; i++ {
				a.ID = 0
				_, err := db.Model(a).
					Column("id").
					Where("name = ?name").
					Returning("id").
					SelectOrInsert(&a.ID)
				Expect(err).NotTo(HaveOccurred())
				Expect(a.ID).NotTo(BeZero())

				if i%(N/C) == 0 {
					err := db.Delete(a)
					if err != pg.ErrNoRows {
						Expect(err).NotTo(HaveOccurred())
					}
				}
			}
		})

		count, err := db.Model((*Author)(nil)).Count()
		Expect(err).NotTo(HaveOccurred())
		Expect(count).To(Equal(1))
	})

	It("WithContext is race free", func() {
		perform(C, func(id int) {
			dbWithCtx := db.WithContext(context.Background())
			Expect(dbWithCtx).NotTo(BeNil())
		})
	})

	It("WithTimeout is race free", func() {
		perform(C, func(id int) {
			dbWithTimeout := db.WithTimeout(5 * time.Second)
			Expect(dbWithTimeout).NotTo(BeNil())
		})
	})

	It("fully initializes model table", func() {
		type TestTable struct {
			tableName struct{} `sql:"'generate_series(0, 9)'"`
		}

		perform(C, func(id int) {
			n, err := db.Model((*TestTable)(nil)).Count()
			Expect(err).NotTo(HaveOccurred())
			Expect(n).To(Equal(10))
		})
	})
})
<|endoftext|>