Navigation Menu

Skip to content
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

Add basic resharding record migration logic for new cluster (no GC yet) #21

Merged
merged 9 commits into from Jun 7, 2020

Conversation

cy-b
Copy link
Contributor

@cy-b cy-b commented May 30, 2020

Basic function for migrating RRs from old clusters to the new cluster and updates config at hash servers.

Example command for a new cluster to start migration:
sudo ./dns_server -migrate -hash "172.31.30.97" -config ./new_config.json -port 9121 -cluster "http://172.31.19.166:12379"

Some functions are not implemented and I will discuss these functions with who picks these tasks:

  • Enable/Disable write requests at hash server side.
  • Garbage collection of migrated RRs at the old Raft clusters.

@cy-b cy-b requested a review from kevinkassimo May 30, 2020 04:22
Copy link
Contributor

@kevinkassimo kevinkassimo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some comments to address

dns/httpapi.go Outdated
@@ -119,6 +196,110 @@ func serveHTTPAPI(store *dnsStore, port int, confChangeC chan<- raftpb.ConfChang
w.WriteHeader(http.StatusNoContent)
})

// TODO: confChange requests
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this TODO: confChange comments. Instead, add a bit more comment about how /addcluster is called (see the format I had for other routes)

dns/httpapi.go Outdated
w.WriteHeader(http.StatusNoContent)
})

// TODO: confChange requests
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment ditto (ditto means similar to above)

RecordsMap dnsRRTypeMap
}

router.HandleFunc("/getrecord", func(w http.ResponseWriter, r *http.Request) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto for usage comments (for example, the body is a number for index, etc.)

dns/httpapi.go Outdated

body, err := ioutil.ReadAll(r.Body)
if err != nil {
log.Printf("Cannot read /addcluster body: %v\n", err)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/addcluster/getrecord

log.Fatal(err)
}
// update cluster info in dnsStore
store.config = jsonClusters
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

read/write lock the store. Similar for many places below.
(Be careful, Go locks are not reentrant and thus can self deadlock)

dns/httpapi.go Outdated
return string(t)
}

// func (h *dnsHTTPAPI) ServeHTTP(w http.ResponseWriter, r *http.Request) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this commented section, since membership update is already implemented.

log.Println("Domain is ", domain)
// log.Println(store.lookup.LocateKey([]byte(domain)).String())
if shouldMigrate(domain, store) {
for _, rrs := range store.store[domainNames[index]] {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to be careful with lock granularity (to avoid blocking normal DNS read requests serving)

Also this API does not seem to do streaming (and thus response body will be huge with large JSON parsing overhead), but I guess I will also let it pass for initial implementation. Leave a comment to warn about this problem though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are locks needed here? The assumption (implied by the new cluster node's migration logic) is that writes at hash servers are disabled at this point, so all operations should be reads.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better still grab the read lock. It is fine to have multiple read locks held anyways.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added read lock around the entire if statement since shouldMigrate() also accesses store.

@@ -48,6 +49,10 @@ type dnsStore struct {
// for sending http Cache requests
cluster []string
id int
// for adding new cluster and migration
config []jsonClusterInfo
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This differs from what I originally thought of (with state temporarily maintained in dedicated thread instead of becoming part of the store state), but I'll also probably give this a pass for initial attempt.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that definitely sounds better, no need to change the store state.

return
}
// this is async, might cause too much traffic
store.ProposeAddRR(rrString)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a small comment to explain why locks are not needed here (due to proposals done through the channel)

migrate := flag.Bool("migrate", false, "need to coordinate migration")
// include the port in hash server ip addr
hashServer := flag.String("hash", "", "the ip address of a hash server to help with migration")
config := flag.String("config", "", "the path to the json file containing the config for this cluster")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a comment to explain the format of the config (mostly how it is different from hash_server config)

@kevinkassimo kevinkassimo changed the title Cb/migration Add basic resharding record migration logic for new cluster (no GC yet) May 31, 2020
@kevinkassimo
Copy link
Contributor

Also I believe this code is not yet tested? (seems the logic for disabling/reenabling writes is not actually implemented). Be sure to do a minimum test before final merge.

@cy-b cy-b requested a review from kevinkassimo June 2, 2020 18:47
Copy link
Contributor

@kevinkassimo kevinkassimo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are still some lock issues

}

// update cluster info in dnsStore
store.clusters = intoClusterMap(jsonClusters)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Locks here too?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes boss

Hasher: hasher{},
}
log.Println("Received cluster update, setting new config")
store.lookup = consistent.New(nil, cfg)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Locks ditto.

log.Println("Received cluster update, setting new config")
store.lookup = consistent.New(nil, cfg)
for _, clusterJSON := range store.config {
store.lookup.Add(clusterToken(clusterJSON.ClusterToken))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lock ditto

log.Println("Domain is ", domain)
// log.Println(store.lookup.LocateKey([]byte(domain)).String())
if shouldMigrate(domain, store) {
for _, rrs := range store.store[domainNames[index]] {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better still grab the read lock. It is fine to have multiple read locks held anyways.

@cy-b cy-b requested a review from kevinkassimo June 7, 2020 18:43
Copy link
Contributor

@kevinkassimo kevinkassimo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@kevinkassimo kevinkassimo merged commit 7af2c8d into master Jun 7, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants