func (s *StateStore) CheckServiceTagNodes(service, tag string) (uint64, structs.CheckServiceNodes) {
	tables := s.queryTables["CheckServiceNodes"]
	tx, err := tables.StartTxn(true)
	if err != nil {
		panic(fmt.Errorf("Failed to start txn: %v", err))
	}
	defer tx.Abort()
	idx, err := tables.LastIndexTxn(tx)
	if err != nil {
		panic(fmt.Errorf("Failed to get last index: %v", err))
	}
	res, err := s.serviceTable.GetTxn(tx, "service", service)
	res = serviceTagFilter(res, tag)
	return idx, s.parseCheckServiceNodes(tx, res, err)
}
CheckServiceNodes returns the nodes associated with a given service, along
with any associated checks
package consul
import (
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"runtime"
	"strings"
	"sync"
	"time"
	"github.com/socketplane/socketplane/Godeps/_workspace/src/github.com/armon/go-radix"
	"github.com/socketplane/socketplane/Godeps/_workspace/src/github.com/armon/gomdb"
	"github.com/socketplane/socketplane/Godeps/_workspace/src/github.com/hashicorp/consul/consul/structs"
)
const (
	dbNodes                  = "nodes"
	dbServices               = "services"
	dbChecks                 = "checks"
	dbKVS                    = "kvs"
	dbTombstone              = "tombstones"
	dbSessions               = "sessions"
	dbSessionChecks          = "sessionChecks"
	dbACLs                   = "acls"
	dbMaxMapSize32bit uint64 = 128 * 1024 * 1024        
	dbMaxMapSize64bit uint64 = 32 * 1024 * 1024 * 1024  
	dbMaxReaders      uint   = 4096                     
)
type kvMode int
const (
	kvSet kvMode = iota
	kvCAS
	kvLock
	kvUnlock
)
type StateStore struct {
	logger            *log.Logger
	path              string
	env               *mdb.Env
	nodeTable         *MDBTable
	serviceTable      *MDBTable
	checkTable        *MDBTable
	kvsTable          *MDBTable
	tombstoneTable    *MDBTable
	sessionTable      *MDBTable
	sessionCheckTable *MDBTable
	aclTable          *MDBTable
	tables            MDBTables
	watch             map[*MDBTable]*NotifyGroup
	queryTables       map[string]MDBTables
	kvWatch     *radix.Tree
	kvWatchLock sync.Mutex
	lockDelay     map[string]time.Time
	lockDelayLock sync.RWMutex
	gc *TombstoneGC
}
type StateSnapshot struct {
	store     *StateStore
	tx        *MDBTxn
	lastIndex uint64
}
type sessionCheck struct {
	Node    string
	CheckID string
	Session string
}
func (s *StateSnapshot) Close() error {
	s.tx.Abort()
	return nil
}
func NewStateStore(gc *TombstoneGC, logOutput io.Writer) (*StateStore, error) {
	path, err := ioutil.TempDir("", "consul")
	if err != nil {
		return nil, err
	}
	return NewStateStorePath(gc, path, logOutput)
}
func NewStateStorePath(gc *TombstoneGC, path string, logOutput io.Writer) (*StateStore, error) {
	env, err := mdb.NewEnv()
	if err != nil {
		return nil, err
	}
	s := &StateStore{
		logger:    log.New(logOutput, "", log.LstdFlags),
		path:      path,
		env:       env,
		watch:     make(map[*MDBTable]*NotifyGroup),
		kvWatch:   radix.New(),
		lockDelay: make(map[string]time.Time),
		gc:        gc,
	}
	if err := s.initialize(); err != nil {
		env.Close()
		os.RemoveAll(path)
		return nil, err
	}
	return s, nil
}
func (s *StateStore) Close() error {
	s.env.Close()
	os.RemoveAll(s.path)
	return nil
}
func (s *StateStore) initialize() error {
	if err := s.env.SetMaxDBs(mdb.DBI(32)); err != nil {
		return err
	}
	dbSize := dbMaxMapSize32bit
	if runtime.GOARCH == "amd64" {
		dbSize = dbMaxMapSize64bit
	}
	if err := s.env.SetMapSize(dbSize); err != nil {
		return err
	}
	if err := s.env.SetMaxReaders(dbMaxReaders); err != nil {
		return err
	}
	var flags uint = mdb.NOMETASYNC | mdb.NOSYNC | mdb.NOTLS
	if err := s.env.Open(s.path, flags, 0755); err != nil {
		return err
	}
	encoder := func(obj interface{}) []byte {
		buf, err := structs.Encode(255, obj)
		if err != nil {
			panic(err)
		}
		return buf[1:]
	}
	s.nodeTable = &MDBTable{
		Name: dbNodes,
		Indexes: map[string]*MDBIndex{
			"id": &MDBIndex{
				Unique:          true,
				Fields:          []string{"Node"},
				CaseInsensitive: true,
			},
		},
		Decoder: func(buf []byte) interface{} {
			out := new(structs.Node)
			if err := structs.Decode(buf, out); err != nil {
				panic(err)
			}
			return out
		},
	}
	s.serviceTable = &MDBTable{
		Name: dbServices,
		Indexes: map[string]*MDBIndex{
			"id": &MDBIndex{
				Unique: true,
				Fields: []string{"Node", "ServiceID"},
			},
			"service": &MDBIndex{
				AllowBlank:      true,
				Fields:          []string{"ServiceName"},
				CaseInsensitive: true,
			},
		},
		Decoder: func(buf []byte) interface{} {
			out := new(structs.ServiceNode)
			if err := structs.Decode(buf, out); err != nil {
				panic(err)
			}
			return out
		},
	}
	s.checkTable = &MDBTable{
		Name: dbChecks,
		Indexes: map[string]*MDBIndex{
			"id": &MDBIndex{
				Unique: true,
				Fields: []string{"Node", "CheckID"},
			},
			"status": &MDBIndex{
				Fields: []string{"Status"},
			},
			"service": &MDBIndex{
				AllowBlank: true,
				Fields:     []string{"ServiceName"},
			},
			"node": &MDBIndex{
				AllowBlank: true,
				Fields:     []string{"Node", "ServiceID"},
			},
		},
		Decoder: func(buf []byte) interface{} {
			out := new(structs.HealthCheck)
			if err := structs.Decode(buf, out); err != nil {
				panic(err)
			}
			return out
		},
	}
	s.kvsTable = &MDBTable{
		Name: dbKVS,
		Indexes: map[string]*MDBIndex{
			"id": &MDBIndex{
				Unique: true,
				Fields: []string{"Key"},
			},
			"id_prefix": &MDBIndex{
				Virtual:   true,
				RealIndex: "id",
				Fields:    []string{"Key"},
				IdxFunc:   DefaultIndexPrefixFunc,
			},
			"session": &MDBIndex{
				AllowBlank: true,
				Fields:     []string{"Session"},
			},
		},
		Decoder: func(buf []byte) interface{} {
			out := new(structs.DirEntry)
			if err := structs.Decode(buf, out); err != nil {
				panic(err)
			}
			return out
		},
	}
	s.tombstoneTable = &MDBTable{
		Name: dbTombstone,
		Indexes: map[string]*MDBIndex{
			"id": &MDBIndex{
				Unique: true,
				Fields: []string{"Key"},
			},
			"id_prefix": &MDBIndex{
				Virtual:   true,
				RealIndex: "id",
				Fields:    []string{"Key"},
				IdxFunc:   DefaultIndexPrefixFunc,
			},
		},
		Decoder: func(buf []byte) interface{} {
			out := new(structs.DirEntry)
			if err := structs.Decode(buf, out); err != nil {
				panic(err)
			}
			return out
		},
	}
	s.sessionTable = &MDBTable{
		Name: dbSessions,
		Indexes: map[string]*MDBIndex{
			"id": &MDBIndex{
				Unique: true,
				Fields: []string{"ID"},
			},
			"node": &MDBIndex{
				AllowBlank: true,
				Fields:     []string{"Node"},
			},
		},
		Decoder: func(buf []byte) interface{} {
			out := new(structs.Session)
			if err := structs.Decode(buf, out); err != nil {
				panic(err)
			}
			return out
		},
	}
	s.sessionCheckTable = &MDBTable{
		Name: dbSessionChecks,
		Indexes: map[string]*MDBIndex{
			"id": &MDBIndex{
				Unique: true,
				Fields: []string{"Node", "CheckID", "Session"},
			},
		},
		Decoder: func(buf []byte) interface{} {
			out := new(sessionCheck)
			if err := structs.Decode(buf, out); err != nil {
				panic(err)
			}
			return out
		},
	}
	s.aclTable = &MDBTable{
		Name: dbACLs,
		Indexes: map[string]*MDBIndex{
			"id": &MDBIndex{
				Unique: true,
				Fields: []string{"ID"},
			},
		},
		Decoder: func(buf []byte) interface{} {
			out := new(structs.ACL)
			if err := structs.Decode(buf, out); err != nil {
				panic(err)
			}
			return out
		},
	}
	s.tables = []*MDBTable{s.nodeTable, s.serviceTable, s.checkTable,
		s.kvsTable, s.tombstoneTable, s.sessionTable, s.sessionCheckTable,
		s.aclTable}
	for _, table := range s.tables {
		table.Env = s.env
		table.Encoder = encoder
		if err := table.Init(); err != nil {
			return err
		}
		s.watch[table] = &NotifyGroup{}
	}
	s.queryTables = map[string]MDBTables{
		"Nodes":             MDBTables{s.nodeTable},
		"Services":          MDBTables{s.serviceTable},
		"ServiceNodes":      MDBTables{s.nodeTable, s.serviceTable},
		"NodeServices":      MDBTables{s.nodeTable, s.serviceTable},
		"ChecksInState":     MDBTables{s.checkTable},
		"NodeChecks":        MDBTables{s.checkTable},
		"ServiceChecks":     MDBTables{s.checkTable},
		"CheckServiceNodes": MDBTables{s.nodeTable, s.serviceTable, s.checkTable},
		"NodeInfo":          MDBTables{s.nodeTable, s.serviceTable, s.checkTable},
		"NodeDump":          MDBTables{s.nodeTable, s.serviceTable, s.checkTable},
		"SessionGet":        MDBTables{s.sessionTable},
		"SessionList":       MDBTables{s.sessionTable},
		"NodeSessions":      MDBTables{s.sessionTable},
		"ACLGet":            MDBTables{s.aclTable},
		"ACLList":           MDBTables{s.aclTable},
	}
	return nil
}
func (s *StateStore) Watch(tables MDBTables, notify chan struct{}) {
	for _, t := range tables {
		s.watch[t].Wait(notify)
	}
}
func (s *StateStore) WatchKV(prefix string, notify chan struct{}) {
	s.kvWatchLock.Lock()
	defer s.kvWatchLock.Unlock()
	if raw, ok := s.kvWatch.Get(prefix); ok {
		grp := raw.(*NotifyGroup)
		grp.Wait(notify)
		return
	}
	grp := &NotifyGroup{}
	grp.Wait(notify)
	s.kvWatch.Insert(prefix, grp)
}
func (s *StateStore) notifyKV(path string, prefix bool) {
	s.kvWatchLock.Lock()
	defer s.kvWatchLock.Unlock()
	var toDelete []string
	fn := func(s string, v interface{}) bool {
		group := v.(*NotifyGroup)
		group.Notify()
		if s != "" {
			toDelete = append(toDelete, s)
		}
		return false
	}
	s.kvWatch.WalkPath(path, fn)
	if prefix {
		s.kvWatch.WalkPrefix(path, fn)
	}
	for i := len(toDelete) - 1; i >= 0; i-- {
		s.kvWatch.Delete(toDelete[i])
	}
}
func (s *StateStore) QueryTables(q string) MDBTables {
	return s.queryTables[q]
}
func (s *StateStore) EnsureRegistration(index uint64, req *structs.RegisterRequest) error {
	tx, err := s.tables.StartTxn(false)
	if err != nil {
		panic(fmt.Errorf("Failed to start txn: %v", err))
	}
	defer tx.Abort()
	node := structs.Node{req.Node, req.Address}
	if err := s.ensureNodeTxn(index, node, tx); err != nil {
		return err
	}
	if req.Service != nil {
		if err := s.ensureServiceTxn(index, req.Node, req.Service, tx); err != nil {
			return err
		}
	}
	if req.Check != nil {
		if err := s.ensureCheckTxn(index, req.Check, tx); err != nil {
			return err
		}
	}
	return tx.Commit()
}
func (s *StateStore) EnsureNode(index uint64, node structs.Node) error {
	tx, err := s.nodeTable.StartTxn(false, nil)
	if err != nil {
		return err
	}
	defer tx.Abort()
	if err := s.ensureNodeTxn(index, node, tx); err != nil {
		return err
	}
	return tx.Commit()
}
func (s *StateStore) ensureNodeTxn(index uint64, node structs.Node, tx *MDBTxn) error {
	if err := s.nodeTable.InsertTxn(tx, node); err != nil {
		return err
	}
	if err := s.nodeTable.SetLastIndexTxn(tx, index); err != nil {
		return err
	}
	tx.Defer(func() { s.watch[s.nodeTable].Notify() })
	return nil
}
func (s *StateStore) GetNode(name string) (uint64, bool, string) {
	idx, res, err := s.nodeTable.Get("id", name)
	if err != nil {
		s.logger.Printf("[ERR] consul.state: Error during node lookup: %v", err)
		return 0, false, ""
	}
	if len(res) == 0 {
		return idx, false, ""
	}
	return idx, true, res[0].(*structs.Node).Address
}
func (s *StateStore) Nodes() (uint64, structs.Nodes) {
	idx, res, err := s.nodeTable.Get("id")
	if err != nil {
		s.logger.Printf("[ERR] consul.state: Error getting nodes: %v", err)
	}
	results := make([]structs.Node, len(res))
	for i, r := range res {
		results[i] = *r.(*structs.Node)
	}
	return idx, results
}
func (s *StateStore) EnsureService(index uint64, node string, ns *structs.NodeService) error {
	tx, err := s.tables.StartTxn(false)
	if err != nil {
		panic(fmt.Errorf("Failed to start txn: %v", err))
	}
	defer tx.Abort()
	if err := s.ensureServiceTxn(index, node, ns, tx); err != nil {
		return nil
	}
	return tx.Commit()
}
func (s *StateStore) ensureServiceTxn(index uint64, node string, ns *structs.NodeService, tx *MDBTxn) error {
	res, err := s.nodeTable.GetTxn(tx, "id", node)
	if err != nil {
		return err
	}
	if len(res) == 0 {
		return fmt.Errorf("Missing node registration")
	}
	entry := structs.ServiceNode{
		Node:           node,
		ServiceID:      ns.ID,
		ServiceName:    ns.Service,
		ServiceTags:    ns.Tags,
		ServiceAddress: ns.Address,
		ServicePort:    ns.Port,
	}
	if err := s.serviceTable.InsertTxn(tx, &entry); err != nil {
		return err
	}
	if err := s.serviceTable.SetLastIndexTxn(tx, index); err != nil {
		return err
	}
	tx.Defer(func() { s.watch[s.serviceTable].Notify() })
	return nil
}
func (s *StateStore) NodeServices(name string) (uint64, *structs.NodeServices) {
	tables := s.queryTables["NodeServices"]
	tx, err := tables.StartTxn(true)
	if err != nil {
		panic(fmt.Errorf("Failed to start txn: %v", err))
	}
	defer tx.Abort()
	return s.parseNodeServices(tables, tx, name)
}
func (s *StateStore) parseNodeServices(tables MDBTables, tx *MDBTxn, name string) (uint64, *structs.NodeServices) {
	ns := &structs.NodeServices{
		Services: make(map[string]*structs.NodeService),
	}
	index, err := tables.LastIndexTxn(tx)
	if err != nil {
		panic(fmt.Errorf("Failed to get last index: %v", err))
	}
	res, err := s.nodeTable.GetTxn(tx, "id", name)
	if err != nil {
		s.logger.Printf("[ERR] consul.state: Failed to get node: %v", err)
	}
	if len(res) == 0 {
		return index, nil
	}
	node := res[0].(*structs.Node)
	ns.Node = *node
	res, err = s.serviceTable.GetTxn(tx, "id", name)
	if err != nil {
		s.logger.Printf("[ERR] consul.state: Failed to get node '%s' services: %v", name, err)
	}
	for _, r := range res {
		service := r.(*structs.ServiceNode)
		srv := &structs.NodeService{
			ID:      service.ServiceID,
			Service: service.ServiceName,
			Tags:    service.ServiceTags,
			Address: service.ServiceAddress,
			Port:    service.ServicePort,
		}
		ns.Services[srv.ID] = srv
	}
	return index, ns
}
func (s *StateStore) DeleteNodeService(index uint64, node, id string) error {
	tx, err := s.tables.StartTxn(false)
	if err != nil {
		panic(fmt.Errorf("Failed to start txn: %v", err))
	}
	defer tx.Abort()
	if n, err := s.serviceTable.DeleteTxn(tx, "id", node, id); err != nil {
		return err
	} else if n > 0 {
		if err := s.serviceTable.SetLastIndexTxn(tx, index); err != nil {
			return err
		}
		tx.Defer(func() { s.watch[s.serviceTable].Notify() })
	}
	checks, err := s.checkTable.GetTxn(tx, "node", node, id)
	if err != nil {
		return err
	}
	for _, c := range checks {
		check := c.(*structs.HealthCheck)
		if err := s.invalidateCheck(index, tx, node, check.CheckID); err != nil {
			return err
		}
	}
	if n, err := s.checkTable.DeleteTxn(tx, "node", node, id); err != nil {
		return err
	} else if n > 0 {
		if err := s.checkTable.SetLastIndexTxn(tx, index); err != nil {
			return err
		}
		tx.Defer(func() { s.watch[s.checkTable].Notify() })
	}
	return tx.Commit()
}
func (s *StateStore) DeleteNode(index uint64, node string) error {
	tx, err := s.tables.StartTxn(false)
	if err != nil {
		panic(fmt.Errorf("Failed to start txn: %v", err))
	}
	defer tx.Abort()
	if err := s.invalidateNode(index, tx, node); err != nil {
		return err
	}
	if n, err := s.serviceTable.DeleteTxn(tx, "id", node); err != nil {
		return err
	} else if n > 0 {
		if err := s.serviceTable.SetLastIndexTxn(tx, index); err != nil {
			return err
		}
		tx.Defer(func() { s.watch[s.serviceTable].Notify() })
	}
	if n, err := s.checkTable.DeleteTxn(tx, "id", node); err != nil {
		return err
	} else if n > 0 {
		if err := s.checkTable.SetLastIndexTxn(tx, index); err != nil {
			return err
		}
		tx.Defer(func() { s.watch[s.checkTable].Notify() })
	}
	if n, err := s.nodeTable.DeleteTxn(tx, "id", node); err != nil {
		return err
	} else if n > 0 {
		if err := s.nodeTable.SetLastIndexTxn(tx, index); err != nil {
			return err
		}
		tx.Defer(func() { s.watch[s.nodeTable].Notify() })
	}
	return tx.Commit()
}
func (s *StateStore) Services() (uint64, map[string][]string) {
	services := make(map[string][]string)
	idx, res, err := s.serviceTable.Get("id")
	if err != nil {
		s.logger.Printf("[ERR] consul.state: Failed to get services: %v", err)
		return idx, services
	}
	for _, r := range res {
		srv := r.(*structs.ServiceNode)
		tags, ok := services[srv.ServiceName]
		if !ok {
			services[srv.ServiceName] = make([]string, 0)
		}
		for _, tag := range srv.ServiceTags {
			if !strContains(tags, tag) {
				tags = append(tags, tag)
				services[srv.ServiceName] = tags
			}
		}
	}
	return idx, services
}
func (s *StateStore) ServiceNodes(service string) (uint64, structs.ServiceNodes) {
	tables := s.queryTables["ServiceNodes"]
	tx, err := tables.StartTxn(true)
	if err != nil {
		panic(fmt.Errorf("Failed to start txn: %v", err))
	}
	defer tx.Abort()
	idx, err := tables.LastIndexTxn(tx)
	if err != nil {
		panic(fmt.Errorf("Failed to get last index: %v", err))
	}
	res, err := s.serviceTable.GetTxn(tx, "service", service)
	return idx, s.parseServiceNodes(tx, s.nodeTable, res, err)
}
func (s *StateStore) ServiceTagNodes(service, tag string) (uint64, structs.ServiceNodes) {
	tables := s.queryTables["ServiceNodes"]
	tx, err := tables.StartTxn(true)
	if err != nil {
		panic(fmt.Errorf("Failed to start txn: %v", err))
	}
	defer tx.Abort()
	idx, err := tables.LastIndexTxn(tx)
	if err != nil {
		panic(fmt.Errorf("Failed to get last index: %v", err))
	}
	res, err := s.serviceTable.GetTxn(tx, "service", service)
	res = serviceTagFilter(res, tag)
	return idx, s.parseServiceNodes(tx, s.nodeTable, res, err)
}
func serviceTagFilter(l []interface{}, tag string) []interface{} {
	n := len(l)
	for i := 0; i < n; i++ {
		srv := l[i].(*structs.ServiceNode)
		if !strContains(ToLowerList(srv.ServiceTags), strings.ToLower(tag)) {
			l[i], l[n-1] = l[n-1], nil
			i--
			n--
		}
	}
	return l[:n]
}
func (s *StateStore) parseServiceNodes(tx *MDBTxn, table *MDBTable, res []interface{}, err error) structs.ServiceNodes {
	nodes := make(structs.ServiceNodes, len(res))
	if err != nil {
		s.logger.Printf("[ERR] consul.state: Failed to get service nodes: %v", err)
		return nodes
	}
	for i, r := range res {
		srv := r.(*structs.ServiceNode)
		nodeRes, err := table.GetTxn(tx, "id", srv.Node)
		if err != nil || len(nodeRes) != 1 {
			s.logger.Printf("[ERR] consul.state: Failed to join service node %#v with node: %v", *srv, err)
			continue
		}
		srv.Address = nodeRes[0].(*structs.Node).Address
		nodes[i] = *srv
	}
	return nodes
}
func (s *StateStore) EnsureCheck(index uint64, check *structs.HealthCheck) error {
	tx, err := s.tables.StartTxn(false)
	if err != nil {
		panic(fmt.Errorf("Failed to start txn: %v", err))
	}
	defer tx.Abort()
	if err := s.ensureCheckTxn(index, check, tx); err != nil {
		return err
	}
	return tx.Commit()
}
func (s *StateStore) ensureCheckTxn(index uint64, check *structs.HealthCheck, tx *MDBTxn) error {
	if check.Status == "" {
		check.Status = structs.HealthCritical
	}
	res, err := s.nodeTable.GetTxn(tx, "id", check.Node)
	if err != nil {
		return err
	}
	if len(res) == 0 {
		return fmt.Errorf("Missing node registration")
	}
	if check.ServiceID != "" {
		res, err = s.serviceTable.GetTxn(tx, "id", check.Node, check.ServiceID)
		if err != nil {
			return err
		}
		if len(res) == 0 {
			return fmt.Errorf("Missing service registration")
		}
		srv := res[0].(*structs.ServiceNode)
		check.ServiceName = srv.ServiceName
	}
	if check.Status == structs.HealthCritical {
		err := s.invalidateCheck(index, tx, check.Node, check.CheckID)
		if err != nil {
			return err
		}
	}
	if err := s.checkTable.InsertTxn(tx, check); err != nil {
		return err
	}
	if err := s.checkTable.SetLastIndexTxn(tx, index); err != nil {
		return err
	}
	tx.Defer(func() { s.watch[s.checkTable].Notify() })
	return nil
}
func (s *StateStore) DeleteNodeCheck(index uint64, node, id string) error {
	tx, err := s.tables.StartTxn(false)
	if err != nil {
		return err
	}
	defer tx.Abort()
	if err := s.invalidateCheck(index, tx, node, id); err != nil {
		return err
	}
	if n, err := s.checkTable.DeleteTxn(tx, "id", node, id); err != nil {
		return err
	} else if n > 0 {
		if err := s.checkTable.SetLastIndexTxn(tx, index); err != nil {
			return err
		}
		tx.Defer(func() { s.watch[s.checkTable].Notify() })
	}
	return tx.Commit()
}
func (s *StateStore) NodeChecks(node string) (uint64, structs.HealthChecks) {
	return s.parseHealthChecks(s.checkTable.Get("id", node))
}
func (s *StateStore) ServiceChecks(service string) (uint64, structs.HealthChecks) {
	return s.parseHealthChecks(s.checkTable.Get("service", service))
}
func (s *StateStore) ChecksInState(state string) (uint64, structs.HealthChecks) {
	var idx uint64
	var res []interface{}
	var err error
	if state == structs.HealthAny {
		idx, res, err = s.checkTable.Get("id")
	} else {
		idx, res, err = s.checkTable.Get("status", state)
	}
	return s.parseHealthChecks(idx, res, err)
}
func (s *StateStore) parseHealthChecks(idx uint64, res []interface{}, err error) (uint64, structs.HealthChecks) {
	results := make([]*structs.HealthCheck, len(res))
	if err != nil {
		s.logger.Printf("[ERR] consul.state: Failed to get health checks: %v", err)
		return idx, results
	}
	for i, r := range res {
		results[i] = r.(*structs.HealthCheck)
	}
	return idx, results
}
func (s *StateStore) CheckServiceNodes(service string) (uint64, structs.CheckServiceNodes) {
	tables := s.queryTables["CheckServiceNodes"]
	tx, err := tables.StartTxn(true)
	if err != nil {
		panic(fmt.Errorf("Failed to start txn: %v", err))
	}
	defer tx.Abort()
	idx, err := tables.LastIndexTxn(tx)
	if err != nil {
		panic(fmt.Errorf("Failed to get last index: %v", err))
	}
	res, err := s.serviceTable.GetTxn(tx, "service", service)
	return idx, s.parseCheckServiceNodes(tx, res, err)
}