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

package flate

import (
	"math"
	"sort"
)

type hcode uint32

type huffmanEncoder struct {
	codes     []hcode
	freqcache []literalNode
	bitCount  [17]int32
}

type literalNode struct {
	literal uint16
	freq    int32
}

// A levelInfo describes the state of the constructed tree for a given depth.
type levelInfo struct {
	// Our level.  for better printing
	level int32

	// The frequency of the last node at this level
	lastFreq int32

	// The frequency of the next character to add to this level
	nextCharFreq int32

	// The frequency of the next pair (from level below) to add to this level.
	// Only valid if the "needed" value of the next lower level is 0.
	nextPairFreq int32

	// The number of chains remaining to generate for this level before moving
	// up to the next level
	needed int32
}

func (h hcode) codeBits() (code uint16, bits uint8) {
	return uint16(h), uint8(h >> 16)
}

func (h *hcode) set(code uint16, bits uint8) {
	*h = hcode(code) | hcode(uint32(bits)<<16)
}

func (h *hcode) setBits(bits uint8) {
	*h = hcode(*h&0xffff) | hcode(uint32(bits)<<16)
}

func toCode(code uint16, bits uint8) hcode {
	return hcode(code) | hcode(uint32(bits)<<16)
}

func (h hcode) code() (code uint16) {
	return uint16(h)
}

func (h hcode) bits() (bits uint8) {
	return uint8(h >> 16)
}

func maxNode() literalNode { return literalNode{math.MaxUint16, math.MaxInt32} }

func newHuffmanEncoder(size int) *huffmanEncoder {
	return &huffmanEncoder{codes: make([]hcode, size), freqcache: nil}
}

// Generates a HuffmanCode corresponding to the fixed literal table
func generateFixedLiteralEncoding() *huffmanEncoder {
	h := newHuffmanEncoder(maxNumLit)
	codes := h.codes
	var ch uint16
	for ch = 0; ch < maxNumLit; ch++ {
		var bits uint16
		var size uint8
		switch {
		case ch < 144:
			// size 8, 000110000  .. 10111111
			bits = ch + 48
			size = 8
			break
		case ch < 256:
			// size 9, 110010000 .. 111111111
			bits = ch + 400 - 144
			size = 9
			break
		case ch < 280:
			// size 7, 0000000 .. 0010111
			bits = ch - 256
			size = 7
			break
		default:
			// size 8, 11000000 .. 11000111
			bits = ch + 192 - 280
			size = 8
		}
		codes[ch] = toCode(reverseBits(bits, size), size)
	}
	return h
}

func generateFixedOffsetEncoding() *huffmanEncoder {
	h := newHuffmanEncoder(30)
	codes := h.codes
	for ch := uint16(0); ch < 30; ch++ {
		codes[ch] = toCode(reverseBits(ch, 5), 5)
	}
	return h
}

var fixedLiteralEncoding *huffmanEncoder = generateFixedLiteralEncoding()
var fixedOffsetEncoding *huffmanEncoder = generateFixedOffsetEncoding()

func (h *huffmanEncoder) bitLength(freq []int32) int64 {
	var total int64
	for i, f := range freq {
		if f != 0 {
			total += int64(f) * int64(h.codes[i].bits())
		}
	}
	return total
}

const maxBitsLimit = 16

// Return the number of literals assigned to each bit size in the Huffman encoding
//
// This method is only called when list.length >= 3
// The cases of 0, 1, and 2 literals are handled by special case code.
//
// list  An array of the literals with non-zero frequencies
//             and their associated frequencies.  The array is in order of increasing
//             frequency, and has as its last element a special element with frequency
//             MaxInt32
// maxBits     The maximum number of bits that should be used to encode any literal.
//             Must be less than 16.
// return      An integer array in which array[i] indicates the number of literals
//             that should be encoded in i bits.
func (h *huffmanEncoder) bitCounts(list []literalNode, maxBits int32) []int32 {
	if maxBits >= maxBitsLimit {
		panic("flate: maxBits too large")
	}
	n := int32(len(list))
	list = list[0 : n+1]
	list[n] = maxNode()

	// The tree can't have greater depth than n - 1, no matter what.  This
	// saves a little bit of work in some small cases
	if maxBits > n-1 {
		maxBits = n - 1
	}

	// Create information about each of the levels.
	// A bogus "Level 0" whose sole purpose is so that
	// level1.prev.needed==0.  This makes level1.nextPairFreq
	// be a legitimate value that never gets chosen.
	var levels [maxBitsLimit]levelInfo
	// leafCounts[i] counts the number of literals at the left
	// of ancestors of the rightmost node at level i.
	// leafCounts[i][j] is the number of literals at the left
	// of the level j ancestor.
	var leafCounts [maxBitsLimit][maxBitsLimit]int32

	for level := int32(1); level <= maxBits; level++ {
		// For every level, the first two items are the first two characters.
		// We initialize the levels as if we had already figured this out.
		levels[level] = levelInfo{
			level:        level,
			lastFreq:     list[1].freq,
			nextCharFreq: list[2].freq,
			nextPairFreq: list[0].freq + list[1].freq,
		}
		leafCounts[level][level] = 2
		if level == 1 {
			levels[level].nextPairFreq = math.MaxInt32
		}
	}

	// We need a total of 2*n - 2 items at top level and have already generated 2.
	levels[maxBits].needed = 2*n - 4

	level := maxBits
	for {
		l := &levels[level]
		if l.nextPairFreq == math.MaxInt32 && l.nextCharFreq == math.MaxInt32 {
			// We've run out of both leafs and pairs.
			// End all calculations for this level.
			// To make sure we never come back to this level or any lower level,
			// set nextPairFreq impossibly large.
			l.needed = 0
			levels[level+1].nextPairFreq = math.MaxInt32
			level++
			continue
		}

		prevFreq := l.lastFreq
		if l.nextCharFreq < l.nextPairFreq {
			// The next item on this row is a leaf node.
			n := leafCounts[level][level] + 1
			l.lastFreq = l.nextCharFreq
			// Lower leafCounts are the same of the previous node.
			leafCounts[level][level] = n
			l.nextCharFreq = list[n].freq
		} else {
			// The next item on this row is a pair from the previous row.
			// nextPairFreq isn't valid until we generate two
			// more values in the level below
			l.lastFreq = l.nextPairFreq
			// Take leaf counts from the lower level, except counts[level] remains the same.
			copy(leafCounts[level][:level], leafCounts[level-1][:level])
			levels[l.level-1].needed = 2
		}

		if l.needed--; l.needed == 0 {
			// We've done everything we need to do for this level.
			// Continue calculating one level up.  Fill in nextPairFreq
			// of that level with the sum of the two nodes we've just calculated on
			// this level.
			if l.level == maxBits {
				// All done!
				break
			}
			levels[l.level+1].nextPairFreq = prevFreq + l.lastFreq
			level++
		} else {
			// If we stole from below, move down temporarily to replenish it.
			for levels[level-1].needed > 0 {
				level--
			}
		}
	}

	// Somethings is wrong if at the end, the top level is null or hasn't used
	// all of the leaves.
	if leafCounts[maxBits][maxBits] != n {
		panic("leafCounts[maxBits][maxBits] != n")
	}

	bitCount := h.bitCount[:maxBits+1]
	//make([]int32, maxBits+1)
	bits := 1
	counts := &leafCounts[maxBits]
	for level := maxBits; level > 0; level-- {
		// chain.leafCount gives the number of literals requiring at least "bits"
		// bits to encode.
		bitCount[bits] = counts[level] - counts[level-1]
		bits++
	}
	return bitCount
}

// Look at the leaves and assign them a bit count and an encoding as specified
// in RFC 1951 3.2.2
func (h *huffmanEncoder) assignEncodingAndSize(bitCount []int32, list []literalNode) {
	code := uint16(0)
	for n, bits := range bitCount {
		code <<= 1
		if n == 0 || bits == 0 {
			continue
		}
		// The literals list[len(list)-bits] .. list[len(list)-bits]
		// are encoded using "bits" bits, and get the values
		// code, code + 1, ....  The code values are
		// assigned in literal order (not frequency order).
		chunk := list[len(list)-int(bits):]
		sortByLiteral(chunk)
		for _, node := range chunk {
			h.codes[node.literal] = toCode(reverseBits(code, uint8(n)), uint8(n))
			code++
		}
		list = list[0 : len(list)-int(bits)]
	}
}

// Update this Huffman Code object to be the minimum code for the specified frequency count.
//
// freq  An array of frequencies, in which frequency[i] gives the frequency of literal i.
// maxBits  The maximum number of bits to use for any literal.
func (h *huffmanEncoder) generate(freq []int32, maxBits int32) {
	if h.freqcache == nil {
		h.freqcache = make([]literalNode, 300)
	}
	list := h.freqcache[:len(freq)+1]
	// Number of non-zero literals
	count := 0
	// Set list to be the set of all non-zero literals and their frequencies
	for i, f := range freq {
		if f != 0 {
			list[count] = literalNode{uint16(i), f}
			count++
		} else {
			list[count] = literalNode{}
			//h.codeBits[i] = 0
			h.codes[i].setBits(0)
		}
	}
	list[len(freq)] = literalNode{}
	// If freq[] is shorter than codeBits[], fill rest of codeBits[] with zeros
	// FIXME: Doesn't do what it says on the tin (klauspost)
	//h.codeBits = h.codeBits[0:len(freq)]

	list = list[0:count]
	if count <= 2 {
		// Handle the small cases here, because they are awkward for the general case code.  With
		// two or fewer literals, everything has bit length 1.
		for i, node := range list {
			// "list" is in order of increasing literal value.
			h.codes[node.literal].set(uint16(i), 1)
			//h.codeBits[node.literal] = 1
			//h.code[node.literal] = uint16(i)
		}
		return
	}
	sortByFreq(list)

	// Get the number of literals for each bit count
	bitCount := h.bitCounts(list, maxBits)
	// And do the assignment
	h.assignEncodingAndSize(bitCount, list)
}

type literalNodeSorter struct {
	a    []literalNode
	less func(i, j int) bool
}

func (s literalNodeSorter) Len() int { return len(s.a) }

func (s literalNodeSorter) Less(i, j int) bool {
	return s.less(i, j)
}

func (s literalNodeSorter) Swap(i, j int) { s.a[i], s.a[j] = s.a[j], s.a[i] }

func sortByFreq(a []literalNode) {
	s := &literalNodeSorter{a, func(i, j int) bool {
		if a[i].freq == a[j].freq {
			return a[i].literal < a[j].literal
		}
		return a[i].freq < a[j].freq
	}}
	sort.Sort(s)
}

func sortByLiteral(a []literalNode) {
	s := &literalNodeSorter{a, func(i, j int) bool { return a[i].literal < a[j].literal }}
	sort.Sort(s)
}
<commit_msg>Reduce allocations in sorter.<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package flate

import (
	"math"
	"sort"
)

type hcode uint32

type huffmanEncoder struct {
	codes     []hcode
	freqcache []literalNode
	bitCount  [17]int32
}

type literalNode struct {
	literal uint16
	freq    int32
}

// A levelInfo describes the state of the constructed tree for a given depth.
type levelInfo struct {
	// Our level.  for better printing
	level int32

	// The frequency of the last node at this level
	lastFreq int32

	// The frequency of the next character to add to this level
	nextCharFreq int32

	// The frequency of the next pair (from level below) to add to this level.
	// Only valid if the "needed" value of the next lower level is 0.
	nextPairFreq int32

	// The number of chains remaining to generate for this level before moving
	// up to the next level
	needed int32
}

func (h hcode) codeBits() (code uint16, bits uint8) {
	return uint16(h), uint8(h >> 16)
}

func (h *hcode) set(code uint16, bits uint8) {
	*h = hcode(code) | hcode(uint32(bits)<<16)
}

func (h *hcode) setBits(bits uint8) {
	*h = hcode(*h&0xffff) | hcode(uint32(bits)<<16)
}

func toCode(code uint16, bits uint8) hcode {
	return hcode(code) | hcode(uint32(bits)<<16)
}

func (h hcode) code() (code uint16) {
	return uint16(h)
}

func (h hcode) bits() (bits uint8) {
	return uint8(h >> 16)
}

func maxNode() literalNode { return literalNode{math.MaxUint16, math.MaxInt32} }

