Skip to content

Commit

Permalink
Merge branch 'main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
seeflood committed Mar 18, 2022
2 parents 1cdb4c5 + 5234a80 commit 80d99a6
Show file tree
Hide file tree
Showing 21 changed files with 694 additions and 117 deletions.
8 changes: 8 additions & 0 deletions cmd/layotto/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,13 +108,15 @@ import (
"mosn.io/layotto/components/lock"
lock_consul "mosn.io/layotto/components/lock/consul"
lock_etcd "mosn.io/layotto/components/lock/etcd"
lock_inmemory "mosn.io/layotto/components/lock/in-memory"
lock_mongo "mosn.io/layotto/components/lock/mongo"
lock_redis "mosn.io/layotto/components/lock/redis"
lock_zookeeper "mosn.io/layotto/components/lock/zookeeper"
runtime_lock "mosn.io/layotto/pkg/runtime/lock"

// Sequencer
sequencer_etcd "mosn.io/layotto/components/sequencer/etcd"
sequencer_inmemory "mosn.io/layotto/components/sequencer/in-memory"
sequencer_mongo "mosn.io/layotto/components/sequencer/mongo"
sequencer_redis "mosn.io/layotto/components/sequencer/redis"
sequencer_zookeeper "mosn.io/layotto/components/sequencer/zookeeper"
Expand Down Expand Up @@ -352,6 +354,9 @@ func NewRuntimeGrpcServer(data json.RawMessage, opts ...grpc.ServerOption) (mgrp
runtime_lock.NewFactory("mongo", func() lock.LockStore {
return lock_mongo.NewMongoLock(log.DefaultLogger)
}),
runtime_lock.NewFactory("in-memory", func() lock.LockStore {
return lock_inmemory.NewInMemoryLock()
}),
),

// bindings
Expand All @@ -375,6 +380,9 @@ func NewRuntimeGrpcServer(data json.RawMessage, opts ...grpc.ServerOption) (mgrp
runtime_sequencer.NewFactory("mongo", func() sequencer.Store {
return sequencer_mongo.NewMongoSequencer(log.DefaultLogger)
}),
runtime_sequencer.NewFactory("in-memory", func() sequencer.Store {
return sequencer_inmemory.NewInMemorySequencer()
}),
),
// secretstores
runtime.WithSecretStoresFactory(
Expand Down
8 changes: 8 additions & 0 deletions cmd/layotto_multiple_api/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,14 @@ import (
"mosn.io/layotto/components/lock"
lock_consul "mosn.io/layotto/components/lock/consul"
lock_etcd "mosn.io/layotto/components/lock/etcd"
lock_inmemory "mosn.io/layotto/components/lock/in-memory"
lock_redis "mosn.io/layotto/components/lock/redis"
lock_zookeeper "mosn.io/layotto/components/lock/zookeeper"
runtime_lock "mosn.io/layotto/pkg/runtime/lock"

// Sequencer
sequencer_etcd "mosn.io/layotto/components/sequencer/etcd"
sequencer_inmemory "mosn.io/layotto/components/sequencer/in-memory"
sequencer_redis "mosn.io/layotto/components/sequencer/redis"
sequencer_zookeeper "mosn.io/layotto/components/sequencer/zookeeper"

Expand Down Expand Up @@ -346,6 +348,9 @@ func NewRuntimeGrpcServer(data json.RawMessage, opts ...grpc.ServerOption) (mgrp
runtime_lock.NewFactory("consul", func() lock.LockStore {
return lock_consul.NewConsulLock(log.DefaultLogger)
}),
runtime_lock.NewFactory("in-memory", func() lock.LockStore {
return lock_inmemory.NewInMemoryLock()
}),
),

// bindings
Expand All @@ -366,6 +371,9 @@ func NewRuntimeGrpcServer(data json.RawMessage, opts ...grpc.ServerOption) (mgrp
runtime_sequencer.NewFactory("zookeeper", func() sequencer.Store {
return sequencer_zookeeper.NewZookeeperSequencer(log.DefaultLogger)
}),
runtime_sequencer.NewFactory("in-memory", func() sequencer.Store {
return sequencer_inmemory.NewInMemorySequencer()
}),
))
return server, err
}
Expand Down
1 change: 1 addition & 0 deletions components/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ require (
go.etcd.io/etcd/client/v3 v3.5.0
go.etcd.io/etcd/server/v3 v3.5.0
go.mongodb.org/mongo-driver v1.8.0
go.uber.org/atomic v1.7.0
golang.org/x/net v0.0.0-20210614182718-04defd469f4e // indirect
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5 // indirect
google.golang.org/grpc v1.38.0
Expand Down
132 changes: 132 additions & 0 deletions components/lock/in-memory/in_memory_lock.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/*
* Copyright 2021 Layotto 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 in_memory

import (
"mosn.io/layotto/components/lock"
"sync"
"time"
)

type InMemoryLock struct {
features []lock.Feature
data *lockMap
}

// memoryLock is a lock holder
type memoryLock struct {
key string
owner string
expireTime time.Time
lock int
}

type lockMap struct {
sync.Mutex
locks map[string]*memoryLock
}

func NewInMemoryLock() *InMemoryLock {
return &InMemoryLock{
features: make([]lock.Feature, 0),
data: &lockMap{
locks: make(map[string]*memoryLock),
},
}
}

func (s *InMemoryLock) Init(_ lock.Metadata) error {
return nil
}

func (s *InMemoryLock) Features() []lock.Feature {
return s.features
}

// Try to add a lock. Currently this is a non-reentrant lock
func (s *InMemoryLock) TryLock(req *lock.TryLockRequest) (*lock.TryLockResponse, error) {
s.data.Lock()
defer s.data.Unlock()
// 1. Find the memoryLock for this resourceId
item, ok := s.data.locks[req.ResourceId]
if !ok {
item = &memoryLock{
key: req.ResourceId,
//0 unlock, 1 lock
lock: 0,
}
s.data.locks[req.ResourceId] = item
}

// 2. Construct a new one if the lockData has expired
//check expire
if item.owner != "" && time.Now().After(item.expireTime) {
item = &memoryLock{
key: req.ResourceId,
lock: 0,
}
s.data.locks[req.ResourceId] = item
}

// 3. Check if it has been locked by others.
// Currently this is a non-reentrant lock
if item.lock == 1 {
//lock failed
return &lock.TryLockResponse{
Success: false,
}, nil
}

// 4. Update owner information
item.lock = 1
item.owner = req.LockOwner
item.expireTime = time.Now().Add(time.Second * time.Duration(req.Expire))

return &lock.TryLockResponse{
Success: true,
}, nil
}

func (s *InMemoryLock) Unlock(req *lock.UnlockRequest) (*lock.UnlockResponse, error) {
s.data.Lock()
defer s.data.Unlock()
// 1. Find the memoryLock for this resourceId
item, ok := s.data.locks[req.ResourceId]

if !ok {
return &lock.UnlockResponse{
Status: lock.LOCK_UNEXIST,
}, nil
}
// 2. check the owner information
if item.lock != 1 {
return &lock.UnlockResponse{
Status: lock.LOCK_UNEXIST,
}, nil
}
if item.owner != req.LockOwner {
return &lock.UnlockResponse{
Status: lock.LOCK_BELONG_TO_OTHERS,
}, nil
}
// 3. unlock and reset the owner information
item.owner = ""
item.lock = 0
return &lock.UnlockResponse{
Status: lock.SUCCESS,
}, nil
}
165 changes: 165 additions & 0 deletions components/lock/in-memory/in_memory_lock_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
/*
* Copyright 2021 Layotto 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 in_memory

import (
"github.com/stretchr/testify/assert"
"mosn.io/layotto/components/lock"
"testing"
"time"
)

func TestNew(t *testing.T) {
s := NewInMemoryLock()
assert.NotNil(t, s)
}

func TestInit(t *testing.T) {
s := NewInMemoryLock()
assert.NotNil(t, s)

err := s.Init(lock.Metadata{})
assert.NoError(t, err)
}

func TestFeatures(t *testing.T) {
s := NewInMemoryLock()
assert.NotNil(t, s)

f := s.Features()
assert.NotNil(t, f)
assert.Equal(t, 0, len(f))
}

func TestTryLock(t *testing.T) {
s := NewInMemoryLock()
assert.NotNil(t, s)

req := &lock.TryLockRequest{
ResourceId: "key111",
LockOwner: "own",
Expire: 3,
}

var err error
var resp *lock.TryLockResponse
resp, err = s.TryLock(req)
assert.NoError(t, err)
assert.NotNil(t, req)
assert.True(t, resp.Success)

resp, err = s.TryLock(req)
assert.NoError(t, err)
assert.NotNil(t, req)
assert.False(t, resp.Success)

req = &lock.TryLockRequest{
ResourceId: "key112",
LockOwner: "own",
Expire: 1,
}

resp, err = s.TryLock(req)
assert.NoError(t, err)
assert.NotNil(t, req)
assert.True(t, resp.Success)

req = &lock.TryLockRequest{
ResourceId: "key112",
LockOwner: "own",
Expire: 1,
}

resp, err = s.TryLock(req)
assert.NoError(t, err)
assert.NotNil(t, req)
assert.False(t, resp.Success)

s.data.locks["key112"].expireTime = time.Now().Add(-2 * time.Second)

resp, err = s.TryLock(req)
assert.NoError(t, err)
assert.NotNil(t, req)
assert.True(t, resp.Success)

}

func TestUnLock(t *testing.T) {
s := NewInMemoryLock()
assert.NotNil(t, s)

req := &lock.UnlockRequest{
ResourceId: "key111",
LockOwner: "own",
}

var err error
var resp *lock.UnlockResponse
resp, err = s.Unlock(req)
assert.NoError(t, err)
assert.NotNil(t, req)
assert.Equal(t, lock.LOCK_UNEXIST, resp.Status)

lockReq := &lock.TryLockRequest{
ResourceId: "key111",
LockOwner: "own",
Expire: 10,
}

var lockResp *lock.TryLockResponse
lockResp, err = s.TryLock(lockReq)
assert.NoError(t, err)
assert.NotNil(t, req)
assert.True(t, lockResp.Success)

resp, err = s.Unlock(req)
assert.NoError(t, err)
assert.NotNil(t, req)
assert.Equal(t, lock.SUCCESS, resp.Status)

lockResp, err = s.TryLock(lockReq)
assert.NoError(t, err)
assert.NotNil(t, req)
assert.True(t, lockResp.Success)

req.LockOwner = "1"

resp, err = s.Unlock(req)
assert.NoError(t, err)
assert.NotNil(t, req)
assert.Equal(t, lock.LOCK_BELONG_TO_OTHERS, resp.Status)

req.ResourceId = "11"
lockReq.ResourceId = "11"
req.LockOwner = "own1"
lockReq.LockOwner = "own1"
lockResp, err = s.TryLock(lockReq)
assert.NoError(t, err)
assert.NotNil(t, req)
assert.True(t, lockResp.Success)

resp, err = s.Unlock(req)
assert.NoError(t, err)
assert.NotNil(t, req)
assert.Equal(t, lock.SUCCESS, resp.Status)

resp, err = s.Unlock(req)
assert.NoError(t, err)
assert.NotNil(t, req)
assert.Equal(t, lock.LOCK_UNEXIST, resp.Status)

}
Loading

0 comments on commit 80d99a6

Please sign in to comment.