From a4a6ef5a1c4d0845f93b82631b52f5449ff52a2d Mon Sep 17 00:00:00 2001 From: Anders Chen Date: Sun, 11 Nov 2018 00:33:06 +0100 Subject: [PATCH] etcd3locker: Update formatting of docs; timeout -> ttl substitution (#216) * Update formatting of docs; timeout -> ttl substitution * Add link to etcd3 locker in main README.md --- README.md | 1 + etcd3locker/lock.go | 6 +++- etcd3locker/locker.go | 64 +++++++++++++++++------------------ etcd3locker/locker_options.go | 32 +++++++++++------- 4 files changed, 58 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index 4afed45..b2baa77 100644 --- a/README.md +++ b/README.md @@ -219,6 +219,7 @@ useful tools: * [**gcsstore**](https://godoc.org/github.com/tus/tusd/gcsstore): A storage backend using Google cloud storage * [**memorylocker**](https://godoc.org/github.com/tus/tusd/memorylocker): An in-memory locker for handling concurrent uploads * [**consullocker**](https://godoc.org/github.com/tus/tusd/consullocker): A locker using the distributed Consul service +* [**etcd3locker**](https://godoc.org/github.com/tus/tusd/etcd3locker): A locker using the distributed KV etcd3 store * [**limitedstore**](https://godoc.org/github.com/tus/tusd/limitedstore): A storage wrapper limiting the total used space for uploads ## Running the testsuite diff --git a/etcd3locker/lock.go b/etcd3locker/lock.go index 1f67238..e1babbe 100644 --- a/etcd3locker/lock.go +++ b/etcd3locker/lock.go @@ -1,4 +1,5 @@ -// Tested on etcd 3.1+ +// Package etcd3locker provides a locking mechanism using an etcd3 cluster. +// Tested on etcd 3.1/3.2./3.3 package etcd3locker import ( @@ -22,6 +23,7 @@ func newEtcd3Lock(session *concurrency.Session, id string) *etcd3Lock { } } +// Acquires a lock from etcd3 func (lock *etcd3Lock) Acquire() error { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() @@ -38,10 +40,12 @@ func (lock *etcd3Lock) Acquire() error { return nil } +// Releases a lock from etcd3 func (lock *etcd3Lock) Release() error { return lock.Mutex.Unlock(context.Background()) } +// Closes etcd3 session func (lock *etcd3Lock) CloseSession() error { return lock.Session.Close() } diff --git a/etcd3locker/locker.go b/etcd3locker/locker.go index 997efd3..60eefdd 100644 --- a/etcd3locker/locker.go +++ b/etcd3locker/locker.go @@ -2,41 +2,41 @@ // // To initialize a locker, a pre-existing connected etcd3 client must be present // -// client, err := clientv3.New(clientv3.Config{ -// Endpoints: []string{harness.Endpoint}, -// DialTimeout: 5 * time.Second, -// }) +// client, err := clientv3.New(clientv3.Config{ +// Endpoints: []string{harness.Endpoint}, +// DialTimeout: 5 * time.Second, +// }) // -// For the most basic locker (e.g. non-shared etcd3 cluster / use default TTLs), -// a locker can be instantiated like the following: +// For the most basic locker (e.g. non-shared etcd3 cluster / use default TTLs), +// a locker can be instantiated like the following: // -// locker, err := etcd3locker.New(client) -// if err != nil { -// return nil, fmt.Errorf("Failed to create etcd locker: %v", err.Error()) -// } +// locker, err := etcd3locker.New(client) +// if err != nil { +// return nil, fmt.Errorf("Failed to create etcd locker: %v", err.Error()) +// } // -// The locker will need to be included in composer that is used by tusd: +// The locker will need to be included in composer that is used by tusd: // -// composer := tusd.NewStoreComposer() -// locker.UseIn(composer) +// composer := tusd.NewStoreComposer() +// locker.UseIn(composer) // -// For a shared etcd3 cluster, you may want to modify the prefix that etcd3locker uses: +// For a shared etcd3 cluster, you may want to modify the prefix that etcd3locker uses: // -// locker, err := etcd3locker.NewWithPrefix(client, "my-prefix") -// if err != nil { -// return nil, fmt.Errorf("Failed to create etcd locker: %v", err.Error()) -// } +// locker, err := etcd3locker.NewWithPrefix(client, "my-prefix") +// if err != nil { +// return nil, fmt.Errorf("Failed to create etcd locker: %v", err.Error()) +// } // // -// For full control over all options, an etcd3.LockerOptions may be passed into -// etcd3.NewWithLockerOptions like the following example: +// For full control over all options, an etcd3.LockerOptions may be passed into +// etcd3.NewWithLockerOptions like the following example: // -// ttl := 15 // seconds -// options := etcd3locker.NewLockerOptions(ttl, "my-prefix") -// locker, err := etcd3locker.NewWithLockerOptions(client, options) -// if err != nil { -// return nil, fmt.Errorf("Failed to create etcd locker: %v", err.Error()) -// } +// ttl := 15 // seconds +// options := etcd3locker.NewLockerOptions(ttl, "my-prefix") +// locker, err := etcd3locker.NewWithLockerOptions(client, options) +// if err != nil { +// return nil, fmt.Errorf("Failed to create etcd locker: %v", err.Error()) +// } // // Tested on etcd 3.1/3.2/3.3 // @@ -64,10 +64,10 @@ type Etcd3Locker struct { // locks is used for storing Etcd3Locks before they are // unlocked. If you want to release a lock, you need the same locker // instance and therefore we need to save them temporarily. - locks map[string]*etcd3Lock - mutex sync.Mutex - prefix string - sessionTimeout int + locks map[string]*etcd3Lock + mutex sync.Mutex + prefix string + sessionTtl int } // New constructs a new locker using the provided client. @@ -85,7 +85,7 @@ func NewWithPrefix(client *etcd3.Client, prefix string) (*Etcd3Locker, error) { // This method may be used if we want control over both prefix/session TTLs. This is used for testing in particular. func NewWithLockerOptions(client *etcd3.Client, opts LockerOptions) (*Etcd3Locker, error) { locksMap := map[string]*etcd3Lock{} - return &Etcd3Locker{Client: client, prefix: opts.Prefix(), sessionTimeout: opts.Timeout(), locks: locksMap, mutex: sync.Mutex{}}, nil + return &Etcd3Locker{Client: client, prefix: opts.Prefix(), sessionTtl: opts.Ttl(), locks: locksMap, mutex: sync.Mutex{}}, nil } // UseIn adds this locker to the passed composer. @@ -137,7 +137,7 @@ func (locker *Etcd3Locker) UnlockUpload(id string) error { } func (locker *Etcd3Locker) createSession() (*concurrency.Session, error) { - return concurrency.NewSession(locker.Client, concurrency.WithTTL(locker.sessionTimeout)) + return concurrency.NewSession(locker.Client, concurrency.WithTTL(locker.sessionTtl)) } func (locker *Etcd3Locker) getId(id string) string { diff --git a/etcd3locker/locker_options.go b/etcd3locker/locker_options.go index 6852fa7..dcbfc73 100644 --- a/etcd3locker/locker_options.go +++ b/etcd3locker/locker_options.go @@ -10,32 +10,38 @@ var ( ) type LockerOptions struct { - timeoutSeconds int - prefix string + ttl int + prefix string } +// DefaultLockerOptions() instantiates an instance of LockerOptions +// with default 60 second time to live and an etcd3 prefix of "/tusd" func DefaultLockerOptions() LockerOptions { return LockerOptions{ - timeoutSeconds: 60, - prefix: "/tusd", + ttl: 60, + prefix: "/tusd", } } -func NewLockerOptions(timeout int, prefix string) LockerOptions { +// NewLockerOptions instantiates an instance of LockerOptions with a +// provided TTL (time to live) and string prefix for keys to be stored in etcd3 +func NewLockerOptions(ttl int, prefix string) LockerOptions { return LockerOptions{ - timeoutSeconds: timeout, - prefix: prefix, + ttl: ttl, + prefix: prefix, } } -func (l *LockerOptions) Timeout() int { - if l.timeoutSeconds == 0 { +// Returns the TTL (time to live) of sessions in etcd3 +func (l *LockerOptions) Ttl() int { + if l.ttl == 0 { return DefaultTtl } else { - return l.timeoutSeconds + return l.ttl } } +// Returns the string prefix used to store keys in etcd3 func (l *LockerOptions) Prefix() string { prefix := l.prefix if !strings.HasPrefix(prefix, "/") { @@ -49,10 +55,12 @@ func (l *LockerOptions) Prefix() string { } } -func (l *LockerOptions) SetTimeout(timeout int) { - l.timeoutSeconds = timeout +// Set etcd3 session TTL (time to live) +func (l *LockerOptions) SetTtl(ttl int) { + l.ttl = ttl } +// Set string prefix to be used in keys stored into etcd3 by the locker func (l *LockerOptions) SetPrefix(prefix string) { l.prefix = prefix }