func newHuffmanEncoder(size int) *huffmanEncoder {
	return &huffmanEncoder{codes: make([]hcode, size), freqcache: nil}
}

// Generates a HuffmanCode corresponding to the fixed literal table
func generateFixedLiteralEncoding() *huffmanEncoder {
	h := newHuffmanEncoder(maxNumLit)
	codes := h.codes
	var ch uint16
	for ch = 0; ch < maxNumLit; ch++ {
		var bits uint16
		var size uint8
		switch {
		case ch < 144:
			// size 8, 000110000  .. 10111111
			bits = ch + 48
			size = 8
			break
		case ch < 256:
			// size 9, 110010000 .. 111111111
			bits = ch + 400 - 144
			size = 9
			break
		case ch < 280:
			// size 7, 0000000 .. 0010111
			bits = ch - 256
			size = 7
			break
		default:
			// size 8, 11000000 .. 11000111
			bits = ch + 192 - 280
			size = 8
		}
		codes[ch] = toCode(reverseBits(bits, size), size)
	}
	return h
}

func generateFixedOffsetEncoding() *huffmanEncoder {
	h := newHuffmanEncoder(30)
	codes := h.codes
	for ch := uint16(0); ch < 30; ch++ {
		codes[ch] = toCode(reverseBits(ch, 5), 5)
	}
	return h
}

var fixedLiteralEncoding *huffmanEncoder = generateFixedLiteralEncoding()
var fixedOffsetEncoding *huffmanEncoder = generateFixedOffsetEncoding()

func (h *huffmanEncoder) bitLength(freq []int32) int64 {
	var total int64
	for i, f := range freq {
		if f != 0 {
			total += int64(f) * int64(h.codes[i].bits())
		}
	}
	return total
}

const maxBitsLimit = 16

// Return the number of literals assigned to each bit size in the Huffman encoding
//
// This method is only called when list.length >= 3
// The cases of 0, 1, and 2 literals are handled by special case code.
//
// list  An array of the literals with non-zero frequencies
//             and their associated frequencies.  The array is in order of increasing
//             frequency, and has as its last element a special element with frequency
//             MaxInt32
// maxBits     The maximum number of bits that should be used to encode any literal.
//             Must be less than 16.
// return      An integer array in which array[i] indicates the number of literals
//             that should be encoded in i bits.
func (h *huffmanEncoder) bitCounts(list []literalNode, maxBits int32) []int32 {
	if maxBits >= maxBitsLimit {
		panic("flate: maxBits too large")
	}
	n := int32(len(list))
	list = list[0 : n+1]
	list[n] = maxNode()

	// The tree can't have greater depth than n - 1, no matter what.  This
	// saves a little bit of work in some small cases
	if maxBits > n-1 {
		maxBits = n - 1
	}

	// Create information about each of the levels.
	// A bogus "Level 0" whose sole purpose is so that
	// level1.prev.needed==0.  This makes level1.nextPairFreq
	// be a legitimate value that never gets chosen.
	var levels [maxBitsLimit]levelInfo
	// leafCounts[i] counts the number of literals at the left
	// of ancestors of the rightmost node at level i.
	// leafCounts[i][j] is the number of literals at the left
	// of the level j ancestor.
	var leafCounts [maxBitsLimit][maxBitsLimit]int32

	for level := int32(1); level <= maxBits; level++ {
		// For every level, the first two items are the first two characters.
		// We initialize the levels as if we had already figured this out.
		levels[level] = levelInfo{
			level:        level,
			lastFreq:     list[1].freq,
			nextCharFreq: list[2].freq,
			nextPairFreq: list[0].freq + list[1].freq,
		}
		leafCounts[level][level] = 2
		if level == 1 {
			levels[level].nextPairFreq = math.MaxInt32
		}
	}

	// We need a total of 2*n - 2 items at top level and have already generated 2.
	levels[maxBits].needed = 2*n - 4

	level := maxBits
	for {
		l := &levels[level]
		if l.nextPairFreq == math.MaxInt32 && l.nextCharFreq == math.MaxInt32 {
			// We've run out of both leafs and pairs.
			// End all calculations for this level.
			// To make sure we never come back to this level or any lower level,
			// set nextPairFreq impossibly large.
			l.needed = 0
			levels[level+1].nextPairFreq = math.MaxInt32
			level++
			continue
		}

		prevFreq := l.lastFreq
		if l.nextCharFreq < l.nextPairFreq {
			// The next item on this row is a leaf node.
			n := leafCounts[level][level] + 1
			l.lastFreq = l.nextCharFreq
			// Lower leafCounts are the same of the previous node.
			leafCounts[level][level] = n
			l.nextCharFreq = list[n].freq
		} else {
			// The next item on this row is a pair from the previous row.
			// nextPairFreq isn't valid until we generate two
			// more values in the level below
			l.lastFreq = l.nextPairFreq
			// Take leaf counts from the lower level, except counts[level] remains the same.
			copy(leafCounts[level][:level], leafCounts[level-1][:level])
			levels[l.level-1].needed = 2
		}

		if l.needed--; l.needed == 0 {
			// We've done everything we need to do for this level.
			// Continue calculating one level up.  Fill in nextPairFreq
			// of that level with the sum of the two nodes we've just calculated on
			// this level.
			if l.level == maxBits {
				// All done!
				break
			}
			levels[l.level+1].nextPairFreq = prevFreq + l.lastFreq
			level++
		} else {
			// If we stole from below, move down temporarily to replenish it.
			for levels[level-1].needed > 0 {
				level--
			}
		}
	}

	// Somethings is wrong if at the end, the top level is null or hasn't used
	// all of the leaves.
	if leafCounts[maxBits][maxBits] != n {
		panic("leafCounts[maxBits][maxBits] != n")
	}

	bitCount := h.bitCount[:maxBits+1]
	//make([]int32, maxBits+1)
	bits := 1
	counts := &leafCounts[maxBits]
	for level := maxBits; level > 0; level-- {
		// chain.leafCount gives the number of literals requiring at least "bits"
		// bits to encode.
		bitCount[bits] = counts[level] - counts[level-1]
		bits++
	}
	return bitCount
}

// Look at the leaves and assign them a bit count and an encoding as specified
// in RFC 1951 3.2.2
func (h *huffmanEncoder) assignEncodingAndSize(bitCount []int32, list []literalNode) {
	code := uint16(0)
	for n, bits := range bitCount {
		code <<= 1
		if n == 0 || bits == 0 {
			continue
		}
		// The literals list[len(list)-bits] .. list[len(list)-bits]
		// are encoded using "bits" bits, and get the values
		// code, code + 1, ....  The code values are
		// assigned in literal order (not frequency order).
		chunk := list[len(list)-int(bits):]
		sortByLiteral(chunk)
		for _, node := range chunk {
			h.codes[node.literal] = toCode(reverseBits(code, uint8(n)), uint8(n))
			code++
		}
		list = list[0 : len(list)-int(bits)]
	}
}

// Update this Huffman Code object to be the minimum code for the specified frequency count.
//
// freq  An array of frequencies, in which frequency[i] gives the frequency of literal i.
// maxBits  The maximum number of bits to use for any literal.
func (h *huffmanEncoder) generate(freq []int32, maxBits int32) {
	if h.freqcache == nil {
		h.freqcache = make([]literalNode, 300)
	}
	list := h.freqcache[:len(freq)+1]
	// Number of non-zero literals
	count := 0
	// Set list to be the set of all non-zero literals and their frequencies
	for i, f := range freq {
		if f != 0 {
			list[count] = literalNode{uint16(i), f}
			count++
		} else {
			list[count] = literalNode{}
			//h.codeBits[i] = 0
			h.codes[i].setBits(0)
		}
	}
	list[len(freq)] = literalNode{}
	// If freq[] is shorter than codeBits[], fill rest of codeBits[] with zeros
	// FIXME: Doesn't do what it says on the tin (klauspost)
	//h.codeBits = h.codeBits[0:len(freq)]

	list = list[0:count]
	if count <= 2 {
		// Handle the small cases here, because they are awkward for the general case code.  With
		// two or fewer literals, everything has bit length 1.
		for i, node := range list {
			// "list" is in order of increasing literal value.
			h.codes[node.literal].set(uint16(i), 1)
			//h.codeBits[node.literal] = 1
			//h.code[node.literal] = uint16(i)
		}
		return
	}
	sortByFreq(list)

	// Get the number of literals for each bit count
	bitCount := h.bitCounts(list, maxBits)
	// And do the assignment
	h.assignEncodingAndSize(bitCount, list)
}

type literalNodeSorter []literalNode

func (s literalNodeSorter) Len() int { return len(s) }

func (s literalNodeSorter) Less(i, j int) bool {
	return s[i].literal < s[j].literal
}

func (s literalNodeSorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] }

type literalFreqSorter []literalNode

func (s literalFreqSorter) Len() int { return len(s) }

func (s literalFreqSorter) Less(i, j int) bool {
	if s[i].freq == s[j].freq {
		return s[i].literal < s[j].literal
	}
	return s[i].freq < s[j].freq
}

func (s literalFreqSorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] }

func sortByFreq(a []literalNode) {
	sort.Sort(literalFreqSorter(a))
}

func sortByLiteral(a []literalNode) {
	// FIXME: Still a single 32B allocation left.
	s := literalNodeSorter(a)
	sort.Sort(s)
}
<|endoftext|>


<commit_before>package forest

import (
	"errors"
	"sort"
	"strings"

	"github.com/go-logr/logr"

	api "sigs.k8s.io/multi-tenancy/incubator/hnc/api/v1alpha1"
)

// HasLocalCritCondition returns if the namespace itself has any local critical conditions, ignoring
// its ancestors. Any code with the "Crit" prefix is a critical condition.
func (ns *Namespace) HasLocalCritCondition() bool {
	for code, _ := range ns.conditions[api.AffectedObject{}] {
		codeNm := (string)(code)
		if strings.HasPrefix(codeNm, "Crit") {
			return true
		}
	}
	return false
}

// GetCritAncestor returns the name of the first ancestor with a critical condition, or the empty
// string if there are no such ancestors. It *can* return the name of the current namespace.
func (ns *Namespace) GetCritAncestor() string {
	if ns.HasLocalCritCondition() {
		return ns.name
	}
	if ns.Parent() == nil {
		return ""
	}
	return ns.Parent().GetCritAncestor()
}

// HasCondition returns true if there's a condition with the given object and code. If code is the
// empty string, it returns true if there's _any_ condition for the given object.
func (ns *Namespace) HasCondition(obj api.AffectedObject, code api.Code) bool {
	if _, exists := ns.conditions[obj]; !exists {
		// Nothing for this obj
		return false
	}
	if code == "" {
		// Something exists for this obj; we don't care what
		return true
	}
	_, exists := ns.conditions[obj][code]
	return exists
}

// ClearCondition clears conditions in the namespace for a single object. If `code` is non-empty, it
// only clears conditions with that code, otherwise it clears all conditions for that object. It
// should only be called by the code that also *sets* the conditions.
//
// It returns true if it made any changes, false otherwise.
func (ns *Namespace) ClearCondition(obj api.AffectedObject, code api.Code) bool {
	if !ns.HasCondition(obj, code) {
		return false
	}

	if code == "" {
		delete(ns.conditions, obj)
	} else {
		delete(ns.conditions[obj], code)
	}

	return true
}

// ClearLocalConditions clears the condition(s) on this namespace.
func (ns *Namespace) ClearLocalConditions() bool {
	return ns.ClearCondition(api.AffectedObject{}, "")
}

func (ns *Namespace) ClearObsoleteConditions(log logr.Logger) {
	// Load ancestors to check CCCAncestors
	isAnc := map[string]bool{}
	for _, anc := range ns.AncestryNames() {
		// The definition of CCCAncestor doesn't include the namespace itself
		if anc != ns.name {
			isAnc[anc] = true
		}
	}

	// Load the subtree to check CCCSubtree, including the namespace itself.
	isSubtree := map[string]bool{ns.name: true}
	for _, dsc := range ns.DescendantNames() {
		isSubtree[dsc] = true
	}

	// For each affected object, remove its condition if that object is no longer relevant.
	for obj, codes := range ns.conditions {
		for code, _ := range codes {
			switch api.ClearConditionCriteria[code] {
			case api.CCCManual:
				// nop - cleared manually
			case api.CCCAncestor:
				if !isAnc[obj.Namespace] {
					log.Info("Cleared obsolete condition from old ancestor", "obj", obj, "code", code)
					ns.ClearCondition(obj, code)
				}
			case api.CCCSubtree:
				if !isSubtree[obj.Namespace] {
					log.Info("Cleared obsolete condition from old descendant", "obj", obj, "code", code)
					ns.ClearCondition(obj, code)
				}
			default:
				err := errors.New("no ClearConditionCriterion")
				log.Error(err, "In clearObsoleteConditions", "code", code, "obj", obj)
			}
		}
	}
}

// SetCondition sets a condition for the specified object and code, returning true if it does not
// exist previously or if the message has changed.
//
// Returns true if the condition wasn't previously set
func (ns *Namespace) SetCondition(obj api.AffectedObject, code api.Code, msg string) bool {
	changed := false
	if _, existed := ns.conditions[obj]; !existed {
		changed = true
		ns.conditions[obj] = map[api.Code]string{}
	}

	if oldMsg, existed := ns.conditions[obj][code]; !existed || msg != oldMsg {
		changed = true
		ns.conditions[obj][code] = msg
	}

	return changed
}

// SetLocalCondition sets a condition that applies to the current namespace.
func (ns *Namespace) SetLocalCondition(code api.Code, msg string) bool {
	return ns.SetCondition(api.AffectedObject{}, code, msg)
}

// Conditions returns a list of conditions in the namespace in the format expected by the API.
func (ns *Namespace) Conditions() []api.Condition {
	// Treat the code/msg combination as a combined key.
	type codeMsg struct {
		code api.Code
		msg  string
	}

	// Reorder so that the objects are grouped by code and message
	byCM := map[codeMsg][]api.AffectedObject{}
	for obj, codes := range ns.conditions {
		for code, msg := range codes {
			cm := codeMsg{code: code, msg: msg}
			byCM[cm] = append(byCM[cm], obj)
		}
	}

	// Flatten into a list of conditions
	conds := []api.Condition{}
	for cm, objs := range byCM {
		// If the only affected object is unnamed (e.g., it refers to the current namespace), omit it.
		c := api.Condition{Code: cm.code, Msg: cm.msg}
		if len(objs) > 0 || objs[0].Name != "" {
			api.SortAffectedObjects(objs)
			c.Affects = objs
		}
		conds = append(conds, c)
	}

	sort.Slice(conds, func(i, j int) bool {
		if conds[i].Code != conds[j].Code {
			return conds[i].Code < conds[j].Code
		}
		return conds[i].Msg < conds[j].Msg
	})

	if len(conds) == 0 {
		conds = nil // prevent anything from appearing in the status
	}
	return conds
}
<commit_msg>Don't add empty AffectedObject entries<commit_after>package forest

import (
	"errors"
	"sort"
	"strings"

	"github.com/go-logr/logr"

	api "sigs.k8s.io/multi-tenancy/incubator/hnc/api/v1alpha1"
)

// HasLocalCritCondition returns if the namespace itself has any local critical conditions, ignoring
// its ancestors. Any code with the "Crit" prefix is a critical condition.
func (ns *Namespace) HasLocalCritCondition() bool {
	for code, _ := range ns.conditions[api.AffectedObject{}] {
		codeNm := (string)(code)
		if strings.HasPrefix(codeNm, "Crit") {
			return true
		}
	}
	return false
}

// GetCritAncestor returns the name of the first ancestor with a critical condition, or the empty
// string if there are no such ancestors. It *can* return the name of the current namespace.
func (ns *Namespace) GetCritAncestor() string {
	if ns.HasLocalCritCondition() {
		return ns.name
	}
	if ns.Parent() == nil {
		return ""
	}
	return ns.Parent().GetCritAncestor()
}

// HasCondition returns true if there's a condition with the given object and code. If code is the
// empty string, it returns true if there's _any_ condition for the given object.
func (ns *Namespace) HasCondition(obj api.AffectedObject, code api.Code) bool {
	if _, exists := ns.conditions[obj]; !exists {
		// Nothing for this obj
		return false
	}
	if code == "" {
		// Something exists for this obj; we don't care what
		return true
	}
	_, exists := ns.conditions[obj][code]
	return exists
}

// ClearCondition clears conditions in the namespace for a single object. If `code` is non-empty, it
// only clears conditions with that code, otherwise it clears all conditions for that object. It
// should only be called by the code that also *sets* the conditions.
//
// It returns true if it made any changes, false otherwise.
func (ns *Namespace) ClearCondition(obj api.AffectedObject, code api.Code) bool {
	if !ns.HasCondition(obj, code) {
		return false
	}

	if code == "" {
		delete(ns.conditions, obj)
	} else {
		delete(ns.conditions[obj], code)
	}

	return true
}

// ClearLocalConditions clears the condition(s) on this namespace.
func (ns *Namespace) ClearLocalConditions() bool {
	return ns.ClearCondition(api.AffectedObject{}, "")
}

func (ns *Namespace) ClearObsoleteConditions(log logr.Logger) {
	// Load ancestors to check CCCAncestors
	isAnc := map[string]bool{}
	for _, anc := range ns.AncestryNames() {
		// The definition of CCCAncestor doesn't include the namespace itself
		if anc != ns.name {
			isAnc[anc] = true
		}
	}

	// Load the subtree to check CCCSubtree, including the namespace itself.
	isSubtree := map[string]bool{ns.name: true}
	for _, dsc := range ns.DescendantNames() {
		isSubtree[dsc] = true
	}

	// For each affected object, remove its condition if that object is no longer relevant.
	for obj, codes := range ns.conditions {
		for code, _ := range codes {
			switch api.ClearConditionCriteria[code] {
			case api.CCCManual:
				// nop - cleared manually
			case api.CCCAncestor:
				if !isAnc[obj.Namespace] {
					log.Info("Cleared obsolete condition from old ancestor", "obj", obj, "code", code)
					ns.ClearCondition(obj, code)
				}
			case api.CCCSubtree:
				if !isSubtree[obj.Namespace] {
					log.Info("Cleared obsolete condition from old descendant", "obj", obj, "code", code)
					ns.ClearCondition(obj, code)
				}
			default:
				err := errors.New("no ClearConditionCriterion")
				log.Error(err, "In clearObsoleteConditions", "code", code, "obj", obj)
			}
		}
	}
}

// SetCondition sets a condition for the specified object and code, returning true if it does not
// exist previously or if the message has changed.
//
// Returns true if the condition wasn't previously set
func (ns *Namespace) SetCondition(obj api.AffectedObject, code api.Code, msg string) bool {
	changed := false
	if _, existed := ns.conditions[obj]; !existed {
		changed = true
		ns.conditions[obj] = map[api.Code]string{}
	}

	if oldMsg, existed := ns.conditions[obj][code]; !existed || msg != oldMsg {
		changed = true
		ns.conditions[obj][code] = msg
	}

	return changed
}

// SetLocalCondition sets a condition that applies to the current namespace.
func (ns *Namespace) SetLocalCondition(code api.Code, msg string) bool {
	return ns.SetCondition(api.AffectedObject{}, code, msg)
}

// Conditions returns a list of conditions in the namespace in the format expected by the API.
func (ns *Namespace) Conditions() []api.Condition {
	// Treat the code/msg combination as a combined key.
	type codeMsg struct {
		code api.Code
		msg  string
	}

	// Reorder so that the objects are grouped by code and message
	byCM := map[codeMsg][]api.AffectedObject{}
	for obj, codes := range ns.conditions {
		for code, msg := range codes {
			cm := codeMsg{code: code, msg: msg}
			byCM[cm] = append(byCM[cm], obj)
		}
	}

	// Flatten into a list of conditions
	conds := []api.Condition{}
	for cm, objs := range byCM {
		// If the only affected object is unnamed (e.g., it refers to the current namespace), omit it.
		c := api.Condition{Code: cm.code, Msg: cm.msg}
		if len(objs) > 0 && objs[0].Name != "" {
			api.SortAffectedObjects(objs)
			c.Affects = objs
		}
		conds = append(conds, c)
	}

	sort.Slice(conds, func(i, j int) bool {
		if conds[i].Code != conds[j].Code {
			return conds[i].Code < conds[j].Code
		}
		return conds[i].Msg < conds[j].Msg
	})

	if len(conds) == 0 {
		conds = nil // prevent anything from appearing in the status
	}
	return conds
}
<|endoftext|>


<commit_before>package simlog

// from beego

import (
	"fmt"
	"log"
	"os"
	"strconv"
	"sync"
	"time"
)

const (
	DayDur   = time.Hour * 24   //一天的duration
	TimerDur = time.Minute * 10 //用于定时判断日期的时间间隔
)

func getdate(t time.Time) int {
	tdate, _ := strconv.Atoi(fmt.Sprintf("%04d%02d%02d", t.Year(), t.Month(), t.Day()))
	return tdate
}

type LogHandler struct {
	BaseName    string
	MaxDataSize int
	MaxFileSize int64 //每个文件最大大小，传参设定
	MaxLogIndex int   //每天最大文件个数，传参设定
	MaxDay      int   //保存文件最大天数，传参设定
	MaxSize     int   //日志判断周期，即生成MAXLOGCNT条日志后开始判断当前文件是否超过设定大小
	logger      *log.Logger
	level       Level      //日志级别
	splitFlag   bool       //是否根据文件大小切割
	logPath     string     //日志根目录，传参设定
	logDate     time.Time  //当天的日期，用来判断日期是否改变
	filePath    string     //日志文件路径，由logbasepath+当前日期得到
	fileIndex   int        //日志文件当前序号
	fileName    string     //日志文件名，由logfilepath+logfileindex.log得到
	file        *os.File   //日志文件
	lock        sync.Mutex //日志锁，在改变全局变量时需要用到
	size        int        //当前日志条数，用来和日志判断周期比较，避免频繁判断文件大小
}

func (this *LogHandler) OutPut(level Level, v ...interface{}) {
	if this.level < level {
		str := fmt.Sprint(v...)
		size := len(str)
		if size > this.MaxDataSize {
			size = this.MaxDataSize
		}
		if this.logger != nil {

			this.lock.Lock()
			this.logger.Output(4, level.String()+str[:size])
			this.size += size
			this.logSplit()
			this.lock.Unlock()
		} else {
			log.Println(level.String() + str[:size])
		}
	}
}

func (this *LogHandler) Trace(v ...interface{}) {
	this.OutPut(LevelTrace, v...)
}

func (this *LogHandler) Debug(v ...interface{}) {
	this.OutPut(LevelDebug, v...)
}

func (this *LogHandler) Info(v ...interface{}) {
	this.OutPut(LevelInfo, v...)
}

func (this *LogHandler) Warn(v ...interface{}) {
	this.OutPut(LevelWarning, v...)
}

func (this *LogHandler) Error(v ...interface{}) {
	this.OutPut(LevelError, v...)
}

func (this *LogHandler) Critical(v ...interface{}) {
	this.OutPut(LevelCritical, v...)
}

func (this *LogHandler) SetLevel(l Level) {
	this.level = l
}

func (this *LogHandler) GetLevel() Level {
	return this.level
}

func (this *LogHandler) SetLogSplit(maxsize, maxindex int) {
	this.splitFlag = true
	this.MaxFileSize = int64(maxsize * 1024 * 1024)
	this.MaxSize = int(this.MaxFileSize / 1024)
	this.MaxLogIndex = maxindex
}

func (this *LogHandler) logSplit() {
	if this.splitFlag {
		if this.size > this.MaxSize {
			this.changelogindex()
			this.size = 0
		}
	}
}

func (this *LogHandler) changelogindex() {
	if filesize, _ := GetFileSize(this.file); filesize >= this.MaxFileSize {
		if this.fileIndex >= this.MaxLogIndex {
			this.fileIndex = 0
		}
		this.fileIndex++
		this.changelogfile(time.Now())
	}
}

