github.com/kardianos/nomad@v0.1.3-0.20151022182107-b13df73ee850/nomad/state/state_store.go (about)

     1  package state
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"log"
     7  	"sync"
     8  
     9  	"github.com/hashicorp/go-memdb"
    10  	"github.com/hashicorp/nomad/nomad/structs"
    11  )
    12  
    13  // The StateStore is responsible for maintaining all the Nomad
    14  // state. It is manipulated by the FSM which maintains consistency
    15  // through the use of Raft. The goals of the StateStore are to provide
    16  // high concurrency for read operations without blocking writes, and
    17  // to provide write availability in the face of reads. EVERY object
    18  // returned as a result of a read against the state store should be
    19  // considered a constant and NEVER modified in place.
    20  type StateStore struct {
    21  	logger *log.Logger
    22  	db     *memdb.MemDB
    23  	watch  *stateWatch
    24  }
    25  
    26  // StateSnapshot is used to provide a point-in-time snapshot
    27  type StateSnapshot struct {
    28  	StateStore
    29  }
    30  
    31  // StateRestore is used to optimize the performance when
    32  // restoring state by only using a single large transaction
    33  // instead of thousands of sub transactions
    34  type StateRestore struct {
    35  	txn        *memdb.Txn
    36  	watch      *stateWatch
    37  	allocNodes map[string]struct{}
    38  }
    39  
    40  // Abort is used to abort the restore operation
    41  func (s *StateRestore) Abort() {
    42  	s.txn.Abort()
    43  }
    44  
    45  // Commit is used to commit the restore operation
    46  func (s *StateRestore) Commit() {
    47  	s.txn.Defer(func() { s.watch.notifyAllocs(s.allocNodes) })
    48  	s.txn.Commit()
    49  }
    50  
    51  // IndexEntry is used with the "index" table
    52  // for managing the latest Raft index affecting a table.
    53  type IndexEntry struct {
    54  	Key   string
    55  	Value uint64
    56  }
    57  
    58  // stateWatch holds shared state for watching updates. This is
    59  // outside of StateStore so it can be shared with snapshots.
    60  type stateWatch struct {
    61  	allocs    map[string]*NotifyGroup
    62  	allocLock sync.Mutex
    63  }
    64  
    65  // NewStateStore is used to create a new state store
    66  func NewStateStore(logOutput io.Writer) (*StateStore, error) {
    67  	// Create the MemDB
    68  	db, err := memdb.NewMemDB(stateStoreSchema())
    69  	if err != nil {
    70  		return nil, fmt.Errorf("state store setup failed: %v", err)
    71  	}
    72  
    73  	// Create the watch entry
    74  	watch := &stateWatch{
    75  		allocs: make(map[string]*NotifyGroup),
    76  	}
    77  
    78  	// Create the state store
    79  	s := &StateStore{
    80  		logger: log.New(logOutput, "", log.LstdFlags),
    81  		db:     db,
    82  		watch:  watch,
    83  	}
    84  	return s, nil
    85  }
    86  
    87  // Snapshot is used to create a point in time snapshot. Because
    88  // we use MemDB, we just need to snapshot the state of the underlying
    89  // database.
    90  func (s *StateStore) Snapshot() (*StateSnapshot, error) {
    91  	snap := &StateSnapshot{
    92  		StateStore: StateStore{
    93  			logger: s.logger,
    94  			db:     s.db.Snapshot(),
    95  			watch:  s.watch,
    96  		},
    97  	}
    98  	return snap, nil
    99  }
   100  
   101  // Restore is used to optimize the efficiency of rebuilding
   102  // state by minimizing the number of transactions and checking
   103  // overhead.
   104  func (s *StateStore) Restore() (*StateRestore, error) {
   105  	txn := s.db.Txn(true)
   106  	r := &StateRestore{
   107  		txn:        txn,
   108  		watch:      s.watch,
   109  		allocNodes: make(map[string]struct{}),
   110  	}
   111  	return r, nil
   112  }
   113  
   114  // WatchAllocs is used to subscribe a channel to changes in allocations for a node
   115  func (s *StateStore) WatchAllocs(node string, notify chan struct{}) {
   116  	s.watch.allocLock.Lock()
   117  	defer s.watch.allocLock.Unlock()
   118  
   119  	// Check for an existing notify group
   120  	if grp, ok := s.watch.allocs[node]; ok {
   121  		grp.Wait(notify)
   122  		return
   123  	}
   124  
   125  	// Create new notify group
   126  	grp := &NotifyGroup{}
   127  	grp.Wait(notify)
   128  	s.watch.allocs[node] = grp
   129  }
   130  
   131  // StopWatchAllocs is used to unsubscribe a channel from changes in allocations
   132  func (s *StateStore) StopWatchAllocs(node string, notify chan struct{}) {
   133  	s.watch.allocLock.Lock()
   134  	defer s.watch.allocLock.Unlock()
   135  
   136  	// Check for an existing notify group
   137  	if grp, ok := s.watch.allocs[node]; ok {
   138  		grp.Clear(notify)
   139  		if grp.Empty() {
   140  			delete(s.watch.allocs, node)
   141  		}
   142  	}
   143  }
   144  
   145  // notifyAllocs is used to notify any node alloc listeners of a change
   146  func (w *stateWatch) notifyAllocs(nodes map[string]struct{}) {
   147  	w.allocLock.Lock()
   148  	defer w.allocLock.Unlock()
   149  
   150  	for node := range nodes {
   151  		if grp, ok := w.allocs[node]; ok {
   152  			grp.Notify()
   153  			delete(w.allocs, node)
   154  		}
   155  	}
   156  }
   157  
   158  // UpsertNode is used to register a node or update a node definition
   159  // This is assumed to be triggered by the client, so we retain the value
   160  // of drain which is set by the scheduler.
   161  func (s *StateStore) UpsertNode(index uint64, node *structs.Node) error {
   162  	txn := s.db.Txn(true)
   163  	defer txn.Abort()
   164  
   165  	// Check if the node already exists
   166  	existing, err := txn.First("nodes", "id", node.ID)
   167  	if err != nil {
   168  		return fmt.Errorf("node lookup failed: %v", err)
   169  	}
   170  
   171  	// Setup the indexes correctly
   172  	if existing != nil {
   173  		exist := existing.(*structs.Node)
   174  		node.CreateIndex = exist.CreateIndex
   175  		node.ModifyIndex = index
   176  		node.Drain = exist.Drain // Retain the drain mode
   177  	} else {
   178  		node.CreateIndex = index
   179  		node.ModifyIndex = index
   180  	}
   181  
   182  	// Insert the node
   183  	if err := txn.Insert("nodes", node); err != nil {
   184  		return fmt.Errorf("node insert failed: %v", err)
   185  	}
   186  	if err := txn.Insert("index", &IndexEntry{"nodes", index}); err != nil {
   187  		return fmt.Errorf("index update failed: %v", err)
   188  	}
   189  
   190  	txn.Commit()
   191  	return nil
   192  }
   193  
   194  // DeleteNode is used to deregister a node
   195  func (s *StateStore) DeleteNode(index uint64, nodeID string) error {
   196  	txn := s.db.Txn(true)
   197  	defer txn.Abort()
   198  
   199  	// Lookup the node
   200  	existing, err := txn.First("nodes", "id", nodeID)
   201  	if err != nil {
   202  		return fmt.Errorf("node lookup failed: %v", err)
   203  	}
   204  	if existing == nil {
   205  		return fmt.Errorf("node not found")
   206  	}
   207  
   208  	// Delete the node
   209  	if err := txn.Delete("nodes", existing); err != nil {
   210  		return fmt.Errorf("node delete failed: %v", err)
   211  	}
   212  	if err := txn.Insert("index", &IndexEntry{"nodes", index}); err != nil {
   213  		return fmt.Errorf("index update failed: %v", err)
   214  	}
   215  
   216  	txn.Commit()
   217  	return nil
   218  }
   219  
   220  // UpdateNodeStatus is used to update the status of a node
   221  func (s *StateStore) UpdateNodeStatus(index uint64, nodeID, status string) error {
   222  	txn := s.db.Txn(true)
   223  	defer txn.Abort()
   224  
   225  	// Lookup the node
   226  	existing, err := txn.First("nodes", "id", nodeID)
   227  	if err != nil {
   228  		return fmt.Errorf("node lookup failed: %v", err)
   229  	}
   230  	if existing == nil {
   231  		return fmt.Errorf("node not found")
   232  	}
   233  
   234  	// Copy the existing node
   235  	existingNode := existing.(*structs.Node)
   236  	copyNode := new(structs.Node)
   237  	*copyNode = *existingNode
   238  
   239  	// Update the status in the copy
   240  	copyNode.Status = status
   241  	copyNode.ModifyIndex = index
   242  
   243  	// Insert the node
   244  	if err := txn.Insert("nodes", copyNode); err != nil {
   245  		return fmt.Errorf("node update failed: %v", err)
   246  	}
   247  	if err := txn.Insert("index", &IndexEntry{"nodes", index}); err != nil {
   248  		return fmt.Errorf("index update failed: %v", err)
   249  	}
   250  
   251  	txn.Commit()
   252  	return nil
   253  }
   254  
   255  // UpdateNodeDrain is used to update the drain of a node
   256  func (s *StateStore) UpdateNodeDrain(index uint64, nodeID string, drain bool) error {
   257  	txn := s.db.Txn(true)
   258  	defer txn.Abort()
   259  
   260  	// Lookup the node
   261  	existing, err := txn.First("nodes", "id", nodeID)
   262  	if err != nil {
   263  		return fmt.Errorf("node lookup failed: %v", err)
   264  	}
   265  	if existing == nil {
   266  		return fmt.Errorf("node not found")
   267  	}
   268  
   269  	// Copy the existing node
   270  	existingNode := existing.(*structs.Node)
   271  	copyNode := new(structs.Node)
   272  	*copyNode = *existingNode
   273  
   274  	// Update the drain in the copy
   275  	copyNode.Drain = drain
   276  	copyNode.ModifyIndex = index
   277  
   278  	// Insert the node
   279  	if err := txn.Insert("nodes", copyNode); err != nil {
   280  		return fmt.Errorf("node update failed: %v", err)
   281  	}
   282  	if err := txn.Insert("index", &IndexEntry{"nodes", index}); err != nil {
   283  		return fmt.Errorf("index update failed: %v", err)
   284  	}
   285  
   286  	txn.Commit()
   287  	return nil
   288  }
   289  
   290  // NodeByID is used to lookup a node by ID
   291  func (s *StateStore) NodeByID(nodeID string) (*structs.Node, error) {
   292  	txn := s.db.Txn(false)
   293  
   294  	existing, err := txn.First("nodes", "id", nodeID)
   295  	if err != nil {
   296  		return nil, fmt.Errorf("node lookup failed: %v", err)
   297  	}
   298  
   299  	if existing != nil {
   300  		return existing.(*structs.Node), nil
   301  	}
   302  	return nil, nil
   303  }
   304  
   305  // Nodes returns an iterator over all the nodes
   306  func (s *StateStore) Nodes() (memdb.ResultIterator, error) {
   307  	txn := s.db.Txn(false)
   308  
   309  	// Walk the entire nodes table
   310  	iter, err := txn.Get("nodes", "id")
   311  	if err != nil {
   312  		return nil, err
   313  	}
   314  	return iter, nil
   315  }
   316  
   317  // UpsertJob is used to register a job or update a job definition
   318  func (s *StateStore) UpsertJob(index uint64, job *structs.Job) error {
   319  	txn := s.db.Txn(true)
   320  	defer txn.Abort()
   321  
   322  	// Check if the job already exists
   323  	existing, err := txn.First("jobs", "id", job.ID)
   324  	if err != nil {
   325  		return fmt.Errorf("job lookup failed: %v", err)
   326  	}
   327  
   328  	// Setup the indexes correctly
   329  	if existing != nil {
   330  		job.CreateIndex = existing.(*structs.Job).CreateIndex
   331  		job.ModifyIndex = index
   332  	} else {
   333  		job.CreateIndex = index
   334  		job.ModifyIndex = index
   335  	}
   336  
   337  	// Insert the job
   338  	if err := txn.Insert("jobs", job); err != nil {
   339  		return fmt.Errorf("job insert failed: %v", err)
   340  	}
   341  	if err := txn.Insert("index", &IndexEntry{"jobs", index}); err != nil {
   342  		return fmt.Errorf("index update failed: %v", err)
   343  	}
   344  
   345  	txn.Commit()
   346  	return nil
   347  }
   348  
   349  // DeleteJob is used to deregister a job
   350  func (s *StateStore) DeleteJob(index uint64, jobID string) error {
   351  	txn := s.db.Txn(true)
   352  	defer txn.Abort()
   353  
   354  	// Lookup the node
   355  	existing, err := txn.First("jobs", "id", jobID)
   356  	if err != nil {
   357  		return fmt.Errorf("job lookup failed: %v", err)
   358  	}
   359  	if existing == nil {
   360  		return fmt.Errorf("job not found")
   361  	}
   362  
   363  	// Delete the node
   364  	if err := txn.Delete("jobs", existing); err != nil {
   365  		return fmt.Errorf("job delete failed: %v", err)
   366  	}
   367  	if err := txn.Insert("index", &IndexEntry{"jobs", index}); err != nil {
   368  		return fmt.Errorf("index update failed: %v", err)
   369  	}
   370  
   371  	txn.Commit()
   372  	return nil
   373  }
   374  
   375  // JobByID is used to lookup a job by its ID
   376  func (s *StateStore) JobByID(id string) (*structs.Job, error) {
   377  	txn := s.db.Txn(false)
   378  
   379  	existing, err := txn.First("jobs", "id", id)
   380  	if err != nil {
   381  		return nil, fmt.Errorf("job lookup failed: %v", err)
   382  	}
   383  
   384  	if existing != nil {
   385  		return existing.(*structs.Job), nil
   386  	}
   387  	return nil, nil
   388  }
   389  
   390  // Jobs returns an iterator over all the jobs
   391  func (s *StateStore) Jobs() (memdb.ResultIterator, error) {
   392  	txn := s.db.Txn(false)
   393  
   394  	// Walk the entire jobs table
   395  	iter, err := txn.Get("jobs", "id")
   396  	if err != nil {
   397  		return nil, err
   398  	}
   399  	return iter, nil
   400  }
   401  
   402  // JobsByScheduler returns an iterator over all the jobs with the specific
   403  // scheduler type.
   404  func (s *StateStore) JobsByScheduler(schedulerType string) (memdb.ResultIterator, error) {
   405  	txn := s.db.Txn(false)
   406  
   407  	// Return an iterator for jobs with the specific type.
   408  	iter, err := txn.Get("jobs", "type", schedulerType)
   409  	if err != nil {
   410  		return nil, err
   411  	}
   412  	return iter, nil
   413  }
   414  
   415  // UpsertEvaluation is used to upsert an evaluation
   416  func (s *StateStore) UpsertEvals(index uint64, evals []*structs.Evaluation) error {
   417  	txn := s.db.Txn(true)
   418  	defer txn.Abort()
   419  
   420  	// Do a nested upsert
   421  	for _, eval := range evals {
   422  		if err := s.nestedUpsertEval(txn, index, eval); err != nil {
   423  			return err
   424  		}
   425  	}
   426  
   427  	txn.Commit()
   428  	return nil
   429  }
   430  
   431  // nestedUpsertEvaluation is used to nest an evaluation upsert within a transaction
   432  func (s *StateStore) nestedUpsertEval(txn *memdb.Txn, index uint64, eval *structs.Evaluation) error {
   433  	// Lookup the evaluation
   434  	existing, err := txn.First("evals", "id", eval.ID)
   435  	if err != nil {
   436  		return fmt.Errorf("eval lookup failed: %v", err)
   437  	}
   438  
   439  	// Update the indexes
   440  	if existing != nil {
   441  		eval.CreateIndex = existing.(*structs.Evaluation).CreateIndex
   442  		eval.ModifyIndex = index
   443  	} else {
   444  		eval.CreateIndex = index
   445  		eval.ModifyIndex = index
   446  	}
   447  
   448  	// Insert the eval
   449  	if err := txn.Insert("evals", eval); err != nil {
   450  		return fmt.Errorf("eval insert failed: %v", err)
   451  	}
   452  	if err := txn.Insert("index", &IndexEntry{"evals", index}); err != nil {
   453  		return fmt.Errorf("index update failed: %v", err)
   454  	}
   455  	return nil
   456  }
   457  
   458  // DeleteEval is used to delete an evaluation
   459  func (s *StateStore) DeleteEval(index uint64, evals []string, allocs []string) error {
   460  	txn := s.db.Txn(true)
   461  	defer txn.Abort()
   462  	nodes := make(map[string]struct{})
   463  
   464  	for _, eval := range evals {
   465  		existing, err := txn.First("evals", "id", eval)
   466  		if err != nil {
   467  			return fmt.Errorf("eval lookup failed: %v", err)
   468  		}
   469  		if existing == nil {
   470  			continue
   471  		}
   472  		if err := txn.Delete("evals", existing); err != nil {
   473  			return fmt.Errorf("eval delete failed: %v", err)
   474  		}
   475  	}
   476  
   477  	for _, alloc := range allocs {
   478  		existing, err := txn.First("allocs", "id", alloc)
   479  		if err != nil {
   480  			return fmt.Errorf("alloc lookup failed: %v", err)
   481  		}
   482  		if existing == nil {
   483  			continue
   484  		}
   485  		nodes[existing.(*structs.Allocation).NodeID] = struct{}{}
   486  		if err := txn.Delete("allocs", existing); err != nil {
   487  			return fmt.Errorf("alloc delete failed: %v", err)
   488  		}
   489  	}
   490  
   491  	// Update the indexes
   492  	if err := txn.Insert("index", &IndexEntry{"evals", index}); err != nil {
   493  		return fmt.Errorf("index update failed: %v", err)
   494  	}
   495  	if err := txn.Insert("index", &IndexEntry{"allocs", index}); err != nil {
   496  		return fmt.Errorf("index update failed: %v", err)
   497  	}
   498  	txn.Defer(func() { s.watch.notifyAllocs(nodes) })
   499  	txn.Commit()
   500  	return nil
   501  }
   502  
   503  // EvalByID is used to lookup an eval by its ID
   504  func (s *StateStore) EvalByID(id string) (*structs.Evaluation, error) {
   505  	txn := s.db.Txn(false)
   506  
   507  	existing, err := txn.First("evals", "id", id)
   508  	if err != nil {
   509  		return nil, fmt.Errorf("eval lookup failed: %v", err)
   510  	}
   511  
   512  	if existing != nil {
   513  		return existing.(*structs.Evaluation), nil
   514  	}
   515  	return nil, nil
   516  }
   517  
   518  // EvalsByJob returns all the evaluations by job id
   519  func (s *StateStore) EvalsByJob(jobID string) ([]*structs.Evaluation, error) {
   520  	txn := s.db.Txn(false)
   521  
   522  	// Get an iterator over the node allocations
   523  	iter, err := txn.Get("evals", "job", jobID)
   524  	if err != nil {
   525  		return nil, err
   526  	}
   527  
   528  	var out []*structs.Evaluation
   529  	for {
   530  		raw := iter.Next()
   531  		if raw == nil {
   532  			break
   533  		}
   534  		out = append(out, raw.(*structs.Evaluation))
   535  	}
   536  	return out, nil
   537  }
   538  
   539  // Evals returns an iterator over all the evaluations
   540  func (s *StateStore) Evals() (memdb.ResultIterator, error) {
   541  	txn := s.db.Txn(false)
   542  
   543  	// Walk the entire table
   544  	iter, err := txn.Get("evals", "id")
   545  	if err != nil {
   546  		return nil, err
   547  	}
   548  	return iter, nil
   549  }
   550  
   551  // UpdateAllocFromClient is used to update an allocation based on input
   552  // from a client. While the schedulers are the authority on the allocation for
   553  // most things, some updates are authoritative from the client. Specifically,
   554  // the desired state comes from the schedulers, while the actual state comes
   555  // from clients.
   556  func (s *StateStore) UpdateAllocFromClient(index uint64, alloc *structs.Allocation) error {
   557  	txn := s.db.Txn(true)
   558  	defer txn.Abort()
   559  
   560  	// Look for existing alloc
   561  	existing, err := txn.First("allocs", "id", alloc.ID)
   562  	if err != nil {
   563  		return fmt.Errorf("alloc lookup failed: %v", err)
   564  	}
   565  
   566  	// Nothing to do if this does not exist
   567  	if existing == nil {
   568  		return nil
   569  	}
   570  	exist := existing.(*structs.Allocation)
   571  
   572  	// Copy everything from the existing allocation
   573  	copyAlloc := new(structs.Allocation)
   574  	*copyAlloc = *exist
   575  
   576  	// Pull in anything the client is the authority on
   577  	copyAlloc.ClientStatus = alloc.ClientStatus
   578  	copyAlloc.ClientDescription = alloc.ClientDescription
   579  
   580  	// Update the modify index
   581  	copyAlloc.ModifyIndex = index
   582  
   583  	// Update the allocation
   584  	if err := txn.Insert("allocs", copyAlloc); err != nil {
   585  		return fmt.Errorf("alloc insert failed: %v", err)
   586  	}
   587  
   588  	// Update the indexes
   589  	if err := txn.Insert("index", &IndexEntry{"allocs", index}); err != nil {
   590  		return fmt.Errorf("index update failed: %v", err)
   591  	}
   592  
   593  	nodes := map[string]struct{}{alloc.NodeID: struct{}{}}
   594  	txn.Defer(func() { s.watch.notifyAllocs(nodes) })
   595  	txn.Commit()
   596  	return nil
   597  }
   598  
   599  // UpsertAllocs is used to evict a set of allocations
   600  // and allocate new ones at the same time.
   601  func (s *StateStore) UpsertAllocs(index uint64, allocs []*structs.Allocation) error {
   602  	txn := s.db.Txn(true)
   603  	defer txn.Abort()
   604  	nodes := make(map[string]struct{})
   605  
   606  	// Handle the allocations
   607  	for _, alloc := range allocs {
   608  		existing, err := txn.First("allocs", "id", alloc.ID)
   609  		if err != nil {
   610  			return fmt.Errorf("alloc lookup failed: %v", err)
   611  		}
   612  
   613  		if existing == nil {
   614  			alloc.CreateIndex = index
   615  			alloc.ModifyIndex = index
   616  		} else {
   617  			exist := existing.(*structs.Allocation)
   618  			alloc.CreateIndex = exist.CreateIndex
   619  			alloc.ModifyIndex = index
   620  			alloc.ClientStatus = exist.ClientStatus
   621  			alloc.ClientDescription = exist.ClientDescription
   622  		}
   623  		nodes[alloc.NodeID] = struct{}{}
   624  		if err := txn.Insert("allocs", alloc); err != nil {
   625  			return fmt.Errorf("alloc insert failed: %v", err)
   626  		}
   627  	}
   628  
   629  	// Update the indexes
   630  	if err := txn.Insert("index", &IndexEntry{"allocs", index}); err != nil {
   631  		return fmt.Errorf("index update failed: %v", err)
   632  	}
   633  
   634  	txn.Defer(func() { s.watch.notifyAllocs(nodes) })
   635  	txn.Commit()
   636  	return nil
   637  }
   638  
   639  // AllocByID is used to lookup an allocation by its ID
   640  func (s *StateStore) AllocByID(id string) (*structs.Allocation, error) {
   641  	txn := s.db.Txn(false)
   642  
   643  	existing, err := txn.First("allocs", "id", id)
   644  	if err != nil {
   645  		return nil, fmt.Errorf("alloc lookup failed: %v", err)
   646  	}
   647  
   648  	if existing != nil {
   649  		return existing.(*structs.Allocation), nil
   650  	}
   651  	return nil, nil
   652  }
   653  
   654  // AllocsByNode returns all the allocations by node
   655  func (s *StateStore) AllocsByNode(node string) ([]*structs.Allocation, error) {
   656  	txn := s.db.Txn(false)
   657  
   658  	// Get an iterator over the node allocations
   659  	iter, err := txn.Get("allocs", "node", node)
   660  	if err != nil {
   661  		return nil, err
   662  	}
   663  
   664  	var out []*structs.Allocation
   665  	for {
   666  		raw := iter.Next()
   667  		if raw == nil {
   668  			break
   669  		}
   670  		out = append(out, raw.(*structs.Allocation))
   671  	}
   672  	return out, nil
   673  }
   674  
   675  // AllocsByJob returns all the allocations by job id
   676  func (s *StateStore) AllocsByJob(jobID string) ([]*structs.Allocation, error) {
   677  	txn := s.db.Txn(false)
   678  
   679  	// Get an iterator over the node allocations
   680  	iter, err := txn.Get("allocs", "job", jobID)
   681  	if err != nil {
   682  		return nil, err
   683  	}
   684  
   685  	var out []*structs.Allocation
   686  	for {
   687  		raw := iter.Next()
   688  		if raw == nil {
   689  			break
   690  		}
   691  		out = append(out, raw.(*structs.Allocation))
   692  	}
   693  	return out, nil
   694  }
   695  
   696  // AllocsByEval returns all the allocations by eval id
   697  func (s *StateStore) AllocsByEval(evalID string) ([]*structs.Allocation, error) {
   698  	txn := s.db.Txn(false)
   699  
   700  	// Get an iterator over the eval allocations
   701  	iter, err := txn.Get("allocs", "eval", evalID)
   702  	if err != nil {
   703  		return nil, err
   704  	}
   705  
   706  	var out []*structs.Allocation
   707  	for {
   708  		raw := iter.Next()
   709  		if raw == nil {
   710  			break
   711  		}
   712  		out = append(out, raw.(*structs.Allocation))
   713  	}
   714  	return out, nil
   715  }
   716  
   717  // Allocs returns an iterator over all the evaluations
   718  func (s *StateStore) Allocs() (memdb.ResultIterator, error) {
   719  	txn := s.db.Txn(false)
   720  
   721  	// Walk the entire table
   722  	iter, err := txn.Get("allocs", "id")
   723  	if err != nil {
   724  		return nil, err
   725  	}
   726  	return iter, nil
   727  }
   728  
   729  // Index finds the matching index value
   730  func (s *StateStore) Index(name string) (uint64, error) {
   731  	txn := s.db.Txn(false)
   732  
   733  	// Lookup the first matching index
   734  	out, err := txn.First("index", "id", name)
   735  	if err != nil {
   736  		return 0, err
   737  	}
   738  	if out == nil {
   739  		return 0, nil
   740  	}
   741  	return out.(*IndexEntry).Value, nil
   742  }
   743  
   744  // Indexes returns an iterator over all the indexes
   745  func (s *StateStore) Indexes() (memdb.ResultIterator, error) {
   746  	txn := s.db.Txn(false)
   747  
   748  	// Walk the entire nodes table
   749  	iter, err := txn.Get("index", "id")
   750  	if err != nil {
   751  		return nil, err
   752  	}
   753  	return iter, nil
   754  }
   755  
   756  // NodeRestore is used to restore a node
   757  func (r *StateRestore) NodeRestore(node *structs.Node) error {
   758  	if err := r.txn.Insert("nodes", node); err != nil {
   759  		return fmt.Errorf("node insert failed: %v", err)
   760  	}
   761  	return nil
   762  }
   763  
   764  // JobRestore is used to restore a job
   765  func (r *StateRestore) JobRestore(job *structs.Job) error {
   766  	if err := r.txn.Insert("jobs", job); err != nil {
   767  		return fmt.Errorf("job insert failed: %v", err)
   768  	}
   769  	return nil
   770  }
   771  
   772  // EvalRestore is used to restore an evaluation
   773  func (r *StateRestore) EvalRestore(eval *structs.Evaluation) error {
   774  	if err := r.txn.Insert("evals", eval); err != nil {
   775  		return fmt.Errorf("eval insert failed: %v", err)
   776  	}
   777  	return nil
   778  }
   779  
   780  // AllocRestore is used to restore an allocation
   781  func (r *StateRestore) AllocRestore(alloc *structs.Allocation) error {
   782  	r.allocNodes[alloc.NodeID] = struct{}{}
   783  	if err := r.txn.Insert("allocs", alloc); err != nil {
   784  		return fmt.Errorf("alloc insert failed: %v", err)
   785  	}
   786  	return nil
   787  }
   788  
   789  // IndexRestore is used to restore an index
   790  func (r *StateRestore) IndexRestore(idx *IndexEntry) error {
   791  	if err := r.txn.Insert("index", idx); err != nil {
   792  		return fmt.Errorf("index insert failed: %v", err)
   793  	}
   794  	return nil
   795  }