-
Notifications
You must be signed in to change notification settings - Fork 341
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[feat] add dlock service, implemented etcd's dlock mechanism (#1191)
- Loading branch information
Showing
10 changed files
with
439 additions
and
10 deletions.
There are no files selected for viewing
This file contains 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,33 @@ | ||
/* | ||
* Licensed to the Apache Software Foundation (ASF) under one or more | ||
* contributor license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright ownership. | ||
* The ASF licenses this file to You 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 dlock provide distributed lock function | ||
package dlock | ||
|
||
import ( | ||
"errors" | ||
) | ||
|
||
var ErrDLockNotExists = errors.New("DLock do not exist") | ||
|
||
type DLock interface { | ||
Lock(key string, ttl int64) error | ||
TryLock(key string, ttl int64) error | ||
Renew(key string) error | ||
IsHoldLock(key string) bool | ||
Unlock(key string) error | ||
} |
This file contains 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,90 @@ | ||
/* | ||
* Licensed to the Apache Software Foundation (ASF) under one or more | ||
* contributor license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright ownership. | ||
* The ASF licenses this file to You 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 dlock_test | ||
|
||
import ( | ||
"testing" | ||
"time" | ||
|
||
"github.com/stretchr/testify/assert" | ||
|
||
"github.com/apache/servicecomb-service-center/datasource/dlock" | ||
_ "github.com/apache/servicecomb-service-center/test" | ||
) | ||
|
||
func TestDLock(t *testing.T) { | ||
t.Run("test lock", func(t *testing.T) { | ||
t.Run("lock the global key for 5s should pass", func(t *testing.T) { | ||
err := dlock.Instance().Lock("global", 5) | ||
assert.Nil(t, err) | ||
isHold := dlock.Instance().IsHoldLock("global") | ||
assert.Equal(t, true, isHold) | ||
}) | ||
t.Run("two locks fight for the same lock 5s, one lock should pass, another lock should fail", func(t *testing.T) { | ||
err := dlock.Instance().Lock("same-lock", 5) | ||
assert.Nil(t, err) | ||
isHold := dlock.Instance().IsHoldLock("same-lock") | ||
assert.Equal(t, true, isHold) | ||
err = dlock.Instance().TryLock("same-lock", 5) | ||
assert.NotNil(t, err) | ||
}) | ||
}) | ||
t.Run("test try lock", func(t *testing.T) { | ||
t.Run("try lock the try key for 5s should pass", func(t *testing.T) { | ||
err := dlock.Instance().TryLock("try-lock", 5) | ||
assert.Nil(t, err) | ||
isHold := dlock.Instance().IsHoldLock("try-lock") | ||
assert.Equal(t, true, isHold) | ||
err = dlock.Instance().TryLock("try-lock", 5) | ||
assert.NotNil(t, err) | ||
}) | ||
}) | ||
t.Run("test renew", func(t *testing.T) { | ||
t.Run("renew the renew key for 5s should pass", func(t *testing.T) { | ||
err := dlock.Instance().Lock("renew", 5) | ||
assert.Nil(t, err) | ||
isHold := dlock.Instance().IsHoldLock("renew") | ||
assert.Equal(t, true, isHold) | ||
time.Sleep(3 * time.Second) | ||
err = dlock.Instance().Renew("renew") | ||
time.Sleep(2 * time.Second) | ||
err = dlock.Instance().TryLock("renew", 5) | ||
assert.NotNil(t, err) | ||
}) | ||
}) | ||
t.Run("test isHoldLock", func(t *testing.T) { | ||
t.Run("already owns the lock should pass", func(t *testing.T) { | ||
err := dlock.Instance().Lock("hold-lock", 5) | ||
assert.Nil(t, err) | ||
isHold := dlock.Instance().IsHoldLock("hold-lock") | ||
assert.Equal(t, true, isHold) | ||
}) | ||
t.Run("key does not exist should fail", func(t *testing.T) { | ||
isHold := dlock.Instance().IsHoldLock("not-exist") | ||
assert.Equal(t, false, isHold) | ||
}) | ||
}) | ||
t.Run("test unlock", func(t *testing.T) { | ||
t.Run("unlock the unlock key should pass", func(t *testing.T) { | ||
err := dlock.Instance().Lock("unlock", 5) | ||
assert.Nil(t, err) | ||
err = dlock.Instance().Unlock("unlock") | ||
assert.Nil(t, err) | ||
}) | ||
}) | ||
} |
This file contains 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,56 @@ | ||
/* | ||
* Licensed to the Apache Software Foundation (ASF) under one or more | ||
* contributor license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright ownership. | ||
* The ASF licenses this file to You 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 dlock | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/apache/servicecomb-service-center/pkg/log" | ||
) | ||
|
||
type initFunc func(opts Options) (DLock, error) | ||
|
||
var ( | ||
plugins = make(map[string]initFunc) | ||
instance DLock | ||
) | ||
|
||
func Install(pluginImplName string, f initFunc) { | ||
plugins[pluginImplName] = f | ||
} | ||
|
||
func Init(opts Options) error { | ||
if opts.Kind == "" { | ||
return nil | ||
} | ||
engineFunc, ok := plugins[opts.Kind] | ||
if !ok { | ||
return fmt.Errorf("plugin implement not supported [%s]", opts.Kind) | ||
} | ||
var err error | ||
instance, err = engineFunc(opts) | ||
if err != nil { | ||
return err | ||
} | ||
log.Info(fmt.Sprintf("dlock plugin [%s] enabled", opts.Kind)) | ||
return nil | ||
} | ||
|
||
func Instance() DLock { | ||
return instance | ||
} |
This file contains 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,23 @@ | ||
/* | ||
* Licensed to the Apache Software Foundation (ASF) under one or more | ||
* contributor license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright ownership. | ||
* The ASF licenses this file to You 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 dlock | ||
|
||
// Options contains configuration for plugins | ||
type Options struct { | ||
Kind string | ||
} |
This file contains 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,90 @@ | ||
/* | ||
* Licensed to the Apache Software Foundation (ASF) under one or more | ||
* contributor license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright ownership. | ||
* The ASF licenses this file to You 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 etcd | ||
|
||
import ( | ||
"sync" | ||
|
||
"github.com/go-chassis/openlog" | ||
"github.com/little-cui/etcdadpt" | ||
|
||
"github.com/apache/servicecomb-service-center/datasource/dlock" | ||
) | ||
|
||
func init() { | ||
dlock.Install("etcd", NewDLock) | ||
dlock.Install("embeded_etcd", NewDLock) | ||
dlock.Install("embedded_etcd", NewDLock) | ||
} | ||
|
||
func NewDLock(opts dlock.Options) (dlock.DLock, error) { | ||
return &DB{lockMap: sync.Map{}}, nil | ||
} | ||
|
||
type DB struct { | ||
lockMap sync.Map | ||
} | ||
|
||
func (d *DB) Lock(key string, ttl int64) error { | ||
lock, err := etcdadpt.Lock(key, ttl) | ||
if err == nil { | ||
d.lockMap.Store(key, lock) | ||
} | ||
return err | ||
} | ||
|
||
func (d *DB) TryLock(key string, ttl int64) error { | ||
lock, err := etcdadpt.TryLock(key, ttl) | ||
if err == nil { | ||
d.lockMap.Store(key, lock) | ||
} | ||
return err | ||
} | ||
|
||
func (d *DB) Renew(key string) error { | ||
if lock, ok := d.lockMap.Load(key); ok { | ||
err := lock.(*etcdadpt.DLock).Refresh() | ||
if err != nil { | ||
openlog.Error("fail to renew key") | ||
d.lockMap.Delete(key) | ||
} | ||
return err | ||
} | ||
return dlock.ErrDLockNotExists | ||
} | ||
|
||
func (d *DB) IsHoldLock(key string) bool { | ||
if lock, ok := d.lockMap.Load(key); ok { | ||
if lock != nil { | ||
return true | ||
} | ||
} | ||
return false | ||
} | ||
|
||
func (d *DB) Unlock(key string) error { | ||
if lock, ok := d.lockMap.Load(key); ok { | ||
err := lock.(*etcdadpt.DLock).Unlock() | ||
if err != nil { | ||
openlog.Error("fail to unlock") | ||
} | ||
d.lockMap.Delete(key) | ||
return err | ||
} | ||
return dlock.ErrDLockNotExists | ||
} |
This file contains 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
This file contains 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
This file contains 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.