func (this *LogHandler) Init(path string, maxday int, loglevel Level) {
	if path == this.logPath && maxday == this.MaxDay && loglevel == this.level {
		return
	}
	this.MaxDataSize = 4096
	now := time.Now()
	this.lock.Lock()
	defer this.lock.Unlock()
	this.MaxDay = maxday
	this.level = loglevel
	this.logDate = now
	this.logPath = path + "/"
	this.filePath = this.logPath
	err := MakeDirAll(this.filePath)
	if nil != err {
		fmt.Printf("[simlog]LogInit|MakeDirAll logpath %s|%s failed\n", this.filePath, err.Error())
		os.Exit(-1)
	}
	if this.BaseName == "" {
		this.BaseName = "all.log"
	}
	this.fileName = this.filePath + this.BaseName

	this.file, err = OpenAndCreateFile(this.fileName, os.O_APPEND)
	if nil != err {
		fmt.Printf("log Start|open log file %s|%s\n", this.fileName, err.Error())
		os.Exit(-1)
	}
	this.logger = log.New(this.file, "\n", log.Ldate|log.Ltime|log.Llongfile)

	if this.logger == nil {
		this.initlogfile()
		this.movelogdir()
		this.removelogdir(this.MaxDay, now)
		go this.changelogdate()
	}
}

func (this *LogHandler) Close() {
	if this.file != nil {
		this.lock.Lock()
		defer this.lock.Unlock()
		this.logger = nil
		this.file.Close()
	}
}

func (this *LogHandler) movelogdir() {
	fis, err := ReadDir(this.logPath)
	if nil != err {
		fmt.Printf("GetLogName|ReadDir %s|%s failed", this.logPath, err.Error())
		os.Exit(-1)
	}
	var name string
	var path string
	now := time.Now()
	nowstr := fmt.Sprintf("%04d%02d%02d", now.Year(), now.Month(), now.Day())
	basepos := len(this.BaseName + ".")
	for _, fi := range fis {
		if fi.IsDir() {
			continue
		}
		if fi.Name() == this.BaseName {
			continue
		}
		name = fi.Name()
		//all.log.20160113
		if len(name) < basepos || name[:len(this.BaseName)] != this.BaseName {
			continue
		}
		if len(name) < basepos+8 || name[basepos:basepos+8] == nowstr {
			continue
		}
		path = this.logPath + name[basepos:basepos+8] + "/"

		if err := MakeDirAll(path); err != nil {
			this.Error("movelogdir failed ", err.Error())
			continue
		}
		oldname := this.logPath + name
		newname := path + name
		if err := os.Rename(oldname, newname); err != nil {
			fmt.Printf("Rename %s -> %s failed err=%s", oldname, newname, err.Error())
			continue
		}
	}
}

func (this *LogHandler) changelogfile(date time.Time) {
	//创建新文件
	//logfilename = logfilepath + LOG_BASE_NAME
	//	if splitFlag {
	for i := 0; i < 1; i++ {
		//关闭上一个文件
		this.file.Close()
		old := this.filePath + fmt.Sprintf("all.log.%04d%02d%02d-%02d%02d%02d.%d",
			date.Year(), date.Month(), date.Day(), date.Hour(), date.Minute(), date.Second(), this.fileIndex)
		if err := os.Rename(this.fileName, old); err != nil {
			fmt.Printf("Rename %s -> %s failed err=%s", this.fileName, old, err.Error())
			break
		}
	}
	var err error
	this.file, err = OpenAndCreateFile(this.fileName, os.O_TRUNC)
	if nil != err {
		fmt.Printf("ChangeLogPathOrFile|open log file %s|%s\n", this.fileName, err.Error())
		return
	}
	this.size = 0
	this.logger = log.New(this.file, "\n", log.Ldate|log.Ltime|log.Llongfile)
}

func (this *LogHandler) initlogfile() {
	this.movelogdir()
	fis, err := ReadDir(this.logPath)
	if nil != err {
		fmt.Printf("GetLogName|ReadDir %s|%s failed", this.logPath, err.Error())
		os.Exit(-1)
	}
	nowdate := time.Now()
	for _, fi := range fis {
		if fi.IsDir() {
			continue
		}
		if fi.Name() != this.BaseName {
			continue
		}

		olddate := fi.ModTime()
		if nowdate.Day() == olddate.Day() &&
			nowdate.Month() == olddate.Month() &&
			nowdate.Year() == olddate.Year() {
			return
		}

		this.changelogfile(olddate)
		break
	}
}

func (this *LogHandler) changelogdate() {
	logTimer := time.NewTicker(TimerDur)
	for {
		select {
		case <-logTimer.C:
			func() {
				this.lock.Lock()
				defer this.lock.Unlock()
				now := time.Now()
				if now.Day() == this.logDate.Day() &&
					now.Month() == this.logDate.Month() &&
					now.Year() == this.logDate.Year() {
					return
				}
				//如果日期改变
				//将全局信息重置
				this.logDate = now
				//logfilepath = logbasepath + MakeLogPath(now) + "/"
				this.fileIndex = 0
				this.fileIndex++
				//logfilename = logfilepath + LOG_BASE_NAME
				st, e := this.file.Stat()
				if e != nil {
					this.Error("logfile.Stat failed|err=", e.Error())
					this.changelogfile(now)
				} else {
					this.changelogfile(st.ModTime())
				}
				//删除配置指定时间的日志文件
				this.movelogdir()
				this.removelogdir(this.MaxDay, now)
			}()
		}
	}
}

func (this *LogHandler) removelogdir(daynum int, now time.Time) {
	tmpdate := now.Add(-DayDur * time.Duration(daynum))
	tmpdir := this.logPath + LogPathName(tmpdate) + "/"
	os.RemoveAll(tmpdir)
}
<commit_msg>Update log_handle.go<commit_after>package simlog

// from beego

import (
	"fmt"
	"log"
	"os"
	"strconv"
	"sync"
	"time"
)

const (
	DayDur   = time.Hour * 24   //一天的duration
	TimerDur = time.Minute * 10 //用于定时判断日期的时间间隔
)

func getdate(t time.Time) int {
	tdate, _ := strconv.Atoi(fmt.Sprintf("%04d%02d%02d", t.Year(), t.Month(), t.Day()))
	return tdate
}

type LogHandler struct {
	BaseName    string
	MaxDataSize int
	MaxFileSize int64 //每个文件最大大小，传参设定
	MaxLogIndex int   //每天最大文件个数，传参设定
	MaxDay      int   //保存文件最大天数，传参设定
	MaxSize     int   //日志判断周期，即生成MAXLOGCNT条日志后开始判断当前文件是否超过设定大小
	logger      *log.Logger
	level       Level      //日志级别
	splitFlag   bool       //是否根据文件大小切割
	logPath     string     //日志根目录，传参设定
	logDate     time.Time  //当天的日期，用来判断日期是否改变
	filePath    string     //日志文件路径，由logbasepath+当前日期得到
	fileIndex   int        //日志文件当前序号
	fileName    string     //日志文件名，由logfilepath+logfileindex.log得到
	file        *os.File   //日志文件
	lock        sync.Mutex //日志锁，在改变全局变量时需要用到
	size        int        //当前日志条数，用来和日志判断周期比较，避免频繁判断文件大小
}

func (this *LogHandler) OutPut(level Level, v ...interface{}) {
	if this.level <= level {
		str := fmt.Sprint(v...)
		size := len(str)
		if size > this.MaxDataSize {
			size = this.MaxDataSize
		}
		if this.logger != nil {

			this.lock.Lock()
			this.logger.Output(4, level.String()+str[:size])
			this.size += size
			this.logSplit()
			this.lock.Unlock()
		} else {
			log.Println(level.String() + str[:size])
		}
	}
}

func (this *LogHandler) Trace(v ...interface{}) {
	this.OutPut(LevelTrace, v...)
}

func (this *LogHandler) Debug(v ...interface{}) {
	this.OutPut(LevelDebug, v...)
}

func (this *LogHandler) Info(v ...interface{}) {
	this.OutPut(LevelInfo, v...)
}

func (this *LogHandler) Warn(v ...interface{}) {
	this.OutPut(LevelWarning, v...)
}

func (this *LogHandler) Error(v ...interface{}) {
	this.OutPut(LevelError, v...)
}

func (this *LogHandler) Critical(v ...interface{}) {
	this.OutPut(LevelCritical, v...)
}

func (this *LogHandler) SetLevel(l Level) {
	this.level = l
}

func (this *LogHandler) GetLevel() Level {
	return this.level
}

func (this *LogHandler) SetLogSplit(maxsize, maxindex int) {
	this.splitFlag = true
	this.MaxFileSize = int64(maxsize * 1024 * 1024)
	this.MaxSize = int(this.MaxFileSize / 1024)
	this.MaxLogIndex = maxindex
}

func (this *LogHandler) logSplit() {
	if this.splitFlag {
		if this.size > this.MaxSize {
			this.changelogindex()
			this.size = 0
		}
	}
}

func (this *LogHandler) changelogindex() {
	if filesize, _ := GetFileSize(this.file); filesize >= this.MaxFileSize {
		if this.fileIndex >= this.MaxLogIndex {
			this.fileIndex = 0
		}
		this.fileIndex++
		this.changelogfile(time.Now())
	}
}

func (this *LogHandler) Init(path string, maxday int, loglevel Level) {
	if path == this.logPath && maxday == this.MaxDay && loglevel == this.level {
		return
	}
	this.MaxDataSize = 4096
	now := time.Now()
	this.lock.Lock()
	defer this.lock.Unlock()
	this.MaxDay = maxday
	this.level = loglevel
	this.logDate = now
	this.logPath = path + "/"
	this.filePath = this.logPath
	err := MakeDirAll(this.filePath)
	if nil != err {
		fmt.Printf("[simlog]LogInit|MakeDirAll logpath %s|%s failed\n", this.filePath, err.Error())
		os.Exit(-1)
	}
	if this.BaseName == "" {
		this.BaseName = "all.log"
	}
	this.fileName = this.filePath + this.BaseName

	this.file, err = OpenAndCreateFile(this.fileName, os.O_APPEND)
	if nil != err {
		fmt.Printf("log Start|open log file %s|%s\n", this.fileName, err.Error())
		os.Exit(-1)
	}
	this.logger = log.New(this.file, "\n", log.Ldate|log.Ltime|log.Llongfile)

	if this.logger == nil {
		this.initlogfile()
		this.movelogdir()
		this.removelogdir(this.MaxDay, now)
		go this.changelogdate()
	}
}

func (this *LogHandler) Close() {
	if this.file != nil {
		this.lock.Lock()
		defer this.lock.Unlock()
		this.logger = nil
		this.file.Close()
	}
}

func (this *LogHandler) movelogdir() {
	fis, err := ReadDir(this.logPath)
	if nil != err {
		fmt.Printf("GetLogName|ReadDir %s|%s failed", this.logPath, err.Error())
		os.Exit(-1)
	}
	var name string
	var path string
	now := time.Now()
	nowstr := fmt.Sprintf("%04d%02d%02d", now.Year(), now.Month(), now.Day())
	basepos := len(this.BaseName + ".")
	for _, fi := range fis {
		if fi.IsDir() {
			continue
		}
		if fi.Name() == this.BaseName {
			continue
		}
		name = fi.Name()
		//all.log.20160113
		if len(name) < basepos || name[:len(this.BaseName)] != this.BaseName {
			continue
		}
		if len(name) < basepos+8 || name[basepos:basepos+8] == nowstr {
			continue
		}
		path = this.logPath + name[basepos:basepos+8] + "/"

		if err := MakeDirAll(path); err != nil {
			this.Error("movelogdir failed ", err.Error())
			continue
		}
		oldname := this.logPath + name
		newname := path + name
		if err := os.Rename(oldname, newname); err != nil {
			fmt.Printf("Rename %s -> %s failed err=%s", oldname, newname, err.Error())
			continue
		}
	}
}

func (this *LogHandler) changelogfile(date time.Time) {
	//创建新文件
	//logfilename = logfilepath + LOG_BASE_NAME
	//	if splitFlag {
	for i := 0; i < 1; i++ {
		//关闭上一个文件
		this.file.Close()
		old := this.filePath + fmt.Sprintf("all.log.%04d%02d%02d-%02d%02d%02d.%d",
			date.Year(), date.Month(), date.Day(), date.Hour(), date.Minute(), date.Second(), this.fileIndex)
		if err := os.Rename(this.fileName, old); err != nil {
			fmt.Printf("Rename %s -> %s failed err=%s", this.fileName, old, err.Error())
			break
		}
	}
	var err error
	this.file, err = OpenAndCreateFile(this.fileName, os.O_TRUNC)
	if nil != err {
		fmt.Printf("ChangeLogPathOrFile|open log file %s|%s\n", this.fileName, err.Error())
		return
	}
	this.size = 0
	this.logger = log.New(this.file, "\n", log.Ldate|log.Ltime|log.Llongfile)
}

