<commit_before>/*
   Copyright The containerd 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 cap provides Linux capability utility
package cap

import (
	"bufio"
	"io"
	"os"
	"strconv"
	"strings"

	"github.com/pkg/errors"
)

// FromNumber returns a cap string like "CAP_SYS_ADMIN"
// that corresponds to the given number like 21.
//
// FromNumber returns an empty string for unknown cap number.
func FromNumber(num int) string {
	if num < 0 || num > len(capsLatest)-1 {
		return ""
	}
	return capsLatest[num]
}

// FromBitmap parses an uint64 bitmap into string slice like
// []{"CAP_SYS_ADMIN", ...}.
//
// Unknown cap numbers are returned as []int.
func FromBitmap(v uint64) ([]string, []int) {
	var (
		res     []string
		unknown []int
	)
	for i := 0; i <= 63; i++ {
		if b := (v >> i) & 0x1; b == 0x1 {
			if s := FromNumber(i); s != "" {
				res = append(res, s)
			} else {
				unknown = append(unknown, i)
			}
		}
	}
	return res, unknown
}

// Type is the type of capability
type Type int

const (
	// Effective is CapEff
	Effective Type = 1 << iota
	// Permitted is CapPrm
	Permitted
	// Inheritable is CapInh
	Inheritable
	// Bounding is CapBnd
	Bounding
	// Ambient is CapAmb
	Ambient
)

// ParseProcPIDStatus returns uint64 bitmap value from /proc/<PID>/status file
func ParseProcPIDStatus(r io.Reader) (map[Type]uint64, error) {
	res := make(map[Type]uint64)
	scanner := bufio.NewScanner(r)
	for scanner.Scan() {
		line := scanner.Text()
		pair := strings.SplitN(line, ":", 2)
		if len(pair) != 2 {
			continue
		}
		k := strings.TrimSpace(pair[0])
		v := strings.TrimSpace(pair[1])
		switch k {
		case "CapInh", "CapPrm", "CapEff", "CapBnd", "CapAmb":
			ui64, err := strconv.ParseUint(v, 16, 64)
			if err != nil {
				return nil, errors.Errorf("failed to parse line %q", line)
			}
			switch k {
			case "CapInh":
				res[Inheritable] = ui64
			case "CapPrm":
				res[Permitted] = ui64
			case "CapEff":
				res[Effective] = ui64
			case "CapBnd":
				res[Bounding] = ui64
			case "CapAmb":
				res[Ambient] = ui64
			}
		}
	}
	if err := scanner.Err(); err != nil {
		return nil, err
	}
	return res, nil
}

// Current returns the list of the effective and the known caps of
// the current process.
//
// The result is like []string{"CAP_SYS_ADMIN", ...}.
//
// The result does not contain caps that are not recognized by
// the "github.com/syndtr/gocapability" library.
func Current() ([]string, error) {
	f, err := os.Open("/proc/self/status")
	if err != nil {
		return nil, err
	}
	defer f.Close()
	caps, err := ParseProcPIDStatus(f)
	if err != nil {
		return nil, err
	}
	capEff := caps[Effective]
	names, _ := FromBitmap(capEff)
	return names, nil
}

var (
	// caps35 is the caps of kernel 3.5 (37 entries)
	caps35 = []string{
		"CAP_CHOWN",            // 2.2
		"CAP_DAC_OVERRIDE",     // 2.2
		"CAP_DAC_READ_SEARCH",  // 2.2
		"CAP_FOWNER",           // 2.2
		"CAP_FSETID",           // 2.2
		"CAP_KILL",             // 2.2
		"CAP_SETGID",           // 2.2
		"CAP_SETUID",           // 2.2
		"CAP_SETPCAP",          // 2.2
		"CAP_LINUX_IMMUTABLE",  // 2.2
		"CAP_NET_BIND_SERVICE", // 2.2
		"CAP_NET_BROADCAST",    // 2.2
		"CAP_NET_ADMIN",        // 2.2
		"CAP_NET_RAW",          // 2.2
		"CAP_IPC_LOCK",         // 2.2
		"CAP_IPC_OWNER",        // 2.2
		"CAP_SYS_MODULE",       // 2.2
		"CAP_SYS_RAWIO",        // 2.2
		"CAP_SYS_CHROOT",       // 2.2
		"CAP_SYS_PTRACE",       // 2.2
		"CAP_SYS_PACCT",        // 2.2
		"CAP_SYS_ADMIN",        // 2.2
		"CAP_SYS_BOOT",         // 2.2
		"CAP_SYS_NICE",         // 2.2
		"CAP_SYS_RESOURCE",     // 2.2
		"CAP_SYS_TIME",         // 2.2
		"CAP_SYS_TTY_CONFIG",   // 2.2
		"CAP_MKNOD",            // 2.4
		"CAP_LEASE",            // 2.4
		"CAP_AUDIT_WRITE",      // 2.6.11
		"CAP_AUDIT_CONTROL",    // 2.6.11
		"CAP_SETFCAP",          // 2.6.24
		"CAP_MAC_OVERRIDE",     // 2.6.25
		"CAP_MAC_ADMIN",        // 2.6.25
		"CAP_SYSLOG",           // 2.6.37
		"CAP_WAKE_ALARM",       // 3.0
		"CAP_BLOCK_SUSPEND",    // 3.5
	}
	// caps316 is the caps of kernel 3.16 (38 entries)
	caps316 = append(caps35, "CAP_AUDIT_READ")
	// caps58 is the caps of kernel 5.8 (40 entries)
	caps58 = append(caps316, []string{"CAP_PERFMON", "CAP_BPF"}...)
	// caps59 is the caps of kernel 5.9 (41 entries)
	caps59     = append(caps58, "CAP_CHECKPOINT_RESTORE")
	capsLatest = caps59
)

// Known returns the known cap strings of the latest kernel.
// The current latest kernel is 5.9.
func Known() []string {
	return capsLatest
}
<commit_msg>pkg/cap: remove an outdated comment<commit_after>/*
   Copyright The containerd 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 cap provides Linux capability utility
package cap

import (
	"bufio"
	"io"
	"os"
	"strconv"
	"strings"

	"github.com/pkg/errors"
)

// FromNumber returns a cap string like "CAP_SYS_ADMIN"
// that corresponds to the given number like 21.
//
// FromNumber returns an empty string for unknown cap number.
func FromNumber(num int) string {
	if num < 0 || num > len(capsLatest)-1 {
		return ""
	}
	return capsLatest[num]
}

// FromBitmap parses an uint64 bitmap into string slice like
// []{"CAP_SYS_ADMIN", ...}.
//
// Unknown cap numbers are returned as []int.
func FromBitmap(v uint64) ([]string, []int) {
	var (
		res     []string
		unknown []int
	)
	for i := 0; i <= 63; i++ {
		if b := (v >> i) & 0x1; b == 0x1 {
			if s := FromNumber(i); s != "" {
				res = append(res, s)
			} else {
				unknown = append(unknown, i)
			}
		}
	}
	return res, unknown
}

// Type is the type of capability
type Type int

const (
	// Effective is CapEff
	Effective Type = 1 << iota
	// Permitted is CapPrm
	Permitted
	// Inheritable is CapInh
	Inheritable
	// Bounding is CapBnd
	Bounding
	// Ambient is CapAmb
	Ambient
)

// ParseProcPIDStatus returns uint64 bitmap value from /proc/<PID>/status file
func ParseProcPIDStatus(r io.Reader) (map[Type]uint64, error) {
	res := make(map[Type]uint64)
	scanner := bufio.NewScanner(r)
	for scanner.Scan() {
		line := scanner.Text()
		pair := strings.SplitN(line, ":", 2)
		if len(pair) != 2 {
			continue
		}
		k := strings.TrimSpace(pair[0])
		v := strings.TrimSpace(pair[1])
		switch k {
		case "CapInh", "CapPrm", "CapEff", "CapBnd", "CapAmb":
			ui64, err := strconv.ParseUint(v, 16, 64)
			if err != nil {
				return nil, errors.Errorf("failed to parse line %q", line)
			}
			switch k {
			case "CapInh":
				res[Inheritable] = ui64
			case "CapPrm":
				res[Permitted] = ui64
			case "CapEff":
				res[Effective] = ui64
			case "CapBnd":
				res[Bounding] = ui64
			case "CapAmb":
				res[Ambient] = ui64
			}
		}
	}
	if err := scanner.Err(); err != nil {
		return nil, err
	}
	return res, nil
}

// Current returns the list of the effective and the known caps of
// the current process.
//
// The result is like []string{"CAP_SYS_ADMIN", ...}.
func Current() ([]string, error) {
	f, err := os.Open("/proc/self/status")
	if err != nil {
		return nil, err
	}
	defer f.Close()
	caps, err := ParseProcPIDStatus(f)
	if err != nil {
		return nil, err
	}
	capEff := caps[Effective]
	names, _ := FromBitmap(capEff)
	return names, nil
}

var (
	// caps35 is the caps of kernel 3.5 (37 entries)
	caps35 = []string{
		"CAP_CHOWN",            // 2.2
		"CAP_DAC_OVERRIDE",     // 2.2
		"CAP_DAC_READ_SEARCH",  // 2.2
		"CAP_FOWNER",           // 2.2
		"CAP_FSETID",           // 2.2
		"CAP_KILL",             // 2.2
		"CAP_SETGID",           // 2.2
		"CAP_SETUID",           // 2.2
		"CAP_SETPCAP",          // 2.2
		"CAP_LINUX_IMMUTABLE",  // 2.2
		"CAP_NET_BIND_SERVICE", // 2.2
		"CAP_NET_BROADCAST",    // 2.2
		"CAP_NET_ADMIN",        // 2.2
		"CAP_NET_RAW",          // 2.2
		"CAP_IPC_LOCK",         // 2.2
		"CAP_IPC_OWNER",        // 2.2
		"CAP_SYS_MODULE",       // 2.2
		"CAP_SYS_RAWIO",        // 2.2
		"CAP_SYS_CHROOT",       // 2.2
		"CAP_SYS_PTRACE",       // 2.2
		"CAP_SYS_PACCT",        // 2.2
		"CAP_SYS_ADMIN",        // 2.2
		"CAP_SYS_BOOT",         // 2.2
		"CAP_SYS_NICE",         // 2.2
		"CAP_SYS_RESOURCE",     // 2.2
		"CAP_SYS_TIME",         // 2.2
		"CAP_SYS_TTY_CONFIG",   // 2.2
		"CAP_MKNOD",            // 2.4
		"CAP_LEASE",            // 2.4
		"CAP_AUDIT_WRITE",      // 2.6.11
		"CAP_AUDIT_CONTROL",    // 2.6.11
		"CAP_SETFCAP",          // 2.6.24
		"CAP_MAC_OVERRIDE",     // 2.6.25
		"CAP_MAC_ADMIN",        // 2.6.25
		"CAP_SYSLOG",           // 2.6.37
		"CAP_WAKE_ALARM",       // 3.0
		"CAP_BLOCK_SUSPEND",    // 3.5
	}
	// caps316 is the caps of kernel 3.16 (38 entries)
	caps316 = append(caps35, "CAP_AUDIT_READ")
	// caps58 is the caps of kernel 5.8 (40 entries)
	caps58 = append(caps316, []string{"CAP_PERFMON", "CAP_BPF"}...)
	// caps59 is the caps of kernel 5.9 (41 entries)
	caps59     = append(caps58, "CAP_CHECKPOINT_RESTORE")
	capsLatest = caps59
)

// Known returns the known cap strings of the latest kernel.
// The current latest kernel is 5.9.
func Known() []string {
	return capsLatest
}
<|endoftext|>


<commit_before>// Code generated by MockGen. DO NOT EDIT.
// Source: pkg/dao/user.go

// Package dao is a generated GoMock package.
package dao

import (
	context "context"
	reflect "reflect"
	models "tplgo/pkg/models"

	gomock "github.com/golang/mock/gomock"
)

// MockUserDao is a mock of UserDao interface.
type MockUserDao struct {
	ctrl     *gomock.Controller
	recorder *MockUserDaoMockRecorder
}

// MockUserDaoMockRecorder is the mock recorder for MockUserDao.
type MockUserDaoMockRecorder struct {
	mock *MockUserDao
}

// NewMockUserDao creates a new mock instance.
func NewMockUserDao(ctrl *gomock.Controller) *MockUserDao {
	mock := &MockUserDao{ctrl: ctrl}
	mock.recorder = &MockUserDaoMockRecorder{mock}
	return mock
}

// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockUserDao) EXPECT() *MockUserDaoMockRecorder {
	return m.recorder
}

// FindByID mocks base method.
func (m *MockUserDao) FindByID(ctx context.Context, id int64) (*models.User, error) {
	m.ctrl.T.Helper()
	ret := m.ctrl.Call(m, "FindByID", ctx, id)
	ret0, _ := ret[0].(*models.User)
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

// FindByID indicates an expected call of FindByID.
func (mr *MockUserDaoMockRecorder) FindByID(ctx, id interface{}) *gomock.Call {
	mr.mock.ctrl.T.Helper()
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindByID", reflect.TypeOf((*MockUserDao)(nil).FindByID), ctx, id)
}
<commit_msg>remove mock_user<commit_after><|endoftext|>


<commit_before>package edit

// Elvish code for default bindings, hooks, and similar initializations. This assumes the `edit`
// namespace as the global namespace.
const elvInit = `
after-command = [
	# Capture the most recent interactive command duration in $edit:command-duration
	# as a convenience for prompt functions. Note: The first time this is run is after
	# shell.sourceRC() finishes so the initial value of command-duration is the time
	# to execute the user's interactive configuration script.
	[m]{
		command-duration = $m[duration]
	}
]

global-binding = (binding-table [
  &Ctrl-'['= $close-mode~
])

insert:binding = (binding-table [
  &Left=  $move-dot-left~
  &Right= $move-dot-right~

  &Ctrl-Left=  $move-dot-left-word~
  &Ctrl-Right= $move-dot-right-word~
  &Alt-Left=   $move-dot-left-word~
  &Alt-Right=  $move-dot-right-word~
  &Alt-b=      $move-dot-left-word~
  &Alt-f=      $move-dot-right-word~

  &Home= $move-dot-sol~
  &End=  $move-dot-eol~

  &Backspace= $kill-rune-left~
  &Ctrl-H=    $kill-rune-left~
  &Delete=    $kill-rune-right~
  &Ctrl-W=    $kill-word-left~
  &Ctrl-U=    $kill-line-left~
  &Ctrl-K=    $kill-line-right~

  &Ctrl-V= $insert-raw~

  &Alt-,=  $lastcmd:start~
  &Alt-.=  $insert-last-word~
  &Ctrl-R= $histlist:start~
  &Ctrl-L= $location:start~
  &Ctrl-N= $navigation:start~
  &Tab=    $completion:smart-start~
  &Up=     $history:start~
  &Alt-x=  $minibuf:start~

  &Enter=   $smart-enter~
  &Ctrl-D=  $return-eof~
])

command:binding = (binding-table [
 &'$'= $move-dot-eol~
 &0=   $move-dot-sol~
 &D=   $kill-line-right~
 &b=   $move-dot-left-word~
 &h=   $move-dot-left~
 &i=   $close-mode~
 &j=   $move-dot-down~
 &k=   $move-dot-up~
 &l=   $move-dot-right~
 &w=   $move-dot-right-word~
 &x=   $kill-rune-right~
])

listing:binding = (binding-table [
  &Up=        $listing:up~
  &Down=      $listing:down~
  &Tab=       $listing:down-cycle~
  &Shift-Tab= $listing:up-cycle~
])

histlist:binding = (binding-table [
  &Ctrl-D= $histlist:toggle-dedup~
])

navigation:binding = (binding-table [
  &Left=     $navigation:left~
  &Right=    $navigation:right~
  &Up=       $navigation:up~
  &Down=     $navigation:down~
  &PageUp=   $navigation:page-up~
  &PageDown= $navigation:page-down~
  &Alt-Up=   $navigation:file-preview-up~
  &Alt-Down= $navigation:file-preview-down~
  &Enter=    $navigation:insert-selected-and-quit~
  &Alt-Enter= $navigation:insert-selected~
  &Ctrl-F=   $navigation:trigger-filter~
  &Ctrl-H=   $navigation:trigger-shown-hidden~
])

completion:binding = (binding-table [
  &Down=     $completion:down~
  &Up=       $completion:up~
  &Tab=      $completion:down-cycle~
  &Shift-Tab=$completion:up-cycle~
  &Left=     $completion:left~
  &Right=    $completion:right~
])

history:binding = (binding-table [
  &Up=       $history:up~
  &Down=     $history:down-or-quit~
  &Ctrl-'['= $close-mode~
])

lastcmd:binding = (binding-table [
  &Alt-,=  $listing:accept~
])

-instant:binding = (binding-table [
  &
])

minibuf:binding = (binding-table [
  &
])
`

// vi: set et:
<commit_msg>Make Alt-x a global binding.<commit_after>package edit

// Elvish code for default bindings, hooks, and similar initializations. This assumes the `edit`
// namespace as the global namespace.
const elvInit = `
after-command = [
	# Capture the most recent interactive command duration in $edit:command-duration
	# as a convenience for prompt functions. Note: The first time this is run is after
	# shell.sourceRC() finishes so the initial value of command-duration is the time
	# to execute the user's interactive configuration script.
	[m]{
		command-duration = $m[duration]
	}
]

global-binding = (binding-table [
  &Ctrl-'['= $close-mode~
  &Alt-x=    $minibuf:start~
])

insert:binding = (binding-table [
  &Left=  $move-dot-left~
  &Right= $move-dot-right~

  &Ctrl-Left=  $move-dot-left-word~
  &Ctrl-Right= $move-dot-right-word~
  &Alt-Left=   $move-dot-left-word~
  &Alt-Right=  $move-dot-right-word~
  &Alt-b=      $move-dot-left-word~
  &Alt-f=      $move-dot-right-word~

  &Home= $move-dot-sol~
  &End=  $move-dot-eol~

  &Backspace= $kill-rune-left~
  &Ctrl-H=    $kill-rune-left~
  &Delete=    $kill-rune-right~
  &Ctrl-W=    $kill-word-left~
  &Ctrl-U=    $kill-line-left~
  &Ctrl-K=    $kill-line-right~

  &Ctrl-V= $insert-raw~

  &Alt-,=  $lastcmd:start~
  &Alt-.=  $insert-last-word~
  &Ctrl-R= $histlist:start~
  &Ctrl-L= $location:start~
  &Ctrl-N= $navigation:start~
  &Tab=    $completion:smart-start~
  &Up=     $history:start~

  &Enter=   $smart-enter~
  &Ctrl-D=  $return-eof~
])

command:binding = (binding-table [
 &'$'= $move-dot-eol~
 &0=   $move-dot-sol~
 &D=   $kill-line-right~
 &b=   $move-dot-left-word~
 &h=   $move-dot-left~
 &i=   $close-mode~
 &j=   $move-dot-down~
 &k=   $move-dot-up~
 &l=   $move-dot-right~
 &w=   $move-dot-right-word~
 &x=   $kill-rune-right~
])

listing:binding = (binding-table [
  &Up=        $listing:up~
  &Down=      $listing:down~
  &Tab=       $listing:down-cycle~
  &Shift-Tab= $listing:up-cycle~
])

histlist:binding = (binding-table [
  &Ctrl-D= $histlist:toggle-dedup~
])

navigation:binding = (binding-table [
  &Left=     $navigation:left~
  &Right=    $navigation:right~
  &Up=       $navigation:up~
  &Down=     $navigation:down~
  &PageUp=   $navigation:page-up~
  &PageDown= $navigation:page-down~
  &Alt-Up=   $navigation:file-preview-up~
  &Alt-Down= $navigation:file-preview-down~
  &Enter=    $navigation:insert-selected-and-quit~
  &Alt-Enter= $navigation:insert-selected~
  &Ctrl-F=   $navigation:trigger-filter~
  &Ctrl-H=   $navigation:trigger-shown-hidden~
])

completion:binding = (binding-table [
  &Down=     $completion:down~
  &Up=       $completion:up~
  &Tab=      $completion:down-cycle~
  &Shift-Tab=$completion:up-cycle~
  &Left=     $completion:left~
  &Right=    $completion:right~
])

history:binding = (binding-table [
  &Up=       $history:up~
  &Down=     $history:down-or-quit~
  &Ctrl-'['= $close-mode~
])

lastcmd:binding = (binding-table [
  &Alt-,=  $listing:accept~
])

-instant:binding = (binding-table [
  &
])

minibuf:binding = (binding-table [
  &
])
`

// vi: set et:
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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

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

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

package engine

import (
	"bytes"
	"fmt"
	"path"
	"sort"
	"strings"
	"text/template"

	"github.com/Masterminds/sprig"

	"k8s.io/helm/pkg/chartutil"
	"k8s.io/helm/pkg/proto/hapi/chart"
)

// Engine is an implementation of 'cmd/tiller/environment'.Engine that uses Go templates.
type Engine struct {
	// FuncMap contains the template functions that will be passed to each
	// render call. This may only be modified before the first call to Render.
	FuncMap template.FuncMap
	// If strict is enabled, template rendering will fail if a template references
	// a value that was not passed in.
	Strict           bool
	CurrentTemplates map[string]renderable
}

// New creates a new Go template Engine instance.
//
// The FuncMap is initialized here. You may modify the FuncMap _prior to_ the
// first invocation of Render.
//
// The FuncMap sets all of the Sprig functions except for those that provide
// access to the underlying OS (env, expandenv).
func New() *Engine {
	f := FuncMap()
	return &Engine{
		FuncMap: f,
	}
}

// FuncMap returns a mapping of all of the functions that Engine has.
//
// Because some functions are late-bound (e.g. contain context-sensitive
// data), the functions may not all perform identically outside of an
// Engine as they will inside of an Engine.
//
// Known late-bound functions:
//
//	- "include": This is late-bound in Engine.Render(). The version
//	   included in the FuncMap is a placeholder.
//      - "required": This is late-bound in Engine.Render(). The version
//	   included in the FuncMap is a placeholder.
//      - "tpl": This is late-bound in Engine.Render(). The version
//	   included in the FuncMap is a placeholder.
func FuncMap() template.FuncMap {
	f := sprig.TxtFuncMap()
	delete(f, "env")
	delete(f, "expandenv")

	// Add some extra functionality
	extra := template.FuncMap{
		"toToml":   chartutil.ToToml,
		"toYaml":   chartutil.ToYaml,
		"fromYaml": chartutil.FromYaml,
		"toJson":   chartutil.ToJson,
		"fromJson": chartutil.FromJson,

		// This is a placeholder for the "include" function, which is
		// late-bound to a template. By declaring it here, we preserve the
		// integrity of the linter.
		"include":  func(string, interface{}) string { return "not implemented" },
		"required": func(string, interface{}) interface{} { return "not implemented" },
		"tpl":      func(string, interface{}) interface{} { return "not implemented" },
	}

	for k, v := range extra {
		f[k] = v
	}

	return f
}

// Render takes a chart, optional values, and value overrides, and attempts to render the Go templates.
//
// Render can be called repeatedly on the same engine.
//
// This will look in the chart's 'templates' data (e.g. the 'templates/' directory)
// and attempt to render the templates there using the values passed in.
//
// Values are scoped to their templates. A dependency template will not have
// access to the values set for its parent. If chart "foo" includes chart "bar",
// "bar" will not have access to the values for "foo".
//
// Values should be prepared with something like `chartutils.ReadValues`.
//
// Values are passed through the templates according to scope. If the top layer
// chart includes the chart foo, which includes the chart bar, the values map
// will be examined for a table called "foo". If "foo" is found in vals,
// that section of the values will be passed into the "foo" chart. And if that
// section contains a value named "bar", that value will be passed on to the
// bar chart during render time.
func (e *Engine) Render(chrt *chart.Chart, values chartutil.Values) (map[string]string, error) {
	// Render the charts
	tmap := allTemplates(chrt, values)
	e.CurrentTemplates = tmap
	return e.render(tmap)
}

// renderable is an object that can be rendered.
type renderable struct {
	// tpl is the current template.
	tpl string
	// vals are the values to be supplied to the template.
	vals chartutil.Values
	// namespace prefix to the templates of the current chart
	basePath string
}

// alterFuncMap takes the Engine's FuncMap and adds context-specific functions.
//
// The resulting FuncMap is only valid for the passed-in template.
func (e *Engine) alterFuncMap(t *template.Template) template.FuncMap {
	// Clone the func map because we are adding context-specific functions.
	var funcMap template.FuncMap = map[string]interface{}{}
	for k, v := range e.FuncMap {
		funcMap[k] = v
	}

	// Add the 'include' function here so we can close over t.
	funcMap["include"] = func(name string, data interface{}) (string, error) {
		buf := bytes.NewBuffer(nil)
		if err := t.ExecuteTemplate(buf, name, data); err != nil {
			return "", err
		}
		return buf.String(), nil
	}

	// Add the 'required' function here
	funcMap["required"] = func(warn string, val interface{}) (interface{}, error) {
		if val == nil {
			return val, fmt.Errorf(warn)
		} else if _, ok := val.(string); ok {
			if val == "" {
				return val, fmt.Errorf(warn)
			}
		}
		return val, nil
	}

	// Add the 'tpl' function here
	funcMap["tpl"] = func(tpl string, vals chartutil.Values) (string, error) {
		basePath, err := vals.PathValue("Template.BasePath")
		if err != nil {
			return "", fmt.Errorf("Cannot retrieve Template.Basepath from values inside tpl function: %s (%s)", tpl, err.Error())
		}

		r := renderable{
			tpl:      tpl,
			vals:     vals,
			basePath: basePath.(string),
		}

		templates := map[string]renderable{}
		templateName, err := vals.PathValue("Template.Name")
		if err != nil {
			return "", fmt.Errorf("Cannot retrieve Template.Name from values inside tpl function: %s (%s)", tpl, err.Error())
		}

		templates[templateName.(string)] = r

		result, err := e.render(templates)
		if err != nil {
			return "", fmt.Errorf("Error during tpl function execution for %q: %s", tpl, err.Error())
		}
		return result[templateName.(string)], nil
	}

	return funcMap
}

// render takes a map of templates/values and renders them.
func (e *Engine) render(tpls map[string]renderable) (map[string]string, error) {
	// Basically, what we do here is start with an empty parent template and then
	// build up a list of templates -- one for each file. Once all of the templates
	// have been parsed, we loop through again and execute every template.
	//
	// The idea with this process is to make it possible for more complex templates
	// to share common blocks, but to make the entire thing feel like a file-based
	// template engine.
	t := template.New("gotpl")
	if e.Strict {
		t.Option("missingkey=error")
	} else {
		// Not that zero will attempt to add default values for types it knows,
		// but will still emit <no value> for others. We mitigate that later.
		t.Option("missingkey=zero")
	}

	funcMap := e.alterFuncMap(t)

	// We want to parse the templates in a predictable order. The order favors
	// higher-level (in file system) templates over deeply nested templates.
	keys := sortTemplates(tpls)

	files := []string{}

	for _, fname := range keys {
		r := tpls[fname]
		t = t.New(fname).Funcs(funcMap)
		if _, err := t.Parse(r.tpl); err != nil {
			return map[string]string{}, fmt.Errorf("parse error in %q: %s", fname, err)
		}
		files = append(files, fname)
	}

	// Adding the engine's currentTemplates to the template context
	// so they can be referenced in the tpl function
	for fname, r := range e.CurrentTemplates {
		if t.Lookup(fname) == nil {
			t = t.New(fname).Funcs(funcMap)
			if _, err := t.Parse(r.tpl); err != nil {
				return map[string]string{}, fmt.Errorf("parse error in %q: %s", fname, err)
			}
		}
	}

	rendered := make(map[string]string, len(files))
	var buf bytes.Buffer
	for _, file := range files {
		// Don't render partials. We don't care out the direct output of partials.
		// They are only included from other templates.
		if strings.HasPrefix(path.Base(file), "_") {
			continue
		}
		// At render time, add information about the template that is being rendered.
		vals := tpls[file].vals
		vals["Template"] = map[string]interface{}{"Name": file, "BasePath": tpls[file].basePath}
		if err := t.ExecuteTemplate(&buf, file, vals); err != nil {
			return map[string]string{}, fmt.Errorf("render error in %q: %s", file, err)
		}

		// Work around the issue where Go will emit "<no value>" even if Options(missing=zero)
		// is set. Since missing=error will never get here, we do not need to handle
		// the Strict case.
		rendered[file] = strings.Replace(buf.String(), "<no value>", "", -1)
		buf.Reset()
	}

	return rendered, nil
}

func sortTemplates(tpls map[string]renderable) []string {
	keys := make([]string, len(tpls))
	i := 0
	for key := range tpls {
		keys[i] = key
		i++
	}
	sort.Sort(sort.Reverse(byPathLen(keys)))
	return keys
}

type byPathLen []string

func (p byPathLen) Len() int      { return len(p) }
func (p byPathLen) Swap(i, j int) { p[j], p[i] = p[i], p[j] }
func (p byPathLen) Less(i, j int) bool {
	a, b := p[i], p[j]
	ca, cb := strings.Count(a, "/"), strings.Count(b, "/")
	if ca == cb {
		return strings.Compare(a, b) == -1
	}
	return ca < cb
}

// allTemplates returns all templates for a chart and its dependencies.
//
// As it goes, it also prepares the values in a scope-sensitive manner.
func allTemplates(c *chart.Chart, vals chartutil.Values) map[string]renderable {
	templates := map[string]renderable{}
	recAllTpls(c, templates, vals, true, "")
	return templates
}

// recAllTpls recurses through the templates in a chart.
//
// As it recurses, it also sets the values to be appropriate for the template
// scope.
func recAllTpls(c *chart.Chart, templates map[string]renderable, parentVals chartutil.Values, top bool, parentID string) {
	// This should never evaluate to a nil map. That will cause problems when
	// values are appended later.
	cvals := chartutil.Values{}
	if top {
		// If this is the top of the rendering tree, assume that parentVals
		// is already resolved to the authoritative values.
		cvals = parentVals
	} else if c.Metadata != nil && c.Metadata.Name != "" {
		// If there is a {{.Values.ThisChart}} in the parent metadata,
		// copy that into the {{.Values}} for this template.
		newVals := chartutil.Values{}
		if vs, err := parentVals.Table("Values"); err == nil {
			if tmp, err := vs.Table(c.Metadata.Name); err == nil {
				newVals = tmp
			}
		}

		cvals = map[string]interface{}{
			"Values":       newVals,
			"Release":      parentVals["Release"],
			"Chart":        c.Metadata,
			"Files":        chartutil.NewFiles(c.Files),
			"Capabilities": parentVals["Capabilities"],
		}
	}

	newParentID := c.Metadata.Name
	if parentID != "" {
		// We artificially reconstruct the chart path to child templates. This
		// creates a namespaced filename that can be used to track down the source
		// of a particular template declaration.
		newParentID = path.Join(parentID, "charts", newParentID)
	}

	for _, child := range c.Dependencies {
		recAllTpls(child, templates, cvals, false, newParentID)
	}
	for _, t := range c.Templates {
		templates[path.Join(newParentID, t.Name)] = renderable{
			tpl:      string(t.Data),
			vals:     cvals,
			basePath: path.Join(newParentID, "templates"),
		}
	}
}
<commit_msg>Added code to recover from a tiller pod crash in an event of template render failure<commit_after>/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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

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

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

package engine

import (
	"bytes"
	"fmt"
	"log"
	"path"
	"sort"
	"strings"
	"text/template"

	"github.com/Masterminds/sprig"

	"k8s.io/helm/pkg/chartutil"
	"k8s.io/helm/pkg/proto/hapi/chart"
)

// Engine is an implementation of 'cmd/tiller/environment'.Engine that uses Go templates.
type Engine struct {
	// FuncMap contains the template functions that will be passed to each
	// render call. This may only be modified before the first call to Render.
	FuncMap template.FuncMap
	// If strict is enabled, template rendering will fail if a template references
	// a value that was not passed in.
	Strict           bool
	CurrentTemplates map[string]renderable
}

// New creates a new Go template Engine instance.
//
// The FuncMap is initialized here. You may modify the FuncMap _prior to_ the
// first invocation of Render.
//
// The FuncMap sets all of the Sprig functions except for those that provide
// access to the underlying OS (env, expandenv).
func New() *Engine {
	f := FuncMap()
	return &Engine{
		FuncMap: f,
	}
}

// FuncMap returns a mapping of all of the functions that Engine has.
//
// Because some functions are late-bound (e.g. contain context-sensitive
// data), the functions may not all perform identically outside of an
// Engine as they will inside of an Engine.
//
// Known late-bound functions:
//
//	- "include": This is late-bound in Engine.Render(). The version
//	   included in the FuncMap is a placeholder.
//      - "required": This is late-bound in Engine.Render(). The version
//	   included in the FuncMap is a placeholder.
//      - "tpl": This is late-bound in Engine.Render(). The version
//	   included in the FuncMap is a placeholder.
func FuncMap() template.FuncMap {
	f := sprig.TxtFuncMap()
	delete(f, "env")
	delete(f, "expandenv")

	// Add some extra functionality
	extra := template.FuncMap{
		"toToml":   chartutil.ToToml,
		"toYaml":   chartutil.ToYaml,
		"fromYaml": chartutil.FromYaml,
		"toJson":   chartutil.ToJson,
		"fromJson": chartutil.FromJson,

		// This is a placeholder for the "include" function, which is
		// late-bound to a template. By declaring it here, we preserve the
		// integrity of the linter.
		"include":  func(string, interface{}) string { return "not implemented" },
		"required": func(string, interface{}) interface{} { return "not implemented" },
		"tpl":      func(string, interface{}) interface{} { return "not implemented" },
	}

	for k, v := range extra {
		f[k] = v
	}

	return f
}

// Render takes a chart, optional values, and value overrides, and attempts to render the Go templates.
//
// Render can be called repeatedly on the same engine.
//
// This will look in the chart's 'templates' data (e.g. the 'templates/' directory)
// and attempt to render the templates there using the values passed in.
//
// Values are scoped to their templates. A dependency template will not have
// access to the values set for its parent. If chart "foo" includes chart "bar",
// "bar" will not have access to the values for "foo".
//
// Values should be prepared with something like `chartutils.ReadValues`.
//
// Values are passed through the templates according to scope. If the top layer
// chart includes the chart foo, which includes the chart bar, the values map
// will be examined for a table called "foo". If "foo" is found in vals,
// that section of the values will be passed into the "foo" chart. And if that
// section contains a value named "bar", that value will be passed on to the
// bar chart during render time.
func (e *Engine) Render(chrt *chart.Chart, values chartutil.Values) (map[string]string, error) {
	// Render the charts
	tmap := allTemplates(chrt, values)
	e.CurrentTemplates = tmap
	return e.render(tmap)
}

// renderable is an object that can be rendered.
type renderable struct {
	// tpl is the current template.
	tpl string
	// vals are the values to be supplied to the template.
	vals chartutil.Values
	// namespace prefix to the templates of the current chart
	basePath string
}

// alterFuncMap takes the Engine's FuncMap and adds context-specific functions.
//
// The resulting FuncMap is only valid for the passed-in template.
func (e *Engine) alterFuncMap(t *template.Template) template.FuncMap {
	// Clone the func map because we are adding context-specific functions.
	var funcMap template.FuncMap = map[string]interface{}{}
	for k, v := range e.FuncMap {
		funcMap[k] = v
	}

	// Add the 'include' function here so we can close over t.
	funcMap["include"] = func(name string, data interface{}) (string, error) {
		buf := bytes.NewBuffer(nil)
		if err := t.ExecuteTemplate(buf, name, data); err != nil {
			return "", err
		}
		return buf.String(), nil
	}

	// Add the 'required' function here
	funcMap["required"] = func(warn string, val interface{}) (interface{}, error) {
		if val == nil {
			return val, fmt.Errorf(warn)
		} else if _, ok := val.(string); ok {
			if val == "" {
				return val, fmt.Errorf(warn)
			}
		}
		return val, nil
	}

	// Add the 'tpl' function here
	funcMap["tpl"] = func(tpl string, vals chartutil.Values) (string, error) {
		basePath, err := vals.PathValue("Template.BasePath")
		if err != nil {
			return "", fmt.Errorf("Cannot retrieve Template.Basepath from values inside tpl function: %s (%s)", tpl, err.Error())
		}

		r := renderable{
			tpl:      tpl,
			vals:     vals,
			basePath: basePath.(string),
		}

		templates := map[string]renderable{}
		templateName, err := vals.PathValue("Template.Name")
		if err != nil {
			return "", fmt.Errorf("Cannot retrieve Template.Name from values inside tpl function: %s (%s)", tpl, err.Error())
		}

		templates[templateName.(string)] = r

		result, err := e.render(templates)
		if err != nil {
			return "", fmt.Errorf("Error during tpl function execution for %q: %s", tpl, err.Error())
		}
		return result[templateName.(string)], nil
	}

	return funcMap
}

// render takes a map of templates/values and renders them.
func (e *Engine) render(tpls map[string]renderable) (map[string]string, error) {
	// Basically, what we do here is start with an empty parent template and then
	// build up a list of templates -- one for each file. Once all of the templates
	// have been parsed, we loop through again and execute every template.
	//
	// The idea with this process is to make it possible for more complex templates
	// to share common blocks, but to make the entire thing feel like a file-based
	// template engine.
	defer func() {
		if err := recover(); err != nil {
			log.Printf("rendering template failed: %v\n", err)
		}
	}()
	t := template.New("gotpl")
	if e.Strict {
		t.Option("missingkey=error")
	} else {
		// Not that zero will attempt to add default values for types it knows,
		// but will still emit <no value> for others. We mitigate that later.
		t.Option("missingkey=zero")
	}

	funcMap := e.alterFuncMap(t)

	// We want to parse the templates in a predictable order. The order favors
	// higher-level (in file system) templates over deeply nested templates.
	keys := sortTemplates(tpls)

	files := []string{}

	for _, fname := range keys {
		r := tpls[fname]
		t = t.New(fname).Funcs(funcMap)
		if _, err := t.Parse(r.tpl); err != nil {
			return map[string]string{}, fmt.Errorf("parse error in %q: %s", fname, err)
		}
		files = append(files, fname)
	}

	// Adding the engine's currentTemplates to the template context
	// so they can be referenced in the tpl function
	for fname, r := range e.CurrentTemplates {
		if t.Lookup(fname) == nil {
			t = t.New(fname).Funcs(funcMap)
			if _, err := t.Parse(r.tpl); err != nil {
				return map[string]string{}, fmt.Errorf("parse error in %q: %s", fname, err)
			}
		}
	}

	rendered := make(map[string]string, len(files))
	var buf bytes.Buffer
	for _, file := range files {
		// Don't render partials. We don't care out the direct output of partials.
		// They are only included from other templates.
		if strings.HasPrefix(path.Base(file), "_") {
			continue
		}
		// At render time, add information about the template that is being rendered.
		vals := tpls[file].vals
		vals["Template"] = map[string]interface{}{"Name": file, "BasePath": tpls[file].basePath}
		if err := t.ExecuteTemplate(&buf, file, vals); err != nil {
			return map[string]string{}, fmt.Errorf("render error in %q: %s", file, err)
		}

		// Work around the issue where Go will emit "<no value>" even if Options(missing=zero)
		// is set. Since missing=error will never get here, we do not need to handle
		// the Strict case.
		rendered[file] = strings.Replace(buf.String(), "<no value>", "", -1)
		buf.Reset()
	}

	return rendered, nil
}

func sortTemplates(tpls map[string]renderable) []string {
	keys := make([]string, len(tpls))
	i := 0
	for key := range tpls {
		keys[i] = key
		i++
	}
	sort.Sort(sort.Reverse(byPathLen(keys)))
	return keys
}

type byPathLen []string

func (p byPathLen) Len() int      { return len(p) }
func (p byPathLen) Swap(i, j int) { p[j], p[i] = p[i], p[j] }
func (p byPathLen) Less(i, j int) bool {
	a, b := p[i], p[j]
	ca, cb := strings.Count(a, "/"), strings.Count(b, "/")
	if ca == cb {
		return strings.Compare(a, b) == -1
	}
	return ca < cb
}

// allTemplates returns all templates for a chart and its dependencies.
//
// As it goes, it also prepares the values in a scope-sensitive manner.
func allTemplates(c *chart.Chart, vals chartutil.Values) map[string]renderable {
	templates := map[string]renderable{}
	recAllTpls(c, templates, vals, true, "")
	return templates
}

// recAllTpls recurses through the templates in a chart.
//
// As it recurses, it also sets the values to be appropriate for the template
// scope.
func recAllTpls(c *chart.Chart, templates map[string]renderable, parentVals chartutil.Values, top bool, parentID string) {
	// This should never evaluate to a nil map. That will cause problems when
	// values are appended later.
	cvals := chartutil.Values{}
	if top {
		// If this is the top of the rendering tree, assume that parentVals
		// is already resolved to the authoritative values.
		cvals = parentVals
	} else if c.Metadata != nil && c.Metadata.Name != "" {
		// If there is a {{.Values.ThisChart}} in the parent metadata,
		// copy that into the {{.Values}} for this template.
		newVals := chartutil.Values{}
		if vs, err := parentVals.Table("Values"); err == nil {
			if tmp, err := vs.Table(c.Metadata.Name); err == nil {
				newVals = tmp
			}
		}

		cvals = map[string]interface{}{
			"Values":       newVals,
			"Release":      parentVals["Release"],
			"Chart":        c.Metadata,
			"Files":        chartutil.NewFiles(c.Files),
			"Capabilities": parentVals["Capabilities"],
		}
	}

	newParentID := c.Metadata.Name
	if parentID != "" {
		// We artificially reconstruct the chart path to child templates. This
		// creates a namespaced filename that can be used to track down the source
		// of a particular template declaration.
		newParentID = path.Join(parentID, "charts", newParentID)
	}

	for _, child := range c.Dependencies {
		recAllTpls(child, templates, cvals, false, newParentID)
	}
	for _, t := range c.Templates {
		templates[path.Join(newParentID, t.Name)] = renderable{
			tpl:      string(t.Data),
			vals:     cvals,
			basePath: path.Join(newParentID, "templates"),
		}
	}
}
<|endoftext|>


<commit_before>package jobs

import (
	"container/list"
	"sync"

	"github.com/cozy/cozy-stack/pkg/couchdb"
)

type (
	// memQueue is a queue in-memory implementation of the Queue interface.
	memQueue struct {
		MaxCapacity int
		Jobs        chan Job

		list *list.List
		run  bool
		jmu  sync.RWMutex
	}

	// memBroker is an in-memory broker implementation of the Broker interface.
	memBroker struct {
		queues map[string]*memQueue
	}
)

// globalStorage is the global job persistence layer used thoughout the stack.
var globalStorage = &couchStorage{couchdb.GlobalJobsDB}

// newMemQueue creates and a new in-memory queue.
func newMemQueue(workerType string) *memQueue {
	return &memQueue{
		list: list.New(),
		Jobs: make(chan Job),
	}
}

// Enqueue into the queue
func (q *memQueue) Enqueue(job Job) error {
	q.jmu.Lock()
	defer q.jmu.Unlock()
	q.list.PushBack(job)
	if !q.run {
		q.run = true
		go q.send()
	}
	return nil
}

func (q *memQueue) send() {
	for {
		q.jmu.Lock()
		e := q.list.Front()
		if e == nil {
			q.run = false
			q.jmu.Unlock()
			return
		}
		q.list.Remove(e)
		q.jmu.Unlock()
		q.Jobs <- e.Value.(Job)
	}
}

// Len returns the length of the queue
func (q *memQueue) Len() int {
	q.jmu.RLock()
	defer q.jmu.RUnlock()
	return q.list.Len()
}

// NewMemBroker creates a new in-memory broker system.
//
// The in-memory implementation of the job system has the specifity that
// workers are actually launched by the broker at its creation.
func NewMemBroker(nbWorkers int, ws WorkersList) Broker {
	setNbSlots(nbWorkers)
	queues := make(map[string]*memQueue)
	for workerType, conf := range ws {
		q := newMemQueue(workerType)
		queues[workerType] = q
		w := &Worker{
			Type: workerType,
			Conf: conf,
		}
		w.Start(q.Jobs)
	}
	return &memBroker{queues: queues}
}

// PushJob will produce a new Job with the given options and enqueue the job in
// the proper queue.
func (b *memBroker) PushJob(req *JobRequest) (*JobInfos, error) {
	workerType := req.WorkerType
	q, ok := b.queues[workerType]
	if !ok {
		return nil, ErrUnknownWorker
	}
	infos := NewJobInfos(req)
	j := Job{
		infos:   infos,
		storage: globalStorage,
	}
	if err := globalStorage.Create(infos); err != nil {
		return nil, err
	}
	if err := q.Enqueue(j); err != nil {
		return nil, err
	}
	return infos, nil
}

// QueueLen returns the size of the number of elements in queue of the
// specified worker type.
func (b *memBroker) QueueLen(workerType string) (int, error) {
	q, ok := b.queues[workerType]
	if !ok {
		return 0, ErrUnknownWorker
	}
	return q.Len(), nil
}

// GetJobInfos returns the informations about a job.
func (b *memBroker) GetJobInfos(domain, jobID string) (*JobInfos, error) {
	return globalStorage.Get(domain, jobID)
}

var (
	_ Broker = &memBroker{}
)
<commit_msg>Fix publishing jobs to realtime with single couchdb storage<commit_after>package jobs

import (
	"container/list"
	"sync"

	"github.com/cozy/cozy-stack/pkg/couchdb"
	"github.com/cozy/cozy-stack/pkg/realtime"
)

type (
	// memQueue is a queue in-memory implementation of the Queue interface.
	memQueue struct {
		MaxCapacity int
		Jobs        chan Job

		list *list.List
		run  bool
		jmu  sync.RWMutex
	}

	// memBroker is an in-memory broker implementation of the Broker interface.
	memBroker struct {
		queues map[string]*memQueue
	}
)

// globalStorage is the global job persistence layer used thoughout the stack.
var globalStorage = &couchStorage{couchdb.GlobalJobsDB}

// newMemQueue creates and a new in-memory queue.
func newMemQueue(workerType string) *memQueue {
	return &memQueue{
		list: list.New(),
		Jobs: make(chan Job),
	}
}

// Enqueue into the queue
func (q *memQueue) Enqueue(job Job) error {
	q.jmu.Lock()
	defer q.jmu.Unlock()
	q.list.PushBack(job)
	if !q.run {
		q.run = true
		go q.send()
	}
	return nil
}

func (q *memQueue) send() {
	for {
		q.jmu.Lock()
		e := q.list.Front()
		if e == nil {
			q.run = false
			q.jmu.Unlock()
			return
		}
		q.list.Remove(e)
		q.jmu.Unlock()
		q.Jobs <- e.Value.(Job)
	}
}

// Len returns the length of the queue
func (q *memQueue) Len() int {
	q.jmu.RLock()
	defer q.jmu.RUnlock()
	return q.list.Len()
}

// NewMemBroker creates a new in-memory broker system.
//
// The in-memory implementation of the job system has the specifity that
// workers are actually launched by the broker at its creation.
func NewMemBroker(nbWorkers int, ws WorkersList) Broker {
	setNbSlots(nbWorkers)
	queues := make(map[string]*memQueue)
	for workerType, conf := range ws {
		q := newMemQueue(workerType)
		queues[workerType] = q
		w := &Worker{
			Type: workerType,
			Conf: conf,
		}
		w.Start(q.Jobs)
	}
	return &memBroker{queues: queues}
}

// PushJob will produce a new Job with the given options and enqueue the job in
// the proper queue.
func (b *memBroker) PushJob(req *JobRequest) (*JobInfos, error) {
	workerType := req.WorkerType
	q, ok := b.queues[workerType]
	if !ok {
		return nil, ErrUnknownWorker
	}
	infos := NewJobInfos(req)
	j := Job{
		infos:   infos,
		storage: globalStorage,
	}
	if err := globalStorage.Create(infos); err != nil {
		return nil, err
	}
	if err := q.Enqueue(j); err != nil {
		return nil, err
	}
	// Writing in couchdb should be enough to publish this event,
	// but it is not published on right domain, so we publish it again.
	realtime.GetHub().Publish(&realtime.Event{
		Verb:   realtime.EventCreate,
		Doc:    infos.Clone(),
		Domain: infos.Domain,
	})
	return infos, nil
}

// QueueLen returns the size of the number of elements in queue of the
// specified worker type.
func (b *memBroker) QueueLen(workerType string) (int, error) {
	q, ok := b.queues[workerType]
	if !ok {
		return 0, ErrUnknownWorker
	}
	return q.Len(), nil
}

// GetJobInfos returns the informations about a job.
func (b *memBroker) GetJobInfos(domain, jobID string) (*JobInfos, error) {
	return globalStorage.Get(domain, jobID)
}

var (
	_ Broker = &memBroker{}
)
<|endoftext|>


<commit_before>// Copyright 2018 Google Inc.
//
// 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 syserr contains sandbox-internal errors. These errors are distinct
// from both the errors returned by host system calls and the errors returned
// to sandboxed applications.
package syserr

import (
	"fmt"
	"syscall"

	"gvisor.googlesource.com/gvisor/pkg/abi/linux"
	"gvisor.googlesource.com/gvisor/pkg/syserror"
)

// Error represents an internal error.
type Error struct {
	string
}

// New creates a new Error and adds a translation for it.
func New(message string, linuxTranslation *linux.Errno) *Error {
	err := &Error{message}
	linuxABITranslations[err] = linuxTranslation

	// TODO: Remove this.
	if linuxTranslation == nil {
		linuxBackwardsTranslations[err] = nil
	} else {
		e := error(syscall.Errno(linuxTranslation.Number()))
		// syserror.ErrWouldBlock gets translated to syserror.EWOULDBLOCK and
		// enables proper blocking semantics. This should temporary address the
		// class of blocking bugs that keep popping up with the current state of
		// the error space.
		if e == syserror.EWOULDBLOCK {
			e = syserror.ErrWouldBlock
		}
		linuxBackwardsTranslations[err] = e
	}

	return err
}

// NewWithoutTranslation creates a new Error. If translation is attempted on
// the error, translation will fail.
func NewWithoutTranslation(message string) *Error {
	return &Error{message}
}

// String implements fmt.Stringer.String.
func (e *Error) String() string {
	if e == nil {
		return "<nil>"
	}
	return e.string
}

// TODO: Remove this.
var linuxBackwardsTranslations = map[*Error]error{}

// ToError translates an Error to a corresponding error value.
//
// TODO: Remove this.
func (e *Error) ToError() error {
	if e == nil {
		return nil
	}
	err, ok := linuxBackwardsTranslations[e]
	if !ok {
		panic(fmt.Sprintf("unknown error: %q", e.string))
	}
	return err
}

// TODO: Remove or replace most of these errors.
//
// Some of the errors should be replaced with package specific errors and
// others should be removed entirely.
var (
	ErrNotPermitted               = New("operation not permitted", linux.EPERM)
	ErrNoFileOrDir                = New("no such file or directory", linux.ENOENT)
	ErrNoProcess                  = New("no such process", linux.ESRCH)
	ErrInterrupted                = New("interrupted system call", linux.EINTR)
	ErrIO                         = New("I/O error", linux.EIO)
	ErrDeviceOrAddress            = New("no such device or address", linux.ENXIO)
	ErrTooManyArgs                = New("argument list too long", linux.E2BIG)
	ErrEcec                       = New("exec format error", linux.ENOEXEC)
	ErrBadFD                      = New("bad file number", linux.EBADF)
	ErrNoChild                    = New("no child processes", linux.ECHILD)
	ErrTryAgain                   = New("try again", linux.EAGAIN)
	ErrNoMemory                   = New("out of memory", linux.ENOMEM)
	ErrPermissionDenied           = New("permission denied", linux.EACCES)
	ErrBadAddress                 = New("bad address", linux.EFAULT)
	ErrNotBlockDevice             = New("block device required", linux.ENOTBLK)
	ErrBusy                       = New("device or resource busy", linux.EBUSY)
	ErrExists                     = New("file exists", linux.EEXIST)
	ErrCrossDeviceLink            = New("cross-device link", linux.EXDEV)
	ErrNoDevice                   = New("no such device", linux.ENODEV)
	ErrNotDir                     = New("not a directory", linux.ENOTDIR)
	ErrIsDir                      = New("is a directory", linux.EISDIR)
	ErrInvalidArgument            = New("invalid argument", linux.EINVAL)
	ErrFileTableOverflow          = New("file table overflow", linux.ENFILE)
	ErrTooManyOpenFiles           = New("too many open files", linux.EMFILE)
	ErrNotTTY                     = New("not a typewriter", linux.ENOTTY)
	ErrTestFileBusy               = New("text file busy", linux.ETXTBSY)
	ErrFileTooBig                 = New("file too large", linux.EFBIG)
	ErrNoSpace                    = New("no space left on device", linux.ENOSPC)
	ErrIllegalSeek                = New("illegal seek", linux.ESPIPE)
	ErrReadOnlyFS                 = New("read-only file system", linux.EROFS)
	ErrTooManyLinks               = New("too many links", linux.EMLINK)
	ErrBrokenPipe                 = New("broken pipe", linux.EPIPE)
	ErrDomain                     = New("math argument out of domain of func", linux.EDOM)
	ErrRange                      = New("math result not representable", linux.ERANGE)
	ErrDeadlock                   = New("resource deadlock would occur", linux.EDEADLOCK)
	ErrNameTooLong                = New("file name too long", linux.ENAMETOOLONG)
	ErrNoLocksAvailable           = New("no record locks available", linux.ENOLCK)
	ErrInvalidSyscall             = New("invalid system call number", linux.ENOSYS)
	ErrDirNotEmpty                = New("directory not empty", linux.ENOTEMPTY)
	ErrLinkLoop                   = New("too many symbolic links encountered", linux.ELOOP)
	ErrWouldBlock                 = New("operation would block", linux.EWOULDBLOCK)
	ErrNoMessage                  = New("no message of desired type", linux.ENOMSG)
	ErrIdentifierRemoved          = New("identifier removed", linux.EIDRM)
	ErrChannelOutOfRange          = New("channel number out of range", linux.ECHRNG)
	ErrLevelTwoNotSynced          = New("level 2 not synchronized", linux.EL2NSYNC)
	ErrLevelThreeHalted           = New("level 3 halted", linux.EL3HLT)
	ErrLevelThreeReset            = New("level 3 reset", linux.EL3RST)
	ErrLinkNumberOutOfRange       = New("link number out of range", linux.ELNRNG)
	ErrProtocolDriverNotAttached  = New("protocol driver not attached", linux.EUNATCH)
	ErrNoCSIAvailable             = New("no CSI structure available", linux.ENOCSI)
	ErrLevelTwoHalted             = New("level 2 halted", linux.EL2HLT)
	ErrInvalidExchange            = New("invalid exchange", linux.EBADE)
	ErrInvalidRequestDescriptor   = New("invalid request descriptor", linux.EBADR)
	ErrExchangeFull               = New("exchange full", linux.EXFULL)
	ErrNoAnode                    = New("no anode", linux.ENOANO)
	ErrInvalidRequestCode         = New("invalid request code", linux.EBADRQC)
	ErrInvalidSlot                = New("invalid slot", linux.EBADSLT)
	ErrBadFontFile                = New("bad font file format", linux.EBFONT)
	ErrNotStream                  = New("device not a stream", linux.ENOSTR)
	ErrNoDataAvailable            = New("no data available", linux.ENODATA)
	ErrTimerExpired               = New("timer expired", linux.ETIME)
	ErrStreamsResourceDepleted    = New("out of streams resources", linux.ENOSR)
	ErrMachineNotOnNetwork        = New("machine is not on the network", linux.ENONET)
	ErrPackageNotInstalled        = New("package not installed", linux.ENOPKG)
	ErrIsRemote                   = New("object is remote", linux.EREMOTE)
	ErrNoLink                     = New("link has been severed", linux.ENOLINK)
	ErrAdvertise                  = New("advertise error", linux.EADV)
	ErrSRMount                    = New("srmount error", linux.ESRMNT)
	ErrSendCommunication          = New("communication error on send", linux.ECOMM)
	ErrProtocol                   = New("protocol error", linux.EPROTO)
	ErrMultihopAttempted          = New("multihop attempted", linux.EMULTIHOP)
	ErrRFS                        = New("RFS specific error", linux.EDOTDOT)
	ErrInvalidDataMessage         = New("not a data message", linux.EBADMSG)
	ErrOverflow                   = New("value too large for defined data type", linux.EOVERFLOW)
	ErrNetworkNameNotUnique       = New("name not unique on network", linux.ENOTUNIQ)
	ErrFDInBadState               = New("file descriptor in bad state", linux.EBADFD)
	ErrRemoteAddressChanged       = New("remote address changed", linux.EREMCHG)
	ErrSharedLibraryInaccessible  = New("can not access a needed shared library", linux.ELIBACC)
	ErrCorruptedSharedLibrary     = New("accessing a corrupted shared library", linux.ELIBBAD)
	ErrLibSectionCorrupted        = New(".lib section in a.out corrupted", linux.ELIBSCN)
	ErrTooManySharedLibraries     = New("attempting to link in too many shared libraries", linux.ELIBMAX)
	ErrSharedLibraryExeced        = New("cannot exec a shared library directly", linux.ELIBEXEC)
	ErrIllegalByteSequence        = New("illegal byte sequence", linux.EILSEQ)
	ErrShouldRestart              = New("interrupted system call should be restarted", linux.ERESTART)
	ErrStreamPipe                 = New("streams pipe error", linux.ESTRPIPE)
	ErrTooManyUsers               = New("too many users", linux.EUSERS)
	ErrNotASocket                 = New("socket operation on non-socket", linux.ENOTSOCK)
	ErrDestinationAddressRequired = New("destination address required", linux.EDESTADDRREQ)
	ErrMessageTooLong             = New("message too long", linux.EMSGSIZE)
	ErrWrongProtocolForSocket     = New("protocol wrong type for socket", linux.EPROTOTYPE)
	ErrProtocolNotAvailable       = New("protocol not available", linux.ENOPROTOOPT)
	ErrProtocolNotSupported       = New("protocol not supported", linux.EPROTONOSUPPORT)
	ErrSocketNotSupported         = New("socket type not supported", linux.ESOCKTNOSUPPORT)
	ErrEndpointOperation          = New("operation not supported on transport endpoint", linux.EOPNOTSUPP)
	ErrProtocolFamilyNotSupported = New("protocol family not supported", linux.EPFNOSUPPORT)
	ErrAddressFamilyNotSupported  = New("address family not supported by protocol", linux.EAFNOSUPPORT)
	ErrAddressInUse               = New("address already in use", linux.EADDRINUSE)
	ErrAddressNotAvailable        = New("cannot assign requested address", linux.EADDRNOTAVAIL)
	ErrNetworkDown                = New("network is down", linux.ENETDOWN)
	ErrNetworkUnreachable         = New("network is unreachable", linux.ENETUNREACH)
	ErrNetworkReset               = New("network dropped connection because of reset", linux.ENETRESET)
	ErrConnectionAborted          = New("software caused connection abort", linux.ECONNABORTED)
	ErrConnectionReset            = New("connection reset by peer", linux.ECONNRESET)
	ErrNoBufferSpace              = New("no buffer space available", linux.ENOBUFS)
	ErrAlreadyConnected           = New("transport endpoint is already connected", linux.EISCONN)
	ErrNotConnected               = New("transport endpoint is not connected", linux.ENOTCONN)
	ErrShutdown                   = New("cannot send after transport endpoint shutdown", linux.ESHUTDOWN)
	ErrTooManyRefs                = New("too many references: cannot splice", linux.ETOOMANYREFS)
	ErrTimedOut                   = New("connection timed out", linux.ETIMEDOUT)
	ErrConnectionRefused          = New("connection refused", linux.ECONNREFUSED)
	ErrHostDown                   = New("host is down", linux.EHOSTDOWN)
	ErrNoRoute                    = New("no route to host", linux.EHOSTUNREACH)
	ErrAlreadyInProgress          = New("operation already in progress", linux.EALREADY)
	ErrInProgress                 = New("operation now in progress", linux.EINPROGRESS)
	ErrStaleFileHandle            = New("stale file handle", linux.ESTALE)
	ErrStructureNeedsCleaning     = New("structure needs cleaning", linux.EUCLEAN)
	ErrIsNamedFile                = New("is a named type file", linux.ENOTNAM)
	ErrRemoteIO                   = New("remote I/O error", linux.EREMOTEIO)
	ErrQuotaExceeded              = New("quota exceeded", linux.EDQUOT)
	ErrNoMedium                   = New("no medium found", linux.ENOMEDIUM)
	ErrWrongMediumType            = New("wrong medium type", linux.EMEDIUMTYPE)
	ErrCanceled                   = New("operation Canceled", linux.ECANCELED)
	ErrNoKey                      = New("required key not available", linux.ENOKEY)
	ErrKeyExpired                 = New("key has expired", linux.EKEYEXPIRED)
	ErrKeyRevoked                 = New("key has been revoked", linux.EKEYREVOKED)
	ErrKeyRejected                = New("key was rejected by service", linux.EKEYREJECTED)
	ErrOwnerDied                  = New("owner died", linux.EOWNERDEAD)
	ErrNotRecoverable             = New("state not recoverable", linux.ENOTRECOVERABLE)
)

// FromError converts a generic error to an *Error.
//
// TODO: Remove this function.
func FromError(err error) *Error {
	if err == nil {
		return nil
	}
	if errno, ok := err.(syscall.Errno); ok {
		return FromHost(errno)
	}
	if errno, ok := syserror.TranslateError(err); ok {
		return FromHost(errno)
	}
	panic("unknown error: " + err.Error())
}
<commit_msg>Clarify that syserr.New must only be called during init<commit_after>// Copyright 2018 Google Inc.
//
// 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 syserr contains sandbox-internal errors. These errors are distinct
// from both the errors returned by host system calls and the errors returned
// to sandboxed applications.
package syserr

import (
	"fmt"
	"syscall"

	"gvisor.googlesource.com/gvisor/pkg/abi/linux"
	"gvisor.googlesource.com/gvisor/pkg/syserror"
)

// Error represents an internal error.
type Error struct {
	string
}

// New creates a new Error and adds a translation for it.
//
// New must only be called at init.
func New(message string, linuxTranslation *linux.Errno) *Error {
	err := &Error{message}
	linuxABITranslations[err] = linuxTranslation

	// TODO: Remove this.
	if linuxTranslation == nil {
		linuxBackwardsTranslations[err] = nil
	} else {
		e := error(syscall.Errno(linuxTranslation.Number()))
		// syserror.ErrWouldBlock gets translated to syserror.EWOULDBLOCK and
		// enables proper blocking semantics. This should temporary address the
		// class of blocking bugs that keep popping up with the current state of
		// the error space.
		if e == syserror.EWOULDBLOCK {
			e = syserror.ErrWouldBlock
		}
		linuxBackwardsTranslations[err] = e
	}

	return err
}

// NewWithoutTranslation creates a new Error. If translation is attempted on
// the error, translation will fail.
func NewWithoutTranslation(message string) *Error {
	return &Error{message}
}

// String implements fmt.Stringer.String.
func (e *Error) String() string {
	if e == nil {
		return "<nil>"
	}
	return e.string
}

// TODO: Remove this.
var linuxBackwardsTranslations = map[*Error]error{}

// ToError translates an Error to a corresponding error value.
//
// TODO: Remove this.
func (e *Error) ToError() error {
	if e == nil {
		return nil
	}
	err, ok := linuxBackwardsTranslations[e]
	if !ok {
		panic(fmt.Sprintf("unknown error: %q", e.string))
	}
	return err
}

// TODO: Remove or replace most of these errors.
//
// Some of the errors should be replaced with package specific errors and
// others should be removed entirely.
var (
	ErrNotPermitted               = New("operation not permitted", linux.EPERM)
	ErrNoFileOrDir                = New("no such file or directory", linux.ENOENT)
	ErrNoProcess                  = New("no such process", linux.ESRCH)
	ErrInterrupted                = New("interrupted system call", linux.EINTR)
	ErrIO                         = New("I/O error", linux.EIO)
	ErrDeviceOrAddress            = New("no such device or address", linux.ENXIO)
	ErrTooManyArgs                = New("argument list too long", linux.E2BIG)
	ErrEcec                       = New("exec format error", linux.ENOEXEC)
	ErrBadFD                      = New("bad file number", linux.EBADF)
	ErrNoChild                    = New("no child processes", linux.ECHILD)
	ErrTryAgain                   = New("try again", linux.EAGAIN)
	ErrNoMemory                   = New("out of memory", linux.ENOMEM)
	ErrPermissionDenied           = New("permission denied", linux.EACCES)
	ErrBadAddress                 = New("bad address", linux.EFAULT)
	ErrNotBlockDevice             = New("block device required", linux.ENOTBLK)
	ErrBusy                       = New("device or resource busy", linux.EBUSY)
	ErrExists                     = New("file exists", linux.EEXIST)
	ErrCrossDeviceLink            = New("cross-device link", linux.EXDEV)
	ErrNoDevice                   = New("no such device", linux.ENODEV)
	ErrNotDir                     = New("not a directory", linux.ENOTDIR)
	ErrIsDir                      = New("is a directory", linux.EISDIR)
	ErrInvalidArgument            = New("invalid argument", linux.EINVAL)
	ErrFileTableOverflow          = New("file table overflow", linux.ENFILE)
	ErrTooManyOpenFiles           = New("too many open files", linux.EMFILE)
	ErrNotTTY                     = New("not a typewriter", linux.ENOTTY)
	ErrTestFileBusy               = New("text file busy", linux.ETXTBSY)
	ErrFileTooBig                 = New("file too large", linux.EFBIG)
	ErrNoSpace                    = New("no space left on device", linux.ENOSPC)
	ErrIllegalSeek                = New("illegal seek", linux.ESPIPE)
	ErrReadOnlyFS                 = New("read-only file system", linux.EROFS)
	ErrTooManyLinks               = New("too many links", linux.EMLINK)
	ErrBrokenPipe                 = New("broken pipe", linux.EPIPE)
	ErrDomain                     = New("math argument out of domain of func", linux.EDOM)
	ErrRange                      = New("math result not representable", linux.ERANGE)
	ErrDeadlock                   = New("resource deadlock would occur", linux.EDEADLOCK)
	ErrNameTooLong                = New("file name too long", linux.ENAMETOOLONG)
	ErrNoLocksAvailable           = New("no record locks available", linux.ENOLCK)
	ErrInvalidSyscall             = New("invalid system call number", linux.ENOSYS)
	ErrDirNotEmpty                = New("directory not empty", linux.ENOTEMPTY)
	ErrLinkLoop                   = New("too many symbolic links encountered", linux.ELOOP)
	ErrWouldBlock                 = New("operation would block", linux.EWOULDBLOCK)
	ErrNoMessage                  = New("no message of desired type", linux.ENOMSG)
	ErrIdentifierRemoved          = New("identifier removed", linux.EIDRM)
	ErrChannelOutOfRange          = New("channel number out of range", linux.ECHRNG)
	ErrLevelTwoNotSynced          = New("level 2 not synchronized", linux.EL2NSYNC)
	ErrLevelThreeHalted           = New("level 3 halted", linux.EL3HLT)
	ErrLevelThreeReset            = New("level 3 reset", linux.EL3RST)
	ErrLinkNumberOutOfRange       = New("link number out of range", linux.ELNRNG)
	ErrProtocolDriverNotAttached  = New("protocol driver not attached", linux.EUNATCH)
	ErrNoCSIAvailable             = New("no CSI structure available", linux.ENOCSI)
	ErrLevelTwoHalted             = New("level 2 halted", linux.EL2HLT)
	ErrInvalidExchange            = New("invalid exchange", linux.EBADE)
	ErrInvalidRequestDescriptor   = New("invalid request descriptor", linux.EBADR)
	ErrExchangeFull               = New("exchange full", linux.EXFULL)
	ErrNoAnode                    = New("no anode", linux.ENOANO)
	ErrInvalidRequestCode         = New("invalid request code", linux.EBADRQC)
	ErrInvalidSlot                = New("invalid slot", linux.EBADSLT)
	ErrBadFontFile                = New("bad font file format", linux.EBFONT)
	ErrNotStream                  = New("device not a stream", linux.ENOSTR)
	ErrNoDataAvailable            = New("no data available", linux.ENODATA)
	ErrTimerExpired               = New("timer expired", linux.ETIME)
	ErrStreamsResourceDepleted    = New("out of streams resources", linux.ENOSR)
	ErrMachineNotOnNetwork        = New("machine is not on the network", linux.ENONET)
	ErrPackageNotInstalled        = New("package not installed", linux.ENOPKG)
	ErrIsRemote                   = New("object is remote", linux.EREMOTE)
	ErrNoLink                     = New("link has been severed", linux.ENOLINK)
	ErrAdvertise                  = New("advertise error", linux.EADV)
	ErrSRMount                    = New("srmount error", linux.ESRMNT)
	ErrSendCommunication          = New("communication error on send", linux.ECOMM)
	ErrProtocol                   = New("protocol error", linux.EPROTO)
	ErrMultihopAttempted          = New("multihop attempted", linux.EMULTIHOP)
	ErrRFS                        = New("RFS specific error", linux.EDOTDOT)
	ErrInvalidDataMessage         = New("not a data message", linux.EBADMSG)
	ErrOverflow                   = New("value too large for defined data type", linux.EOVERFLOW)
	ErrNetworkNameNotUnique       = New("name not unique on network", linux.ENOTUNIQ)
	ErrFDInBadState               = New("file descriptor in bad state", linux.EBADFD)
	ErrRemoteAddressChanged       = New("remote address changed", linux.EREMCHG)
	ErrSharedLibraryInaccessible  = New("can not access a needed shared library", linux.ELIBACC)
	ErrCorruptedSharedLibrary     = New("accessing a corrupted shared library", linux.ELIBBAD)
	ErrLibSectionCorrupted        = New(".lib section in a.out corrupted", linux.ELIBSCN)
	ErrTooManySharedLibraries     = New("attempting to link in too many shared libraries", linux.ELIBMAX)
	ErrSharedLibraryExeced        = New("cannot exec a shared library directly", linux.ELIBEXEC)
	ErrIllegalByteSequence        = New("illegal byte sequence", linux.EILSEQ)
	ErrShouldRestart              = New("interrupted system call should be restarted", linux.ERESTART)
	ErrStreamPipe                 = New("streams pipe error", linux.ESTRPIPE)
	ErrTooManyUsers               = New("too many users", linux.EUSERS)
	ErrNotASocket                 = New("socket operation on non-socket", linux.ENOTSOCK)
	ErrDestinationAddressRequired = New("destination address required", linux.EDESTADDRREQ)
	ErrMessageTooLong             = New("message too long", linux.EMSGSIZE)
	ErrWrongProtocolForSocket     = New("protocol wrong type for socket", linux.EPROTOTYPE)
	ErrProtocolNotAvailable       = New("protocol not available", linux.ENOPROTOOPT)
	ErrProtocolNotSupported       = New("protocol not supported", linux.EPROTONOSUPPORT)
	ErrSocketNotSupported         = New("socket type not supported", linux.ESOCKTNOSUPPORT)
	ErrEndpointOperation          = New("operation not supported on transport endpoint", linux.EOPNOTSUPP)
	ErrProtocolFamilyNotSupported = New("protocol family not supported", linux.EPFNOSUPPORT)
	ErrAddressFamilyNotSupported  = New("address family not supported by protocol", linux.EAFNOSUPPORT)
	ErrAddressInUse               = New("address already in use", linux.EADDRINUSE)
	ErrAddressNotAvailable        = New("cannot assign requested address", linux.EADDRNOTAVAIL)
	ErrNetworkDown                = New("network is down", linux.ENETDOWN)
	ErrNetworkUnreachable         = New("network is unreachable", linux.ENETUNREACH)
	ErrNetworkReset               = New("network dropped connection because of reset", linux.ENETRESET)
	ErrConnectionAborted          = New("software caused connection abort", linux.ECONNABORTED)
	ErrConnectionReset            = New("connection reset by peer", linux.ECONNRESET)
	ErrNoBufferSpace              = New("no buffer space available", linux.ENOBUFS)
	ErrAlreadyConnected           = New("transport endpoint is already connected", linux.EISCONN)
	ErrNotConnected               = New("transport endpoint is not connected", linux.ENOTCONN)
	ErrShutdown                   = New("cannot send after transport endpoint shutdown", linux.ESHUTDOWN)
	ErrTooManyRefs                = New("too many references: cannot splice", linux.ETOOMANYREFS)
	ErrTimedOut                   = New("connection timed out", linux.ETIMEDOUT)
	ErrConnectionRefused          = New("connection refused", linux.ECONNREFUSED)
	ErrHostDown                   = New("host is down", linux.EHOSTDOWN)
	ErrNoRoute                    = New("no route to host", linux.EHOSTUNREACH)
	ErrAlreadyInProgress          = New("operation already in progress", linux.EALREADY)
	ErrInProgress                 = New("operation now in progress", linux.EINPROGRESS)
	ErrStaleFileHandle            = New("stale file handle", linux.ESTALE)
	ErrStructureNeedsCleaning     = New("structure needs cleaning", linux.EUCLEAN)
	ErrIsNamedFile                = New("is a named type file", linux.ENOTNAM)
	ErrRemoteIO                   = New("remote I/O error", linux.EREMOTEIO)
	ErrQuotaExceeded              = New("quota exceeded", linux.EDQUOT)
	ErrNoMedium                   = New("no medium found", linux.ENOMEDIUM)
	ErrWrongMediumType            = New("wrong medium type", linux.EMEDIUMTYPE)
	ErrCanceled                   = New("operation Canceled", linux.ECANCELED)
	ErrNoKey                      = New("required key not available", linux.ENOKEY)
	ErrKeyExpired                 = New("key has expired", linux.EKEYEXPIRED)
	ErrKeyRevoked                 = New("key has been revoked", linux.EKEYREVOKED)
	ErrKeyRejected                = New("key was rejected by service", linux.EKEYREJECTED)
	ErrOwnerDied                  = New("owner died", linux.EOWNERDEAD)
	ErrNotRecoverable             = New("state not recoverable", linux.ENOTRECOVERABLE)
)

// FromError converts a generic error to an *Error.
//
// TODO: Remove this function.
func FromError(err error) *Error {
	if err == nil {
		return nil
	}
	if errno, ok := err.(syscall.Errno); ok {
		return FromHost(errno)
	}
	if errno, ok := syserror.TranslateError(err); ok {
		return FromHost(errno)
	}
	panic("unknown error: " + err.Error())
}
<|endoftext|>


<commit_before>package update

import (
	"crypto"
	"encoding/base64"
	"fmt"
	"io/ioutil"

	"time"
	"unicode/utf8"

	"math"

	"github.com/blang/semver"
	"github.com/containerum/chkit/pkg/chkitErrors"
	"github.com/inconshreveable/go-update"
	"github.com/vbauerster/mpb"
	"github.com/vbauerster/mpb/decor"
)

var PublicKeyB64 = "cHVibGljIGtleQo="

const (
	ErrUpdateApply = chkitErrors.Err("update apply failed")
)

func verifiedUpdate(upd *Package) error {
	checksum, err := ioutil.ReadAll(upd.Hash)
	if err != nil {
		return chkitErrors.Wrap(ErrUpdateApply, err)
	}

	signature, err := ioutil.ReadAll(upd.Signature)
	if err != nil {
		return chkitErrors.Wrap(ErrUpdateApply, err)
	}

	opts := update.Options{
		Checksum:  checksum,
		Signature: signature,
		Verifier:  update.NewECDSAVerifier(),
		Hash:      crypto.SHA256,
	}
	publicKey, err := base64.StdEncoding.DecodeString(PublicKeyB64)
	if err != nil {
		return chkitErrors.Wrap(ErrUpdateApply, err)
	}

	err = opts.SetPublicKeyPEM(publicKey)
	if err != nil {
		return chkitErrors.Wrap(ErrUpdateApply, err)
	}

	err = update.Apply(upd.Binary, opts)
	if err != nil {
		return chkitErrors.Wrap(ErrUpdateApply, err)
	}

	return nil
}

func speedDecorator(minWidth int, conf byte) decor.DecoratorFunc {
	format := "%%"
	if (conf & decor.DidentRight) != 0 {
		format += "-"
	}
	format += "%ds"
	var (
		prevCount         int64
		prevDuration      time.Duration
		integrSpeed       float64
		measurementsCount float64
	)
	return func(s *decor.Statistics, widthAccumulator chan<- int, widthDistributor <-chan int) string {
		var str string
		measurementsCount++
		curSpeed := float64(s.Current-prevCount) / (s.TimeElapsed - prevDuration).Seconds() // bytes per second
		if !math.IsNaN(curSpeed) && !math.IsInf(curSpeed, 1) && !math.IsInf(curSpeed, -1) {
			integrSpeed += curSpeed
		}
		speedToShow := integrSpeed / measurementsCount
		prevCount = s.Current
		prevDuration = s.TimeElapsed
		switch {
		case speedToShow < 1<<10:
			str = fmt.Sprintf("%.1f B/s", speedToShow)
		case speedToShow >= 1<<10 && speedToShow < 1<<20:
			str = fmt.Sprintf("%.1f KiB/s", speedToShow/(1<<10))
		case speedToShow >= 1<<20 && speedToShow < 1<<30:
			str = fmt.Sprintf("%.1f MiB/s", speedToShow/(1<<20))
		default:
			str = fmt.Sprintf("%.1f GiB/s", speedToShow/(1<<30))
		}
		if (conf & decor.DwidthSync) != 0 {
			widthAccumulator <- utf8.RuneCountInString(str)
			max := <-widthDistributor
			if (conf & decor.DextraSpace) != 0 {
				max++
			}
			return fmt.Sprintf(fmt.Sprintf(format, max), str)
		}
		return fmt.Sprintf(fmt.Sprintf(format, minWidth), str)
	}
}

func Update(currentVersion semver.Version, downloader LatestCheckerDownloader, restartAfter bool) error {
	latestVersion, err := downloader.LatestVersion()
	if err != nil {
		return err
	}
	if latestVersion.LE(currentVersion) {
		fmt.Println("You already using latest version. Update not needed.")
		return nil
	}

	archive, size, err := downloader.Download(latestVersion)
	if err != nil {
		return err
	}
	defer archive.Close()

	p := mpb.New()
	bar := p.AddBar(size, mpb.PrependDecorators(
		decor.CountersKiloByte("%.1f / %.1f", 3, decor.DextraSpace),
		decor.StaticName(" (", 1, 0),
		decor.Percentage(3, 0),
		decor.StaticName(")", 1, 0),
	), mpb.AppendDecorators(
		speedDecorator(3, decor.DextraSpace),
		decor.StaticName(" ETA:", 3, decor.DextraSpace),
		decor.ETA(3, decor.DextraSpace),
	))
	archive = bar.ProxyReader(archive)

	pkg, err := unpack(archive)
	if err != nil {
		return err
	}
	p.Wait()

	err = verifiedUpdate(pkg)
	if err != nil {
		return err
	}
	fmt.Printf("Updated to version %s\n", latestVersion)

	if restartAfter {
		gracefulRestart()
	}

	return nil
}
<commit_msg>Print message about new version.<commit_after>package update

import (
	"crypto"
	"encoding/base64"
	"fmt"
	"io/ioutil"

	"time"
	"unicode/utf8"

	"math"

	"github.com/blang/semver"
	"github.com/containerum/chkit/pkg/chkitErrors"
	"github.com/inconshreveable/go-update"
	"github.com/vbauerster/mpb"
	"github.com/vbauerster/mpb/decor"
)

var PublicKeyB64 = "cHVibGljIGtleQo="

const (
	ErrUpdateApply = chkitErrors.Err("update apply failed")
)

func verifiedUpdate(upd *Package) error {
	checksum, err := ioutil.ReadAll(upd.Hash)
	if err != nil {
		return chkitErrors.Wrap(ErrUpdateApply, err)
	}

	signature, err := ioutil.ReadAll(upd.Signature)
	if err != nil {
		return chkitErrors.Wrap(ErrUpdateApply, err)
	}

	opts := update.Options{
		Checksum:  checksum,
		Signature: signature,
		Verifier:  update.NewECDSAVerifier(),
		Hash:      crypto.SHA256,
	}
	publicKey, err := base64.StdEncoding.DecodeString(PublicKeyB64)
	if err != nil {
		return chkitErrors.Wrap(ErrUpdateApply, err)
	}

	err = opts.SetPublicKeyPEM(publicKey)
	if err != nil {
		return chkitErrors.Wrap(ErrUpdateApply, err)
	}

	err = update.Apply(upd.Binary, opts)
	if err != nil {
		return chkitErrors.Wrap(ErrUpdateApply, err)
	}

	return nil
}

func speedDecorator(minWidth int, conf byte) decor.DecoratorFunc {
	format := "%%"
	if (conf & decor.DidentRight) != 0 {
		format += "-"
	}
	format += "%ds"
	var (
		prevCount         int64
		prevDuration      time.Duration
		integrSpeed       float64
		measurementsCount float64
	)
	return func(s *decor.Statistics, widthAccumulator chan<- int, widthDistributor <-chan int) string {
		var str string
		measurementsCount++
		curSpeed := float64(s.Current-prevCount) / (s.TimeElapsed - prevDuration).Seconds() // bytes per second
		if !math.IsNaN(curSpeed) && !math.IsInf(curSpeed, 1) && !math.IsInf(curSpeed, -1) {
			integrSpeed += curSpeed
		}
		speedToShow := integrSpeed / measurementsCount
		prevCount = s.Current
		prevDuration = s.TimeElapsed
		switch {
		case speedToShow < 1<<10:
			str = fmt.Sprintf("%.1f B/s", speedToShow)
		case speedToShow >= 1<<10 && speedToShow < 1<<20:
			str = fmt.Sprintf("%.1f KiB/s", speedToShow/(1<<10))
		case speedToShow >= 1<<20 && speedToShow < 1<<30:
			str = fmt.Sprintf("%.1f MiB/s", speedToShow/(1<<20))
		default:
			str = fmt.Sprintf("%.1f GiB/s", speedToShow/(1<<30))
		}
		if (conf & decor.DwidthSync) != 0 {
			widthAccumulator <- utf8.RuneCountInString(str)
			max := <-widthDistributor
			if (conf & decor.DextraSpace) != 0 {
				max++
			}
			return fmt.Sprintf(fmt.Sprintf(format, max), str)
		}
		return fmt.Sprintf(fmt.Sprintf(format, minWidth), str)
	}
}

func Update(currentVersion semver.Version, downloader LatestCheckerDownloader, restartAfter bool) error {
	latestVersion, err := downloader.LatestVersion()
	if err != nil {
		return err
	}
	if latestVersion.LE(currentVersion) {
		fmt.Println("You already using latest version. Update not needed.")
		return nil
	} else {
		fmt.Printf("Found newer version: %s. Updating...\n", latestVersion)
	}

	archive, size, err := downloader.Download(latestVersion)
	if err != nil {
		return err
	}
	defer archive.Close()

	p := mpb.New()
	bar := p.AddBar(size, mpb.PrependDecorators(
		decor.CountersKiloByte("%.1f / %.1f", 3, decor.DextraSpace),
		decor.StaticName(" (", 1, 0),
		decor.Percentage(3, 0),
		decor.StaticName(")", 1, 0),
	), mpb.AppendDecorators(
		speedDecorator(3, decor.DextraSpace),
		decor.StaticName(" ETA:", 3, decor.DextraSpace),
		decor.ETA(3, decor.DextraSpace),
	))
	archive = bar.ProxyReader(archive)

	pkg, err := unpack(archive)
	if err != nil {
		return err
	}
	p.Wait()

	err = verifiedUpdate(pkg)
	if err != nil {
		return err
	}
	fmt.Printf("Updated to version %s\n", latestVersion)

	if restartAfter {
		gracefulRestart()
	}

	return nil
}
<|endoftext|>


<commit_before>/*
Copyright IBM Corp. 2016 All Rights Reserved.

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

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

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

package lockbasedtxmgr

import (
	commonledger "github.com/hyperledger/fabric/common/ledger"
	"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/rwsetutil"
	"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/statedb"
	"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/version"
	"github.com/hyperledger/fabric/core/ledger/ledgerconfig"
	"github.com/hyperledger/fabric/protos/ledger/queryresult"
	"github.com/hyperledger/fabric/protos/ledger/rwset/kvrwset"
)

type queryHelper struct {
	txmgr        *LockBasedTxMgr
	rwsetBuilder *rwsetutil.RWSetBuilder
	itrs         []*resultsItr
	err          error
	doneInvoked  bool
}

func (h *queryHelper) getState(ns string, key string) ([]byte, error) {
	h.checkDone()
	versionedValue, err := h.txmgr.db.GetState(ns, key)
	if err != nil {
		return nil, err
	}
	val, ver := decomposeVersionedValue(versionedValue)
	if h.rwsetBuilder != nil {
		h.rwsetBuilder.AddToReadSet(ns, key, ver)
	}
	return val, nil
}

func (h *queryHelper) getStateMultipleKeys(namespace string, keys []string) ([][]byte, error) {
	h.checkDone()
	versionedValues, err := h.txmgr.db.GetStateMultipleKeys(namespace, keys)
	if err != nil {
		return nil, nil
	}
	values := make([][]byte, len(versionedValues))
	for i, versionedValue := range versionedValues {
		val, ver := decomposeVersionedValue(versionedValue)
		if h.rwsetBuilder != nil {
			h.rwsetBuilder.AddToReadSet(namespace, keys[i], ver)
		}
		values[i] = val
	}
	return values, nil
}

func (h *queryHelper) getStateRangeScanIterator(namespace string, startKey string, endKey string) (commonledger.ResultsIterator, error) {
	h.checkDone()
	itr, err := newResultsItr(namespace, startKey, endKey, h.txmgr.db, h.rwsetBuilder,
		ledgerconfig.IsQueryReadsHashingEnabled(), ledgerconfig.GetMaxDegreeQueryReadsHashing())
	if err != nil {
		return nil, err
	}
	h.itrs = append(h.itrs, itr)
	return itr, nil
}

func (h *queryHelper) executeQuery(namespace, query string) (commonledger.ResultsIterator, error) {
	dbItr, err := h.txmgr.db.ExecuteQuery(namespace, query)
	if err != nil {
		return nil, err
	}
	return &queryResultsItr{DBItr: dbItr, RWSetBuilder: h.rwsetBuilder}, nil
}

func (h *queryHelper) done() {
	if h.doneInvoked {
		return
	}
	defer h.txmgr.commitRWLock.RUnlock()
	h.doneInvoked = true
	for _, itr := range h.itrs {
		itr.Close()
		if h.rwsetBuilder != nil {
			results, hash, err := itr.rangeQueryResultsHelper.Done()
			if results != nil {
				itr.rangeQueryInfo.SetRawReads(results)
			}
			if hash != nil {
				itr.rangeQueryInfo.SetMerkelSummary(hash)
			}
			// TODO Change the method signature of done() to return error. However, this will have
			// repercurssions in the chaincode package, so deferring to a separate changeset.
			// For now, capture the first error that is encountered
			// during final processing and return the error when the caller retrieves the simulation results.
			if h.err == nil {
				h.err = err
			}
			h.rwsetBuilder.AddToRangeQuerySet(itr.ns, itr.rangeQueryInfo)
		}
	}
}

func (h *queryHelper) checkDone() {
	if h.doneInvoked {
		panic("This instance should not be used after calling Done()")
	}
}

// resultsItr implements interface ledger.ResultsIterator
// this wraps the actual db iterator and intercept the calls
// to build rangeQueryInfo in the ReadWriteSet that is used
// for performing phantom read validation during commit
type resultsItr struct {
	ns                      string
	endKey                  string
	dbItr                   statedb.ResultsIterator
	rwSetBuilder            *rwsetutil.RWSetBuilder
	rangeQueryInfo          *kvrwset.RangeQueryInfo
	rangeQueryResultsHelper *rwsetutil.RangeQueryResultsHelper
}

func newResultsItr(ns string, startKey string, endKey string,
	db statedb.VersionedDB, rwsetBuilder *rwsetutil.RWSetBuilder, enableHashing bool, maxDegree uint32) (*resultsItr, error) {
	dbItr, err := db.GetStateRangeScanIterator(ns, startKey, endKey)
	if err != nil {
		return nil, err
	}
	itr := &resultsItr{ns: ns, dbItr: dbItr}
	// it's a simulation request so, enable capture of range query info
	if rwsetBuilder != nil {
		itr.rwSetBuilder = rwsetBuilder
		itr.endKey = endKey
		// just set the StartKey... set the EndKey later below in the Next() method.
		itr.rangeQueryInfo = &kvrwset.RangeQueryInfo{StartKey: startKey}
		resultsHelper, err := rwsetutil.NewRangeQueryResultsHelper(enableHashing, maxDegree)
		if err != nil {
			return nil, err
		}
		itr.rangeQueryResultsHelper = resultsHelper
	}
	return itr, nil
}

// Next implements method in interface ledger.ResultsIterator
// Before returning the next result, update the EndKey and ItrExhausted in rangeQueryInfo
// If we set the EndKey in the constructor (as we do for the StartKey) to what is
// supplied in the original query, we may be capturing the unnecessary longer range if the
// caller decides to stop iterating at some intermidiate point. Alternatively, we could have
// set the EndKey and ItrExhausted in the Close() function but it may not be desirable to change
// transactional behaviour based on whether the Close() was invoked or not
func (itr *resultsItr) Next() (commonledger.QueryResult, error) {
	queryResult, err := itr.dbItr.Next()
	if err != nil {
		return nil, err
	}
	itr.updateRangeQueryInfo(queryResult)
	if queryResult == nil {
		return nil, nil
	}
	versionedKV := queryResult.(*statedb.VersionedKV)
	return &queryresult.KV{Key: versionedKV.Key, Value: versionedKV.Value}, nil
}

// updateRangeQueryInfo updates two attributes of the rangeQueryInfo
// 1) The EndKey - set to either a) latest key that is to be returned to the caller (if the iterator is not exhausted)
//                                  because, we do not know if the caller is again going to invoke Next() or not.
//                            or b) the last key that was supplied in the original query (if the iterator is exhausted)
// 2) The ItrExhausted - set to true if the iterator is going to return nil as a result of the Next() call
func (itr *resultsItr) updateRangeQueryInfo(queryResult statedb.QueryResult) {
	if itr.rwSetBuilder == nil {
		return
	}

	if queryResult == nil {
		// caller scanned till the iterator got exhausted.
		// So, set the endKey to the actual endKey supplied in the query
		itr.rangeQueryInfo.ItrExhausted = true
		itr.rangeQueryInfo.EndKey = itr.endKey
		return
	}
	versionedKV := queryResult.(*statedb.VersionedKV)
	itr.rangeQueryResultsHelper.AddResult(rwsetutil.NewKVRead(versionedKV.Key, versionedKV.Version))
	// Set the end key to the latest key retrieved by the caller.
	// Because, the caller may actually not invoke the Next() function again
	itr.rangeQueryInfo.EndKey = versionedKV.Key
}

// Close implements method in interface ledger.ResultsIterator
func (itr *resultsItr) Close() {
	itr.dbItr.Close()
}

type queryResultsItr struct {
	DBItr        statedb.ResultsIterator
	RWSetBuilder *rwsetutil.RWSetBuilder
}

// Next implements method in interface ledger.ResultsIterator
func (itr *queryResultsItr) Next() (commonledger.QueryResult, error) {

	queryResult, err := itr.DBItr.Next()
	if err != nil {
		return nil, err
	}
	if queryResult == nil {
		return nil, nil
	}
	versionedQueryRecord := queryResult.(*statedb.VersionedKV)
	logger.Debugf("queryResultsItr.Next() returned a record:%s", string(versionedQueryRecord.Value))

	if itr.RWSetBuilder != nil {
		itr.RWSetBuilder.AddToReadSet(versionedQueryRecord.Namespace, versionedQueryRecord.Key, versionedQueryRecord.Version)
	}
	return &queryresult.KV{Key: versionedQueryRecord.Key, Value: versionedQueryRecord.Value}, nil
}

// Close implements method in interface ledger.ResultsIterator
func (itr *queryResultsItr) Close() {
	itr.DBItr.Close()
}

func decomposeVersionedValue(versionedValue *statedb.VersionedValue) ([]byte, *version.Height) {
	var value []byte
	var ver *version.Height
	if versionedValue != nil {
		value = versionedValue.Value
		ver = versionedValue.Version
	}
	return value, ver
}
<commit_msg>[FAB-3270] Cleanup a TODO in Ledger queryHelper done()<commit_after>/*
Copyright IBM Corp. 2016 All Rights Reserved.

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

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

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

package lockbasedtxmgr

import (
	commonledger "github.com/hyperledger/fabric/common/ledger"
	"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/rwsetutil"
	"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/statedb"
	"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/version"
	"github.com/hyperledger/fabric/core/ledger/ledgerconfig"
	"github.com/hyperledger/fabric/protos/ledger/queryresult"
	"github.com/hyperledger/fabric/protos/ledger/rwset/kvrwset"
)

type queryHelper struct {
	txmgr        *LockBasedTxMgr
	rwsetBuilder *rwsetutil.RWSetBuilder
	itrs         []*resultsItr
	err          error
	doneInvoked  bool
}

func (h *queryHelper) getState(ns string, key string) ([]byte, error) {
	h.checkDone()
	versionedValue, err := h.txmgr.db.GetState(ns, key)
	if err != nil {
		return nil, err
	}
	val, ver := decomposeVersionedValue(versionedValue)
	if h.rwsetBuilder != nil {
		h.rwsetBuilder.AddToReadSet(ns, key, ver)
	}
	return val, nil
}

func (h *queryHelper) getStateMultipleKeys(namespace string, keys []string) ([][]byte, error) {
	h.checkDone()
	versionedValues, err := h.txmgr.db.GetStateMultipleKeys(namespace, keys)
	if err != nil {
		return nil, nil
	}
	values := make([][]byte, len(versionedValues))
	for i, versionedValue := range versionedValues {
		val, ver := decomposeVersionedValue(versionedValue)
		if h.rwsetBuilder != nil {
			h.rwsetBuilder.AddToReadSet(namespace, keys[i], ver)
		}
		values[i] = val
	}
	return values, nil
}

func (h *queryHelper) getStateRangeScanIterator(namespace string, startKey string, endKey string) (commonledger.ResultsIterator, error) {
	h.checkDone()
	itr, err := newResultsItr(namespace, startKey, endKey, h.txmgr.db, h.rwsetBuilder,
		ledgerconfig.IsQueryReadsHashingEnabled(), ledgerconfig.GetMaxDegreeQueryReadsHashing())
	if err != nil {
		return nil, err
	}
	h.itrs = append(h.itrs, itr)
	return itr, nil
}

func (h *queryHelper) executeQuery(namespace, query string) (commonledger.ResultsIterator, error) {
	dbItr, err := h.txmgr.db.ExecuteQuery(namespace, query)
	if err != nil {
		return nil, err
	}
	return &queryResultsItr{DBItr: dbItr, RWSetBuilder: h.rwsetBuilder}, nil
}

func (h *queryHelper) done() {
	if h.doneInvoked {
		return
	}

	defer func() {
		h.txmgr.commitRWLock.RUnlock()
		h.doneInvoked = true
		for _, itr := range h.itrs {
			itr.Close()
		}
	}()

	for _, itr := range h.itrs {
		if h.rwsetBuilder != nil {
			results, hash, err := itr.rangeQueryResultsHelper.Done()
			if err != nil {
				h.err = err
				return
			}
			if results != nil {
				itr.rangeQueryInfo.SetRawReads(results)
			}
			if hash != nil {
				itr.rangeQueryInfo.SetMerkelSummary(hash)
			}
			h.rwsetBuilder.AddToRangeQuerySet(itr.ns, itr.rangeQueryInfo)
		}
	}
}

func (h *queryHelper) checkDone() {
	if h.doneInvoked {
		panic("This instance should not be used after calling Done()")
	}
}

// resultsItr implements interface ledger.ResultsIterator
// this wraps the actual db iterator and intercept the calls
// to build rangeQueryInfo in the ReadWriteSet that is used
// for performing phantom read validation during commit
type resultsItr struct {
	ns                      string
	endKey                  string
	dbItr                   statedb.ResultsIterator
	rwSetBuilder            *rwsetutil.RWSetBuilder
	rangeQueryInfo          *kvrwset.RangeQueryInfo
	rangeQueryResultsHelper *rwsetutil.RangeQueryResultsHelper
}

func newResultsItr(ns string, startKey string, endKey string,
	db statedb.VersionedDB, rwsetBuilder *rwsetutil.RWSetBuilder, enableHashing bool, maxDegree uint32) (*resultsItr, error) {
	dbItr, err := db.GetStateRangeScanIterator(ns, startKey, endKey)
	if err != nil {
		return nil, err
	}
	itr := &resultsItr{ns: ns, dbItr: dbItr}
	// it's a simulation request so, enable capture of range query info
	if rwsetBuilder != nil {
		itr.rwSetBuilder = rwsetBuilder
		itr.endKey = endKey
		// just set the StartKey... set the EndKey later below in the Next() method.
		itr.rangeQueryInfo = &kvrwset.RangeQueryInfo{StartKey: startKey}
		resultsHelper, err := rwsetutil.NewRangeQueryResultsHelper(enableHashing, maxDegree)
		if err != nil {
			return nil, err
		}
		itr.rangeQueryResultsHelper = resultsHelper
	}
	return itr, nil
}

// Next implements method in interface ledger.ResultsIterator
// Before returning the next result, update the EndKey and ItrExhausted in rangeQueryInfo
// If we set the EndKey in the constructor (as we do for the StartKey) to what is
// supplied in the original query, we may be capturing the unnecessary longer range if the
// caller decides to stop iterating at some intermidiate point. Alternatively, we could have
// set the EndKey and ItrExhausted in the Close() function but it may not be desirable to change
// transactional behaviour based on whether the Close() was invoked or not
func (itr *resultsItr) Next() (commonledger.QueryResult, error) {
	queryResult, err := itr.dbItr.Next()
	if err != nil {
		return nil, err
	}
	itr.updateRangeQueryInfo(queryResult)
	if queryResult == nil {
		return nil, nil
	}
	versionedKV := queryResult.(*statedb.VersionedKV)
	return &queryresult.KV{Key: versionedKV.Key, Value: versionedKV.Value}, nil
}

// updateRangeQueryInfo updates two attributes of the rangeQueryInfo
// 1) The EndKey - set to either a) latest key that is to be returned to the caller (if the iterator is not exhausted)
//                                  because, we do not know if the caller is again going to invoke Next() or not.
//                            or b) the last key that was supplied in the original query (if the iterator is exhausted)
// 2) The ItrExhausted - set to true if the iterator is going to return nil as a result of the Next() call
func (itr *resultsItr) updateRangeQueryInfo(queryResult statedb.QueryResult) {
	if itr.rwSetBuilder == nil {
		return
	}

	if queryResult == nil {
		// caller scanned till the iterator got exhausted.
		// So, set the endKey to the actual endKey supplied in the query
		itr.rangeQueryInfo.ItrExhausted = true
		itr.rangeQueryInfo.EndKey = itr.endKey
		return
	}
	versionedKV := queryResult.(*statedb.VersionedKV)
	itr.rangeQueryResultsHelper.AddResult(rwsetutil.NewKVRead(versionedKV.Key, versionedKV.Version))
	// Set the end key to the latest key retrieved by the caller.
	// Because, the caller may actually not invoke the Next() function again
	itr.rangeQueryInfo.EndKey = versionedKV.Key
}

// Close implements method in interface ledger.ResultsIterator
func (itr *resultsItr) Close() {
	itr.dbItr.Close()
}

type queryResultsItr struct {
	DBItr        statedb.ResultsIterator
	RWSetBuilder *rwsetutil.RWSetBuilder
}

// Next implements method in interface ledger.ResultsIterator
func (itr *queryResultsItr) Next() (commonledger.QueryResult, error) {

	queryResult, err := itr.DBItr.Next()
	if err != nil {
		return nil, err
	}
	if queryResult == nil {
		return nil, nil
	}
	versionedQueryRecord := queryResult.(*statedb.VersionedKV)
	logger.Debugf("queryResultsItr.Next() returned a record:%s", string(versionedQueryRecord.Value))

	if itr.RWSetBuilder != nil {
		itr.RWSetBuilder.AddToReadSet(versionedQueryRecord.Namespace, versionedQueryRecord.Key, versionedQueryRecord.Version)
	}
	return &queryresult.KV{Key: versionedQueryRecord.Key, Value: versionedQueryRecord.Value}, nil
}

// Close implements method in interface ledger.ResultsIterator
func (itr *queryResultsItr) Close() {
	itr.DBItr.Close()
}

func decomposeVersionedValue(versionedValue *statedb.VersionedValue) ([]byte, *version.Height) {
	var value []byte
	var ver *version.Height
	if versionedValue != nil {
		value = versionedValue.Value
		ver = versionedValue.Version
	}
	return value, ver
}
<|endoftext|>