aboutsummaryrefslogtreecommitdiff
path: root/weed/server/master_grpc_server_admin.go
diff options
context:
space:
mode:
authorChris Lu <chris.lu@gmail.com>2020-04-23 01:55:44 -0700
committerChris Lu <chris.lu@gmail.com>2020-04-23 01:55:44 -0700
commit77873b832be692a791c3b17b079a0d14bd317bcd (patch)
tree846bb1ee5f24d46dab474c258b4a578b2bf3ed7d /weed/server/master_grpc_server_admin.go
parent369aa8a10aa51e5ba529a58cb402b6fa0a3ef666 (diff)
downloadseaweedfs-77873b832be692a791c3b17b079a0d14bd317bcd.tar.xz
seaweedfs-77873b832be692a791c3b17b079a0d14bd317bcd.zip
add master side code for cluster wise exclusive lock
Diffstat (limited to 'weed/server/master_grpc_server_admin.go')
-rw-r--r--weed/server/master_grpc_server_admin.go107
1 files changed, 107 insertions, 0 deletions
diff --git a/weed/server/master_grpc_server_admin.go b/weed/server/master_grpc_server_admin.go
new file mode 100644
index 000000000..b74e9291d
--- /dev/null
+++ b/weed/server/master_grpc_server_admin.go
@@ -0,0 +1,107 @@
+package weed_server
+
+import (
+ "context"
+ "math/rand"
+ "time"
+
+ "github.com/chrislusf/seaweedfs/weed/pb/master_pb"
+)
+
+/*
+How exclusive lock works?
+-----------
+
+Shell
+------
+When shell lock,
+ * lease an admin token (lockTime, token)
+ * start a goroutine to renew the admin token periodically
+For later volume operations, send (lockTime, token) to volume servers for exclusive access
+ * need to pause renewal a few seconds, to prevent race condition
+
+When shell unlock
+ * stop the renewal goroutine
+ * sends a release lock request
+
+Master
+------
+Master maintains:
+ * randomNumber
+ * lastLockTime
+When master receives the lease/renew request from shell
+ If lastLockTime still fresh {
+ if is a renew and token is valid {
+ // for renew
+ generate the randomNumber => token
+ return
+ }
+ refuse
+ return
+ } else {
+ // for fresh lease request
+ generate the randomNumber => token
+ return
+ }
+
+When master receives the release lock request from shell
+ set the lastLockTime to zero
+
+When master receives the verfication request from volume servers
+ return secret+lockTime == token && lockTime == lastLockTime
+
+Volume
+------
+When receives (lockTime, token), ask the master whether this is valid
+
+
+*/
+
+const (
+ LockDuration = 10 * time.Second
+)
+
+func (ms *MasterServer) LeaseAdminToken(ctx context.Context, req *master_pb.LeaseAdminTokenRequest) (*master_pb.LeaseAdminTokenResponse, error) {
+ resp := &master_pb.LeaseAdminTokenResponse{}
+
+ if ms.adminAccessLockTime.Add(LockDuration).After(time.Now()) {
+ if req.PreviousToken != 0 && ms.isValidToken(time.Unix(0, req.PreviousLockTime), req.PreviousToken) {
+ // for renew
+ ts, token := ms.generateToken()
+ resp.Token, resp.LockTsNs = token, ts.UnixNano()
+ return resp, nil
+ }
+ // refuse since still locked
+ resp.Error = "already locked"
+ return resp, nil
+ }
+ // for fresh lease request
+ ts, token := ms.generateToken()
+ resp.Token, resp.LockTsNs = token, ts.UnixNano()
+ return resp, nil
+}
+
+func (ms *MasterServer) isValidToken(ts time.Time, token int64) bool {
+ return ms.adminAccessLockTime.Equal(ts) && ms.adminAccessSecret == token
+}
+func (ms *MasterServer) generateToken() (ts time.Time, token int64) {
+ ms.adminAccessLockTime = time.Now()
+ ms.adminAccessSecret = rand.Int63()
+ return ms.adminAccessLockTime, ms.adminAccessSecret
+}
+
+func (ms *MasterServer) ReleaseAdminToken(ctx context.Context, req *master_pb.ReleaseAdminTokenRequest) (*master_pb.ReleaseAdminTokenResponse, error) {
+ resp := &master_pb.ReleaseAdminTokenResponse{}
+ if ms.isValidToken(time.Unix(0, req.PreviousLockTime), req.PreviousToken) {
+ ms.adminAccessSecret = 0
+ }
+ return resp, nil
+}
+
+func (ms *MasterServer) VerifyAdminToken(ctx context.Context, req *master_pb.VerifyAdminTokenRequest) (*master_pb.VerifyAdminTokenResponse, error) {
+ resp := &master_pb.VerifyAdminTokenResponse{}
+ if ms.isValidToken(time.Unix(0, req.LockTime), req.Token) {
+ resp.IsValid = true
+ }
+ return resp, nil
+}