func (this *LogHandler) initlogfile() {
	this.movelogdir()
	fis, err := ReadDir(this.logPath)
	if nil != err {
		fmt.Printf("GetLogName|ReadDir %s|%s failed", this.logPath, err.Error())
		os.Exit(-1)
	}
	nowdate := time.Now()
	for _, fi := range fis {
		if fi.IsDir() {
			continue
		}
		if fi.Name() != this.BaseName {
			continue
		}

		olddate := fi.ModTime()
		if nowdate.Day() == olddate.Day() &&
			nowdate.Month() == olddate.Month() &&
			nowdate.Year() == olddate.Year() {
			return
		}

		this.changelogfile(olddate)
		break
	}
}

func (this *LogHandler) changelogdate() {
	logTimer := time.NewTicker(TimerDur)
	for {
		select {
		case <-logTimer.C:
			func() {
				this.lock.Lock()
				defer this.lock.Unlock()
				now := time.Now()
				if now.Day() == this.logDate.Day() &&
					now.Month() == this.logDate.Month() &&
					now.Year() == this.logDate.Year() {
					return
				}
				//如果日期改变
				//将全局信息重置
				this.logDate = now
				//logfilepath = logbasepath + MakeLogPath(now) + "/"
				this.fileIndex = 0
				this.fileIndex++
				//logfilename = logfilepath + LOG_BASE_NAME
				st, e := this.file.Stat()
				if e != nil {
					this.Error("logfile.Stat failed|err=", e.Error())
					this.changelogfile(now)
				} else {
					this.changelogfile(st.ModTime())
				}
				//删除配置指定时间的日志文件
				this.movelogdir()
				this.removelogdir(this.MaxDay, now)
			}()
		}
	}
}

func (this *LogHandler) removelogdir(daynum int, now time.Time) {
	tmpdate := now.Add(-DayDur * time.Duration(daynum))
	tmpdir := this.logPath + LogPathName(tmpdate) + "/"
	os.RemoveAll(tmpdir)
}
<|endoftext|>


<commit_before>package focker_test

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"os"

	"github.com/hatofmonkeys/cloudfocker/focker"

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

var _ = Describe("Focker", func() {
	var (
		testfocker *focker.Focker
		buffer     *gbytes.Buffer
	)
	BeforeEach(func() {
		testfocker = focker.NewFocker()
		buffer = gbytes.NewBuffer()
	})

	Describe("Displaying the docker version", func() {
		It("should tell Docker to output its version", func() {
			testfocker.DockerVersion(buffer)
			Eventually(buffer).Should(gbytes.Say(`Checking Docker version`))
			Eventually(buffer).Should(gbytes.Say(`Client API version: `))
			Eventually(buffer).Should(gbytes.Say(`Go version \(client\): go`))
		})
	})

	Describe("Bootstrapping the base image", func() {
		//This works, but speed depends on your net connection
		XIt("should download and tag the lucid64 filesystem", func() {
			fmt.Println("Downloading lucid64 - this could take a while")
			testfocker.ImportRootfsImage(buffer)
			Eventually(buffer, 600).Should(gbytes.Say(`[a-f0-9]{64}`))
		})
	})

	Describe("Writing a dockerfile", func() {
		It("should write a valid dockerfile", func() {
			testfocker.WriteDockerfile(buffer)
			Eventually(buffer).Should(gbytes.Say(`FROM`))
		})
	})

	Describe("Building a docker image", func() {
		It("should output a built image tag", func() {
			testfocker.BuildImage(buffer)
			Eventually(buffer, 20).Should(gbytes.Say(`Successfully built [a-f0-9]{12}`))
		})
	})

	Describe("Running the docker container", func() {
		It("should output a valid URL for the running application", func() {
			testfocker.RunContainer(buffer)
			Eventually(buffer, 20).Should(gbytes.Say(`Successfully built [a-f0-9]{12}`))
			Eventually(buffer).Should(gbytes.Say(`[a-f0-9]{64}`))
			Eventually(buffer).Should(gbytes.Say(`Connect to your running application at http://localhost:8080/`))
			Eventually(statusCodeChecker).Should(Equal(200))
			testfocker.StopContainer(buffer)
		})
	})

	Describe("Stopping the docker container", func() {
		It("should output the stopped image ID, not respond to HTTP, and delete the container", func() {
			testfocker.RunContainer(buffer)
			testfocker.StopContainer(buffer)
			Eventually(buffer).Should(gbytes.Say(`Stopping the CloudFocker container...`))
			Eventually(buffer).Should(gbytes.Say(`cloudfocker-container`))
			Eventually(statusCodeChecker).Should(Equal(0))
			Eventually(buffer).Should(gbytes.Say(`Deleting the CloudFocker container...`))
			Eventually(buffer).Should(gbytes.Say(`cloudfocker-container`))
		})
	})

	Describe("Adding a buildpack", func() {
		XIt("should download the buildpack and add it to the buildpack directory", func() {
			//This works, but speed depends on your net connection
			buildpackDir, _ := ioutil.TempDir(os.TempDir(), "cfocker-buildpack-test")
			buffer := gbytes.NewBuffer()
			testfocker.AddBuildpack(buffer, "https://github.com/hatofmonkeys/ruby-buildpack", buildpackDir)
			Eventually(buffer).Should(gbytes.Say(`Downloading buildpack...`))
			Eventually(buffer, 120).Should(gbytes.Say(`Downloaded buildpack.`))
			os.RemoveAll(buildpackDir)
		})
	})

	Describe("Staging an application", func() {
		It("should run the buildpack runner from linux-circus", func() {
			err := testfocker.StageApp(buffer, "/tmp/made-up-directory-that-will-not-exist")
			Expect(err).Should(MatchError("no valid buildpacks detected"))
			Eventually(buffer).Should(gbytes.Say(`Running Buildpacks...`))
		})
	})
})

func statusCodeChecker() int {
	res, err := http.Get("http://localhost:8080/")
	if err != nil {
		return 0
	} else {
		return res.StatusCode
	}
}
<commit_msg>Clarified description between staging and droplet building<commit_after>package focker_test

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"os"

	"github.com/hatofmonkeys/cloudfocker/focker"

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

var _ = Describe("Focker", func() {
	var (
		testfocker *focker.Focker
		buffer     *gbytes.Buffer
	)
	BeforeEach(func() {
		testfocker = focker.NewFocker()
		buffer = gbytes.NewBuffer()
	})

	Describe("Displaying the docker version", func() {
		It("should tell Docker to output its version", func() {
			testfocker.DockerVersion(buffer)
			Eventually(buffer).Should(gbytes.Say(`Checking Docker version`))
			Eventually(buffer).Should(gbytes.Say(`Client API version: `))
			Eventually(buffer).Should(gbytes.Say(`Go version \(client\): go`))
		})
	})

	Describe("Bootstrapping the base image", func() {
		//This works, but speed depends on your net connection
		XIt("should download and tag the lucid64 filesystem", func() {
			fmt.Println("Downloading lucid64 - this could take a while")
			testfocker.ImportRootfsImage(buffer)
			Eventually(buffer, 600).Should(gbytes.Say(`[a-f0-9]{64}`))
		})
	})

	Describe("Writing a dockerfile", func() {
		It("should write a valid dockerfile", func() {
			testfocker.WriteDockerfile(buffer)
			Eventually(buffer).Should(gbytes.Say(`FROM`))
		})
	})

	Describe("Building a docker image", func() {
		It("should output a built image tag", func() {
			testfocker.BuildImage(buffer)
			Eventually(buffer, 20).Should(gbytes.Say(`Successfully built [a-f0-9]{12}`))
		})
	})

	Describe("Running the docker container", func() {
		It("should output a valid URL for the running application", func() {
			testfocker.RunContainer(buffer)
			Eventually(buffer, 20).Should(gbytes.Say(`Successfully built [a-f0-9]{12}`))
			Eventually(buffer).Should(gbytes.Say(`[a-f0-9]{64}`))
			Eventually(buffer).Should(gbytes.Say(`Connect to your running application at http://localhost:8080/`))
			Eventually(statusCodeChecker).Should(Equal(200))
			testfocker.StopContainer(buffer)
		})
	})

	Describe("Stopping the docker container", func() {
		It("should output the stopped image ID, not respond to HTTP, and delete the container", func() {
			testfocker.RunContainer(buffer)
			testfocker.StopContainer(buffer)
			Eventually(buffer).Should(gbytes.Say(`Stopping the CloudFocker container...`))
			Eventually(buffer).Should(gbytes.Say(`cloudfocker-container`))
			Eventually(statusCodeChecker).Should(Equal(0))
			Eventually(buffer).Should(gbytes.Say(`Deleting the CloudFocker container...`))
			Eventually(buffer).Should(gbytes.Say(`cloudfocker-container`))
		})
	})

	Describe("Adding a buildpack", func() {
		XIt("should download the buildpack and add it to the buildpack directory", func() {
			//This works, but speed depends on your net connection
			buildpackDir, _ := ioutil.TempDir(os.TempDir(), "cfocker-buildpack-test")
			buffer := gbytes.NewBuffer()
			testfocker.AddBuildpack(buffer, "https://github.com/hatofmonkeys/ruby-buildpack", buildpackDir)
			Eventually(buffer).Should(gbytes.Say(`Downloading buildpack...`))
			Eventually(buffer, 120).Should(gbytes.Say(`Downloaded buildpack.`))
			os.RemoveAll(buildpackDir)
		})
	})

	Describe("Building an application droplet", func() {
		It("should run the buildpack runner from linux-circus", func() {
			err := testfocker.StageApp(buffer, "/tmp/made-up-directory-that-will-not-exist")
			Expect(err).Should(MatchError("no valid buildpacks detected"))
			Eventually(buffer).Should(gbytes.Say(`Running Buildpacks...`))
		})
	})
})

