-
Notifications
You must be signed in to change notification settings - Fork 756
apiv2: keyspace management #5313
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
105 commits
Select commit
Hold shift + click to select a range
54a9a53
storage: keyspace storage
AmoebaProtozoa 235d463
storage: encode spaceID string as base 10
AmoebaProtozoa 2008600
storage: add save/load keyspace ID
AmoebaProtozoa 78ee5c6
server: keyspace
AmoebaProtozoa 01bb8e1
make id allocator more general purporse
AmoebaProtozoa 406a79f
use new idAllocator
AmoebaProtozoa 60b72e9
added tests
AmoebaProtozoa 4a7a4d2
Merge branch 'tikv:master' into keyspace_server
AmoebaProtozoa e3de2be
server: added concurrent update tests
AmoebaProtozoa 6782d26
client: keyspace client
AmoebaProtozoa 7d1fa32
server: fix updare and create request
AmoebaProtozoa d3d0dc8
server: fix updare and create request
AmoebaProtozoa db42ebf
storage: remove keyspace
AmoebaProtozoa f3e0e65
server: change create keyspace order
AmoebaProtozoa b6c248d
API: basic implementation
AmoebaProtozoa 2311533
API: added swaggo annotations
AmoebaProtozoa 27ba850
update comments
AmoebaProtozoa 253b2c7
address comments
AmoebaProtozoa 43632d9
move helper functions to utils.go
AmoebaProtozoa 812e38e
Merge branch 'keyspace_server' of github.com:AmoebaProtozoa/pd into k…
AmoebaProtozoa ff7718d
get keyspace manager
AmoebaProtozoa a97405d
get keyspace manager
AmoebaProtozoa ee5a028
server: fix watch
AmoebaProtozoa f7e13fb
client: added integration tests
AmoebaProtozoa 90f8dbf
server: fix watch
AmoebaProtozoa baf49ca
Merge branch 'keyspace_client' of github.com:AmoebaProtozoa/pd into k…
AmoebaProtozoa 3af3d55
update update apis
AmoebaProtozoa 09e8526
server: fix case where request does not contain initial config
AmoebaProtozoa 1ca5ebc
api: use updated design
AmoebaProtozoa 299f612
api: use updated design
AmoebaProtozoa abad762
Merge branch 'tikv:master' into keyspace_api
AmoebaProtozoa a983476
added JSON unmarshall method to handler request
AmoebaProtozoa 2445ca1
added API Integration tests
AmoebaProtozoa 32a29c6
update state integration test
AmoebaProtozoa 73930f9
Merge branch 'master' of github.com:tikv/pd into keyspace_server
AmoebaProtozoa 7e0c73b
server: initi default keyspace
AmoebaProtozoa 15b8085
Merge branch 'keyspace_server' of github.com:AmoebaProtozoa/pd into k…
AmoebaProtozoa b3fce35
client: removed update config rpc, added default keyspace tests
AmoebaProtozoa 0200684
Merge branch 'keyspace_client' of github.com:AmoebaProtozoa/pd into k…
AmoebaProtozoa 156d046
Merge branch 'master' of github.com:tikv/pd into keyspace_api
AmoebaProtozoa fbe2581
api: fix tests
AmoebaProtozoa dec67b5
added RunInTxn style interface to base kv
AmoebaProtozoa 898b2d1
added unit tests
AmoebaProtozoa 290487b
server: export default keyspace name and id
AmoebaProtozoa 7df25aa
client: use exported default keyspace
AmoebaProtozoa 4a4c4db
api: add unit test for load all
AmoebaProtozoa 8c61ff2
update comments
AmoebaProtozoa cf54caf
Merge branch 'master' into RunInTxn
AmoebaProtozoa 5811b0d
storage: fix lint
AmoebaProtozoa a96fd68
server: export default keyspace name and id
AmoebaProtozoa 29da7ff
client: use exported default keyspace
AmoebaProtozoa 7cc5a59
server: export default keyspace name and id
AmoebaProtozoa 2bd8eac
storage: fix lint
AmoebaProtozoa 3a4426b
storage: fix lint
AmoebaProtozoa 3fbd8e2
server: fix lint
AmoebaProtozoa 7ada7b9
Merge branch 'keyspace_server' of github.com:AmoebaProtozoa/pd into k…
AmoebaProtozoa d205a80
fmt
AmoebaProtozoa d64d8fd
Merge branch 'keyspace_client' of github.com:AmoebaProtozoa/pd into k…
AmoebaProtozoa 04961f7
fix lint
AmoebaProtozoa a6f2521
change update config to follow apiv2 standard
AmoebaProtozoa 7d8760c
use lock group to control keyspace concurrency
AmoebaProtozoa 20d6ed5
Merge branch 'keyspace_server' of github.com:AmoebaProtozoa/pd into k…
AmoebaProtozoa 6f5a8ff
Merge branch 'master' of github.com:tikv/pd into keyspace_server
AmoebaProtozoa 26990e4
typo fix
AmoebaProtozoa 834116b
lower lockgroup test concurrency for ci test
AmoebaProtozoa fab7886
address comments
AmoebaProtozoa f4d66f1
let keyspace service wrap GrpcService, add cluster id check
AmoebaProtozoa 7360193
make lockGroup more general
AmoebaProtozoa 0753820
Merge branch 'keyspace_server' of github.com:AmoebaProtozoa/pd into k…
AmoebaProtozoa 9383b4c
Merge branch 'keyspace_client' of github.com:AmoebaProtozoa/pd into k…
AmoebaProtozoa 517b990
added init keyspace check
AmoebaProtozoa 23cdc0a
fixed dial client leak
AmoebaProtozoa 9b274df
lower lockgroup test concurrency
AmoebaProtozoa e91776c
cleanup cluster before watch keyspace test
AmoebaProtozoa bbac817
typo fix
AmoebaProtozoa bd6b9ac
reinstate checks for leadership
AmoebaProtozoa 9dda292
reformat import for client
AmoebaProtozoa 57c178a
Merge branch 'master' of github.com:tikv/pd into keyspace_api
AmoebaProtozoa af3d314
update keyspace api to new manager requests
AmoebaProtozoa a31704e
update keyspace api to RESTful
AmoebaProtozoa a6e0cbb
Merge branch 'master' of github.com:tikv/pd into keyspace_api
AmoebaProtozoa 2dca250
swag fmt
AmoebaProtozoa 05cf81c
address comments
AmoebaProtozoa 0ad3539
Merge remote-tracking branch 'upstream/master' into RunInTxn
AmoebaProtozoa be81039
sort import
AmoebaProtozoa d98d3d2
Merge branch 'master' into RunInTxn
AmoebaProtozoa 149ce0c
pin create revision when key not exist
AmoebaProtozoa d5f462e
init commit
AmoebaProtozoa dfaa8cd
fix test
AmoebaProtozoa 3106c83
Merge remote-tracking branch 'upstream/master' into RefactorKeyspaceM…
AmoebaProtozoa b65de48
fix test
AmoebaProtozoa 2b61a68
Merge branch 'RefactorKeyspaceManager' into keyspace_api
AmoebaProtozoa c6e1a58
fix test
AmoebaProtozoa fefea02
update kvproto go mod
AmoebaProtozoa 8840e9e
Merge branch 'master' into keyspace_api
AmoebaProtozoa 85a85c8
Merge remote-tracking branch 'upstream/master' into keyspace_api
AmoebaProtozoa 62f7c16
remove unused manager method
AmoebaProtozoa 59e3ac9
Merge branch 'master' into keyspace_api
AmoebaProtozoa 3f3618b
Merge branch 'master' into keyspace_api
AmoebaProtozoa 352a3ef
Merge branch 'master' into keyspace_api
AmoebaProtozoa 5ea4cb6
Merge branch 'master' into keyspace_api
AmoebaProtozoa 3ac722b
address comments
AmoebaProtozoa 0e84e4c
Merge branch 'master' into keyspace_api
ti-chi-bot 186a821
empty commit to trigger ci
AmoebaProtozoa 52547cd
Merge branch 'master' into keyspace_api
ti-chi-bot File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,341 @@ | ||
| // Copyright 2023 TiKV Project Authors. | ||
| // | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file except in compliance with the License. | ||
| // You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, software | ||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
|
|
||
| package handlers | ||
|
|
||
| import ( | ||
| "encoding/json" | ||
| "net/http" | ||
| "strconv" | ||
| "strings" | ||
| "time" | ||
|
|
||
| "github.com/gin-gonic/gin" | ||
| "github.com/pingcap/errors" | ||
| "github.com/pingcap/kvproto/pkg/keyspacepb" | ||
| "github.com/tikv/pd/pkg/errs" | ||
| "github.com/tikv/pd/server" | ||
| "github.com/tikv/pd/server/apiv2/middlewares" | ||
| "github.com/tikv/pd/server/keyspace" | ||
| ) | ||
|
|
||
| // RegisterKeyspace register keyspace related handlers to router paths. | ||
| func RegisterKeyspace(r *gin.RouterGroup) { | ||
| router := r.Group("keyspaces") | ||
| router.Use(middlewares.BootstrapChecker()) | ||
| router.POST("", CreateKeyspace) | ||
| router.GET("", LoadAllKeyspaces) | ||
| router.GET("/:name", LoadKeyspace) | ||
| router.PATCH("/:name/config", UpdateKeyspaceConfig) | ||
| router.PUT("/:name/state", UpdateKeyspaceState) | ||
| } | ||
|
|
||
| // CreateKeyspaceParams represents parameters needed when creating a new keyspace. | ||
| // NOTE: This type is exported by HTTP API. Please pay more attention when modifying it. | ||
| type CreateKeyspaceParams struct { | ||
| Name string `json:"name"` | ||
| Config map[string]string `json:"config"` | ||
| } | ||
|
|
||
| // CreateKeyspace creates keyspace according to given input. | ||
| // @Tags keyspaces | ||
| // @Summary Create new keyspace. | ||
| // @Param body body CreateKeyspaceParams true "Create keyspace parameters" | ||
| // @Produce json | ||
| // @Success 200 {object} KeyspaceMeta | ||
| // @Failure 400 {string} string "The input is invalid." | ||
| // @Failure 500 {string} string "PD server failed to proceed the request." | ||
| // @Router /keyspaces [post] | ||
| func CreateKeyspace(c *gin.Context) { | ||
| svr := c.MustGet("server").(*server.Server) | ||
| manager := svr.GetKeyspaceManager() | ||
| createParams := &CreateKeyspaceParams{} | ||
| err := c.BindJSON(createParams) | ||
| if err != nil { | ||
| c.AbortWithStatusJSON(http.StatusBadRequest, errs.ErrBindJSON.Wrap(err).GenWithStackByCause()) | ||
| return | ||
| } | ||
| req := &keyspace.CreateKeyspaceRequest{ | ||
| Name: createParams.Name, | ||
| Config: createParams.Config, | ||
| Now: time.Now().Unix(), | ||
| } | ||
| meta, err := manager.CreateKeyspace(req) | ||
| if err != nil { | ||
| c.AbortWithStatusJSON(http.StatusInternalServerError, err.Error()) | ||
| return | ||
| } | ||
| c.IndentedJSON(http.StatusOK, &KeyspaceMeta{meta}) | ||
| } | ||
|
|
||
| // LoadKeyspace returns target keyspace. | ||
| // @Tags keyspaces | ||
| // @Summary Get keyspace info. | ||
| // @Param name path string true "Keyspace Name" | ||
| // @Produce json | ||
| // @Success 200 {object} KeyspaceMeta | ||
| // @Failure 500 {string} string "PD server failed to proceed the request." | ||
| // @Router /keyspaces/{name} [get] | ||
| func LoadKeyspace(c *gin.Context) { | ||
| svr := c.MustGet("server").(*server.Server) | ||
| manager := svr.GetKeyspaceManager() | ||
| name := c.Param("name") | ||
| meta, err := manager.LoadKeyspace(name) | ||
| if err != nil { | ||
| c.AbortWithStatusJSON(http.StatusInternalServerError, err.Error()) | ||
| return | ||
| } | ||
| c.IndentedJSON(http.StatusOK, &KeyspaceMeta{meta}) | ||
| } | ||
|
|
||
| // parseLoadAllQuery parses LoadAllKeyspaces' query parameters. | ||
| // page_token: | ||
| // The keyspace id of the scan start. If not set, scan from keyspace with id 1. | ||
| // It's string of spaceID of the previous scan result's last element (next_page_token). | ||
| // limit: | ||
| // The maximum number of keyspace metas to return. If not set, no limit is posed. | ||
| // Every scan scans limit + 1 keyspaces (if limit != 0), the extra scanned keyspace | ||
| // is to check if there's more, and used to set next_page_token in response. | ||
| func parseLoadAllQuery(c *gin.Context) (scanStart uint32, scanLimit int, err error) { | ||
| pageToken, set := c.GetQuery("page_token") | ||
| if !set || pageToken == "" { | ||
| // If pageToken is empty or unset, then scan from spaceID of 1. | ||
| scanStart = 0 | ||
| } else { | ||
| scanStart64, err := strconv.ParseUint(pageToken, 10, 32) | ||
| if err != nil { | ||
| return 0, 0, err | ||
| } | ||
| scanStart = uint32(scanStart64) | ||
| } | ||
|
|
||
| limitStr, set := c.GetQuery("limit") | ||
| if !set || limitStr == "" || limitStr == "0" { | ||
| // If limit is unset or empty or 0, then no limit is posed for scan. | ||
| scanLimit = 0 | ||
| } else { | ||
| scanLimit64, err := strconv.ParseInt(limitStr, 10, 64) | ||
| if err != nil { | ||
| return 0, 0, err | ||
| } | ||
| // Scan an extra element for next_page_token. | ||
| scanLimit = int(scanLimit64) + 1 | ||
| } | ||
|
|
||
| return scanStart, scanLimit, nil | ||
| } | ||
|
|
||
| // LoadAllKeyspacesResponse represents response given when loading all keyspaces. | ||
| // NOTE: This type is exported by HTTP API. Please pay more attention when modifying it. | ||
| type LoadAllKeyspacesResponse struct { | ||
| Keyspaces []*KeyspaceMeta `json:"keyspaces"` | ||
| // Token that can be used to read immediate next page. | ||
| // If it's empty, then end has been reached. | ||
| NextPageToken string `json:"next_page_token"` | ||
| } | ||
|
|
||
| // LoadAllKeyspaces loads range of keyspaces. | ||
| // @Tags keyspaces | ||
| // @Summary list keyspaces. | ||
| // @Param page_token query string false "page token" | ||
| // @Param limit query string false "maximum number of results to return" | ||
| // @Produce json | ||
| // @Success 200 {object} LoadAllKeyspacesResponse | ||
| // @Failure 400 {string} string "The input is invalid." | ||
| // @Failure 500 {string} string "PD server failed to proceed the request." | ||
| // @Router /keyspaces [get] | ||
| func LoadAllKeyspaces(c *gin.Context) { | ||
| svr := c.MustGet("server").(*server.Server) | ||
| manager := svr.GetKeyspaceManager() | ||
| scanStart, scanLimit, err := parseLoadAllQuery(c) | ||
| if err != nil { | ||
| c.AbortWithStatusJSON(http.StatusBadRequest, err.Error()) | ||
| return | ||
| } | ||
| scanned, err := manager.LoadRangeKeyspace(scanStart, scanLimit) | ||
| if err != nil { | ||
| c.AbortWithStatusJSON(http.StatusInternalServerError, err.Error()) | ||
| return | ||
| } | ||
| resp := &LoadAllKeyspacesResponse{} | ||
| // If scanned 0 keyspaces, return result immediately. | ||
| if len(scanned) == 0 { | ||
| c.IndentedJSON(http.StatusOK, resp) | ||
| return | ||
| } | ||
| var resultKeyspaces []*KeyspaceMeta | ||
| if scanLimit == 0 || len(scanned) < scanLimit { | ||
| // No next page, all scanned are results. | ||
| resultKeyspaces = make([]*KeyspaceMeta, len(scanned)) | ||
| for i, meta := range scanned { | ||
| resultKeyspaces[i] = &KeyspaceMeta{meta} | ||
| } | ||
| } else { | ||
| // Scanned limit + 1 keyspaces, there is next page, all but last are results. | ||
| resultKeyspaces = make([]*KeyspaceMeta, len(scanned)-1) | ||
| for i := range resultKeyspaces { | ||
| resultKeyspaces[i] = &KeyspaceMeta{scanned[i]} | ||
| } | ||
| // Also set next_page_token here. | ||
| resp.NextPageToken = strconv.Itoa(int(scanned[len(scanned)-1].Id)) | ||
| } | ||
| resp.Keyspaces = resultKeyspaces | ||
| c.IndentedJSON(http.StatusOK, resp) | ||
| } | ||
|
|
||
| // UpdateConfigParams represents parameters needed to modify target keyspace's configs. | ||
| // NOTE: This type is exported by HTTP API. Please pay more attention when modifying it. | ||
| // A Map of string to string pointer is used to differentiate between json null and "", | ||
| // which will both be set to "" if value type is string during binding. | ||
| type UpdateConfigParams struct { | ||
| Config map[string]*string `json:"config"` | ||
| } | ||
|
|
||
| // UpdateKeyspaceConfig updates target keyspace's config. | ||
| // This api uses PATCH semantic and supports JSON Merge Patch. | ||
| // format and processing rules. | ||
| // @Tags keyspaces | ||
| // @Summary Update keyspace config. | ||
| // @Param name path string true "Keyspace Name" | ||
| // @Param body body UpdateConfigParams true "Update keyspace parameters" | ||
| // @Produce json | ||
| // @Success 200 {object} KeyspaceMeta | ||
| // @Failure 400 {string} string "The input is invalid." | ||
| // @Failure 500 {string} string "PD server failed to proceed the request." | ||
| // Router /keyspaces/{name}/config [patch] | ||
| func UpdateKeyspaceConfig(c *gin.Context) { | ||
| svr := c.MustGet("server").(*server.Server) | ||
| manager := svr.GetKeyspaceManager() | ||
| name := c.Param("name") | ||
| configParams := &UpdateConfigParams{} | ||
| err := c.BindJSON(configParams) | ||
| if err != nil { | ||
| c.AbortWithStatusJSON(http.StatusBadRequest, errs.ErrBindJSON.Wrap(err).GenWithStackByCause()) | ||
| return | ||
| } | ||
| mutations := getMutations(configParams.Config) | ||
| meta, err := manager.UpdateKeyspaceConfig(name, mutations) | ||
| if err != nil { | ||
| c.AbortWithStatusJSON(http.StatusInternalServerError, err.Error()) | ||
| return | ||
| } | ||
| c.IndentedJSON(http.StatusOK, &KeyspaceMeta{meta}) | ||
| } | ||
|
|
||
| // getMutations converts a given JSON merge patch to a series of keyspace config mutations. | ||
| func getMutations(patch map[string]*string) []*keyspace.Mutation { | ||
| mutations := make([]*keyspace.Mutation, 0, len(patch)) | ||
| for k, v := range patch { | ||
| if v == nil { | ||
| mutations = append(mutations, &keyspace.Mutation{ | ||
| Op: keyspace.OpDel, | ||
| Key: k, | ||
| }) | ||
| } else { | ||
| mutations = append(mutations, &keyspace.Mutation{ | ||
| Op: keyspace.OpPut, | ||
| Key: k, | ||
| Value: *v, | ||
| }) | ||
| } | ||
| } | ||
| return mutations | ||
| } | ||
|
|
||
| // UpdateStateParam represents parameters needed to modify target keyspace's state. | ||
| // NOTE: This type is exported by HTTP API. Please pay more attention when modifying it. | ||
| type UpdateStateParam struct { | ||
| State string `json:"state"` | ||
| } | ||
|
|
||
| // UpdateKeyspaceState update the target keyspace's state. | ||
| // @Tags keyspaces | ||
| // @Summary Update keyspace state. | ||
| // @Param name path string true "Keyspace Name" | ||
| // @Param body body UpdateStateParam true "New state for the keyspace" | ||
| // @Produce json | ||
| // @Success 200 {object} KeyspaceMeta | ||
| // @Failure 400 {string} string "The input is invalid." | ||
| // @Failure 500 {string} string "PD server failed to proceed the request." | ||
| // Router /keyspaces/{name}/state [put] | ||
| func UpdateKeyspaceState(c *gin.Context) { | ||
| svr := c.MustGet("server").(*server.Server) | ||
| manager := svr.GetKeyspaceManager() | ||
| name := c.Param("name") | ||
| param := &UpdateStateParam{} | ||
| err := c.BindJSON(param) | ||
| if err != nil { | ||
| c.AbortWithStatusJSON(http.StatusBadRequest, errs.ErrBindJSON.Wrap(err).GenWithStackByCause()) | ||
| return | ||
| } | ||
| targetState, ok := keyspacepb.KeyspaceState_value[strings.ToUpper(param.State)] | ||
| if !ok { | ||
| c.AbortWithStatusJSON(http.StatusBadRequest, errors.Errorf("unknown target state: %s", param.State)) | ||
AmoebaProtozoa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| return | ||
| } | ||
| meta, err := manager.UpdateKeyspaceState(name, keyspacepb.KeyspaceState(targetState), time.Now().Unix()) | ||
| if err != nil { | ||
| c.AbortWithStatusJSON(http.StatusInternalServerError, err.Error()) | ||
| return | ||
| } | ||
| c.IndentedJSON(http.StatusOK, &KeyspaceMeta{meta}) | ||
| } | ||
|
|
||
| // KeyspaceMeta wraps keyspacepb.KeyspaceMeta to provide custom JSON marshal. | ||
| type KeyspaceMeta struct { | ||
| *keyspacepb.KeyspaceMeta | ||
| } | ||
|
|
||
| // MarshalJSON creates custom marshal of KeyspaceMeta with the following: | ||
| // 1. Keyspace ID are removed from marshal result to avoid exposure of internal mechanics. | ||
| // 2. Keyspace State are marshaled to their corresponding name for better readability. | ||
| func (meta *KeyspaceMeta) MarshalJSON() ([]byte, error) { | ||
| return json.Marshal(&struct { | ||
| Name string `json:"name,omitempty"` | ||
| State string `json:"state,omitempty"` | ||
| CreatedAt int64 `json:"created_at,omitempty"` | ||
| StateChangedAt int64 `json:"state_changed_at,omitempty"` | ||
| Config map[string]string `json:"config,omitempty"` | ||
| }{ | ||
| meta.Name, | ||
| meta.State.String(), | ||
| meta.CreatedAt, | ||
| meta.StateChangedAt, | ||
| meta.Config, | ||
| }) | ||
| } | ||
|
|
||
| // UnmarshalJSON reverse KeyspaceMeta's the Custom JSON marshal. | ||
| func (meta *KeyspaceMeta) UnmarshalJSON(data []byte) error { | ||
| aux := &struct { | ||
| Name string `json:"name,omitempty"` | ||
| State string `json:"state,omitempty"` | ||
| CreatedAt int64 `json:"created_at,omitempty"` | ||
| StateChangedAt int64 `json:"state_changed_at,omitempty"` | ||
| Config map[string]string `json:"config,omitempty"` | ||
| }{} | ||
|
|
||
| if err := json.Unmarshal(data, aux); err != nil { | ||
| return err | ||
| } | ||
| pbMeta := &keyspacepb.KeyspaceMeta{ | ||
| Name: aux.Name, | ||
| State: keyspacepb.KeyspaceState(keyspacepb.KeyspaceState_value[aux.State]), | ||
| CreatedAt: aux.CreatedAt, | ||
| StateChangedAt: aux.StateChangedAt, | ||
| Config: aux.Config, | ||
| } | ||
| meta.KeyspaceMeta = pbMeta | ||
| return nil | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.