func (s *StateStore) Watch(tables MDBTables, notify chan struct{}) {
	for _, t := range tables {
		s.watch[t].Wait(notify)
	}
}
Watch is used to subscribe a channel to a set of MDBTables
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
}