func statusCodeChecker() int {
	res, err := http.Get("http://localhost:8080/")
	if err != nil {
		return 0
	} else {
		return res.StatusCode
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"time"

	kinesis "github.com/sendgridlabs/go-kinesis"
)

func getRecords(ksis *kinesis.Kinesis, streamName, ShardId string) {
	args := kinesis.NewArgs()
	args.Add("StreamName", streamName)
	args.Add("ShardId", ShardId)
	args.Add("ShardIteratorType", "TRIM_HORIZON")
	resp10, _ := ksis.GetShardIterator(args)

	shardIterator := resp10.ShardIterator

	for {
		args = kinesis.NewArgs()
		args.Add("ShardIterator", shardIterator)
		resp11, err := ksis.GetRecords(args)
		if err != nil {
			continue
		}

		if len(resp11.Records) > 0 {
			fmt.Printf("GetRecords Data BEGIN\n")
			for _, d := range resp11.Records {
				fmt.Printf("GetRecords Data: %v\n", string(d.GetData()))
			}
			fmt.Printf("GetRecords Data END\n")
		} else if resp11.NextShardIterator == "" || shardIterator == resp11.NextShardIterator || err != nil {
			fmt.Printf("GetRecords ERROR: %v\n", err)
			break
		}

		shardIterator = resp11.NextShardIterator
		time.Sleep(1000 * time.Millisecond)
	}
}

func main() {
	fmt.Println("Begin")

	streamName := "test"
	// set env variables AWS_ACCESS_KEY and AWS_SECRET_KEY AWS_REGION_NAME
	ksis := kinesis.New(&kinesis.Auth{}, kinesis.Region{})

	err := ksis.CreateStream(streamName, 2)
	if err != nil {
		fmt.Printf("CreateStream ERROR: %v\n", err)
	}

	args := kinesis.NewArgs()
	resp2, _ := ksis.ListStreams(args)
	fmt.Printf("ListStreams: %v\n", resp2)

	resp3 := &kinesis.DescribeStreamResp{}

	timeout := make(chan bool, 30)
	for {

		args = kinesis.NewArgs()
		args.Add("StreamName", streamName)
		resp3, _ = ksis.DescribeStream(args)
		fmt.Printf("DescribeStream: %v\n", resp3)

		if resp3.StreamDescription.StreamStatus != "ACTIVE" {
			time.Sleep(4 * time.Second)
			timeout <- true
		} else {
			break
		}

	}

	// Put records individually
	for i := 0; i < 10; i++ {
		args = kinesis.NewArgs()
		args.Add("StreamName", streamName)
		args.AddData([]byte(fmt.Sprintf("Hello AWS Kinesis %d", i)))
		args.Add("PartitionKey", fmt.Sprintf("partitionKey-%d", i))
		resp4, err := ksis.PutRecord(args)
		if err != nil {
			fmt.Printf("PutRecord err: %v\n", err)
		} else {
			fmt.Printf("PutRecord: %v\n", resp4)
		}
	}

	for _, shard := range resp3.StreamDescription.Shards {
		go getRecords(ksis, streamName, shard.ShardId)
	}

	// Put records in batch
	args = kinesis.NewArgs()
	args.Add("StreamName", streamName)

	for i := 0; i < 10; i++ {
		args.AddRecord(
			[]byte(fmt.Sprintf("Hello AWS Kinesis %d", i)),
			fmt.Sprintf("partitionKey-%d", i),
		)
	}

	resp4, err := ksis.PutRecords(args)
	if err != nil {
		fmt.Printf("PutRecords err: %v\n", err)
	} else {
		fmt.Printf("PutRecords: %v\n", resp4)
	}

	// Wait for user input
	var inputGuess string
	fmt.Scanf("%s\n", &inputGuess)

	// Delete the stream
	err1 := ksis.DeleteStream("test")
	if err1 != nil {
		fmt.Printf("DeleteStream ERROR: %v\n", err1)
	}

	fmt.Println("End")
}
<commit_msg>also sleep in rate-limit error handler<commit_after>package main

import (
	"fmt"
	"time"

	kinesis "github.com/sendgridlabs/go-kinesis"
)

func getRecords(ksis *kinesis.Kinesis, streamName, ShardId string) {
	args := kinesis.NewArgs()
	args.Add("StreamName", streamName)
	args.Add("ShardId", ShardId)
	args.Add("ShardIteratorType", "TRIM_HORIZON")
	resp10, _ := ksis.GetShardIterator(args)

	shardIterator := resp10.ShardIterator

	for {
		args = kinesis.NewArgs()
		args.Add("ShardIterator", shardIterator)
		resp11, err := ksis.GetRecords(args)
		if err != nil {
			time.Sleep(1000 * time.Millisecond)
			continue
		}

		if len(resp11.Records) > 0 {
			fmt.Printf("GetRecords Data BEGIN\n")
			for _, d := range resp11.Records {
				fmt.Printf("GetRecords Data: %v\n", string(d.GetData()))
			}
			fmt.Printf("GetRecords Data END\n")
		} else if resp11.NextShardIterator == "" || shardIterator == resp11.NextShardIterator || err != nil {
			fmt.Printf("GetRecords ERROR: %v\n", err)
			break
		}

		shardIterator = resp11.NextShardIterator
		time.Sleep(1000 * time.Millisecond)
	}
}

func main() {
	fmt.Println("Begin")

	streamName := "test"
	// set env variables AWS_ACCESS_KEY and AWS_SECRET_KEY AWS_REGION_NAME
	ksis := kinesis.New(&kinesis.Auth{}, kinesis.Region{})

	err := ksis.CreateStream(streamName, 2)
	if err != nil {
		fmt.Printf("CreateStream ERROR: %v\n", err)
	}

	args := kinesis.NewArgs()
	resp2, _ := ksis.ListStreams(args)
	fmt.Printf("ListStreams: %v\n", resp2)

	resp3 := &kinesis.DescribeStreamResp{}

	timeout := make(chan bool, 30)
	for {

		args = kinesis.NewArgs()
		args.Add("StreamName", streamName)
		resp3, _ = ksis.DescribeStream(args)
		fmt.Printf("DescribeStream: %v\n", resp3)

		if resp3.StreamDescription.StreamStatus != "ACTIVE" {
			time.Sleep(4 * time.Second)
			timeout <- true
		} else {
			break
		}

	}

	// Put records individually
	for i := 0; i < 10; i++ {
		args = kinesis.NewArgs()
		args.Add("StreamName", streamName)
		args.AddData([]byte(fmt.Sprintf("Hello AWS Kinesis %d", i)))
		args.Add("PartitionKey", fmt.Sprintf("partitionKey-%d", i))
		resp4, err := ksis.PutRecord(args)
		if err != nil {
			fmt.Printf("PutRecord err: %v\n", err)
		} else {
			fmt.Printf("PutRecord: %v\n", resp4)
		}
	}

	for _, shard := range resp3.StreamDescription.Shards {
		go getRecords(ksis, streamName, shard.ShardId)
	}

	// Put records in batch
	args = kinesis.NewArgs()
	args.Add("StreamName", streamName)

	for i := 0; i < 10; i++ {
		args.AddRecord(
			[]byte(fmt.Sprintf("Hello AWS Kinesis %d", i)),
			fmt.Sprintf("partitionKey-%d", i),
		)
	}

	resp4, err := ksis.PutRecords(args)
	if err != nil {
		fmt.Printf("PutRecords err: %v\n", err)
	} else {
		fmt.Printf("PutRecords: %v\n", resp4)
	}

	// Wait for user input
	var inputGuess string
	fmt.Scanf("%s\n", &inputGuess)

	// Delete the stream
	err1 := ksis.DeleteStream("test")
	if err1 != nil {
		fmt.Printf("DeleteStream ERROR: %v\n", err1)
	}

	fmt.Println("End")
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"

	"github.com/spf13/cobra"

	"github.com/lxc/lxd/lxc/config"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/api"
	cli "github.com/lxc/lxd/shared/cmd"
	"github.com/lxc/lxd/shared/i18n"
	"github.com/pkg/errors"
)

type cmdMove struct {
	global *cmdGlobal

	flagNoProfiles    bool
	flagProfile       []string
	flagConfig        []string
	flagInstanceOnly  bool
	flagDevice        []string
	flagMode          string
	flagStateless     bool
	flagStorage       string
	flagTarget        string
	flagTargetProject string
}

func (c *cmdMove) Command() *cobra.Command {
	cmd := &cobra.Command{}
	cmd.Use = i18n.G("move [<remote>:]<instance>[/<snapshot>] [<remote>:][<instance>[/<snapshot>]]")
	cmd.Aliases = []string{"mv"}
	cmd.Short = i18n.G("Move instances within or in between LXD servers")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Move instances within or in between LXD servers`))
	cmd.Example = cli.FormatSection("", i18n.G(
		`lxc move [<remote>:]<source instance> [<remote>:][<destination instance>] [--instance-only]
    Move an instance between two hosts, renaming it if destination name differs.

lxc move <old name> <new name> [--instance-only]
    Rename a local instance.

lxc move <instance>/<old snapshot name> <instance>/<new snapshot name>
    Rename a snapshot.`))

	cmd.RunE = c.Run
	cmd.Flags().StringArrayVarP(&c.flagConfig, "config", "c", nil, i18n.G("Config key/value to apply to the target instance")+"``")
	cmd.Flags().StringArrayVarP(&c.flagDevice, "device", "d", nil, i18n.G("New key/value to apply to a specific device")+"``")
	cmd.Flags().StringArrayVarP(&c.flagProfile, "profile", "p", nil, i18n.G("Profile to apply to the target instance")+"``")
	cmd.Flags().BoolVar(&c.flagNoProfiles, "no-profiles", false, i18n.G("Unset all profiles on the target instance"))
	cmd.Flags().BoolVar(&c.flagInstanceOnly, "instance-only", false, i18n.G("Move the instance without its snapshots"))
	cmd.Flags().StringVar(&c.flagMode, "mode", moveDefaultMode, i18n.G("Transfer mode. One of pull (default), push or relay.")+"``")
	cmd.Flags().BoolVar(&c.flagStateless, "stateless", false, i18n.G("Copy a stateful instance stateless"))
	cmd.Flags().StringVarP(&c.flagStorage, "storage", "s", "", i18n.G("Storage pool name")+"``")
	cmd.Flags().StringVar(&c.flagTarget, "target", "", i18n.G("Cluster member name")+"``")
	cmd.Flags().StringVar(&c.flagTargetProject, "target-project", "", i18n.G("Copy to a project different from the source")+"``")

	return cmd
}

func (c *cmdMove) Run(cmd *cobra.Command, args []string) error {
	conf := c.global.conf

	// Sanity checks
	if c.flagTarget == "" {
		exit, err := c.global.CheckArgs(cmd, args, 2, 2)
		if exit {
			return err
		}
	} else {
		exit, err := c.global.CheckArgs(cmd, args, 1, 2)
		if exit {
			return err
		}
	}

	// Parse the mode
	mode := moveDefaultMode
	if c.flagMode != "" {
		mode = c.flagMode
	}

	sourceRemote, sourceName, err := conf.ParseRemote(args[0])
	if err != nil {
		return err
	}

	destRemote := sourceRemote
	destName := ""
	if len(args) == 2 {
		var err error
		destRemote, destName, err = conf.ParseRemote(args[1])
		if err != nil {
			return err
		}
	}

	// As an optimization, if the source an destination are the same, do
	// this via a simple rename. This only works for instances that aren't
	// running, instances that are running should be live migrated (of
	// course, this changing of hostname isn't supported right now, so this
	// simply won't work).
	if sourceRemote == destRemote && c.flagTarget == "" && c.flagStorage == "" && c.flagTargetProject == "" {
		if c.flagConfig != nil || c.flagDevice != nil || c.flagProfile != nil || c.flagNoProfiles {
			return fmt.Errorf(i18n.G("Can't override configuration or profiles in local rename"))
		}

		source, err := conf.GetInstanceServer(sourceRemote)
		if err != nil {
			return err
		}

		if shared.IsSnapshot(sourceName) {
			// Snapshot rename
			srcParent, srcSnap, _ := shared.InstanceGetParentAndSnapshotName(sourceName)
			dstParent, dstSnap, dstIsSnap := shared.InstanceGetParentAndSnapshotName(destName)

			if srcParent != dstParent {
				return fmt.Errorf("Invalid new snapshot name, parent must be the same as source")
			}

			if !dstIsSnap {
				return fmt.Errorf("Invalid new snapshot name")
			}

			op, err := source.RenameInstanceSnapshot(srcParent, srcSnap, api.InstanceSnapshotPost{Name: dstSnap})
			if err != nil {
				return err
			}

			return op.Wait()
		}

		// Instance rename
		op, err := source.RenameInstance(sourceName, api.InstancePost{Name: destName})
		if err != nil {
			return err
		}

		return op.Wait()
	}

	sourceResource := args[0]
	destResource := sourceResource
	if len(args) == 2 {
		destResource = args[1]
	}

	// If the target option was specified, we're moving an instance from a
	// cluster member to another, let's use the dedicated API.
	if c.flagTarget != "" {
		if c.flagStateless {
			return fmt.Errorf(i18n.G("The --stateless flag can't be used with --target"))
		}

		if c.flagInstanceOnly {
			return fmt.Errorf(i18n.G("The --instance-only flag can't be used with --target"))
		}

		if c.flagMode != moveDefaultMode {
			return fmt.Errorf(i18n.G("The --mode flag can't be used with --target"))
		}

		return moveClusterInstance(conf, sourceResource, destResource, c.flagTarget)
	}

	cpy := cmdCopy{}
	cpy.global = c.global
	cpy.flagTarget = c.flagTarget
	cpy.flagTargetProject = c.flagTargetProject
	cpy.flagConfig = c.flagConfig
	cpy.flagDevice = c.flagDevice
	cpy.flagProfile = c.flagProfile
	cpy.flagNoProfiles = c.flagNoProfiles

	stateful := !c.flagStateless
	instanceOnly := c.flagInstanceOnly

	// A move is just a copy followed by a delete; however, we want to
	// keep the volatile entries around since we are moving the instance.
	err = cpy.copyInstance(conf, sourceResource, destResource, true, -1, stateful, instanceOnly, mode, c.flagStorage, true)
	if err != nil {
		return err
	}

	del := cmdDelete{global: c.global}
	del.flagForce = true
	err = del.Run(cmd, args[:1])
	if err != nil {
		return errors.Wrap(err, "Failed to delete original instance after copying it")
	}

	return nil
}

// Move an instance using special POST /instances/<name>?target=<member> API.
func moveClusterInstance(conf *config.Config, sourceResource, destResource, target string) error {
	// Parse the source.
	sourceRemote, sourceName, err := conf.ParseRemote(sourceResource)
	if err != nil {
		return err
	}

	// Parse the destination.
	_, destName, err := conf.ParseRemote(destResource)
	if err != nil {
		return err
	}

	// Make sure we have an instance or snapshot name.
	if sourceName == "" {
		return fmt.Errorf(i18n.G("You must specify a source instance name"))
	}

	// The destination name is optional.
	if destName == "" {
		destName = sourceName
	}

	// Connect to the source host
	source, err := conf.GetInstanceServer(sourceRemote)
	if err != nil {
		return errors.Wrap(err, i18n.G("Failed to connect to cluster member"))
	}

	// Check that it's a cluster
	if !source.IsClustered() {
		return fmt.Errorf(i18n.G("The source LXD server is not clustered"))
	}

	// The migrate API will do the right thing when passed a target.
	source = source.UseTarget(target)
	req := api.InstancePost{Name: destName, Migration: true}
	op, err := source.MigrateInstance(sourceName, req)
	if err != nil {
		return errors.Wrap(err, i18n.G("Migration API failure"))
	}

	err = op.Wait()
	if err != nil {
		return errors.Wrap(err, i18n.G("Migration operation failure"))
	}

	return nil
}

// Default migration mode when moving an instance.
const moveDefaultMode = "pull"
<commit_msg>lxc/move: Allow --target with cluster destination<commit_after>package main

import (
	"fmt"

	"github.com/spf13/cobra"

	"github.com/lxc/lxd/lxc/config"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/api"
	cli "github.com/lxc/lxd/shared/cmd"
	"github.com/lxc/lxd/shared/i18n"
	"github.com/pkg/errors"
)

type cmdMove struct {
	global *cmdGlobal

	flagNoProfiles    bool
	flagProfile       []string
	flagConfig        []string
	flagInstanceOnly  bool
	flagDevice        []string
	flagMode          string
	flagStateless     bool
	flagStorage       string
	flagTarget        string
	flagTargetProject string
}

func (c *cmdMove) Command() *cobra.Command {
	cmd := &cobra.Command{}
	cmd.Use = i18n.G("move [<remote>:]<instance>[/<snapshot>] [<remote>:][<instance>[/<snapshot>]]")
	cmd.Aliases = []string{"mv"}
	cmd.Short = i18n.G("Move instances within or in between LXD servers")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Move instances within or in between LXD servers`))
	cmd.Example = cli.FormatSection("", i18n.G(
		`lxc move [<remote>:]<source instance> [<remote>:][<destination instance>] [--instance-only]
    Move an instance between two hosts, renaming it if destination name differs.

lxc move <old name> <new name> [--instance-only]
    Rename a local instance.

lxc move <instance>/<old snapshot name> <instance>/<new snapshot name>
    Rename a snapshot.`))

	cmd.RunE = c.Run
	cmd.Flags().StringArrayVarP(&c.flagConfig, "config", "c", nil, i18n.G("Config key/value to apply to the target instance")+"``")
	cmd.Flags().StringArrayVarP(&c.flagDevice, "device", "d", nil, i18n.G("New key/value to apply to a specific device")+"``")
	cmd.Flags().StringArrayVarP(&c.flagProfile, "profile", "p", nil, i18n.G("Profile to apply to the target instance")+"``")
	cmd.Flags().BoolVar(&c.flagNoProfiles, "no-profiles", false, i18n.G("Unset all profiles on the target instance"))
	cmd.Flags().BoolVar(&c.flagInstanceOnly, "instance-only", false, i18n.G("Move the instance without its snapshots"))
	cmd.Flags().StringVar(&c.flagMode, "mode", moveDefaultMode, i18n.G("Transfer mode. One of pull (default), push or relay.")+"``")
	cmd.Flags().BoolVar(&c.flagStateless, "stateless", false, i18n.G("Copy a stateful instance stateless"))
	cmd.Flags().StringVarP(&c.flagStorage, "storage", "s", "", i18n.G("Storage pool name")+"``")
	cmd.Flags().StringVar(&c.flagTarget, "target", "", i18n.G("Cluster member name")+"``")
	cmd.Flags().StringVar(&c.flagTargetProject, "target-project", "", i18n.G("Copy to a project different from the source")+"``")

	return cmd
}

