forked from edulinq/autograder-server
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
first iteration of lockmanager with tests
- Loading branch information
Showing
2 changed files
with
107 additions
and
0 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,56 @@ | ||
package util | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"sync" | ||
"time" | ||
) | ||
|
||
type Lock struct { | ||
key string; | ||
timestamp time.Time; | ||
} | ||
|
||
type LockManager struct { | ||
locks map[string]*Lock; | ||
mutex sync.Mutex; | ||
staleDuration time.Duration; | ||
} | ||
|
||
func NewLockManager(staleDuration time.Duration) *LockManager { | ||
lm := &LockManager{ | ||
locks: make(map[string]*Lock), | ||
staleDuration: staleDuration, | ||
} | ||
go lm.removeStaleLocks(); | ||
return lm; | ||
} | ||
|
||
func (lm *LockManager) Lock(key string) { | ||
lm.mutex.Lock(); | ||
lm.locks[key] = &Lock{key: key, timestamp: time.Now()}; | ||
} | ||
|
||
func (lm *LockManager) Unlock(key string) error { | ||
// Check if key exists in the lock map | ||
_, ok := lm.locks[key]; | ||
if ok { | ||
defer lm.mutex.Unlock(); | ||
delete(lm.locks, key); | ||
return nil; | ||
} else { | ||
log.Fatal("Key not found.") | ||
return fmt.Errorf("Error. Key not found."); | ||
} | ||
} | ||
|
||
func (lm *LockManager) removeStaleLocks() { | ||
time.Sleep(lm.staleDuration); | ||
for key, lock := range lm.locks { | ||
if time.Since(lock.timestamp) > lm.staleDuration { | ||
delete(lm.locks, key); | ||
lm.mutex.Unlock(); | ||
} | ||
} | ||
} |
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,51 @@ | ||
package util | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
"time" | ||
) | ||
|
||
|
||
func TestLockAcquisition(t *testing.T) { | ||
lm := NewLockManager(3 * time.Second); | ||
key := "testkey" | ||
fmt.Println("Main Thread!") | ||
lm.Lock(key) | ||
lm.Lock(key) | ||
|
||
fmt.Println("Got past the first lock from removeStaleLocks go routine") | ||
|
||
go func() { | ||
fmt.Println("1st Go Routine Started") | ||
|
||
startTime := time.Now(); | ||
lm.Lock(key) | ||
lockWaitDuration := time.Since(startTime); | ||
fmt.Printf("Waited %v long to aquire the lock in the 1st go routine\n", lockWaitDuration); | ||
|
||
go func() { | ||
fmt.Println("2nd Go Routine Started") | ||
startTime := time.Now(); | ||
lm.Lock(key); | ||
lockWaitDuration := time.Since(startTime); | ||
fmt.Printf("Waited %v long to aquire the lock in the 2nd go routine\n", lockWaitDuration); | ||
defer lm.Unlock(key); | ||
fmt.Println("2nd Go Routine Done") | ||
}() | ||
|
||
|
||
defer lm.Unlock(key) | ||
fmt.Println("1st Go Routine Done") | ||
time.Sleep(3 * time.Second) | ||
}() | ||
|
||
fmt.Println("Main Thread Almost Done") | ||
time.Sleep(1 * time.Second) | ||
lm.Unlock(key) | ||
|
||
time.Sleep(4 * time.Second) | ||
|
||
fmt.Println("Main Thread Done!") | ||
|
||
} |