Skip to content

Commit 272d561

Browse files
committed
Implement more HTTP APIs
Signed-off-by: JmPotato <[email protected]>
1 parent 86831ce commit 272d561

File tree

3 files changed

+216
-25
lines changed

3 files changed

+216
-25
lines changed

Diff for: client/http/api.go

+94-10
Original file line numberDiff line numberDiff line change
@@ -17,24 +17,58 @@ package http
1717
import (
1818
"fmt"
1919
"net/url"
20+
"time"
2021
)
2122

2223
// The following constants are the paths of PD HTTP APIs.
2324
const (
24-
HotRead = "/pd/api/v1/hotspot/regions/read"
25-
HotWrite = "/pd/api/v1/hotspot/regions/write"
26-
Regions = "/pd/api/v1/regions"
27-
regionByID = "/pd/api/v1/region/id"
28-
regionByKey = "/pd/api/v1/region/key"
29-
regionsByKey = "/pd/api/v1/regions/key"
30-
regionsByStoreID = "/pd/api/v1/regions/store"
31-
Stores = "/pd/api/v1/stores"
25+
// Metadata
26+
HotRead = "/pd/api/v1/hotspot/regions/read"
27+
HotWrite = "/pd/api/v1/hotspot/regions/write"
28+
HotHistory = "/pd/api/v1/hotspot/regions/history"
29+
RegionByIDPrefix = "/pd/api/v1/region/id"
30+
regionByKey = "/pd/api/v1/region/key"
31+
Regions = "/pd/api/v1/regions"
32+
regionsByKey = "/pd/api/v1/regions/key"
33+
RegionsByStoreIDPrefix = "/pd/api/v1/regions/store"
34+
EmptyRegions = "/pd/api/v1/regions/check/empty-region"
35+
accelerateSchedule = "/pd/api/v1/regions/accelerate-schedule"
36+
store = "/pd/api/v1/store"
37+
Stores = "/pd/api/v1/stores"
38+
StatsRegion = "/pd/api/v1/stats/region"
39+
// Config
40+
Config = "/pd/api/v1/config"
41+
ClusterVersion = "/pd/api/v1/config/cluster-version"
42+
ScheduleConfig = "/pd/api/v1/config/schedule"
43+
ReplicateConfig = "/pd/api/v1/config/replicate"
44+
// Rule
45+
PlacementRule = "/pd/api/v1/config/rule"
46+
PlacementRules = "/pd/api/v1/config/rules"
47+
placementRulesByGroup = "/pd/api/v1/config/rules/group"
48+
RegionLabelRule = "/pd/api/v1/config/region-label/rule"
49+
// Scheduler
50+
Schedulers = "/pd/api/v1/schedulers"
51+
scatterRangeScheduler = "/pd/api/v1/schedulers/scatter-range-"
52+
// Admin
53+
ResetTS = "/pd/api/v1/admin/reset-ts"
54+
BaseAllocID = "/pd/api/v1/admin/base-alloc-id"
55+
SnapshotRecoveringMark = "/pd/api/v1/admin/cluster/markers/snapshot-recovering"
56+
// Debug
57+
PProfProfile = "/pd/api/v1/debug/pprof/profile"
58+
PProfHeap = "/pd/api/v1/debug/pprof/heap"
59+
PProfMutex = "/pd/api/v1/debug/pprof/mutex"
60+
PProfAllocs = "/pd/api/v1/debug/pprof/allocs"
61+
PProfBlock = "/pd/api/v1/debug/pprof/block"
62+
PProfGoroutine = "/pd/api/v1/debug/pprof/goroutine"
63+
// Others
3264
MinResolvedTSPrefix = "/pd/api/v1/min-resolved-ts"
65+
Status = "/pd/api/v1/status"
66+
Version = "/pd/api/v1/version"
3367
)
3468

3569
// RegionByID returns the path of PD HTTP API to get region by ID.
3670
func RegionByID(regionID uint64) string {
37-
return fmt.Sprintf("%s/%d", regionByID, regionID)
71+
return fmt.Sprintf("%s/%d", RegionByIDPrefix, regionID)
3872
}
3973