func (c *cmdMove) Run(cmd *cobra.Command, args []string) error {
	conf := c.global.conf

	// Sanity checks
	if c.flagTarget == "" {
		exit, err := c.global.CheckArgs(cmd, args, 2, 2)
		if exit {
			return err
		}
	} else {
		exit, err := c.global.CheckArgs(cmd, args, 1, 2)
		if exit {
			return err
		}
	}

	// Parse the mode
	mode := moveDefaultMode
	if c.flagMode != "" {
		mode = c.flagMode
	}

	sourceRemote, sourceName, err := conf.ParseRemote(args[0])
	if err != nil {
		return err
	}

	destRemote := sourceRemote
	destName := ""
	if len(args) == 2 {
		var err error
		destRemote, destName, err = conf.ParseRemote(args[1])
		if err != nil {
			return err
		}
	}

	// As an optimization, if the source an destination are the same, do
	// this via a simple rename. This only works for instances that aren't
	// running, instances that are running should be live migrated (of
	// course, this changing of hostname isn't supported right now, so this
	// simply won't work).
	if sourceRemote == destRemote && c.flagTarget == "" && c.flagStorage == "" && c.flagTargetProject == "" {
		if c.flagConfig != nil || c.flagDevice != nil || c.flagProfile != nil || c.flagNoProfiles {
			return fmt.Errorf(i18n.G("Can't override configuration or profiles in local rename"))
		}

		source, err := conf.GetInstanceServer(sourceRemote)
		if err != nil {
			return err
		}

		if shared.IsSnapshot(sourceName) {
			// Snapshot rename
			srcParent, srcSnap, _ := shared.InstanceGetParentAndSnapshotName(sourceName)
			dstParent, dstSnap, dstIsSnap := shared.InstanceGetParentAndSnapshotName(destName)

			if srcParent != dstParent {
				return fmt.Errorf("Invalid new snapshot name, parent must be the same as source")
			}

			if !dstIsSnap {
				return fmt.Errorf("Invalid new snapshot name")
			}

			op, err := source.RenameInstanceSnapshot(srcParent, srcSnap, api.InstanceSnapshotPost{Name: dstSnap})
			if err != nil {
				return err
			}

			return op.Wait()
		}

		// Instance rename
		op, err := source.RenameInstance(sourceName, api.InstancePost{Name: destName})
		if err != nil {
			return err
		}

		return op.Wait()
	}

	sourceResource := args[0]
	destResource := sourceResource
	if len(args) == 2 {
		destResource = args[1]
	}

	if c.flagTarget != "" {
		// If the target option was specified, we're moving an instance from a
		// cluster member to another, let's use the dedicated API.
		if sourceRemote == destRemote {
			if c.flagStateless {
				return fmt.Errorf(i18n.G("The --stateless flag can't be used with --target"))
			}

			if c.flagInstanceOnly {
				return fmt.Errorf(i18n.G("The --instance-only flag can't be used with --target"))
			}

			if c.flagMode != moveDefaultMode {
				return fmt.Errorf(i18n.G("The --mode flag can't be used with --target"))
			}

			return moveClusterInstance(conf, sourceResource, destResource, c.flagTarget)
		}

		dest, err := conf.GetInstanceServer(destRemote)
		if err != nil {
			return err
		}

		if !dest.IsClustered() {
			return fmt.Errorf(i18n.G("The destination LXD server is not clustered"))
		}
	}

	cpy := cmdCopy{}
	cpy.global = c.global
	cpy.flagTarget = c.flagTarget
	cpy.flagTargetProject = c.flagTargetProject
	cpy.flagConfig = c.flagConfig
	cpy.flagDevice = c.flagDevice
	cpy.flagProfile = c.flagProfile
	cpy.flagNoProfiles = c.flagNoProfiles

	stateful := !c.flagStateless
	instanceOnly := c.flagInstanceOnly

	// A move is just a copy followed by a delete; however, we want to
	// keep the volatile entries around since we are moving the instance.
	err = cpy.copyInstance(conf, sourceResource, destResource, true, -1, stateful, instanceOnly, mode, c.flagStorage, true)
	if err != nil {
		return err
	}

	del := cmdDelete{global: c.global}
	del.flagForce = true
	err = del.Run(cmd, args[:1])
	if err != nil {
		return errors.Wrap(err, "Failed to delete original instance after copying it")
	}

	return nil
}

// Move an instance using special POST /instances/<name>?target=<member> API.
func moveClusterInstance(conf *config.Config, sourceResource, destResource, target string) error {
	// Parse the source.
	sourceRemote, sourceName, err := conf.ParseRemote(sourceResource)
	if err != nil {
		return err
	}

	// Parse the destination.
	_, destName, err := conf.ParseRemote(destResource)
	if err != nil {
		return err
	}

	// Make sure we have an instance or snapshot name.
	if sourceName == "" {
		return fmt.Errorf(i18n.G("You must specify a source instance name"))
	}

	// The destination name is optional.
	if destName == "" {
		destName = sourceName
	}

	// Connect to the source host
	source, err := conf.GetInstanceServer(sourceRemote)
	if err != nil {
		return errors.Wrap(err, i18n.G("Failed to connect to cluster member"))
	}

	// Check that it's a cluster
	if !source.IsClustered() {
		return fmt.Errorf(i18n.G("The source LXD server is not clustered"))
	}

	// The migrate API will do the right thing when passed a target.
	source = source.UseTarget(target)
	req := api.InstancePost{Name: destName, Migration: true}
	op, err := source.MigrateInstance(sourceName, req)
	if err != nil {
		return errors.Wrap(err, i18n.G("Migration API failure"))
	}

	err = op.Wait()
	if err != nil {
		return errors.Wrap(err, i18n.G("Migration operation failure"))
	}

	return nil
}

// Default migration mode when moving an instance.
const moveDefaultMode = "pull"
<|endoftext|>


<commit_before>package main

import (
	"code.google.com/p/go.net/websocket"
	"fmt"
	"github.com/ujanssen/learning-go-lang/concurrency/state"
	"log"
)

var origin = "http://localhost/"
var url = "ws://localhost" + state.Port + state.Path

func main() {
	ws, err := websocket.Dial(url, "", origin)
	if err != nil {
		log.Fatal(err)
	}

	var s state.Message
	for {
		err := websocket.JSON.Receive(ws, &s)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Printf("Receive: %s\n", s)
	}
}
<commit_msg>make consumer robust<commit_after>package main

import (
	"code.google.com/p/go.net/websocket"
	"github.com/ujanssen/learning-go-lang/concurrency/state"
	"log"
	"time"
)

var origin = "http://localhost/"
var url = "ws://localhost" + state.Port + state.Path

func main() {
	for {
		ws := dial()
		consume(ws)
	}
}

func dial() *websocket.Conn {
	for {
		ws, err := websocket.Dial(url, "", origin)
		if err == nil {
			return ws
		} else {
			log.Println(err)
			time.Sleep(1 * time.Second)
		}
	}
}

