func (m *RuleManager) Initialize(maxReplica int, locationLabels []string) error {
	m.Lock()
	defer m.Unlock()
	if m.initialized {
		return nil
	}
	if err := m.loadRules(); err != nil {
		return err
	}
	if err := m.loadGroups(); err != nil {
		return err
	}
	if len(m.ruleConfig.rules) == 0 {
		defaultRule := &Rule{
			GroupID:        "pd",
			ID:             "default",
			Role:           Voter,
			Count:          maxReplica,
			LocationLabels: locationLabels,
		}
		if err := m.storage.SaveRule(defaultRule.StoreKey(), defaultRule); err != nil {
			return err
		}
		m.ruleConfig.setRule(defaultRule)
	}
	m.ruleConfig.adjust()
	ruleList, err := buildRuleList(m.ruleConfig)
	if err != nil {
		return err
	}
	m.ruleList = ruleList
	m.initialized = true
	return nil
}
Initialize loads rules from storage. If Placement Rules feature is never enabled, it creates default rule that is
compatible with previous configuration.
package placement
import (
	"bytes"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"regexp"
	"sort"
	"strings"
	"sync"
	"github.com/pingcap/errors"
	"github.com/pingcap/log"
	"github.com/tikv/pd/pkg/codec"
	"github.com/tikv/pd/pkg/errs"
	"github.com/tikv/pd/server/config"
	"github.com/tikv/pd/server/core"
	"go.uber.org/zap"
)
type RuleManager struct {
	storage *core.Storage
	sync.RWMutex
	initialized bool
	ruleConfig  *ruleConfig
	ruleList    ruleList
	keyType          string
	storeSetInformer core.StoreSetInformer
	cache            *RegionRuleFitCacheManager
	opt              *config.PersistOptions
}
func NewRuleManager(storage *core.Storage, storeSetInformer core.StoreSetInformer, opt *config.PersistOptions) *RuleManager {
	return &RuleManager{
		storage:          storage,
		storeSetInformer: storeSetInformer,
		opt:              opt,
		ruleConfig:       newRuleConfig(),
		cache:            NewRegionRuleFitCacheManager(),
	}
}