func (r *IndexRegistry) MarkOutdated(idx Index) {
	r.statuses[indexKey{idx.Database(), idx.ID()}] = IndexOutdated
}
MarkOutdated sets the index status as outdated. This method is not thread
safe and should not be used directly except for testing.
package sql
import (
	"io"
	"strings"
	"sync"
	"github.com/src-d/go-mysql-server/internal/similartext"
	"github.com/sirupsen/logrus"
	"gopkg.in/src-d/go-errors.v1"
)
const IndexBatchSize = uint64(10000)
const ChecksumKey = "checksum"
type Checksumable interface {
	Checksum() (string, error)
}
type PartitionIndexKeyValueIter interface {
	Next() (Partition, IndexKeyValueIter, error)
	io.Closer
}
type IndexKeyValueIter interface {
	Next() ([]interface{}, []byte, error)
	io.Closer
}
type IndexValueIter interface {
	Next() ([]byte, error)
	io.Closer
}
type Index interface {
	Get(key ...interface{}) (IndexLookup, error)
	Has(partition Partition, key ...interface{}) (bool, error)
	ID() string
	Database() string
	Table() string
	Expressions() []string
	Driver() string
}
type AscendIndex interface {
	AscendGreaterOrEqual(keys ...interface{}) (IndexLookup, error)
	AscendLessThan(keys ...interface{}) (IndexLookup, error)
	AscendRange(greaterOrEqual, lessThan []interface{}) (IndexLookup, error)
}
type DescendIndex interface {
	DescendGreater(keys ...interface{}) (IndexLookup, error)
	DescendLessOrEqual(keys ...interface{}) (IndexLookup, error)
	DescendRange(lessOrEqual, greaterThan []interface{}) (IndexLookup, error)
}
type NegateIndex interface {
	Not(keys ...interface{}) (IndexLookup, error)
}
type IndexLookup interface {
	Values(Partition) (IndexValueIter, error)
	Indexes() []string
}
type SetOperations interface {
	Intersection(...IndexLookup) IndexLookup
	Union(...IndexLookup) IndexLookup
	Difference(...IndexLookup) IndexLookup
}
type Mergeable interface {
	IsMergeable(IndexLookup) bool
}
type IndexDriver interface {
	ID() string
	Create(db, table, id string, expressions []Expression, config map[string]string) (Index, error)
	LoadAll(db, table string) ([]Index, error)
	Save(*Context, Index, PartitionIndexKeyValueIter) error
	Delete(Index, PartitionIter) error
}
type indexKey struct {
	db, id string
}
type IndexRegistry struct {
	Root string
	mut        sync.RWMutex
	indexes    map[indexKey]Index
	indexOrder []indexKey
	statuses   map[indexKey]IndexStatus
	driversMut sync.RWMutex
	drivers    map[string]IndexDriver
	rcmut            sync.RWMutex
	refCounts        map[indexKey]int
	deleteIndexQueue map[indexKey]chan<- struct{}
}
func NewIndexRegistry() *IndexRegistry {
	return &IndexRegistry{
		indexes:          make(map[indexKey]Index),
		statuses:         make(map[indexKey]IndexStatus),
		drivers:          make(map[string]IndexDriver),
		refCounts:        make(map[indexKey]int),
		deleteIndexQueue: make(map[indexKey]chan<- struct{}),
	}
}
func (r *IndexRegistry) IndexDriver(id string) IndexDriver {
	r.driversMut.RLock()
	defer r.driversMut.RUnlock()
	return r.drivers[id]
}
func (r *IndexRegistry) DefaultIndexDriver() IndexDriver {
	r.driversMut.RLock()
	defer r.driversMut.RUnlock()
	if len(r.drivers) == 1 {
		for _, d := range r.drivers {
			return d
		}
	}
	return nil
}
func (r *IndexRegistry) RegisterIndexDriver(driver IndexDriver) {
	r.driversMut.Lock()
	defer r.driversMut.Unlock()
	r.drivers[driver.ID()] = driver
}
func (r *IndexRegistry) LoadIndexes(dbs Databases) error {
	r.driversMut.RLock()
	defer r.driversMut.RUnlock()
	r.mut.Lock()
	defer r.mut.Unlock()
	for _, driver := range r.drivers {
		for _, db := range dbs {
			for _, t := range db.Tables() {
				indexes, err := driver.LoadAll(db.Name(), t.Name())
				if err != nil {
					return err
				}
				var checksum string
				if c, ok := t.(Checksumable); ok && len(indexes) != 0 {
					checksum, err = c.Checksum()
					if err != nil {
						return err
					}
				}
				for _, idx := range indexes {
					k := indexKey{db.Name(), idx.ID()}
					r.indexes[k] = idx
					r.indexOrder = append(r.indexOrder, k)
					var idxChecksum string
					if c, ok := idx.(Checksumable); ok {
						idxChecksum, err = c.Checksum()
						if err != nil {
							return err
						}
					}
					if checksum == "" || checksum == idxChecksum {
						r.statuses[k] = IndexReady
					} else {
						logrus.Warnf(
							"index %q is outdated and will not be used, you can remove it using `DROP INDEX %s ON %s`",
							idx.ID(),
							idx.ID(),
							idx.Table(),
						)
						r.MarkOutdated(idx)
					}
				}
			}
		}
	}
	return nil
}