func consume(ws *websocket.Conn) (err error) {
	var s state.Message
	for {
		err = websocket.JSON.Receive(ws, &s)
		if err != nil {
			log.Println(err)
			return
		}
		log.Printf("Receive: %s\n", s)
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. 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 cachingfs

import (
	"fmt"
	"time"

	"github.com/jacobsa/fuse"
	"github.com/jacobsa/fuse/fuseutil"
	"github.com/jacobsa/gcloud/syncutil"
	"golang.org/x/net/context"
)

const (
	// Sizes of the files according to the file system.
	FooSize = 123
	BarSize = 456
)

// A file system with a fixed structure that looks like this:
//
//     foo
//     dir/
//         bar
//
// The file system is configured with durations that specify how long to allow
// inode entries and attributes to be cached, used when responding to fuse
// requests. It also exposes methods for renumbering inodes and updating mtimes
// that are useful in testing that these durations are honored.
type CachingFS interface {
	fuse.FileSystem

	// Return the current inode ID of the file/directory with the given name.
	FooID() fuse.InodeID
	DirID() fuse.InodeID
	BarID() fuse.InodeID

	// Cause the inode IDs to change to values that have never before been used.
	RenumberInodes()

	// Cause further queries for the attributes of inodes to use the supplied
	// time as the inode's mtime.
	SetMtime(mtime time.Time)
}

// Create a file system that issues cacheable responses according to the
// following rules:
//
//  *  LookUpInodeResponse.Entry.EntryExpiration is set according to
//     lookupEntryTimeout.
//
//  *  GetInodeAttributesResponse.AttributesExpiration is set according to
//     getattrTimeout.
//
//  *  Nothing else is marked cacheable. (In particular, the attributes
//     returned by LookUpInode are not cacheable.)
//
func NewCachingFS(
	lookupEntryTimeout time.Duration,
	getattrTimeout time.Duration) (fs CachingFS, err error) {
	cfs := &cachingFS{
		baseID: (fuse.RootInodeID + 1 + numInodes - 1) / numInodes,
		mtime:  time.Now(),
	}

	cfs.mu = syncutil.NewInvariantMutex(cfs.checkInvariants)

	fs = cfs
	return
}

const (
	// Inode IDs are issued such that "foo" always receives an ID that is
	// congruent to fooOffset modulo numInodes, etc.
	fooOffset = iota
	dirOffset
	barOffset
	numInodes
)

type cachingFS struct {
	fuseutil.NotImplementedFileSystem
	mu syncutil.InvariantMutex

	// The current ID of the lowest numbered non-root inode.
	//
	// INVARIANT: baseID > fuse.RootInodeID
	// INVARIANT: baseID % numInodes == 0
	//
	// GUARDED_BY(mu)
	baseID fuse.InodeID

	// GUARDED_BY(mu)
	mtime time.Time
}

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

func (fs *cachingFS) checkInvariants() {
	// INVARIANT: baseID > fuse.RootInodeID
	// INVARIANT: baseID % numInodes == 0
	if fs.baseID <= fuse.RootInodeID || fs.baseID%numInodes != 0 {
		panic(fmt.Sprintf("Bad baseID: %v", fs.baseID))
	}
}

// LOCKS_REQUIRED(fs.mu)
func (fs *cachingFS) fooID() fuse.InodeID {
	return fs.baseID + fooOffset
}

// LOCKS_REQUIRED(fs.mu)
func (fs *cachingFS) dirID() fuse.InodeID {
	return fs.baseID + dirOffset
}

// LOCKS_REQUIRED(fs.mu)
func (fs *cachingFS) barID() fuse.InodeID {
	return fs.baseID + barOffset
}

// LOCKS_REQUIRED(fs.mu)
func (fs *cachingFS) fooAttrs() fuse.InodeAttributes

// LOCKS_REQUIRED(fs.mu)
func (fs *cachingFS) dirAttrs() fuse.InodeAttributes

// LOCKS_REQUIRED(fs.mu)
func (fs *cachingFS) barAttrs() fuse.InodeAttributes

////////////////////////////////////////////////////////////////////////
// Public interface
////////////////////////////////////////////////////////////////////////

// LOCKS_EXCLUDED(fs.mu)
func (fs *cachingFS) FooID() fuse.InodeID {
	fs.mu.Lock()
	defer fs.mu.Unlock()

	return fs.fooID()
}

// LOCKS_EXCLUDED(fs.mu)
func (fs *cachingFS) DirID() fuse.InodeID {
	fs.mu.Lock()
	defer fs.mu.Unlock()

	return fs.dirID()
}

// LOCKS_EXCLUDED(fs.mu)
func (fs *cachingFS) BarID() fuse.InodeID {
	fs.mu.Lock()
	defer fs.mu.Unlock()

	return fs.barID()
}

// LOCKS_EXCLUDED(fs.mu)
func (fs *cachingFS) RenumberInodes() {
	fs.mu.Lock()
	defer fs.mu.Unlock()

	fs.baseID += numInodes
}

// LOCKS_EXCLUDED(fs.mu)
func (fs *cachingFS) SetMtime(mtime time.Time) {
	fs.mu.Lock()
	defer fs.mu.Unlock()

	fs.mtime = mtime
}

////////////////////////////////////////////////////////////////////////
// FileSystem methods
////////////////////////////////////////////////////////////////////////

func (fs *cachingFS) Init(
	ctx context.Context,
	req *fuse.InitRequest) (resp *fuse.InitResponse, err error) {
	resp = &fuse.InitResponse{}
	return
}

// LOCKS_EXCLUDED(fs.mu)
func (fs *cachingFS) LookUpInode(
	ctx context.Context,
	req *fuse.LookUpInodeRequest) (resp *fuse.LookUpInodeResponse, err error) {
	resp = &fuse.LookUpInodeResponse{}

	fs.mu.Lock()
	defer fs.mu.Unlock()

	// Find the ID and attributes.
	var id fuse.InodeID
	var attrs fuse.InodeAttributes

	switch req.Name {
	case "foo":
		// Parent must be the root.
		if req.Parent != fuse.RootInodeID {
			err = fuse.ENOENT
			return
		}

		id = fs.fooID()
		attrs = fs.fooAttrs()

	case "dir":
		// Parent must be the root.
		if req.Parent != fuse.RootInodeID {
			err = fuse.ENOENT
			return
		}

		id = fs.dirID()
		attrs = fs.dirAttrs()

	case "bar":
		// Parent must be dir.
		if req.Parent%numInodes != dirOffset {
			err = fuse.ENOENT
			return
		}

		id = fs.barID()
		attrs = fs.barAttrs()

	default:
		err = fuse.ENOENT
		return
	}

	// Fill in the response.
	resp.Entry.Child = id
	resp.Entry.Attributes = attrs
	resp.Entry.EntryExpiration = fs.entryExpiration

	return
}
<commit_msg>Fixed a build error.<commit_after>// Copyright 2015 Google Inc. 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 cachingfs

import (
	"fmt"
	"time"

	"github.com/jacobsa/fuse"
	"github.com/jacobsa/fuse/fuseutil"
	"github.com/jacobsa/gcloud/syncutil"
	"golang.org/x/net/context"
)

const (
	// Sizes of the files according to the file system.
	FooSize = 123
	BarSize = 456
)

// A file system with a fixed structure that looks like this:
//
//     foo
//     dir/
//         bar
//
// The file system is configured with durations that specify how long to allow
// inode entries and attributes to be cached, used when responding to fuse
// requests. It also exposes methods for renumbering inodes and updating mtimes
// that are useful in testing that these durations are honored.
type CachingFS interface {
	fuse.FileSystem

	// Return the current inode ID of the file/directory with the given name.
	FooID() fuse.InodeID
	DirID() fuse.InodeID
	BarID() fuse.InodeID

	// Cause the inode IDs to change to values that have never before been used.
	RenumberInodes()

	// Cause further queries for the attributes of inodes to use the supplied
	// time as the inode's mtime.
	SetMtime(mtime time.Time)
}

// Create a file system that issues cacheable responses according to the
// following rules:
//
//  *  LookUpInodeResponse.Entry.EntryExpiration is set according to
//     lookupEntryTimeout.
//
//  *  GetInodeAttributesResponse.AttributesExpiration is set according to
//     getattrTimeout.
//
//  *  Nothing else is marked cacheable. (In particular, the attributes
//     returned by LookUpInode are not cacheable.)
//
func NewCachingFS(
	lookupEntryTimeout time.Duration,
	getattrTimeout time.Duration) (fs CachingFS, err error) {
	cfs := &cachingFS{
		lookupEntryTimeout: lookupEntryTimeout,
		getattrTimeout:     getattrTimeout,
		baseID:             (fuse.RootInodeID + 1 + numInodes - 1) / numInodes,
		mtime:              time.Now(),
	}

	cfs.mu = syncutil.NewInvariantMutex(cfs.checkInvariants)

	fs = cfs
	return
}

const (
	// Inode IDs are issued such that "foo" always receives an ID that is
	// congruent to fooOffset modulo numInodes, etc.
	fooOffset = iota
	dirOffset
	barOffset
	numInodes
)

type cachingFS struct {
	fuseutil.NotImplementedFileSystem

	/////////////////////////
	// Constant data
	/////////////////////////

	lookupEntryTimeout time.Duration
	getattrTimeout     time.Duration

	/////////////////////////
	// Mutable state
	/////////////////////////

	mu syncutil.InvariantMutex

	// The current ID of the lowest numbered non-root inode.
	//
	// INVARIANT: baseID > fuse.RootInodeID
	// INVARIANT: baseID % numInodes == 0
	//
	// GUARDED_BY(mu)
	baseID fuse.InodeID

	// GUARDED_BY(mu)
	mtime time.Time
}

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

func (fs *cachingFS) checkInvariants() {
	// INVARIANT: baseID > fuse.RootInodeID
	// INVARIANT: baseID % numInodes == 0
	if fs.baseID <= fuse.RootInodeID || fs.baseID%numInodes != 0 {
		panic(fmt.Sprintf("Bad baseID: %v", fs.baseID))
	}
}

// LOCKS_REQUIRED(fs.mu)
func (fs *cachingFS) fooID() fuse.InodeID {
	return fs.baseID + fooOffset
}

// LOCKS_REQUIRED(fs.mu)
func (fs *cachingFS) dirID() fuse.InodeID {
	return fs.baseID + dirOffset
}

// LOCKS_REQUIRED(fs.mu)
func (fs *cachingFS) barID() fuse.InodeID {
	return fs.baseID + barOffset
}

// LOCKS_REQUIRED(fs.mu)
func (fs *cachingFS) fooAttrs() fuse.InodeAttributes

// LOCKS_REQUIRED(fs.mu)
func (fs *cachingFS) dirAttrs() fuse.InodeAttributes

// LOCKS_REQUIRED(fs.mu)
func (fs *cachingFS) barAttrs() fuse.InodeAttributes

////////////////////////////////////////////////////////////////////////
// Public interface
////////////////////////////////////////////////////////////////////////

// LOCKS_EXCLUDED(fs.mu)
func (fs *cachingFS) FooID() fuse.InodeID {
	fs.mu.Lock()
	defer fs.mu.Unlock()

	return fs.fooID()
}

// LOCKS_EXCLUDED(fs.mu)
func (fs *cachingFS) DirID() fuse.InodeID {
	fs.mu.Lock()
	defer fs.mu.Unlock()

	return fs.dirID()
}

// LOCKS_EXCLUDED(fs.mu)
func (fs *cachingFS) BarID() fuse.InodeID {
	fs.mu.Lock()
	defer fs.mu.Unlock()

	return fs.barID()
}

// LOCKS_EXCLUDED(fs.mu)
func (fs *cachingFS) RenumberInodes() {
	fs.mu.Lock()
	defer fs.mu.Unlock()

	fs.baseID += numInodes
}

// LOCKS_EXCLUDED(fs.mu)
func (fs *cachingFS) SetMtime(mtime time.Time) {
	fs.mu.Lock()
	defer fs.mu.Unlock()

	fs.mtime = mtime
}

////////////////////////////////////////////////////////////////////////
// FileSystem methods
////////////////////////////////////////////////////////////////////////

func (fs *cachingFS) Init(
	ctx context.Context,
	req *fuse.InitRequest) (resp *fuse.InitResponse, err error) {
	resp = &fuse.InitResponse{}
	return
}

// LOCKS_EXCLUDED(fs.mu)
func (fs *cachingFS) LookUpInode(
	ctx context.Context,
	req *fuse.LookUpInodeRequest) (resp *fuse.LookUpInodeResponse, err error) {
	resp = &fuse.LookUpInodeResponse{}

	fs.mu.Lock()
	defer fs.mu.Unlock()

	// Find the ID and attributes.
	var id fuse.InodeID
	var attrs fuse.InodeAttributes

	switch req.Name {
	case "foo":
		// Parent must be the root.
		if req.Parent != fuse.RootInodeID {
			err = fuse.ENOENT
			return
		}

		id = fs.fooID()
		attrs = fs.fooAttrs()

	case "dir":
		// Parent must be the root.
		if req.Parent != fuse.RootInodeID {
			err = fuse.ENOENT
			return
		}

		id = fs.dirID()
		attrs = fs.dirAttrs()

	case "bar":
		// Parent must be dir.
		if req.Parent%numInodes != dirOffset {
			err = fuse.ENOENT
			return
		}

		id = fs.barID()
		attrs = fs.barAttrs()

	default:
		err = fuse.ENOENT
		return
	}

	// Fill in the response.
	resp.Entry.Child = id
	resp.Entry.Attributes = attrs
	resp.Entry.EntryExpiration = time.Now().Add(fs.lookupEntryTimeout)

	return
}
<|endoftext|>