-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
6a9cf21
commit 3a786ae
Showing
7 changed files
with
179 additions
and
7 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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
package pgsql | ||
|
||
import ( | ||
"database/sql" | ||
"time" | ||
|
||
cerrors "github.com/coreos/clair/utils/errors" | ||
) | ||
|
||
// Lock tries to set a temporary lock in the database. | ||
// | ||
// Lock does not block, instead, it returns true and its expiration time | ||
// is the lock has been successfully acquired or false otherwise | ||
func (pgSQL *pgSQL) Lock(name string, owner string, duration time.Duration, renew bool) (bool, time.Time) { | ||
if name == "" || owner == "" || duration == 0 { | ||
log.Warning("could not create an invalid lock") | ||
return false, time.Time{} | ||
} | ||
|
||
// Prune locks. | ||
pgSQL.pruneLocks() | ||
|
||
// Compute expiration. | ||
until := time.Now().Add(duration) | ||
|
||
if renew { | ||
// Renew lock. | ||
r, err := pgSQL.Exec(getQuery("u_lock"), name, owner, until) | ||
if err != nil { | ||
handleError("u_lock", err) | ||
return false, until | ||
} | ||
if n, _ := r.RowsAffected(); n > 0 { | ||
// Updated successfully. | ||
return true, until | ||
} | ||
} | ||
|
||
// Lock. | ||
_, err := pgSQL.Exec(getQuery("i_lock"), name, owner, until) | ||
if err != nil { | ||
if !isErrUniqueViolation(err) { | ||
handleError("i_lock", err) | ||
} | ||
return false, until | ||
} | ||
|
||
return true, until | ||
} | ||
|
||
// Unlock unlocks a lock specified by its name if I own it | ||
func (pgSQL *pgSQL) Unlock(name, owner string) { | ||
if name == "" || owner == "" { | ||
log.Warning("could not delete an invalid lock") | ||
return | ||
} | ||
|
||
pgSQL.Exec(getQuery("r_lock"), name, owner) | ||
} | ||
|
||
// FindLock returns the owner of a lock specified by its name and its | ||
// expiration time. | ||
func (pgSQL *pgSQL) FindLock(name string) (string, time.Time, error) { | ||
if name == "" { | ||
log.Warning("could not find an invalid lock") | ||
return "", time.Time{}, cerrors.NewBadRequestError("could not find an invalid lock") | ||
} | ||
|
||
var owner string | ||
var until time.Time | ||
err := pgSQL.QueryRow(getQuery("f_lock"), name).Scan(&owner, &until) | ||
|
||
if err == sql.ErrNoRows { | ||
return owner, until, cerrors.ErrNotFound | ||
} | ||
if err != nil { | ||
return owner, until, handleError("f_lock", err) | ||
} | ||
|
||
return owner, until, nil | ||
} | ||
|
||
// pruneLocks removes every expired locks from the database | ||
func (pgSQL *pgSQL) pruneLocks() { | ||
if _, err := pgSQL.Exec(getQuery("r_lock_expired")); err != nil { | ||
handleError("r_lock_expired", 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,55 @@ | ||
package pgsql | ||
|
||
import ( | ||
"testing" | ||
"time" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestLock(t *testing.T) { | ||
datastore, err := OpenForTest("InsertNamespace", false) | ||
if err != nil { | ||
t.Error(err) | ||
return | ||
} | ||
defer datastore.Close() | ||
|
||
var l bool | ||
var et time.Time | ||
|
||
// Create a first lock. | ||
l, _ = datastore.Lock("test1", "owner1", time.Minute, false) | ||
assert.True(t, l) | ||
|
||
// Try to lock the same lock with another owner. | ||
l, _ = datastore.Lock("test1", "owner2", time.Minute, true) | ||
assert.False(t, l) | ||
|
||
l, _ = datastore.Lock("test1", "owner2", time.Minute, false) | ||
assert.False(t, l) | ||
|
||
// Renew the lock. | ||
l, _ = datastore.Lock("test1", "owner1", 2*time.Minute, true) | ||
assert.True(t, l) | ||
|
||
// Unlock and then relock by someone else. | ||
datastore.Unlock("test1", "owner1") | ||
|
||
l, et = datastore.Lock("test1", "owner2", time.Minute, false) | ||
assert.True(t, l) | ||
|
||
// LockInfo | ||
o, et2, err := datastore.FindLock("test1") | ||
assert.Nil(t, err) | ||
assert.Equal(t, "owner2", o) | ||
assert.Equal(t, et.Second(), et2.Second()) | ||
|
||
// Create a second lock which is actually already expired ... | ||
l, _ = datastore.Lock("test2", "owner1", -time.Minute, false) | ||
assert.True(t, l) | ||
|
||
// Take over the lock | ||
l, _ = datastore.Lock("test2", "owner2", time.Minute, false) | ||
assert.True(t, l) | ||
} |
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