mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00
clean up from yifan
This commit is contained in:
parent
a568c6dc75
commit
da83ee223b
20
command.go
20
command.go
@ -9,7 +9,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
etcdErr "github.com/coreos/etcd/error"
|
etcdErr "github.com/coreos/etcd/error"
|
||||||
"github.com/coreos/etcd/file_system"
|
"github.com/coreos/etcd/store"
|
||||||
"github.com/coreos/go-raft"
|
"github.com/coreos/go-raft"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -39,7 +39,7 @@ func (c *CreateCommand) CommandName() string {
|
|||||||
|
|
||||||
// Create node
|
// Create node
|
||||||
func (c *CreateCommand) Apply(server *raft.Server) (interface{}, error) {
|
func (c *CreateCommand) Apply(server *raft.Server) (interface{}, error) {
|
||||||
e, err := etcdFs.Create(c.Key, c.Value, c.ExpireTime, server.CommitIndex(), server.Term())
|
e, err := etcdStore.Create(c.Key, c.Value, c.ExpireTime, server.CommitIndex(), server.Term())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
debug(err)
|
debug(err)
|
||||||
@ -63,7 +63,7 @@ func (c *UpdateCommand) CommandName() string {
|
|||||||
|
|
||||||
// Update node
|
// Update node
|
||||||
func (c *UpdateCommand) Apply(server *raft.Server) (interface{}, error) {
|
func (c *UpdateCommand) Apply(server *raft.Server) (interface{}, error) {
|
||||||
e, err := etcdFs.Update(c.Key, c.Value, c.ExpireTime, server.CommitIndex(), server.Term())
|
e, err := etcdStore.Update(c.Key, c.Value, c.ExpireTime, server.CommitIndex(), server.Term())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
debug(err)
|
debug(err)
|
||||||
@ -89,7 +89,7 @@ func (c *TestAndSetCommand) CommandName() string {
|
|||||||
|
|
||||||
// Set the key-value pair if the current value of the key equals to the given prevValue
|
// Set the key-value pair if the current value of the key equals to the given prevValue
|
||||||
func (c *TestAndSetCommand) Apply(server *raft.Server) (interface{}, error) {
|
func (c *TestAndSetCommand) Apply(server *raft.Server) (interface{}, error) {
|
||||||
e, err := etcdFs.TestAndSet(c.Key, c.PrevValue, c.PrevIndex,
|
e, err := etcdStore.TestAndSet(c.Key, c.PrevValue, c.PrevIndex,
|
||||||
c.Value, c.ExpireTime, server.CommitIndex(), server.Term())
|
c.Value, c.ExpireTime, server.CommitIndex(), server.Term())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -114,7 +114,7 @@ func (c *GetCommand) CommandName() string {
|
|||||||
|
|
||||||
// Get the value of key
|
// Get the value of key
|
||||||
func (c *GetCommand) Apply(server *raft.Server) (interface{}, error) {
|
func (c *GetCommand) Apply(server *raft.Server) (interface{}, error) {
|
||||||
e, err := etcdFs.Get(c.Key, c.Recursive, c.Sorted, server.CommitIndex(), server.Term())
|
e, err := etcdStore.Get(c.Key, c.Recursive, c.Sorted, server.CommitIndex(), server.Term())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
debug(err)
|
debug(err)
|
||||||
@ -137,7 +137,7 @@ func (c *DeleteCommand) CommandName() string {
|
|||||||
|
|
||||||
// Delete the key
|
// Delete the key
|
||||||
func (c *DeleteCommand) Apply(server *raft.Server) (interface{}, error) {
|
func (c *DeleteCommand) Apply(server *raft.Server) (interface{}, error) {
|
||||||
e, err := etcdFs.Delete(c.Key, c.Recursive, server.CommitIndex(), server.Term())
|
e, err := etcdStore.Delete(c.Key, c.Recursive, server.CommitIndex(), server.Term())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
debug(err)
|
debug(err)
|
||||||
@ -160,7 +160,7 @@ func (c *WatchCommand) CommandName() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *WatchCommand) Apply(server *raft.Server) (interface{}, error) {
|
func (c *WatchCommand) Apply(server *raft.Server) (interface{}, error) {
|
||||||
eventChan, err := etcdFs.Watch(c.Key, c.Recursive, c.SinceIndex, server.CommitIndex(), server.Term())
|
eventChan, err := etcdStore.Watch(c.Key, c.Recursive, c.SinceIndex, server.CommitIndex(), server.Term())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -197,7 +197,7 @@ func (c *JoinCommand) CommandName() string {
|
|||||||
func (c *JoinCommand) Apply(raftServer *raft.Server) (interface{}, error) {
|
func (c *JoinCommand) Apply(raftServer *raft.Server) (interface{}, error) {
|
||||||
|
|
||||||
// check if the join command is from a previous machine, who lost all its previous log.
|
// check if the join command is from a previous machine, who lost all its previous log.
|
||||||
e, _ := etcdFs.Get(path.Join("/_etcd/machines", c.Name), false, false, raftServer.CommitIndex(), raftServer.Term())
|
e, _ := etcdStore.Get(path.Join("/_etcd/machines", c.Name), false, false, raftServer.CommitIndex(), raftServer.Term())
|
||||||
|
|
||||||
b := make([]byte, 8)
|
b := make([]byte, 8)
|
||||||
binary.PutUvarint(b, raftServer.CommitIndex())
|
binary.PutUvarint(b, raftServer.CommitIndex())
|
||||||
@ -221,7 +221,7 @@ func (c *JoinCommand) Apply(raftServer *raft.Server) (interface{}, error) {
|
|||||||
// add machine in etcd storage
|
// add machine in etcd storage
|
||||||
key := path.Join("_etcd/machines", c.Name)
|
key := path.Join("_etcd/machines", c.Name)
|
||||||
value := fmt.Sprintf("raft=%s&etcd=%s&raftVersion=%s", c.RaftURL, c.EtcdURL, c.RaftVersion)
|
value := fmt.Sprintf("raft=%s&etcd=%s&raftVersion=%s", c.RaftURL, c.EtcdURL, c.RaftVersion)
|
||||||
etcdFs.Create(key, value, fileSystem.Permanent, raftServer.CommitIndex(), raftServer.Term())
|
etcdStore.Create(key, value, store.Permanent, raftServer.CommitIndex(), raftServer.Term())
|
||||||
|
|
||||||
if c.Name != r.Name() { // do not add self to the peer list
|
if c.Name != r.Name() { // do not add self to the peer list
|
||||||
r.peersStats[c.Name] = &raftPeerStats{MinLatency: 1 << 63}
|
r.peersStats[c.Name] = &raftPeerStats{MinLatency: 1 << 63}
|
||||||
@ -250,7 +250,7 @@ func (c *RemoveCommand) Apply(raftServer *raft.Server) (interface{}, error) {
|
|||||||
// remove machine in etcd storage
|
// remove machine in etcd storage
|
||||||
key := path.Join("_etcd/machines", c.Name)
|
key := path.Join("_etcd/machines", c.Name)
|
||||||
|
|
||||||
_, err := etcdFs.Delete(key, false, raftServer.CommitIndex(), raftServer.Term())
|
_, err := etcdStore.Delete(key, false, raftServer.CommitIndex(), raftServer.Term())
|
||||||
delete(r.peersStats, c.Name)
|
delete(r.peersStats, c.Name)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -32,27 +32,27 @@ func init() {
|
|||||||
errors = make(map[int]string)
|
errors = make(map[int]string)
|
||||||
|
|
||||||
// command related errors
|
// command related errors
|
||||||
errors[100] = "Key Not Found"
|
errors[EcodeKeyNotFound] = "Key Not Found"
|
||||||
errors[101] = "Test Failed" //test and set
|
errors[EcodeTestFailed] = "Test Failed" //test and set
|
||||||
errors[102] = "Not A File"
|
errors[EcodeNotFile] = "Not A File"
|
||||||
errors[103] = "Reached the max number of machines in the cluster"
|
errors[EcodeNoMoreMachine] = "Reached the max number of machines in the cluster"
|
||||||
errors[104] = "Not A Directory"
|
errors[EcodeNotDir] = "Not A Directory"
|
||||||
errors[105] = "Already exists" // create
|
errors[EcodeNodeExist] = "Already exists" // create
|
||||||
errors[106] = "The prefix of given key is a keyword in etcd"
|
errors[EcodeKeyIsPreserved] = "The prefix of given key is a keyword in etcd"
|
||||||
|
|
||||||
// Post form related errors
|
// Post form related errors
|
||||||
errors[200] = "Value is Required in POST form"
|
errors[EcodeValueRequired] = "Value is Required in POST form"
|
||||||
errors[201] = "PrevValue is Required in POST form"
|
errors[EcodePrevValueRequired] = "PrevValue is Required in POST form"
|
||||||
errors[202] = "The given TTL in POST form is not a number"
|
errors[EcodeTTLNaN] = "The given TTL in POST form is not a number"
|
||||||
errors[203] = "The given index in POST form is not a number"
|
errors[EcodeIndexNaN] = "The given index in POST form is not a number"
|
||||||
|
|
||||||
// raft related errors
|
// raft related errors
|
||||||
errors[300] = "Raft Internal Error"
|
errors[EcodeRaftInternal] = "Raft Internal Error"
|
||||||
errors[301] = "During Leader Election"
|
errors[EcodeLeaderElect] = "During Leader Election"
|
||||||
|
|
||||||
// etcd related errors
|
// etcd related errors
|
||||||
errors[400] = "watcher is cleared due to etcd recovery"
|
errors[EcodeWatcherCleared] = "watcher is cleared due to etcd recovery"
|
||||||
errors[401] = "The event in requested index is outdated and cleared"
|
errors[EcodeEventIndexCleared] = "The event in requested index is outdated and cleared"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
6
etcd.go
6
etcd.go
@ -10,7 +10,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/coreos/etcd/file_system"
|
"github.com/coreos/etcd/store"
|
||||||
"github.com/coreos/go-raft"
|
"github.com/coreos/go-raft"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -136,7 +136,7 @@ type TLSConfig struct {
|
|||||||
//
|
//
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
var etcdFs *fileSystem.FileSystem
|
var etcdStore *store.Store
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
@ -204,7 +204,7 @@ func main() {
|
|||||||
info := getInfo(dirPath)
|
info := getInfo(dirPath)
|
||||||
|
|
||||||
// Create etcd key-value store
|
// Create etcd key-value store
|
||||||
etcdFs = fileSystem.New()
|
etcdStore = store.New()
|
||||||
|
|
||||||
snapConf = newSnapshotConf()
|
snapConf = newSnapshotConf()
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
etcdErr "github.com/coreos/etcd/error"
|
etcdErr "github.com/coreos/etcd/error"
|
||||||
"github.com/coreos/etcd/file_system"
|
"github.com/coreos/etcd/store"
|
||||||
"github.com/coreos/go-raft"
|
"github.com/coreos/go-raft"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -120,7 +120,7 @@ func UpdateHttpHandler(w http.ResponseWriter, req *http.Request) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: update should give at least one option
|
// TODO: update should give at least one option
|
||||||
if value == "" && expireTime.Sub(fileSystem.Permanent) == 0 {
|
if value == "" && expireTime.Sub(store.Permanent) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,8 +223,7 @@ func VersionHttpHandler(w http.ResponseWriter, req *http.Request) error {
|
|||||||
// Handler to return the basic stats of etcd
|
// Handler to return the basic stats of etcd
|
||||||
func StatsHttpHandler(w http.ResponseWriter, req *http.Request) error {
|
func StatsHttpHandler(w http.ResponseWriter, req *http.Request) error {
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
//w.Write(etcdStore.Stats())
|
w.Write(etcdStore.JsonStats())
|
||||||
w.Write(etcdFs.Stats.GetStats())
|
|
||||||
w.Write(r.Stats())
|
w.Write(r.Stats())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -1,146 +0,0 @@
|
|||||||
package fileSystem
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Operations that will be running serializely
|
|
||||||
StatsSetsHit = 100
|
|
||||||
StatsSetsMiss = 101
|
|
||||||
StatsDeletesHit = 102
|
|
||||||
StatsDeletesMiss = 103
|
|
||||||
StatsUpdatesHit = 104
|
|
||||||
StatsUpdatesMiss = 105
|
|
||||||
StatsTestAndSetsHit = 106
|
|
||||||
StatsTestAndSetsMiss = 107
|
|
||||||
StatsRecoveryHit = 108
|
|
||||||
StatsRecoveryMiss = 109
|
|
||||||
|
|
||||||
// concurrent operations
|
|
||||||
StatsGetsHit = 200
|
|
||||||
StatsGetsMiss = 201
|
|
||||||
|
|
||||||
StatsWatchHit = 300
|
|
||||||
StatsWatchMiss = 301
|
|
||||||
StatsInWatchingNum = 302
|
|
||||||
|
|
||||||
StatsSaveHit = 400
|
|
||||||
StatsSaveMiss = 401
|
|
||||||
)
|
|
||||||
|
|
||||||
type EtcdStats struct {
|
|
||||||
|
|
||||||
// Lock for synchronization
|
|
||||||
rwlock sync.RWMutex
|
|
||||||
|
|
||||||
// Number of get requests
|
|
||||||
GetsHit uint64 `json:"gets_hits"`
|
|
||||||
GetsMiss uint64 `json:"gets_misses"`
|
|
||||||
|
|
||||||
// Number of sets requests
|
|
||||||
SetsHit uint64 `json:"sets_hits"`
|
|
||||||
SetsMiss uint64 `json:"sets_misses"`
|
|
||||||
|
|
||||||
// Number of delete requests
|
|
||||||
DeletesHit uint64 `json:"deletes_hits"`
|
|
||||||
DeletesMiss uint64 `json:"deletes_misses"`
|
|
||||||
|
|
||||||
// Number of update requests
|
|
||||||
UpdatesHit uint64 `json:"updates_hits"`
|
|
||||||
UpdatesMiss uint64 `json:"updates_misses"`
|
|
||||||
|
|
||||||
// Number of testAndSet requests
|
|
||||||
TestAndSetsHit uint64 `json:"testAndSets_hits"`
|
|
||||||
TestAndSetsMiss uint64 `json:"testAndSets_misses"`
|
|
||||||
|
|
||||||
// Number of Watch requests
|
|
||||||
WatchHit uint64 `json:"watch_hit"`
|
|
||||||
WatchMiss uint64 `json:"watch_miss"`
|
|
||||||
InWatchingNum uint64 `json:"in_watching_number"`
|
|
||||||
|
|
||||||
// Number of save requests
|
|
||||||
SaveHit uint64 `json:"save_hit"`
|
|
||||||
SaveMiss uint64 `json:"save_miss"`
|
|
||||||
|
|
||||||
// Number of recovery requests
|
|
||||||
RecoveryHit uint64 `json:"recovery_hit"`
|
|
||||||
RecoveryMiss uint64 `json:"recovery_miss"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func newStats() *EtcdStats {
|
|
||||||
e := new(EtcdStats)
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// Status() return the statistics info of etcd storage its recent start
|
|
||||||
func (e *EtcdStats) GetStats() []byte {
|
|
||||||
b, _ := json.Marshal(e)
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *EtcdStats) TotalReads() uint64 {
|
|
||||||
return e.GetsHit + e.GetsMiss
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *EtcdStats) TotalWrites() uint64 {
|
|
||||||
return e.SetsHit + e.SetsMiss +
|
|
||||||
e.DeletesHit + e.DeletesMiss +
|
|
||||||
e.UpdatesHit + e.UpdatesMiss +
|
|
||||||
e.TestAndSetsHit + e.TestAndSetsMiss
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *EtcdStats) IncStats(field int) {
|
|
||||||
if field >= 200 {
|
|
||||||
e.rwlock.Lock()
|
|
||||||
|
|
||||||
switch field {
|
|
||||||
case StatsGetsHit:
|
|
||||||
e.GetsHit++
|
|
||||||
case StatsGetsMiss:
|
|
||||||
e.GetsMiss++
|
|
||||||
case StatsWatchHit:
|
|
||||||
e.WatchHit++
|
|
||||||
case StatsWatchMiss:
|
|
||||||
e.WatchMiss++
|
|
||||||
case StatsInWatchingNum:
|
|
||||||
e.InWatchingNum++
|
|
||||||
case StatsSaveHit:
|
|
||||||
e.SaveHit++
|
|
||||||
case StatsSaveMiss:
|
|
||||||
e.SaveMiss++
|
|
||||||
}
|
|
||||||
|
|
||||||
e.rwlock.Unlock()
|
|
||||||
|
|
||||||
} else {
|
|
||||||
e.rwlock.RLock()
|
|
||||||
|
|
||||||
switch field {
|
|
||||||
case StatsSetsHit:
|
|
||||||
e.SetsHit++
|
|
||||||
case StatsSetsMiss:
|
|
||||||
e.SetsMiss++
|
|
||||||
case StatsDeletesHit:
|
|
||||||
e.DeletesHit++
|
|
||||||
case StatsDeletesMiss:
|
|
||||||
e.DeletesMiss++
|
|
||||||
case StatsUpdatesHit:
|
|
||||||
e.UpdatesHit++
|
|
||||||
case StatsUpdatesMiss:
|
|
||||||
e.UpdatesMiss++
|
|
||||||
case StatsTestAndSetsHit:
|
|
||||||
e.TestAndSetsHit++
|
|
||||||
case StatsTestAndSetsMiss:
|
|
||||||
e.TestAndSetsMiss++
|
|
||||||
case StatsRecoveryHit:
|
|
||||||
e.RecoveryHit++
|
|
||||||
case StatsRecoveryMiss:
|
|
||||||
e.RecoveryMiss++
|
|
||||||
}
|
|
||||||
|
|
||||||
e.rwlock.RUnlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,221 +0,0 @@
|
|||||||
package fileSystem
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math/rand"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
//"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestBasicStats(t *testing.T) {
|
|
||||||
fs := New()
|
|
||||||
keys := GenKeys(rand.Intn(100), 5)
|
|
||||||
|
|
||||||
i := uint64(0)
|
|
||||||
GetsHit := uint64(0)
|
|
||||||
GetsMiss := uint64(0)
|
|
||||||
SetsHit := uint64(0)
|
|
||||||
SetsMiss := uint64(0)
|
|
||||||
DeletesHit := uint64(0)
|
|
||||||
DeletesMiss := uint64(0)
|
|
||||||
UpdatesHit := uint64(0)
|
|
||||||
UpdatesMiss := uint64(0)
|
|
||||||
TestAndSetsHit := uint64(0)
|
|
||||||
TestAndSetsMiss := uint64(0)
|
|
||||||
WatchHit := uint64(0)
|
|
||||||
WatchMiss := uint64(0)
|
|
||||||
InWatchingNum := uint64(0)
|
|
||||||
SaveHit := uint64(0)
|
|
||||||
SaveMiss := uint64(0)
|
|
||||||
RecoveryHit := uint64(0)
|
|
||||||
RecoveryMiss := uint64(0)
|
|
||||||
|
|
||||||
for _, k := range keys {
|
|
||||||
i++
|
|
||||||
_, err := fs.Create(k, "bar", time.Now().Add(time.Second*time.Duration(rand.Intn(10))), i, 1)
|
|
||||||
if err != nil {
|
|
||||||
SetsMiss++
|
|
||||||
} else {
|
|
||||||
SetsHit++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, k := range keys {
|
|
||||||
_, err := fs.Get(k, false, false, i, 1)
|
|
||||||
if err != nil {
|
|
||||||
GetsMiss++
|
|
||||||
} else {
|
|
||||||
GetsHit++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, k := range keys {
|
|
||||||
i++
|
|
||||||
_, err := fs.Update(k, "foo", time.Now().Add(time.Second*time.Duration(rand.Intn(5))), i, 1)
|
|
||||||
if err != nil {
|
|
||||||
UpdatesMiss++
|
|
||||||
} else {
|
|
||||||
UpdatesHit++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, k := range keys {
|
|
||||||
_, err := fs.Get(k, false, false, i, 1)
|
|
||||||
if err != nil {
|
|
||||||
GetsMiss++
|
|
||||||
} else {
|
|
||||||
GetsHit++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, k := range keys {
|
|
||||||
i++
|
|
||||||
_, err := fs.TestAndSet(k, "foo", 0, "bar", Permanent, i, 1)
|
|
||||||
if err != nil {
|
|
||||||
TestAndSetsMiss++
|
|
||||||
} else {
|
|
||||||
TestAndSetsHit++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//fmt.Printf("#TestAndSet [%d]\n", TestAndSetsHit)
|
|
||||||
|
|
||||||
for _, k := range keys {
|
|
||||||
_, err := fs.Watch(k, false, 0, i, 1)
|
|
||||||
if err != nil {
|
|
||||||
WatchMiss++
|
|
||||||
} else {
|
|
||||||
WatchHit++
|
|
||||||
InWatchingNum++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//fmt.Printf("#Watch [%d]\n", WatchHit)
|
|
||||||
|
|
||||||
for _, k := range keys {
|
|
||||||
_, err := fs.Get(k, false, false, i, 1)
|
|
||||||
if err != nil {
|
|
||||||
GetsMiss++
|
|
||||||
} else {
|
|
||||||
GetsHit++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//fmt.Println("fs.index ", fs.Index)
|
|
||||||
for j := 0; j < 5; j++ {
|
|
||||||
b := make([]byte, 10)
|
|
||||||
err := fs.Recovery(b)
|
|
||||||
if err != nil {
|
|
||||||
RecoveryMiss++
|
|
||||||
}
|
|
||||||
|
|
||||||
b, err = fs.Save()
|
|
||||||
if err != nil {
|
|
||||||
SaveMiss++
|
|
||||||
} else {
|
|
||||||
SaveHit++
|
|
||||||
}
|
|
||||||
|
|
||||||
err = fs.Recovery(b)
|
|
||||||
if err != nil {
|
|
||||||
RecoveryMiss++
|
|
||||||
} else {
|
|
||||||
RecoveryHit++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//fmt.Println("fs.index after ", fs.Index)
|
|
||||||
//fmt.Println("stats.inwatching ", fs.Stats.InWatchingNum)
|
|
||||||
|
|
||||||
for _, k := range keys {
|
|
||||||
i++
|
|
||||||
_, err := fs.Delete(k, false, i, 1)
|
|
||||||
if err != nil {
|
|
||||||
DeletesMiss++
|
|
||||||
} else {
|
|
||||||
InWatchingNum--
|
|
||||||
DeletesHit++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//fmt.Printf("#Delete [%d] stats.deletehit [%d] \n", DeletesHit, fs.Stats.DeletesHit)
|
|
||||||
|
|
||||||
for _, k := range keys {
|
|
||||||
_, err := fs.Get(k, false, false, i, 1)
|
|
||||||
if err != nil {
|
|
||||||
GetsMiss++
|
|
||||||
} else {
|
|
||||||
GetsHit++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if GetsHit != fs.Stats.GetsHit {
|
|
||||||
t.Fatalf("GetsHit [%d] != Stats.GetsHit [%d]", GetsHit, fs.Stats.GetsHit)
|
|
||||||
}
|
|
||||||
|
|
||||||
if GetsMiss != fs.Stats.GetsMiss {
|
|
||||||
t.Fatalf("GetsMiss [%d] != Stats.GetsMiss [%d]", GetsMiss, fs.Stats.GetsMiss)
|
|
||||||
}
|
|
||||||
|
|
||||||
if SetsHit != fs.Stats.SetsHit {
|
|
||||||
t.Fatalf("SetsHit [%d] != Stats.SetsHit [%d]", SetsHit, fs.Stats.SetsHit)
|
|
||||||
}
|
|
||||||
|
|
||||||
if SetsMiss != fs.Stats.SetsMiss {
|
|
||||||
t.Fatalf("SetsMiss [%d] != Stats.SetsMiss [%d]", SetsMiss, fs.Stats.SetsMiss)
|
|
||||||
}
|
|
||||||
|
|
||||||
if DeletesHit != fs.Stats.DeletesHit {
|
|
||||||
t.Fatalf("DeletesHit [%d] != Stats.DeletesHit [%d]", DeletesHit, fs.Stats.DeletesHit)
|
|
||||||
}
|
|
||||||
|
|
||||||
if DeletesMiss != fs.Stats.DeletesMiss {
|
|
||||||
t.Fatalf("DeletesMiss [%d] != Stats.DeletesMiss [%d]", DeletesMiss, fs.Stats.DeletesMiss)
|
|
||||||
}
|
|
||||||
|
|
||||||
if UpdatesHit != fs.Stats.UpdatesHit {
|
|
||||||
t.Fatalf("UpdatesHit [%d] != Stats.UpdatesHit [%d]", UpdatesHit, fs.Stats.UpdatesHit)
|
|
||||||
}
|
|
||||||
|
|
||||||
if UpdatesMiss != fs.Stats.UpdatesMiss {
|
|
||||||
t.Fatalf("UpdatesMiss [%d] != Stats.UpdatesMiss [%d]", UpdatesMiss, fs.Stats.UpdatesMiss)
|
|
||||||
}
|
|
||||||
|
|
||||||
if TestAndSetsHit != fs.Stats.TestAndSetsHit {
|
|
||||||
t.Fatalf("TestAndSetsHit [%d] != Stats.TestAndSetsHit [%d]", TestAndSetsHit, fs.Stats.TestAndSetsHit)
|
|
||||||
}
|
|
||||||
|
|
||||||
if TestAndSetsMiss != fs.Stats.TestAndSetsMiss {
|
|
||||||
t.Fatalf("TestAndSetsMiss [%d] != Stats.TestAndSetsMiss [%d]", TestAndSetsMiss, fs.Stats.TestAndSetsMiss)
|
|
||||||
}
|
|
||||||
|
|
||||||
if SaveHit != fs.Stats.SaveHit {
|
|
||||||
t.Fatalf("SaveHit [%d] != Stats.SaveHit [%d]", SaveHit, fs.Stats.SaveHit)
|
|
||||||
}
|
|
||||||
|
|
||||||
if SaveMiss != fs.Stats.SaveMiss {
|
|
||||||
t.Fatalf("SaveMiss [%d] != Stats.SaveMiss [%d]", SaveMiss, fs.Stats.SaveMiss)
|
|
||||||
}
|
|
||||||
|
|
||||||
if WatchHit != fs.Stats.WatchHit {
|
|
||||||
t.Fatalf("WatchHit [%d] != Stats.WatchHit [%d]", WatchHit, fs.Stats.WatchHit)
|
|
||||||
}
|
|
||||||
|
|
||||||
if WatchMiss != fs.Stats.WatchMiss {
|
|
||||||
t.Fatalf("WatchMiss [%d] != Stats.WatchMiss [%d]", WatchMiss, fs.Stats.WatchMiss)
|
|
||||||
}
|
|
||||||
|
|
||||||
if InWatchingNum != fs.Stats.InWatchingNum {
|
|
||||||
t.Fatalf("InWatchingNum [%d] != Stats.InWatchingNum [%d]", InWatchingNum, fs.Stats.InWatchingNum)
|
|
||||||
}
|
|
||||||
|
|
||||||
if RecoveryHit != fs.Stats.RecoveryHit {
|
|
||||||
t.Fatalf("RecoveryHit [%d] != Stats.RecoveryHit [%d]", RecoveryHit, fs.Stats.RecoveryHit)
|
|
||||||
}
|
|
||||||
|
|
||||||
if RecoveryMiss != fs.Stats.RecoveryMiss {
|
|
||||||
t.Fatalf("RecoveryMiss [%d] != Stats.RecoveryMiss [%d]", RecoveryMiss, fs.Stats.RecoveryMiss)
|
|
||||||
}
|
|
||||||
|
|
||||||
//fmt.Println(GetsHit, GetsMiss, SetsHit, SetsMiss, DeletesHit, DeletesMiss, UpdatesHit, UpdatesMiss, TestAndSetsHit, TestAndSetsMiss, WatchHit, WatchMiss, InWatchingNum, SaveHit, SaveMiss, RecoveryHit, RecoveryMiss)
|
|
||||||
|
|
||||||
}
|
|
@ -2,7 +2,7 @@ package main
|
|||||||
|
|
||||||
// machineNum returns the number of machines in the cluster
|
// machineNum returns the number of machines in the cluster
|
||||||
func machineNum() int {
|
func machineNum() int {
|
||||||
e, err := etcdFs.Get("/_etcd/machines", false, false, r.CommitIndex(), r.Term())
|
e, err := etcdStore.Get("/_etcd/machines", false, false, r.CommitIndex(), r.Term())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0
|
return 0
|
||||||
|
@ -56,7 +56,7 @@ func readURL(nodeName string, urlName string) (string, bool) {
|
|||||||
// convert nodeName to url from etcd storage
|
// convert nodeName to url from etcd storage
|
||||||
key := path.Join("/_etcd/machines", nodeName)
|
key := path.Join("/_etcd/machines", nodeName)
|
||||||
|
|
||||||
e, err := etcdFs.Get(key, false, false, r.CommitIndex(), r.Term())
|
e, err := etcdStore.Get(key, false, false, r.CommitIndex(), r.Term())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", false
|
return "", false
|
||||||
|
@ -36,7 +36,7 @@ func newRaftServer(name string, url string, listenHost string, tlsConf *TLSConfi
|
|||||||
raftTransporter := newTransporter(tlsConf.Scheme, tlsConf.Client, ElectionTimeout)
|
raftTransporter := newTransporter(tlsConf.Scheme, tlsConf.Client, ElectionTimeout)
|
||||||
|
|
||||||
// Create raft server
|
// Create raft server
|
||||||
server, err := raft.NewServer(name, dirPath, raftTransporter, etcdFs, nil)
|
server, err := raft.NewServer(name, dirPath, raftTransporter, etcdStore, nil)
|
||||||
|
|
||||||
check(err)
|
check(err)
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package fileSystem
|
package store
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -6,7 +6,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
etcdErr "github.com/xiangli-cmu/etcd/error"
|
etcdErr "github.com/coreos/etcd/error"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
@ -1,4 +1,4 @@
|
|||||||
package fileSystem
|
package store
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
@ -1,4 +1,4 @@
|
|||||||
package fileSystem
|
package store
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"path"
|
"path"
|
||||||
@ -6,7 +6,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
etcdErr "github.com/xiangli-cmu/etcd/error"
|
etcdErr "github.com/coreos/etcd/error"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
91
store/stats.go
Normal file
91
store/stats.go
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
package store
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"sync/atomic"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
SetSuccess = 100
|
||||||
|
SetFail = 101
|
||||||
|
DeleteSuccess = 102
|
||||||
|
DeleteFail = 103
|
||||||
|
UpdateSuccess = 104
|
||||||
|
UpdateFail = 105
|
||||||
|
TestAndSetSuccess = 106
|
||||||
|
TestAndSetFail = 107
|
||||||
|
GetSuccess = 110
|
||||||
|
GetFail = 111
|
||||||
|
)
|
||||||
|
|
||||||
|
type Stats struct {
|
||||||
|
|
||||||
|
// Number of get requests
|
||||||
|
GetSuccess uint64 `json:"getsSuccess"`
|
||||||
|
GetFail uint64 `json:"getsFail"`
|
||||||
|
|
||||||
|
// Number of sets requests
|
||||||
|
SetSuccess uint64 `json:"setsSuccess"`
|
||||||
|
SetFail uint64 `json:"setsFail"`
|
||||||
|
|
||||||
|
// Number of delete requests
|
||||||
|
DeleteSuccess uint64 `json:"deleteSuccess"`
|
||||||
|
DeleteFail uint64 `json:"deleteFail"`
|
||||||
|
|
||||||
|
// Number of update requests
|
||||||
|
UpdateSuccess uint64 `json:"updateSuccess"`
|
||||||
|
UpdateFail uint64 `json:"updateFail"`
|
||||||
|
|
||||||
|
// Number of testAndSet requests
|
||||||
|
TestAndSetSuccess uint64 `json:"testAndSetSuccess"`
|
||||||
|
TestAndSetFail uint64 `json:"testAndSetFail"`
|
||||||
|
|
||||||
|
Watchers uint64 `json:"watchers"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func newStats() *Stats {
|
||||||
|
s := new(Stats)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Status() return the statistics info of etcd storage its recent start
|
||||||
|
func (s *Stats) toJson() []byte {
|
||||||
|
b, _ := json.Marshal(s)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Stats) TotalReads() uint64 {
|
||||||
|
return s.GetSuccess + s.GetFail
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Stats) TotalWrites() uint64 {
|
||||||
|
return s.SetSuccess + s.SetFail +
|
||||||
|
s.DeleteSuccess + s.DeleteFail +
|
||||||
|
s.TestAndSetSuccess + s.TestAndSetFail +
|
||||||
|
s.UpdateSuccess + s.UpdateFail
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Stats) Inc(field int) {
|
||||||
|
switch field {
|
||||||
|
case SetSuccess:
|
||||||
|
atomic.AddUint64(&s.SetSuccess, 1)
|
||||||
|
case SetFail:
|
||||||
|
atomic.AddUint64(&s.SetFail, 1)
|
||||||
|
case DeleteSuccess:
|
||||||
|
atomic.AddUint64(&s.DeleteSuccess, 1)
|
||||||
|
case DeleteFail:
|
||||||
|
atomic.AddUint64(&s.DeleteFail, 1)
|
||||||
|
case GetSuccess:
|
||||||
|
atomic.AddUint64(&s.GetSuccess, 1)
|
||||||
|
case GetFail:
|
||||||
|
atomic.AddUint64(&s.GetFail, 1)
|
||||||
|
case UpdateSuccess:
|
||||||
|
atomic.AddUint64(&s.UpdateSuccess, 1)
|
||||||
|
case UpdateFail:
|
||||||
|
atomic.AddUint64(&s.UpdateFail, 1)
|
||||||
|
case TestAndSetSuccess:
|
||||||
|
atomic.AddUint64(&s.TestAndSetSuccess, 1)
|
||||||
|
case TestAndSetFail:
|
||||||
|
atomic.AddUint64(&s.TestAndSetFail, 1)
|
||||||
|
}
|
||||||
|
}
|
139
store/stats_test.go
Normal file
139
store/stats_test.go
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
package store
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/rand"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBasicStats(t *testing.T) {
|
||||||
|
s := New()
|
||||||
|
keys := GenKeys(rand.Intn(100), 5)
|
||||||
|
|
||||||
|
var i uint64
|
||||||
|
var GetSuccess, GetFail, SetSuccess, SetFail, DeleteSuccess, DeleteFail uint64
|
||||||
|
var UpdateSuccess, UpdateFail, TestAndSetSuccess, TestAndSetFail, watcher_number uint64
|
||||||
|
|
||||||
|
for _, k := range keys {
|
||||||
|
i++
|
||||||
|
_, err := s.Create(k, "bar", time.Now().Add(time.Second*time.Duration(rand.Intn(10))), i, 1)
|
||||||
|
if err != nil {
|
||||||
|
SetFail++
|
||||||
|
} else {
|
||||||
|
SetSuccess++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, k := range keys {
|
||||||
|
_, err := s.Get(k, false, false, i, 1)
|
||||||
|
if err != nil {
|
||||||
|
GetFail++
|
||||||
|
} else {
|
||||||
|
GetSuccess++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, k := range keys {
|
||||||
|
i++
|
||||||
|
_, err := s.Update(k, "foo", time.Now().Add(time.Second*time.Duration(rand.Intn(5))), i, 1)
|
||||||
|
if err != nil {
|
||||||
|
UpdateFail++
|
||||||
|
} else {
|
||||||
|
UpdateSuccess++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, k := range keys {
|
||||||
|
_, err := s.Get(k, false, false, i, 1)
|
||||||
|
if err != nil {
|
||||||
|
GetFail++
|
||||||
|
} else {
|
||||||
|
GetSuccess++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, k := range keys {
|
||||||
|
i++
|
||||||
|
_, err := s.TestAndSet(k, "foo", 0, "bar", Permanent, i, 1)
|
||||||
|
if err != nil {
|
||||||
|
TestAndSetFail++
|
||||||
|
} else {
|
||||||
|
TestAndSetSuccess++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, k := range keys {
|
||||||
|
s.Watch(k, false, 0, i, 1)
|
||||||
|
watcher_number++
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, k := range keys {
|
||||||
|
_, err := s.Get(k, false, false, i, 1)
|
||||||
|
if err != nil {
|
||||||
|
GetFail++
|
||||||
|
} else {
|
||||||
|
GetSuccess++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, k := range keys {
|
||||||
|
i++
|
||||||
|
_, err := s.Delete(k, false, i, 1)
|
||||||
|
if err != nil {
|
||||||
|
DeleteFail++
|
||||||
|
} else {
|
||||||
|
watcher_number--
|
||||||
|
DeleteSuccess++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, k := range keys {
|
||||||
|
_, err := s.Get(k, false, false, i, 1)
|
||||||
|
if err != nil {
|
||||||
|
GetFail++
|
||||||
|
} else {
|
||||||
|
GetSuccess++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if GetSuccess != s.Stats.GetSuccess {
|
||||||
|
t.Fatalf("GetSuccess [%d] != Stats.GetSuccess [%d]", GetSuccess, s.Stats.GetSuccess)
|
||||||
|
}
|
||||||
|
|
||||||
|
if GetFail != s.Stats.GetFail {
|
||||||
|
t.Fatalf("GetFail [%d] != Stats.GetFail [%d]", GetFail, s.Stats.GetFail)
|
||||||
|
}
|
||||||
|
|
||||||
|
if SetSuccess != s.Stats.SetSuccess {
|
||||||
|
t.Fatalf("SetSuccess [%d] != Stats.SetSuccess [%d]", SetSuccess, s.Stats.SetSuccess)
|
||||||
|
}
|
||||||
|
|
||||||
|
if SetFail != s.Stats.SetFail {
|
||||||
|
t.Fatalf("SetFail [%d] != Stats.SetFail [%d]", SetFail, s.Stats.SetFail)
|
||||||
|
}
|
||||||
|
|
||||||
|
if DeleteSuccess != s.Stats.DeleteSuccess {
|
||||||
|
t.Fatalf("DeleteSuccess [%d] != Stats.DeleteSuccess [%d]", DeleteSuccess, s.Stats.DeleteSuccess)
|
||||||
|
}
|
||||||
|
|
||||||
|
if DeleteFail != s.Stats.DeleteFail {
|
||||||
|
t.Fatalf("DeleteFail [%d] != Stats.DeleteFail [%d]", DeleteFail, s.Stats.DeleteFail)
|
||||||
|
}
|
||||||
|
|
||||||
|
if UpdateSuccess != s.Stats.UpdateSuccess {
|
||||||
|
t.Fatalf("UpdateSuccess [%d] != Stats.UpdateSuccess [%d]", UpdateSuccess, s.Stats.UpdateSuccess)
|
||||||
|
}
|
||||||
|
|
||||||
|
if UpdateFail != s.Stats.UpdateFail {
|
||||||
|
t.Fatalf("UpdateFail [%d] != Stats.UpdateFail [%d]", UpdateFail, s.Stats.UpdateFail)
|
||||||
|
}
|
||||||
|
|
||||||
|
if TestAndSetSuccess != s.Stats.TestAndSetSuccess {
|
||||||
|
t.Fatalf("TestAndSetSuccess [%d] != Stats.TestAndSetSuccess [%d]", TestAndSetSuccess, s.Stats.TestAndSetSuccess)
|
||||||
|
}
|
||||||
|
|
||||||
|
if TestAndSetFail != s.Stats.TestAndSetFail {
|
||||||
|
t.Fatalf("TestAndSetFail [%d] != Stats.TestAndSetFail [%d]", TestAndSetFail, s.Stats.TestAndSetFail)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package fileSystem
|
package store
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@ -8,34 +8,34 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
etcdErr "github.com/xiangli-cmu/etcd/error"
|
etcdErr "github.com/coreos/etcd/error"
|
||||||
)
|
)
|
||||||
|
|
||||||
type FileSystem struct {
|
type Store struct {
|
||||||
Root *Node
|
Root *Node
|
||||||
WatcherHub *watcherHub
|
WatcherHub *watcherHub
|
||||||
Index uint64
|
Index uint64
|
||||||
Term uint64
|
Term uint64
|
||||||
Stats *EtcdStats
|
Stats *Stats
|
||||||
}
|
}
|
||||||
|
|
||||||
func New() *FileSystem {
|
func New() *Store {
|
||||||
fs := new(FileSystem)
|
s := new(Store)
|
||||||
fs.Root = newDir("/", 0, 0, nil, "", Permanent)
|
s.Root = newDir("/", 0, 0, nil, "", Permanent)
|
||||||
fs.Stats = newStats()
|
s.Stats = newStats()
|
||||||
fs.WatcherHub = newWatchHub(1000, fs.Stats)
|
s.WatcherHub = newWatchHub(1000)
|
||||||
|
|
||||||
return fs
|
return s
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *FileSystem) Get(nodePath string, recursive, sorted bool, index uint64, term uint64) (*Event, error) {
|
func (s *Store) Get(nodePath string, recursive, sorted bool, index uint64, term uint64) (*Event, error) {
|
||||||
nodePath = path.Clean(path.Join("/", nodePath))
|
nodePath = path.Clean(path.Join("/", nodePath))
|
||||||
|
|
||||||
n, err := fs.InternalGet(nodePath, index, term)
|
n, err := s.InternalGet(nodePath, index, term)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fs.Stats.IncStats(StatsGetsMiss)
|
s.Stats.Inc(GetFail)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,61 +82,62 @@ func (fs *FileSystem) Get(nodePath string, recursive, sorted bool, index uint64,
|
|||||||
e.TTL = int64(n.ExpireTime.Sub(time.Now())/time.Second) + 1
|
e.TTL = int64(n.ExpireTime.Sub(time.Now())/time.Second) + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.Stats.IncStats(StatsGetsHit)
|
s.Stats.Inc(GetSuccess)
|
||||||
|
|
||||||
return e, nil
|
return e, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create function creates the Node at nodePath. Create will help to create intermediate directories with no ttl.
|
// Create function creates the Node at nodePath. Create will help to create intermediate directories with no ttl.
|
||||||
// If the node has already existed, create will fail.
|
// If the node has already existed, create will fail.
|
||||||
// If any node on the path is a file, create will fail.
|
// If any node on the path is a file, create will fail.
|
||||||
func (fs *FileSystem) Create(nodePath string, value string, expireTime time.Time, index uint64, term uint64) (*Event, error) {
|
func (s *Store) Create(nodePath string, value string, expireTime time.Time, index uint64, term uint64) (*Event, error) {
|
||||||
nodePath = path.Clean(path.Join("/", nodePath))
|
nodePath = path.Clean(path.Join("/", nodePath))
|
||||||
|
|
||||||
// make sure we can create the node
|
// make sure we can create the node
|
||||||
_, err := fs.InternalGet(nodePath, index, term)
|
_, err := s.InternalGet(nodePath, index, term)
|
||||||
|
|
||||||
if err == nil { // key already exists
|
if err == nil { // key already exists
|
||||||
fs.Stats.IncStats(StatsSetsMiss)
|
s.Stats.Inc(SetFail)
|
||||||
return nil, etcdErr.NewError(etcdErr.EcodeNodeExist, nodePath)
|
return nil, etcdErr.NewError(etcdErr.EcodeNodeExist, nodePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
etcdError, _ := err.(etcdErr.Error)
|
etcdError, _ := err.(etcdErr.Error)
|
||||||
|
|
||||||
if etcdError.ErrorCode == 104 { // we cannot create the key due to meet a file while walking
|
if etcdError.ErrorCode == 104 { // we cannot create the key due to meet a file while walking
|
||||||
fs.Stats.IncStats(StatsSetsMiss)
|
s.Stats.Inc(SetFail)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
dir, _ := path.Split(nodePath)
|
dir, _ := path.Split(nodePath)
|
||||||
|
|
||||||
// walk through the nodePath, create dirs and get the last directory node
|
// walk through the nodePath, create dirs and get the last directory node
|
||||||
d, err := fs.walk(dir, fs.checkDir)
|
d, err := s.walk(dir, s.checkDir)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fs.Stats.IncStats(StatsSetsMiss)
|
s.Stats.Inc(SetFail)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
e := newEvent(Create, nodePath, fs.Index, fs.Term)
|
e := newEvent(Create, nodePath, s.Index, s.Term)
|
||||||
|
|
||||||
var n *Node
|
var n *Node
|
||||||
|
|
||||||
if len(value) != 0 { // create file
|
if len(value) != 0 { // create file
|
||||||
e.Value = value
|
e.Value = value
|
||||||
|
|
||||||
n = newFile(nodePath, value, fs.Index, fs.Term, d, "", expireTime)
|
n = newFile(nodePath, value, s.Index, s.Term, d, "", expireTime)
|
||||||
|
|
||||||
} else { // create directory
|
} else { // create directory
|
||||||
e.Dir = true
|
e.Dir = true
|
||||||
|
|
||||||
n = newDir(nodePath, fs.Index, fs.Term, d, "", expireTime)
|
n = newDir(nodePath, s.Index, s.Term, d, "", expireTime)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = d.Add(n)
|
err = d.Add(n)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fs.Stats.IncStats(StatsSetsMiss)
|
s.Stats.Inc(SetFail)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,28 +148,28 @@ func (fs *FileSystem) Create(nodePath string, value string, expireTime time.Time
|
|||||||
e.TTL = int64(expireTime.Sub(time.Now())/time.Second) + 1
|
e.TTL = int64(expireTime.Sub(time.Now())/time.Second) + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.WatcherHub.notify(e)
|
s.WatcherHub.notify(e)
|
||||||
fs.Stats.IncStats(StatsSetsHit)
|
s.Stats.Inc(SetSuccess)
|
||||||
return e, nil
|
return e, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update function updates the value/ttl of the node.
|
// Update function updates the value/ttl of the node.
|
||||||
// If the node is a file, the value and the ttl can be updated.
|
// If the node is a file, the value and the ttl can be updated.
|
||||||
// If the node is a directory, only the ttl can be updated.
|
// If the node is a directory, only the ttl can be updated.
|
||||||
func (fs *FileSystem) Update(nodePath string, value string, expireTime time.Time, index uint64, term uint64) (*Event, error) {
|
func (s *Store) Update(nodePath string, value string, expireTime time.Time, index uint64, term uint64) (*Event, error) {
|
||||||
n, err := fs.InternalGet(nodePath, index, term)
|
n, err := s.InternalGet(nodePath, index, term)
|
||||||
|
|
||||||
if err != nil { // if the node does not exist, return error
|
if err != nil { // if the node does not exist, return error
|
||||||
fs.Stats.IncStats(StatsUpdatesMiss)
|
s.Stats.Inc(UpdateFail)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
e := newEvent(Update, nodePath, fs.Index, fs.Term)
|
e := newEvent(Update, nodePath, s.Index, s.Term)
|
||||||
|
|
||||||
if n.IsDir() { // if the node is a directory, we can only update ttl
|
if n.IsDir() { // if the node is a directory, we can only update ttl
|
||||||
|
|
||||||
if len(value) != 0 {
|
if len(value) != 0 {
|
||||||
fs.Stats.IncStats(StatsUpdatesMiss)
|
s.Stats.Inc(UpdateFail)
|
||||||
return nil, etcdErr.NewError(etcdErr.EcodeNotFile, nodePath)
|
return nil, etcdErr.NewError(etcdErr.EcodeNotFile, nodePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,23 +195,23 @@ func (fs *FileSystem) Update(nodePath string, value string, expireTime time.Time
|
|||||||
e.TTL = int64(expireTime.Sub(time.Now())/time.Second) + 1
|
e.TTL = int64(expireTime.Sub(time.Now())/time.Second) + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.WatcherHub.notify(e)
|
s.WatcherHub.notify(e)
|
||||||
fs.Stats.IncStats(StatsUpdatesHit)
|
s.Stats.Inc(UpdateSuccess)
|
||||||
return e, nil
|
return e, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *FileSystem) TestAndSet(nodePath string, prevValue string, prevIndex uint64,
|
func (s *Store) TestAndSet(nodePath string, prevValue string, prevIndex uint64,
|
||||||
value string, expireTime time.Time, index uint64, term uint64) (*Event, error) {
|
value string, expireTime time.Time, index uint64, term uint64) (*Event, error) {
|
||||||
|
|
||||||
f, err := fs.InternalGet(nodePath, index, term)
|
f, err := s.InternalGet(nodePath, index, term)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fs.Stats.IncStats(StatsTestAndSetsMiss)
|
s.Stats.Inc(TestAndSetFail)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if f.IsDir() { // can only test and set file
|
if f.IsDir() { // can only test and set file
|
||||||
fs.Stats.IncStats(StatsTestAndSetsMiss)
|
s.Stats.Inc(TestAndSetFail)
|
||||||
return nil, etcdErr.NewError(etcdErr.EcodeNotFile, nodePath)
|
return nil, etcdErr.NewError(etcdErr.EcodeNotFile, nodePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,23 +222,23 @@ func (fs *FileSystem) TestAndSet(nodePath string, prevValue string, prevIndex ui
|
|||||||
e.Value = value
|
e.Value = value
|
||||||
f.Write(value, index, term)
|
f.Write(value, index, term)
|
||||||
|
|
||||||
fs.WatcherHub.notify(e)
|
s.WatcherHub.notify(e)
|
||||||
fs.Stats.IncStats(StatsTestAndSetsHit)
|
s.Stats.Inc(TestAndSetSuccess)
|
||||||
return e, nil
|
return e, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
cause := fmt.Sprintf("[%v != %v] [%v != %v]", prevValue, f.Value, prevIndex, f.ModifiedIndex)
|
cause := fmt.Sprintf("[%v != %v] [%v != %v]", prevValue, f.Value, prevIndex, f.ModifiedIndex)
|
||||||
fs.Stats.IncStats(StatsTestAndSetsMiss)
|
s.Stats.Inc(TestAndSetFail)
|
||||||
return nil, etcdErr.NewError(etcdErr.EcodeTestFailed, cause)
|
return nil, etcdErr.NewError(etcdErr.EcodeTestFailed, cause)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete function deletes the node at the given path.
|
// Delete function deletes the node at the given path.
|
||||||
// If the node is a directory, recursive must be true to delete it.
|
// If the node is a directory, recursive must be true to delete it.
|
||||||
func (fs *FileSystem) Delete(nodePath string, recursive bool, index uint64, term uint64) (*Event, error) {
|
func (s *Store) Delete(nodePath string, recursive bool, index uint64, term uint64) (*Event, error) {
|
||||||
n, err := fs.InternalGet(nodePath, index, term)
|
n, err := s.InternalGet(nodePath, index, term)
|
||||||
|
|
||||||
if err != nil { // if the node does not exist, return error
|
if err != nil { // if the node does not exist, return error
|
||||||
fs.Stats.IncStats(StatsDeletesMiss)
|
s.Stats.Inc(DeleteFail)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,37 +251,37 @@ func (fs *FileSystem) Delete(nodePath string, recursive bool, index uint64, term
|
|||||||
}
|
}
|
||||||
|
|
||||||
callback := func(path string) { // notify function
|
callback := func(path string) { // notify function
|
||||||
fs.WatcherHub.notifyWithPath(e, path, true)
|
s.WatcherHub.notifyWithPath(e, path, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = n.Remove(recursive, callback)
|
err = n.Remove(recursive, callback)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fs.Stats.IncStats(StatsDeletesMiss)
|
s.Stats.Inc(DeleteFail)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.WatcherHub.notify(e)
|
s.WatcherHub.notify(e)
|
||||||
fs.Stats.IncStats(StatsDeletesHit)
|
s.Stats.Inc(DeleteSuccess)
|
||||||
|
|
||||||
return e, nil
|
return e, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *FileSystem) Watch(prefix string, recursive bool, sinceIndex uint64, index uint64, term uint64) (<-chan *Event, error) {
|
func (s *Store) Watch(prefix string, recursive bool, sinceIndex uint64, index uint64, term uint64) (<-chan *Event, error) {
|
||||||
fs.Index, fs.Term = index, term
|
s.Index, s.Term = index, term
|
||||||
|
|
||||||
if sinceIndex == 0 {
|
if sinceIndex == 0 {
|
||||||
return fs.WatcherHub.watch(prefix, recursive, index+1)
|
return s.WatcherHub.watch(prefix, recursive, index+1)
|
||||||
}
|
}
|
||||||
|
|
||||||
return fs.WatcherHub.watch(prefix, recursive, sinceIndex)
|
return s.WatcherHub.watch(prefix, recursive, sinceIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
// walk function walks all the nodePath and apply the walkFunc on each directory
|
// walk function walks all the nodePath and apply the walkFunc on each directory
|
||||||
func (fs *FileSystem) walk(nodePath string, walkFunc func(prev *Node, component string) (*Node, error)) (*Node, error) {
|
func (s *Store) walk(nodePath string, walkFunc func(prev *Node, component string) (*Node, error)) (*Node, error) {
|
||||||
components := strings.Split(nodePath, "/")
|
components := strings.Split(nodePath, "/")
|
||||||
|
|
||||||
curr := fs.Root
|
curr := s.Root
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
for i := 1; i < len(components); i++ {
|
for i := 1; i < len(components); i++ {
|
||||||
@ -299,11 +300,11 @@ func (fs *FileSystem) walk(nodePath string, walkFunc func(prev *Node, component
|
|||||||
}
|
}
|
||||||
|
|
||||||
// InternalGet function get the node of the given nodePath.
|
// InternalGet function get the node of the given nodePath.
|
||||||
func (fs *FileSystem) InternalGet(nodePath string, index uint64, term uint64) (*Node, error) {
|
func (s *Store) InternalGet(nodePath string, index uint64, term uint64) (*Node, error) {
|
||||||
nodePath = path.Clean(path.Join("/", nodePath))
|
nodePath = path.Clean(path.Join("/", nodePath))
|
||||||
|
|
||||||
// update file system known index and term
|
// update file system known index and term
|
||||||
fs.Index, fs.Term = index, term
|
s.Index, s.Term = index, term
|
||||||
|
|
||||||
walkFunc := func(parent *Node, name string) (*Node, error) {
|
walkFunc := func(parent *Node, name string) (*Node, error) {
|
||||||
|
|
||||||
@ -319,7 +320,7 @@ func (fs *FileSystem) InternalGet(nodePath string, index uint64, term uint64) (*
|
|||||||
return nil, etcdErr.NewError(etcdErr.EcodeKeyNotFound, path.Join(parent.Path, name))
|
return nil, etcdErr.NewError(etcdErr.EcodeKeyNotFound, path.Join(parent.Path, name))
|
||||||
}
|
}
|
||||||
|
|
||||||
f, err := fs.walk(nodePath, walkFunc)
|
f, err := s.walk(nodePath, walkFunc)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -332,14 +333,14 @@ func (fs *FileSystem) InternalGet(nodePath string, index uint64, term uint64) (*
|
|||||||
// If it is a directory, this function will return the pointer to that node.
|
// If it is a directory, this function will return the pointer to that node.
|
||||||
// If it does not exist, this function will create a new directory and return the pointer to that node.
|
// If it does not exist, this function will create a new directory and return the pointer to that node.
|
||||||
// If it is a file, this function will return error.
|
// If it is a file, this function will return error.
|
||||||
func (fs *FileSystem) checkDir(parent *Node, dirName string) (*Node, error) {
|
func (s *Store) checkDir(parent *Node, dirName string) (*Node, error) {
|
||||||
subDir, ok := parent.Children[dirName]
|
subDir, ok := parent.Children[dirName]
|
||||||
|
|
||||||
if ok {
|
if ok {
|
||||||
return subDir, nil
|
return subDir, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
n := newDir(path.Join(parent.Path, dirName), fs.Index, fs.Term, parent, parent.ACL, Permanent)
|
n := newDir(path.Join(parent.Path, dirName), s.Index, s.Term, parent, parent.ACL, Permanent)
|
||||||
|
|
||||||
parent.Children[dirName] = n
|
parent.Children[dirName] = n
|
||||||
|
|
||||||
@ -350,24 +351,20 @@ func (fs *FileSystem) checkDir(parent *Node, dirName string) (*Node, error) {
|
|||||||
// Save function will not be able to save the state of watchers.
|
// Save function will not be able to save the state of watchers.
|
||||||
// Save function will not save the parent field of the node. Or there will
|
// Save function will not save the parent field of the node. Or there will
|
||||||
// be cyclic dependencies issue for the json package.
|
// be cyclic dependencies issue for the json package.
|
||||||
func (fs *FileSystem) Save() ([]byte, error) {
|
func (s *Store) Save() ([]byte, error) {
|
||||||
|
clonedStore := New()
|
||||||
|
clonedStore.Root = s.Root.Clone()
|
||||||
|
clonedStore.WatcherHub = s.WatcherHub
|
||||||
|
clonedStore.Index = s.Index
|
||||||
|
clonedStore.Term = s.Term
|
||||||
|
clonedStore.Stats = s.Stats
|
||||||
|
|
||||||
fs.Stats.IncStats(StatsSaveHit)
|
b, err := json.Marshal(clonedStore)
|
||||||
cloneFs := New()
|
|
||||||
cloneFs.Root = fs.Root.Clone()
|
|
||||||
|
|
||||||
b, err := json.Marshal(fs)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fs.Stats.IncStats(StatsSaveMiss)
|
|
||||||
fs.Stats.rwlock.Lock()
|
|
||||||
fs.Stats.SaveHit-- // restore the savehit
|
|
||||||
fs.Stats.rwlock.Unlock()
|
|
||||||
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.Stats.IncStats(StatsSaveHit)
|
|
||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -375,15 +372,18 @@ func (fs *FileSystem) Save() ([]byte, error) {
|
|||||||
// It needs to recovery the parent field of the nodes.
|
// It needs to recovery the parent field of the nodes.
|
||||||
// It needs to delete the expired nodes since the saved time and also
|
// It needs to delete the expired nodes since the saved time and also
|
||||||
// need to create monitor go routines.
|
// need to create monitor go routines.
|
||||||
func (fs *FileSystem) Recovery(state []byte) error {
|
func (s *Store) Recovery(state []byte) error {
|
||||||
err := json.Unmarshal(state, fs)
|
err := json.Unmarshal(state, s)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fs.Stats.IncStats(StatsRecoveryMiss)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.Root.recoverAndclean()
|
s.Root.recoverAndclean()
|
||||||
fs.Stats.IncStats(StatsRecoveryHit)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Store) JsonStats() []byte {
|
||||||
|
s.Stats.Watchers = uint64(s.WatcherHub.count)
|
||||||
|
return s.Stats.toJson()
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package fileSystem
|
package store
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/rand"
|
"math/rand"
|
||||||
@ -8,46 +8,46 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestCreateAndGet(t *testing.T) {
|
func TestCreateAndGet(t *testing.T) {
|
||||||
fs := New()
|
s := New()
|
||||||
|
|
||||||
fs.Create("/foobar", "bar", Permanent, 1, 1)
|
s.Create("/foobar", "bar", Permanent, 1, 1)
|
||||||
|
|
||||||
// already exist, create should fail
|
// already exist, create should fail
|
||||||
_, err := fs.Create("/foobar", "bar", Permanent, 1, 1)
|
_, err := s.Create("/foobar", "bar", Permanent, 1, 1)
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("Create should fail")
|
t.Fatal("Create should fail")
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.Delete("/foobar", true, 1, 1)
|
s.Delete("/foobar", true, 1, 1)
|
||||||
|
|
||||||
// this should create successfully
|
// this should create successfully
|
||||||
createAndGet(fs, "/foobar", t)
|
createAndGet(s, "/foobar", t)
|
||||||
createAndGet(fs, "/foo/bar", t)
|
createAndGet(s, "/foo/bar", t)
|
||||||
createAndGet(fs, "/foo/foo/bar", t)
|
createAndGet(s, "/foo/foo/bar", t)
|
||||||
|
|
||||||
// meet file, create should fail
|
// meet file, create should fail
|
||||||
_, err = fs.Create("/foo/bar/bar", "bar", Permanent, 2, 1)
|
_, err = s.Create("/foo/bar/bar", "bar", Permanent, 2, 1)
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("Create should fail")
|
t.Fatal("Create should fail")
|
||||||
}
|
}
|
||||||
|
|
||||||
// create a directory
|
// create a directory
|
||||||
_, err = fs.Create("/fooDir", "", Permanent, 3, 1)
|
_, err = s.Create("/fooDir", "", Permanent, 3, 1)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("Cannot create /fooDir")
|
t.Fatal("Cannot create /fooDir")
|
||||||
}
|
}
|
||||||
|
|
||||||
e, err := fs.Get("/fooDir", false, false, 3, 1)
|
e, err := s.Get("/fooDir", false, false, 3, 1)
|
||||||
|
|
||||||
if err != nil || e.Dir != true {
|
if err != nil || e.Dir != true {
|
||||||
t.Fatal("Cannot create /fooDir ")
|
t.Fatal("Cannot create /fooDir ")
|
||||||
}
|
}
|
||||||
|
|
||||||
// create a file under directory
|
// create a file under directory
|
||||||
_, err = fs.Create("/fooDir/bar", "bar", Permanent, 4, 1)
|
_, err = s.Create("/fooDir/bar", "bar", Permanent, 4, 1)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("Cannot create /fooDir/bar = bar")
|
t.Fatal("Cannot create /fooDir/bar = bar")
|
||||||
@ -56,21 +56,21 @@ func TestCreateAndGet(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestUpdateFile(t *testing.T) {
|
func TestUpdateFile(t *testing.T) {
|
||||||
fs := New()
|
s := New()
|
||||||
|
|
||||||
_, err := fs.Create("/foo/bar", "bar", Permanent, 1, 1)
|
_, err := s.Create("/foo/bar", "bar", Permanent, 1, 1)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("cannot create %s=bar [%s]", "/foo/bar", err.Error())
|
t.Fatalf("cannot create %s=bar [%s]", "/foo/bar", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = fs.Update("/foo/bar", "barbar", Permanent, 2, 1)
|
_, err = s.Update("/foo/bar", "barbar", Permanent, 2, 1)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("cannot update %s=barbar [%s]", "/foo/bar", err.Error())
|
t.Fatalf("cannot update %s=barbar [%s]", "/foo/bar", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
e, err := fs.Get("/foo/bar", false, false, 2, 1)
|
e, err := s.Get("/foo/bar", false, false, 2, 1)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("cannot get %s [%s]", "/foo/bar", err.Error())
|
t.Fatalf("cannot get %s [%s]", "/foo/bar", err.Error())
|
||||||
@ -82,37 +82,37 @@ func TestUpdateFile(t *testing.T) {
|
|||||||
|
|
||||||
// create a directory, update its ttl, to see if it will be deleted
|
// create a directory, update its ttl, to see if it will be deleted
|
||||||
|
|
||||||
_, err = fs.Create("/foo/foo", "", Permanent, 3, 1)
|
_, err = s.Create("/foo/foo", "", Permanent, 3, 1)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("cannot create dir [%s] [%s]", "/foo/foo", err.Error())
|
t.Fatalf("cannot create dir [%s] [%s]", "/foo/foo", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = fs.Create("/foo/foo/foo1", "bar1", Permanent, 4, 1)
|
_, err = s.Create("/foo/foo/foo1", "bar1", Permanent, 4, 1)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("cannot create [%s]", err.Error())
|
t.Fatal("cannot create [%s]", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = fs.Create("/foo/foo/foo2", "", Permanent, 5, 1)
|
_, err = s.Create("/foo/foo/foo2", "", Permanent, 5, 1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("cannot create [%s]", err.Error())
|
t.Fatal("cannot create [%s]", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = fs.Create("/foo/foo/foo2/boo", "boo1", Permanent, 6, 1)
|
_, err = s.Create("/foo/foo/foo2/boo", "boo1", Permanent, 6, 1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("cannot create [%s]", err.Error())
|
t.Fatal("cannot create [%s]", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
expire := time.Now().Add(time.Second * 2)
|
expire := time.Now().Add(time.Second * 2)
|
||||||
_, err = fs.Update("/foo/foo", "", expire, 7, 1)
|
_, err = s.Update("/foo/foo", "", expire, 7, 1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("cannot update dir [%s] [%s]", "/foo/foo", err.Error())
|
t.Fatalf("cannot update dir [%s] [%s]", "/foo/foo", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// sleep 50ms, it should still reach the node
|
// sleep 50ms, it should still reach the node
|
||||||
time.Sleep(time.Microsecond * 50)
|
time.Sleep(time.Microsecond * 50)
|
||||||
e, err = fs.Get("/foo/foo", true, false, 7, 1)
|
e, err = s.Get("/foo/foo", true, false, 7, 1)
|
||||||
|
|
||||||
if err != nil || e.Key != "/foo/foo" {
|
if err != nil || e.Key != "/foo/foo" {
|
||||||
t.Fatalf("cannot get dir before expiration [%s]", err.Error())
|
t.Fatalf("cannot get dir before expiration [%s]", err.Error())
|
||||||
@ -132,23 +132,23 @@ func TestUpdateFile(t *testing.T) {
|
|||||||
|
|
||||||
// wait for expiration
|
// wait for expiration
|
||||||
time.Sleep(time.Second * 3)
|
time.Sleep(time.Second * 3)
|
||||||
e, err = fs.Get("/foo/foo", true, false, 7, 1)
|
e, err = s.Get("/foo/foo", true, false, 7, 1)
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("still can get dir after expiration [%s]")
|
t.Fatal("still can get dir after expiration [%s]")
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = fs.Get("/foo/foo/foo1", true, false, 7, 1)
|
_, err = s.Get("/foo/foo/foo1", true, false, 7, 1)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("still can get sub node after expiration [%s]")
|
t.Fatal("still can get sub node after expiration [%s]")
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = fs.Get("/foo/foo/foo2", true, false, 7, 1)
|
_, err = s.Get("/foo/foo/foo2", true, false, 7, 1)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("still can get sub dir after expiration [%s]")
|
t.Fatal("still can get sub dir after expiration [%s]")
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = fs.Get("/foo/foo/foo2/boo", true, false, 7, 1)
|
_, err = s.Get("/foo/foo/foo2/boo", true, false, 7, 1)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("still can get sub node of sub dir after expiration [%s]", err.Error())
|
t.Fatalf("still can get sub node of sub dir after expiration [%s]", err.Error())
|
||||||
}
|
}
|
||||||
@ -156,17 +156,17 @@ func TestUpdateFile(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestListDirectory(t *testing.T) {
|
func TestListDirectory(t *testing.T) {
|
||||||
fs := New()
|
s := New()
|
||||||
|
|
||||||
// create dir /foo
|
// create dir /foo
|
||||||
// set key-value /foo/foo=bar
|
// set key-value /foo/foo=bar
|
||||||
fs.Create("/foo/foo", "bar", Permanent, 1, 1)
|
s.Create("/foo/foo", "bar", Permanent, 1, 1)
|
||||||
|
|
||||||
// create dir /foo/fooDir
|
// create dir /foo/fooDir
|
||||||
// set key-value /foo/fooDir/foo=bar
|
// set key-value /foo/fooDir/foo=bar
|
||||||
fs.Create("/foo/fooDir/foo", "bar", Permanent, 2, 1)
|
s.Create("/foo/fooDir/foo", "bar", Permanent, 2, 1)
|
||||||
|
|
||||||
e, err := fs.Get("/foo", true, false, 2, 1)
|
e, err := s.Get("/foo", true, false, 2, 1)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%v", err)
|
t.Fatalf("%v", err)
|
||||||
@ -191,9 +191,9 @@ func TestListDirectory(t *testing.T) {
|
|||||||
|
|
||||||
// create dir /foo/_hidden
|
// create dir /foo/_hidden
|
||||||
// set key-value /foo/_hidden/foo -> bar
|
// set key-value /foo/_hidden/foo -> bar
|
||||||
fs.Create("/foo/_hidden/foo", "bar", Permanent, 3, 1)
|
s.Create("/foo/_hidden/foo", "bar", Permanent, 3, 1)
|
||||||
|
|
||||||
e, _ = fs.Get("/foo", false, false, 2, 1)
|
e, _ = s.Get("/foo", false, false, 2, 1)
|
||||||
|
|
||||||
if len(e.KVPairs) != 2 {
|
if len(e.KVPairs) != 2 {
|
||||||
t.Fatalf("hidden node is not hidden! %s", e.KVPairs[2].Key)
|
t.Fatalf("hidden node is not hidden! %s", e.KVPairs[2].Key)
|
||||||
@ -201,38 +201,38 @@ func TestListDirectory(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestRemove(t *testing.T) {
|
func TestRemove(t *testing.T) {
|
||||||
fs := New()
|
s := New()
|
||||||
|
|
||||||
fs.Create("/foo", "bar", Permanent, 1, 1)
|
s.Create("/foo", "bar", Permanent, 1, 1)
|
||||||
_, err := fs.Delete("/foo", false, 1, 1)
|
_, err := s.Delete("/foo", false, 1, 1)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("cannot delete %s [%s]", "/foo", err.Error())
|
t.Fatalf("cannot delete %s [%s]", "/foo", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = fs.Get("/foo", false, false, 1, 1)
|
_, err = s.Get("/foo", false, false, 1, 1)
|
||||||
|
|
||||||
if err == nil || err.Error() != "Key Not Found" {
|
if err == nil || err.Error() != "Key Not Found" {
|
||||||
t.Fatalf("can get the node after deletion")
|
t.Fatalf("can get the node after deletion")
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.Create("/foo/bar", "bar", Permanent, 1, 1)
|
s.Create("/foo/bar", "bar", Permanent, 1, 1)
|
||||||
fs.Create("/foo/car", "car", Permanent, 1, 1)
|
s.Create("/foo/car", "car", Permanent, 1, 1)
|
||||||
fs.Create("/foo/dar/dar", "dar", Permanent, 1, 1)
|
s.Create("/foo/dar/dar", "dar", Permanent, 1, 1)
|
||||||
|
|
||||||
_, err = fs.Delete("/foo", false, 1, 1)
|
_, err = s.Delete("/foo", false, 1, 1)
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("should not be able to delete a directory without recursive")
|
t.Fatalf("should not be able to delete a directory without recursive")
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = fs.Delete("/foo", true, 1, 1)
|
_, err = s.Delete("/foo", true, 1, 1)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("cannot delete %s [%s]", "/foo", err.Error())
|
t.Fatalf("cannot delete %s [%s]", "/foo", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = fs.Get("/foo", false, false, 1, 1)
|
_, err = s.Get("/foo", false, false, 1, 1)
|
||||||
|
|
||||||
if err == nil || err.Error() != "Key Not Found" {
|
if err == nil || err.Error() != "Key Not Found" {
|
||||||
t.Fatalf("can get the node after deletion ")
|
t.Fatalf("can get the node after deletion ")
|
||||||
@ -241,13 +241,13 @@ func TestRemove(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestExpire(t *testing.T) {
|
func TestExpire(t *testing.T) {
|
||||||
fs := New()
|
s := New()
|
||||||
|
|
||||||
expire := time.Now().Add(time.Second)
|
expire := time.Now().Add(time.Second)
|
||||||
|
|
||||||
fs.Create("/foo", "bar", expire, 1, 1)
|
s.Create("/foo", "bar", expire, 1, 1)
|
||||||
|
|
||||||
_, err := fs.InternalGet("/foo", 1, 1)
|
_, err := s.InternalGet("/foo", 1, 1)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("can not get the node")
|
t.Fatalf("can not get the node")
|
||||||
@ -255,7 +255,7 @@ func TestExpire(t *testing.T) {
|
|||||||
|
|
||||||
time.Sleep(time.Second * 2)
|
time.Sleep(time.Second * 2)
|
||||||
|
|
||||||
_, err = fs.InternalGet("/foo", 1, 1)
|
_, err = s.InternalGet("/foo", 1, 1)
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("can get the node after expiration time")
|
t.Fatalf("can get the node after expiration time")
|
||||||
@ -263,10 +263,10 @@ func TestExpire(t *testing.T) {
|
|||||||
|
|
||||||
// test if we can reach the node before expiration
|
// test if we can reach the node before expiration
|
||||||
expire = time.Now().Add(time.Second)
|
expire = time.Now().Add(time.Second)
|
||||||
fs.Create("/foo", "bar", expire, 1, 1)
|
s.Create("/foo", "bar", expire, 1, 1)
|
||||||
|
|
||||||
time.Sleep(time.Millisecond * 50)
|
time.Sleep(time.Millisecond * 50)
|
||||||
_, err = fs.InternalGet("/foo", 1, 1)
|
_, err = s.InternalGet("/foo", 1, 1)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("cannot get the node before expiration", err.Error())
|
t.Fatalf("cannot get the node before expiration", err.Error())
|
||||||
@ -274,8 +274,8 @@ func TestExpire(t *testing.T) {
|
|||||||
|
|
||||||
expire = time.Now().Add(time.Second)
|
expire = time.Now().Add(time.Second)
|
||||||
|
|
||||||
fs.Create("/foo", "bar", expire, 1, 1)
|
s.Create("/foo", "bar", expire, 1, 1)
|
||||||
_, err = fs.Delete("/foo", false, 1, 1)
|
_, err = s.Delete("/foo", false, 1, 1)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("cannot delete the node before expiration", err.Error())
|
t.Fatalf("cannot delete the node before expiration", err.Error())
|
||||||
@ -284,17 +284,17 @@ func TestExpire(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestTestAndSet(t *testing.T) { // TODO prevValue == nil ?
|
func TestTestAndSet(t *testing.T) { // TODO prevValue == nil ?
|
||||||
fs := New()
|
s := New()
|
||||||
fs.Create("/foo", "bar", Permanent, 1, 1)
|
s.Create("/foo", "bar", Permanent, 1, 1)
|
||||||
|
|
||||||
// test on wrong previous value
|
// test on wrong previous value
|
||||||
_, err := fs.TestAndSet("/foo", "barbar", 0, "car", Permanent, 2, 1)
|
_, err := s.TestAndSet("/foo", "barbar", 0, "car", Permanent, 2, 1)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("test and set should fail barbar != bar")
|
t.Fatal("test and set should fail barbar != bar")
|
||||||
}
|
}
|
||||||
|
|
||||||
// test on value
|
// test on value
|
||||||
e, err := fs.TestAndSet("/foo", "bar", 0, "car", Permanent, 3, 1)
|
e, err := s.TestAndSet("/foo", "bar", 0, "car", Permanent, 3, 1)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("test and set should succeed bar == bar")
|
t.Fatal("test and set should succeed bar == bar")
|
||||||
@ -305,7 +305,7 @@ func TestTestAndSet(t *testing.T) { // TODO prevValue == nil ?
|
|||||||
}
|
}
|
||||||
|
|
||||||
// test on index
|
// test on index
|
||||||
e, err = fs.TestAndSet("/foo", "", 3, "bar", Permanent, 4, 1)
|
e, err = s.TestAndSet("/foo", "", 3, "bar", Permanent, 4, 1)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("test and set should succeed index 3 == 3")
|
t.Fatal("test and set should succeed index 3 == 3")
|
||||||
@ -318,61 +318,61 @@ func TestTestAndSet(t *testing.T) { // TODO prevValue == nil ?
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestWatch(t *testing.T) {
|
func TestWatch(t *testing.T) {
|
||||||
fs := New()
|
s := New()
|
||||||
// watch at a deeper path
|
// watch at a deeper path
|
||||||
c, _ := fs.WatcherHub.watch("/foo/foo/foo", false, 0)
|
c, _ := s.WatcherHub.watch("/foo/foo/foo", false, 0)
|
||||||
fs.Create("/foo/foo/foo", "bar", Permanent, 1, 1)
|
s.Create("/foo/foo/foo", "bar", Permanent, 1, 1)
|
||||||
|
|
||||||
e := nonblockingRetrive(c)
|
e := nonblockingRetrive(c)
|
||||||
if e.Key != "/foo/foo/foo" {
|
if e.Key != "/foo/foo/foo" {
|
||||||
t.Fatal("watch for Create node fails")
|
t.Fatal("watch for Create node fails")
|
||||||
}
|
}
|
||||||
|
|
||||||
c, _ = fs.WatcherHub.watch("/foo/foo/foo", false, 0)
|
c, _ = s.WatcherHub.watch("/foo/foo/foo", false, 0)
|
||||||
fs.Update("/foo/foo/foo", "car", Permanent, 2, 1)
|
s.Update("/foo/foo/foo", "car", Permanent, 2, 1)
|
||||||
e = nonblockingRetrive(c)
|
e = nonblockingRetrive(c)
|
||||||
if e.Key != "/foo/foo/foo" {
|
if e.Key != "/foo/foo/foo" {
|
||||||
t.Fatal("watch for Update node fails")
|
t.Fatal("watch for Update node fails")
|
||||||
}
|
}
|
||||||
|
|
||||||
c, _ = fs.WatcherHub.watch("/foo/foo/foo", false, 0)
|
c, _ = s.WatcherHub.watch("/foo/foo/foo", false, 0)
|
||||||
fs.TestAndSet("/foo/foo/foo", "car", 0, "bar", Permanent, 3, 1)
|
s.TestAndSet("/foo/foo/foo", "car", 0, "bar", Permanent, 3, 1)
|
||||||
e = nonblockingRetrive(c)
|
e = nonblockingRetrive(c)
|
||||||
if e.Key != "/foo/foo/foo" {
|
if e.Key != "/foo/foo/foo" {
|
||||||
t.Fatal("watch for TestAndSet node fails")
|
t.Fatal("watch for TestAndSet node fails")
|
||||||
}
|
}
|
||||||
|
|
||||||
c, _ = fs.WatcherHub.watch("/foo/foo/foo", false, 0)
|
c, _ = s.WatcherHub.watch("/foo/foo/foo", false, 0)
|
||||||
fs.Delete("/foo", true, 4, 1) //recursively delete
|
s.Delete("/foo", true, 4, 1) //recursively delete
|
||||||
e = nonblockingRetrive(c)
|
e = nonblockingRetrive(c)
|
||||||
if e.Key != "/foo" {
|
if e.Key != "/foo" {
|
||||||
t.Fatal("watch for Delete node fails")
|
t.Fatal("watch for Delete node fails")
|
||||||
}
|
}
|
||||||
|
|
||||||
// watch at a prefix
|
// watch at a prefix
|
||||||
c, _ = fs.WatcherHub.watch("/foo", true, 0)
|
c, _ = s.WatcherHub.watch("/foo", true, 0)
|
||||||
fs.Create("/foo/foo/boo", "bar", Permanent, 5, 1)
|
s.Create("/foo/foo/boo", "bar", Permanent, 5, 1)
|
||||||
e = nonblockingRetrive(c)
|
e = nonblockingRetrive(c)
|
||||||
if e.Key != "/foo/foo/boo" {
|
if e.Key != "/foo/foo/boo" {
|
||||||
t.Fatal("watch for Create subdirectory fails")
|
t.Fatal("watch for Create subdirectory fails")
|
||||||
}
|
}
|
||||||
|
|
||||||
c, _ = fs.WatcherHub.watch("/foo", true, 0)
|
c, _ = s.WatcherHub.watch("/foo", true, 0)
|
||||||
fs.Update("/foo/foo/boo", "foo", Permanent, 6, 1)
|
s.Update("/foo/foo/boo", "foo", Permanent, 6, 1)
|
||||||
e = nonblockingRetrive(c)
|
e = nonblockingRetrive(c)
|
||||||
if e.Key != "/foo/foo/boo" {
|
if e.Key != "/foo/foo/boo" {
|
||||||
t.Fatal("watch for Update subdirectory fails")
|
t.Fatal("watch for Update subdirectory fails")
|
||||||
}
|
}
|
||||||
|
|
||||||
c, _ = fs.WatcherHub.watch("/foo", true, 0)
|
c, _ = s.WatcherHub.watch("/foo", true, 0)
|
||||||
fs.TestAndSet("/foo/foo/boo", "foo", 0, "bar", Permanent, 7, 1)
|
s.TestAndSet("/foo/foo/boo", "foo", 0, "bar", Permanent, 7, 1)
|
||||||
e = nonblockingRetrive(c)
|
e = nonblockingRetrive(c)
|
||||||
if e.Key != "/foo/foo/boo" {
|
if e.Key != "/foo/foo/boo" {
|
||||||
t.Fatal("watch for TestAndSet subdirectory fails")
|
t.Fatal("watch for TestAndSet subdirectory fails")
|
||||||
}
|
}
|
||||||
|
|
||||||
c, _ = fs.WatcherHub.watch("/foo", true, 0)
|
c, _ = s.WatcherHub.watch("/foo", true, 0)
|
||||||
fs.Delete("/foo/foo/boo", false, 8, 1)
|
s.Delete("/foo/foo/boo", false, 8, 1)
|
||||||
e = nonblockingRetrive(c)
|
e = nonblockingRetrive(c)
|
||||||
if e.Key != "/foo/foo/boo" {
|
if e.Key != "/foo/foo/boo" {
|
||||||
t.Fatal("watch for Delete subdirectory fails")
|
t.Fatal("watch for Delete subdirectory fails")
|
||||||
@ -381,14 +381,14 @@ func TestWatch(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestSort(t *testing.T) {
|
func TestSort(t *testing.T) {
|
||||||
fs := New()
|
s := New()
|
||||||
|
|
||||||
// simulating random creation
|
// simulating random creation
|
||||||
keys := GenKeys(80, 4)
|
keys := GenKeys(80, 4)
|
||||||
|
|
||||||
i := uint64(1)
|
i := uint64(1)
|
||||||
for _, k := range keys {
|
for _, k := range keys {
|
||||||
_, err := fs.Create(k, "bar", Permanent, i, 1)
|
_, err := s.Create(k, "bar", Permanent, i, 1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
} else {
|
} else {
|
||||||
@ -396,7 +396,7 @@ func TestSort(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
e, err := fs.Get("/foo", true, true, i, 1)
|
e, err := s.Get("/foo", true, true, i, 1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("get dir nodes failed [%s]", err.Error())
|
t.Fatalf("get dir nodes failed [%s]", err.Error())
|
||||||
}
|
}
|
||||||
@ -419,14 +419,14 @@ func TestSort(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestSaveAndRecover(t *testing.T) {
|
func TestSaveAndRecover(t *testing.T) {
|
||||||
fs := New()
|
s := New()
|
||||||
|
|
||||||
// simulating random creation
|
// simulating random creation
|
||||||
keys := GenKeys(8, 4)
|
keys := GenKeys(8, 4)
|
||||||
|
|
||||||
i := uint64(1)
|
i := uint64(1)
|
||||||
for _, k := range keys {
|
for _, k := range keys {
|
||||||
_, err := fs.Create(k, "bar", Permanent, i, 1)
|
_, err := s.Create(k, "bar", Permanent, i, 1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
} else {
|
} else {
|
||||||
@ -438,8 +438,8 @@ func TestSaveAndRecover(t *testing.T) {
|
|||||||
// test if we can reach the node before expiration
|
// test if we can reach the node before expiration
|
||||||
|
|
||||||
expire := time.Now().Add(time.Second)
|
expire := time.Now().Add(time.Second)
|
||||||
fs.Create("/foo/foo", "bar", expire, 1, 1)
|
s.Create("/foo/foo", "bar", expire, 1, 1)
|
||||||
b, err := fs.Save()
|
b, err := s.Save()
|
||||||
|
|
||||||
cloneFs := New()
|
cloneFs := New()
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
@ -453,18 +453,18 @@ func TestSaveAndRecover(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if fs.WatcherHub.EventHistory.StartIndex != cloneFs.WatcherHub.EventHistory.StartIndex {
|
if s.WatcherHub.EventHistory.StartIndex != cloneFs.WatcherHub.EventHistory.StartIndex {
|
||||||
t.Fatal("Error recovered event history start index")
|
t.Fatal("Error recovered event history start index")
|
||||||
}
|
}
|
||||||
|
|
||||||
for i = 0; int(i) < fs.WatcherHub.EventHistory.Queue.Size; i++ {
|
for i = 0; int(i) < s.WatcherHub.EventHistory.Queue.Size; i++ {
|
||||||
if fs.WatcherHub.EventHistory.Queue.Events[i].Key !=
|
if s.WatcherHub.EventHistory.Queue.Events[i].Key !=
|
||||||
cloneFs.WatcherHub.EventHistory.Queue.Events[i].Key {
|
cloneFs.WatcherHub.EventHistory.Queue.Events[i].Key {
|
||||||
t.Fatal("Error recovered event history")
|
t.Fatal("Error recovered event history")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = fs.Get("/foo/foo", false, false, 1, 1)
|
_, err = s.Get("/foo/foo", false, false, 1, 1)
|
||||||
|
|
||||||
if err == nil || err.Error() != "Key Not Found" {
|
if err == nil || err.Error() != "Key Not Found" {
|
||||||
t.Fatalf("can get the node after deletion ")
|
t.Fatalf("can get the node after deletion ")
|
||||||
@ -488,14 +488,14 @@ func GenKeys(num int, depth int) []string {
|
|||||||
return keys
|
return keys
|
||||||
}
|
}
|
||||||
|
|
||||||
func createAndGet(fs *FileSystem, path string, t *testing.T) {
|
func createAndGet(s *Store, path string, t *testing.T) {
|
||||||
_, err := fs.Create(path, "bar", Permanent, 1, 1)
|
_, err := s.Create(path, "bar", Permanent, 1, 1)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("cannot create %s=bar [%s]", path, err.Error())
|
t.Fatalf("cannot create %s=bar [%s]", path, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
e, err := fs.Get(path, false, false, 1, 1)
|
e, err := s.Get(path, false, false, 1, 1)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("cannot get %s [%s]", path, err.Error())
|
t.Fatalf("cannot get %s [%s]", path, err.Error())
|
@ -1,16 +1,16 @@
|
|||||||
package fileSystem
|
package store
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"container/list"
|
"container/list"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync/atomic"
|
||||||
)
|
)
|
||||||
|
|
||||||
type watcherHub struct {
|
type watcherHub struct {
|
||||||
watchers map[string]*list.List
|
watchers map[string]*list.List
|
||||||
count uint64 // current number of watchers
|
count int64 // current number of watchers.
|
||||||
EventHistory *EventHistory
|
EventHistory *EventHistory
|
||||||
Stats *EtcdStats
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type watcher struct {
|
type watcher struct {
|
||||||
@ -19,11 +19,10 @@ type watcher struct {
|
|||||||
sinceIndex uint64
|
sinceIndex uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
func newWatchHub(capacity int, stats *EtcdStats) *watcherHub {
|
func newWatchHub(capacity int) *watcherHub {
|
||||||
return &watcherHub{
|
return &watcherHub{
|
||||||
watchers: make(map[string]*list.List),
|
watchers: make(map[string]*list.List),
|
||||||
EventHistory: newEventHistory(capacity),
|
EventHistory: newEventHistory(capacity),
|
||||||
Stats: stats,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,13 +36,9 @@ func (wh *watcherHub) watch(prefix string, recursive bool, index uint64) (<-chan
|
|||||||
e, err := wh.EventHistory.scan(prefix, index)
|
e, err := wh.EventHistory.scan(prefix, index)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
wh.Stats.IncStats(StatsWatchMiss)
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
wh.Stats.IncStats(StatsWatchHit)
|
|
||||||
wh.Stats.IncStats(StatsInWatchingNum)
|
|
||||||
|
|
||||||
if e != nil {
|
if e != nil {
|
||||||
eventChan <- e
|
eventChan <- e
|
||||||
return eventChan, nil
|
return eventChan, nil
|
||||||
@ -66,6 +61,8 @@ func (wh *watcherHub) watch(prefix string, recursive bool, index uint64) (<-chan
|
|||||||
wh.watchers[prefix] = l
|
wh.watchers[prefix] = l
|
||||||
}
|
}
|
||||||
|
|
||||||
|
atomic.AddInt64(&wh.count, 1)
|
||||||
|
|
||||||
return eventChan, nil
|
return eventChan, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,10 +91,8 @@ func (wh *watcherHub) notifyWithPath(e *Event, path string, force bool) {
|
|||||||
|
|
||||||
if (w.recursive || force || e.Key == path) && e.Index >= w.sinceIndex {
|
if (w.recursive || force || e.Key == path) && e.Index >= w.sinceIndex {
|
||||||
w.eventChan <- e
|
w.eventChan <- e
|
||||||
wh.Stats.rwlock.Lock() // lock the InWatchingNum
|
|
||||||
wh.Stats.InWatchingNum--
|
|
||||||
wh.Stats.rwlock.Unlock()
|
|
||||||
l.Remove(curr)
|
l.Remove(curr)
|
||||||
|
atomic.AddInt64(&wh.count, -1)
|
||||||
} else {
|
} else {
|
||||||
notifiedAll = false
|
notifiedAll = false
|
||||||
}
|
}
|
@ -1,12 +1,12 @@
|
|||||||
package fileSystem
|
package store
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestWatcher(t *testing.T) {
|
func TestWatcher(t *testing.T) {
|
||||||
fs := New()
|
s := New()
|
||||||
wh := fs.WatcherHub
|
wh := s.WatcherHub
|
||||||
c, err := wh.watch("/foo", true, 0)
|
c, err := wh.watch("/foo", true, 0)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
6
util.go
6
util.go
@ -15,7 +15,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
etcdErr "github.com/coreos/etcd/error"
|
etcdErr "github.com/coreos/etcd/error"
|
||||||
"github.com/coreos/etcd/file_system"
|
"github.com/coreos/etcd/store"
|
||||||
"github.com/coreos/etcd/web"
|
"github.com/coreos/etcd/web"
|
||||||
"github.com/coreos/go-raft"
|
"github.com/coreos/go-raft"
|
||||||
)
|
)
|
||||||
@ -30,12 +30,12 @@ func durationToExpireTime(strDuration string) (time.Time, error) {
|
|||||||
duration, err := strconv.Atoi(strDuration)
|
duration, err := strconv.Atoi(strDuration)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fileSystem.Permanent, err
|
return store.Permanent, err
|
||||||
}
|
}
|
||||||
return time.Now().Add(time.Second * (time.Duration)(duration)), nil
|
return time.Now().Add(time.Second * (time.Duration)(duration)), nil
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return fileSystem.Permanent, nil
|
return store.Permanent, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user