4074
// RegionByKey returns the path of PD HTTP API to get region by key.
@@ -50,5 +84,55 @@ func RegionsByKey(startKey, endKey []byte, limit int) string {
5084

5185
// RegionsByStoreID returns the path of PD HTTP API to get regions by store ID.
5286
func RegionsByStoreID(storeID uint64) string {
53-
return fmt.Sprintf("%s/%d", regionsByStoreID, storeID)
87+
return fmt.Sprintf("%s/%d", RegionsByStoreIDPrefix, storeID)
88+
}
89+
90+
// RegionStatsByStartEndKey returns the path of PD HTTP API to get region stats by start key and end key.
91+
func RegionStatsByStartEndKey(startKey, endKey string) string {
92+
return fmt.Sprintf("%s?start_key=%s&end_key=%s", StatsRegion, startKey, endKey)
93+
}
94+
95+
// StoreByID returns the store API with store ID parameter.
96+
func StoreByID(id uint64) string {
97+
return fmt.Sprintf("%s/%d", store, id)
98+
}
99+
100+
// StoreLabelByID returns the store label API with store ID parameter.
101+
func StoreLabelByID(id uint64) string {
102+
return fmt.Sprintf("%s/%d/label", store, id)
103+
}
104+
105+
// ConfigWithTTLSeconds returns the config API with the TTL seconds parameter.
106+
func ConfigWithTTLSeconds(ttlSeconds float64) string {
107+
return fmt.Sprintf("%s?ttlSecond=%.0f", Config, ttlSeconds)
108+
}
109+
110+
// PlacementRulesByGroup returns the path of PD HTTP API to get placement rules by group.
111+
func PlacementRulesByGroup(group string) string {
112+
return fmt.Sprintf("%s/%s", placementRulesByGroup, group)
113+
}
114+
115+
// PlacementRuleByGroupAndID returns the path of PD HTTP API to get placement rule by group and ID.
116+
func PlacementRuleByGroupAndID(group, id string) string {
117+
return fmt.Sprintf("%s/%s/%s", PlacementRule, group, id)
118+
}
119+
120+
// SchedulerByName returns the scheduler API with the given scheduler name.
121+
func SchedulerByName(name string) string {
122+
return fmt.Sprintf("%s/%s", Schedulers, name)
123+
}
124+
125+
// ScatterRangeSchedulerWithName returns the scatter range scheduler API with name parameter.
126+
func ScatterRangeSchedulerWithName(name string) string {
127+
return fmt.Sprintf("%s%s", scatterRangeScheduler, name)
128+
}
129+
130+
// PProfProfileAPIWithInterval returns the pprof profile API with interval parameter.
131+
func PProfProfileAPIWithInterval(interval time.Duration) string {
132+
return fmt.Sprintf("%s?seconds=%d", PProfProfile, interval/time.Second)
133+
}
134+
135+
// PProfGoroutineWithDebugLevel returns the pprof goroutine API with debug level parameter.
136+
func PProfGoroutineWithDebugLevel(level int) string {
137+
return fmt.Sprintf("%s?debug=%d", PProfGoroutine, level)
54138
}

Diff for: client/http/client.go

+58-15
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,13 @@ type Client interface {
4747
GetRegionsByStoreID(context.Context, uint64) (*RegionsInfo, error)
4848
GetHotReadRegions(context.Context) (*StoreHotPeersInfos, error)
4949
GetHotWriteRegions(context.Context) (*StoreHotPeersInfos, error)
50+
GetRegionStatusByKey(context.Context, []byte, []byte) (*RegionStats, error)
5051
GetStores(context.Context) (*StoresInfo, error)
52+
GetPlacementRulesByGroup(context.Context, string) ([]*Rule, error)
53+
SetPlacementRule(context.Context, *Rule) error
54+
DeletePlacementRule(context.Context, string, string) error
5155
GetMinResolvedTSByStoresIDs(context.Context, []uint64) (uint64, map[uint64]uint64, error)
56+
AccelerateSchedule(context.Context, []byte, []byte) error
5257
Close()
5358
}
5459

@@ -154,7 +159,7 @@ func (c *client) execDuration(name string, duration time.Duration) {
154159
// it consistent with the current implementation of some clients (e.g. TiDB).
155160
func (c *client) requestWithRetry(
156161
ctx context.Context,
157-
name, uri string,
162+
name, uri, method string,
158163
res interface{},
159164
) error {
160165
var (
@@ -163,7 +168,7 @@ func (c *client) requestWithRetry(
163168
)
164169
for idx := 0; idx < len(c.pdAddrs); idx++ {
165170
addr = c.pdAddrs[idx]
166-
err = c.request(ctx, name, addr, uri, res)
171+
err = c.request(ctx, name, fmt.Sprintf("%s%s", addr, uri), method, res)
167172
if err == nil {
168173
break
169174
}
@@ -175,16 +180,15 @@ func (c *client) requestWithRetry(
175180

176181
func (c *client) request(
177182
ctx context.Context,
178-
name, addr, uri string,
183+
name, url, method string,
179184
res interface{},
180185
) error {
181-
reqURL := fmt.Sprintf("%s%s", addr, uri)
182186
logFields := []zap.Field{
183187
zap.String("name", name),
184-
zap.String("url", reqURL),
188+
zap.String("url", url),
185189
}
186190
log.Debug("[pd] request the http url", logFields...)
187-
req, err := http.NewRequestWithContext(ctx, http.MethodGet, reqURL, nil)
191+
req, err := http.NewRequestWithContext(ctx, method, url, nil)
188192
if err != nil {
189193
log.Error("[pd] create http request failed", append(logFields, zap.Error(err))...)
190194
return errors.Trace(err)
@@ -229,7 +233,7 @@ func (c *client) request(
229233
// GetRegionByID gets the region info by ID.
230234
func (c *client) GetRegionByID(ctx context.Context, regionID uint64) (*RegionInfo, error) {
231235
var region RegionInfo
232-
err := c.requestWithRetry(ctx, "GetRegionByID", RegionByID(regionID), &region)
236+
err := c.requestWithRetry(ctx, "GetRegionByID", RegionByID(regionID), http.MethodGet, &region)
233237
if err != nil {
234238
return nil, err
235239
}
@@ -239,7 +243,7 @@ func (c *client) GetRegionByID(ctx context.Context, regionID uint64) (*RegionInf
239243
// GetRegionByKey gets the region info by key.
240244
func (c *client) GetRegionByKey(ctx context.Context, key []byte) (*RegionInfo, error) {
241245
var region RegionInfo
242-
err := c.requestWithRetry(ctx, "GetRegionByKey", RegionByKey(key), &region)
246+
err := c.requestWithRetry(ctx, "GetRegionByKey", RegionByKey(key), http.MethodGet, &region)
243247
if err != nil {
244248
return nil, err
245249
}
@@ -249,7 +253,7 @@ func (c *client) GetRegionByKey(ctx context.Context, key []byte) (*RegionInfo, e
249253
// GetRegions gets the regions info.
250254
func (c *client) GetRegions(ctx context.Context) (*RegionsInfo, error) {
251255
var regions RegionsInfo
252-
err := c.requestWithRetry(ctx, "GetRegions", Regions, &regions)
256+
err := c.requestWithRetry(ctx, "GetRegions", Regions, http.MethodGet, &regions)
253257
if err != nil {
254258
return nil, err
255259
}
@@ -259,7 +263,7 @@ func (c *client) GetRegions(ctx context.Context) (*RegionsInfo, error) {
259263
// GetRegionsByKey gets the regions info by key range. If the limit is -1, it will return all regions within the range.
260264
func (c *client) GetRegionsByKey(ctx context.Context, startKey, endKey []byte, limit int) (*RegionsInfo, error) {
261265
var regions RegionsInfo
262-
err := c.requestWithRetry(ctx, "GetRegionsByKey", RegionsByKey(startKey, endKey, limit), &regions)
266+
err := c.requestWithRetry(ctx, "GetRegionsByKey", RegionsByKey(startKey, endKey, limit), http.MethodGet, &regions)
263267
if err != nil {
264268
return nil, err
265269
}
@@ -269,7 +273,7 @@ func (c *client) GetRegionsByKey(ctx context.Context, startKey, endKey []byte, l
269273
// GetRegionsByStoreID gets the regions info by store ID.
270274
func (c *client) GetRegionsByStoreID(ctx context.Context, storeID uint64) (*RegionsInfo, error) {
271275
var regions RegionsInfo
272-
err := c.requestWithRetry(ctx, "GetRegionsByStoreID", RegionsByStoreID(storeID), &regions)
276+
err := c.requestWithRetry(ctx, "GetRegionsByStoreID", RegionsByStoreID(storeID), http.MethodGet, &regions)
273277
if err != nil {
274278
return nil, err
275279
}
@@ -279,7 +283,7 @@ func (c *client) GetRegionsByStoreID(ctx context.Context, storeID uint64) (*Regi
279283
// GetHotReadRegions gets the hot read region statistics info.
280284
func (c *client) GetHotReadRegions(ctx context.Context) (*StoreHotPeersInfos, error) {
281285
var hotReadRegions StoreHotPeersInfos
282-
err := c.requestWithRetry(ctx, "GetHotReadRegions", HotRead, &hotReadRegions)
286+
err := c.requestWithRetry(ctx, "GetHotReadRegions", HotRead, http.MethodGet, &hotReadRegions)
283287
if err != nil {
284288
return nil, err
285289
}
@@ -289,23 +293,57 @@ func (c *client) GetHotReadRegions(ctx context.Context) (*StoreHotPeersInfos, er
289293
// GetHotWriteRegions gets the hot write region statistics info.
290294
func (c *client) GetHotWriteRegions(ctx context.Context) (*StoreHotPeersInfos, error) {
291295
var hotWriteRegions StoreHotPeersInfos
292-
err := c.requestWithRetry(ctx, "GetHotWriteRegions", HotWrite, &hotWriteRegions)
296+
err := c.requestWithRetry(ctx, "GetHotWriteRegions", HotWrite, http.MethodGet, &hotWriteRegions)
293297
if err != nil {
294298
return nil, err
295299
}
296300
return &hotWriteRegions, nil
297301
}
298302

303+
// GetRegionStatusByKey gets the region status by key range.
304+
func (c *client) GetRegionStatusByKey(ctx context.Context, startKey, endKey []byte) (*RegionStats, error) {
305+
var regionStats RegionStats
306+
err := c.requestWithRetry(
307+
ctx, "GetRegionStatusByKey",
308+
RegionStatsByStartEndKey(string(startKey), string(endKey)), http.MethodGet,
309+
&regionStats,
310+
)
311+
if err != nil {
312+
return nil, err
313+
}
314+
return &regionStats, nil
315+
}
316+
299317
// GetStores gets the stores info.
300318
func (c *client) GetStores(ctx context.Context) (*StoresInfo, error) {
301319
var stores StoresInfo
302-
err := c.requestWithRetry(ctx, "GetStores", Stores, &stores)
320+
err := c.requestWithRetry(ctx, "GetStores", Stores, http.MethodGet, &stores)
303321
if err != nil {
304322
return nil, err
305323
}
306324
return &stores, nil
307325
}
308326

327+
// GetPlacementRulesByGroup gets the placement rules by group.
328+
func (c *client) GetPlacementRulesByGroup(ctx context.Context, group string) ([]*Rule, error) {
329+
var rules []*Rule
330+
err := c.requestWithRetry(ctx, "GetPlacementRulesByGroup", PlacementRulesByGroup(group), http.MethodGet, &rules)
331+
if err != nil {
332+
return nil, err
333+
}
334+
return rules, nil
335+
}
336+
337+
// SetPlacementRule sets the placement rule.
338+
func (c *client) SetPlacementRule(ctx context.Context, rule *Rule) error {
339+
return c.requestWithRetry(ctx, "SetPlacementRule", PlacementRule, http.MethodPost, nil)
340+
}
341+
342+
// DeletePlacementRule deletes the placement rule.
343+
func (c *client) DeletePlacementRule(ctx context.Context, group, id string) error {
344+
return c.requestWithRetry(ctx, "DeletePlacementRule", PlacementRuleByGroupAndID(group, id), http.MethodDelete, nil)
345+
}
346+
309347
// GetMinResolvedTSByStoresIDs get min-resolved-ts by stores IDs.
310348
func (c *client) GetMinResolvedTSByStoresIDs(ctx context.Context, storeIDs []uint64) (uint64, map[uint64]uint64, error) {
311349
uri := MinResolvedTSPrefix
@@ -326,7 +364,7 @@ func (c *client) GetMinResolvedTSByStoresIDs(ctx context.Context, storeIDs []uin
326364
IsRealTime bool `json:"is_real_time,omitempty"`
327365
StoresMinResolvedTS map[uint64]uint64 `json:"stores_min_resolved_ts"`
328366
}{}
329-
err := c.requestWithRetry(ctx, "GetMinResolvedTSByStoresIDs", uri, &resp)
367+
err := c.requestWithRetry(ctx, "GetMinResolvedTSByStoresIDs", uri, http.MethodGet, &resp)
330368
if err != nil {
331369
return 0, nil, err
332370
}
@@ -335,3 +373,8 @@ func (c *client) GetMinResolvedTSByStoresIDs(ctx context.Context, storeIDs []uin
335373
}
336374
return resp.MinResolvedTS, resp.StoresMinResolvedTS, nil
337375
}
376+
377+
// AccelerateSchedule accelerates the scheduling of the regions within the given key range.
378+
func (c *client) AccelerateSchedule(ctx context.Context, startKey, endKey []byte) error {
379+
return c.requestWithRetry(ctx, "AccelerateSchedule", accelerateSchedule, http.MethodPost, nil)
380+
}

Diff for: client/http/types.go

+64
Original file line numberDiff line numberDiff line change
@@ -176,3 +176,67 @@ type StoreStatus struct {
176176
LastHeartbeatTS time.Time `json:"last_heartbeat_ts"`
177177
Uptime string `json:"uptime"`
178178
}
179+
180+
// RegionStats stores the statistics of regions.
181+
type RegionStats struct {
182+
Count int `json:"count"`
183+
EmptyCount int `json:"empty_count"`
184+
StorageSize int64 `json:"storage_size"`
185+
StorageKeys int64 `json:"storage_keys"`
186+
StoreLeaderCount map[uint64]int `json:"store_leader_count"`
187+
StorePeerCount map[uint64]int `json:"store_peer_count"`
188+
}
189+
190+
// PeerRoleType is the expected peer type of the placement rule.
191+
type PeerRoleType string
192+
193+
const (
194+
// Voter can either match a leader peer or follower peer
195+
Voter PeerRoleType = "voter"
196+
// Leader matches a leader.
197+
Leader PeerRoleType = "leader"
198+
// Follower matches a follower.
199+
Follower PeerRoleType = "follower"
200+
// Learner matches a learner.
201+
Learner PeerRoleType = "learner"
202+
)
203+
204+
// LabelConstraint is used to filter store when trying to place peer of a region.
205+
type LabelConstraint struct {
206+
Key string `json:"key,omitempty"`
207+
Op LabelConstraintOp `json:"op,omitempty"`
208+
Values []string `json:"values,omitempty"`
209+
}
210+
211+
// LabelConstraintOp defines how a LabelConstraint matches a store. It can be one of
212+
// 'in', 'notIn', 'exists', or 'notExists'.
213+
type LabelConstraintOp string
214+
215+
const (
216+
// In restricts the store label value should in the value list.
217+
// If label does not exist, `in` is always false.
218+
In LabelConstraintOp = "in"
219+
// NotIn restricts the store label value should not in the value list.
220+
// If label does not exist, `notIn` is always true.
221+
NotIn LabelConstraintOp = "notIn"
222+
// Exists restricts the store should have the label.
223+
Exists LabelConstraintOp = "exists"
224+
// NotExists restricts the store should not have the label.
225+
NotExists LabelConstraintOp = "notExists"
226+
)
227+
228+
// Rule is the placement rule that can be checked against a region. When
229+
// applying rules (apply means schedule regions to match selected rules), the
230+
// apply order is defined by the tuple [GroupIndex, GroupID, Index, ID].
231+
type Rule struct {
232+
GroupID string `json:"group_id"`
233+
ID string `json:"id"`
234+
Index int `json:"index,omitempty"`
235+
Override bool `json:"override,omitempty"`
236+
StartKeyHex string `json:"start_key"`
237+
EndKeyHex string `json:"end_key"`
238+
Role PeerRoleType `json:"role"`
239+
Count int `json:"count"`
240+
Constraints LabelConstraint `json:"label_constraints,omitempty"`
241+
LocationLabels []string `json:"location_labels,omitempty"`
242+
}

0 commit comments

Comments
 (0)