func (s *Storage) LoadRegions(ctx context.Context, f func(region *RegionInfo) []*RegionInfo) error {
	if atomic.LoadInt32(&s.useRegionStorage) > 0 {
		return loadRegions(ctx, s.regionStorage, s.encryptionKeyManager, f)
	}
	return loadRegions(ctx, s.Base, s.encryptionKeyManager, f)
}
LoadRegions loads all regions from storage to RegionsInfo.
package core
import (
	"context"
	"encoding/json"
	"fmt"
	"math"
	"path"
	"strconv"
	"strings"
	"sync"
	"sync/atomic"
	"time"
	"github.com/gogo/protobuf/proto"
	"github.com/pingcap/errors"
	"github.com/pingcap/kvproto/pkg/metapb"
	"github.com/pingcap/log"
	"github.com/tikv/pd/pkg/encryption"
	"github.com/tikv/pd/pkg/errs"
	"github.com/tikv/pd/server/encryptionkm"
	"github.com/tikv/pd/server/kv"
	"go.etcd.io/etcd/clientv3"
)
const (
	clusterPath                = "raft"
	configPath                 = "config"
	schedulePath               = "schedule"
	gcPath                     = "gc"
	rulesPath                  = "rules"
	ruleGroupPath              = "rule_group"
	regionLabelPath            = "region_label"
	replicationPath            = "replication_mode"
	componentPath              = "component"
	customScheduleConfigPath   = "scheduler_config"
	encryptionKeysPath         = "encryption_keys"
	gcWorkerServiceSafePointID = "gc_worker"
)
const (
	maxKVRangeLimit = 10000
	minKVRangeLimit = 100
)
type Storage struct {
	kv.Base
	regionStorage        *RegionStorage
	encryptionKeyManager *encryptionkm.KeyManager
	useRegionStorage     int32
	regionLoaded         int32
	mu                   sync.Mutex
}
type StorageOpt struct {
	regionStorage        *RegionStorage
	encryptionKeyManager *encryptionkm.KeyManager
}
type StorageOption func(*StorageOpt)
func WithRegionStorage(regionStorage *RegionStorage) StorageOption {
	return func(opt *StorageOpt) {
		opt.regionStorage = regionStorage
	}
}
func WithEncryptionKeyManager(encryptionKeyManager *encryptionkm.KeyManager) StorageOption {
	return func(opt *StorageOpt) {
		opt.encryptionKeyManager = encryptionKeyManager
	}
}
func NewStorage(base kv.Base, opts ...StorageOption) *Storage {
	options := &StorageOpt{}
	for _, opt := range opts {
		opt(options)
	}
	return &Storage{
		Base:                 base,
		regionStorage:        options.regionStorage,
		encryptionKeyManager: options.encryptionKeyManager,
	}
}
func (s *Storage) GetRegionStorage() *RegionStorage {
	return s.regionStorage
}
func (s *Storage) SwitchToRegionStorage() {
	atomic.StoreInt32(&s.useRegionStorage, 1)
}
func (s *Storage) SwitchToDefaultStorage() {
	atomic.StoreInt32(&s.useRegionStorage, 0)
}
func (s *Storage) storePath(storeID uint64) string {
	return path.Join(clusterPath, "s", fmt.Sprintf("%020d", storeID))
}
func regionPath(regionID uint64) string {
	return path.Join(clusterPath, "r", fmt.Sprintf("%020d", regionID))
}
func (s *Storage) ClusterStatePath(option string) string {
	return path.Join(clusterPath, "status", option)
}
func (s *Storage) storeLeaderWeightPath(storeID uint64) string {
	return path.Join(schedulePath, "store_weight", fmt.Sprintf("%020d", storeID), "leader")
}
func (s *Storage) storeRegionWeightPath(storeID uint64) string {
	return path.Join(schedulePath, "store_weight", fmt.Sprintf("%020d", storeID), "region")
}
func (s *Storage) EncryptionKeysPath() string {
	return path.Join(encryptionKeysPath, "keys")
}
func (s *Storage) SaveScheduleConfig(scheduleName string, data []byte) error {
	configPath := path.Join(customScheduleConfigPath, scheduleName)
	return s.Save(configPath, string(data))
}
func (s *Storage) RemoveScheduleConfig(scheduleName string) error {
	configPath := path.Join(customScheduleConfigPath, scheduleName)
	return s.Remove(configPath)
}
func (s *Storage) LoadScheduleConfig(scheduleName string) (string, error) {
	configPath := path.Join(customScheduleConfigPath, scheduleName)
	return s.Load(configPath)
}
func (s *Storage) LoadMeta(meta *metapb.Cluster) (bool, error) {
	return loadProto(s.Base, clusterPath, meta)
}
func (s *Storage) SaveMeta(meta *metapb.Cluster) error {
	return saveProto(s.Base, clusterPath, meta)
}
func (s *Storage) LoadStore(storeID uint64, store *metapb.Store) (bool, error) {
	return loadProto(s.Base, s.storePath(storeID), store)
}
func (s *Storage) SaveStore(store *metapb.Store) error {
	return saveProto(s.Base, s.storePath(store.GetId()), store)
}
func (s *Storage) DeleteStore(store *metapb.Store) error {
	return s.Remove(s.storePath(store.GetId()))
}
func (s *Storage) LoadRegion(regionID uint64, region *metapb.Region) (ok bool, err error) {
	if atomic.LoadInt32(&s.useRegionStorage) > 0 {
		return loadRegion(s.regionStorage, s.encryptionKeyManager, regionID, region)
	}
	return loadRegion(s.Base, s.encryptionKeyManager, regionID, region)
}