mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00
mod/lock
This commit is contained in:
parent
228754a99c
commit
32861246b9
49
mod/lock/acquire_handler.go
Normal file
49
mod/lock/acquire_handler.go
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package lock
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"path"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
)
|
||||||
|
|
||||||
|
// acquireHandler attempts to acquire a lock on the given key.
|
||||||
|
func (h *handler) acquireHandler(w http.ResponseWriter, req *http.Request) {
|
||||||
|
vars := mux.Vars(req)
|
||||||
|
keypath := path.Join(prefix, vars["key"])
|
||||||
|
ttl, err := strconv.Atoi(vars["ttl"])
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "invalid ttl: " + err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an incrementing id for the lock.
|
||||||
|
resp, err := h.client.AddChild(keypath, "X", ttl)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "add lock index error: " + err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract the lock index.
|
||||||
|
index, _ := strconv.Atoi(path.Base(resp.Key))
|
||||||
|
|
||||||
|
// Read all indices.
|
||||||
|
resp, err = h.client.GetAll(key)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "lock children lookup error: " + err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
indices := extractResponseIndices(resp)
|
||||||
|
|
||||||
|
// TODO: child_keys := parse_and_sort_child_keys
|
||||||
|
// TODO: if index == min(child_keys) then return 200
|
||||||
|
// TODO: else:
|
||||||
|
// TODO: h.client.WatchAll(key)
|
||||||
|
// TODO: if next_lowest_key is deleted
|
||||||
|
// TODO: get_all_keys
|
||||||
|
// TODO: if index == min(child_keys) then return 200
|
||||||
|
// TODO: rinse_and_repeat until we're the lowest.
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
}
|
@ -1,19 +1,20 @@
|
|||||||
package lock
|
package lock
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
|
||||||
"path"
|
"path"
|
||||||
"time"
|
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
"github.com/coreos/go-etcd/etcd"
|
"github.com/coreos/go-etcd/etcd"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const prefix = "/_etcd/locks"
|
||||||
|
|
||||||
// handler manages the lock HTTP request.
|
// handler manages the lock HTTP request.
|
||||||
type handler struct {
|
type handler struct {
|
||||||
*mux.Router
|
*mux.Router
|
||||||
client string
|
client *etcd.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewHandler creates an HTTP handler that can be registered on a router.
|
// NewHandler creates an HTTP handler that can be registered on a router.
|
||||||
@ -22,23 +23,33 @@ func NewHandler(addr string) (http.Handler) {
|
|||||||
Router: mux.NewRouter(),
|
Router: mux.NewRouter(),
|
||||||
client: etcd.NewClient([]string{addr}),
|
client: etcd.NewClient([]string{addr}),
|
||||||
}
|
}
|
||||||
h.HandleFunc("/{key:.+}", h.getLockHandler).Methods("GET")
|
h.StrictSlash(false)
|
||||||
h.HandleFunc("/{key:.+}", h.acquireLockHandler).Methods("PUT")
|
h.HandleFunc("/{key:.*}", h.acquireHandler).Methods("POST")
|
||||||
h.HandleFunc("/{key:.+}", h.releaseLockHandler).Methods("DELETE")
|
h.HandleFunc("/{key_with_index:.*}", h.renewLockHandler).Methods("PUT")
|
||||||
|
h.HandleFunc("/{key_with_index:.*}", h.releaseLockHandler).Methods("DELETE")
|
||||||
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
// getLockHandler retrieves whether a lock has been obtained for a given key.
|
|
||||||
func (h *handler) getLockHandler(w http.ResponseWriter, req *http.Request) {
|
// extractResponseIndices extracts a sorted list of indicies from a response.
|
||||||
// TODO
|
func extractResponseIndices(resp *etcd.Response) []int {
|
||||||
|
var indices []int
|
||||||
|
for _, kv := range resp.Kvs {
|
||||||
|
if index, _ := strconv.Atoi(path.Base(kv.Key)); index > 0 {
|
||||||
|
indicies = append(indices, index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return indices
|
||||||
}
|
}
|
||||||
|
|
||||||
// acquireLockHandler attempts to acquire a lock on the given key.
|
// findPrevIndex retrieves the previous index before the given index.
|
||||||
// The lock is released when the connection is disconnected.
|
func findPrevIndex(indices []int, idx int) int {
|
||||||
func (h *handler) acquireLockHandler(w http.ResponseWriter, req *http.Request) {
|
var prevIndex int
|
||||||
// TODO
|
for _, index := range indices {
|
||||||
|
if index == idx {
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
prevIndex = index
|
||||||
// releaseLockHandler forces the release of a lock on the given key.
|
}
|
||||||
func (h *handler) releaseLockHandler(w http.ResponseWriter, req *http.Request) {
|
return prevIndex
|
||||||
// TODO
|
|
||||||
}
|
}
|
||||||
|
11
mod/lock/release_handler.go
Normal file
11
mod/lock/release_handler.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package lock
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// releaseLockHandler deletes the lock.
|
||||||
|
func (h *handler) releaseLockHandler(w http.ResponseWriter, req *http.Request) {
|
||||||
|
// TODO: h.client.Delete(key_with_index)
|
||||||
|
}
|
||||||
|
|
16
mod/lock/renew_handler.go
Normal file
16
mod/lock/renew_handler.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package lock
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// renewLockHandler attempts to update the TTL on an existing lock.
|
||||||
|
// Returns a 200 OK if successful. Otherwie
|
||||||
|
func (h *handler) renewLockHandler(w http.ResponseWriter, req *http.Request) {
|
||||||
|
vars := mux.Vars(req)
|
||||||
|
key := path.Join(prefix, vars["key"])
|
||||||
|
ttl := vars["ttl"]
|
||||||
|
w.Write([]byte(fmt.Sprintf("%s-%s", key, ttl)))
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
}
|
@ -1,17 +1,32 @@
|
|||||||
package lock
|
package lock
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/coreos/etcd/server"
|
||||||
|
"github.com/coreos/etcd/tests"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Ensure that a lock can be acquired and released.
|
// Ensure that a lock can be acquired and released.
|
||||||
func TestModLockAcquire(t *testing.T) {
|
func TestModLockAcquire(t *testing.T) {
|
||||||
// TODO: Acquire lock.
|
v := url.Values{}
|
||||||
|
tests.RunServer(func(s *server.Server) {
|
||||||
|
// Acquire lock.
|
||||||
|
resp, err := tests.PutForm(fmt.Sprintf("http://%s%s", s.URL(), "/mod/lock"), v)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
ret := tests.ReadBody(resp)
|
||||||
|
assert.Equal(t, string(ret), "XXX")
|
||||||
|
|
||||||
|
fmt.Println("URL:", fmt.Sprintf("http://%s%s", s.URL(), "/mod/lock"))
|
||||||
|
time.Sleep(60 * time.Second)
|
||||||
// TODO: Check that it has been acquired.
|
// TODO: Check that it has been acquired.
|
||||||
// TODO: Release lock.
|
// TODO: Release lock.
|
||||||
// TODO: Check that it has been released.
|
// TODO: Check that it has been released.
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that a lock can be acquired and another process is blocked until released.
|
// Ensure that a lock can be acquired and another process is blocked until released.
|
@ -13,9 +13,9 @@ var ServeMux *http.Handler
|
|||||||
|
|
||||||
func HttpHandler() (handler http.Handler) {
|
func HttpHandler() (handler http.Handler) {
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
r.PathPrefix("/dashboard/").
|
r.PathPrefix("/dashboard/").Handler(http.StripPrefix("/dashboard/", dashboard.HttpHandler()))
|
||||||
Handler(http.StripPrefix("/dashboard/", dashboard.HttpHandler()))
|
|
||||||
r.PathPrefix("/lock/").
|
// TODO: Use correct addr.
|
||||||
Handler(http.StripPrefix("/lock", lock.NewHandler()))
|
r.PathPrefix("/lock").Handler(http.StripPrefix("/lock", lock.NewHandler("127.0.0.1:4001")))
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user