Browse Source

etcdserver: autodetect v0.4 WALs and upgrade them to v0.5 automatically

Barak Michener 11 years ago
parent
commit
78ea3335bf
2 changed files with 74 additions and 5 deletions
  1. 27 5
      etcdserver/server.go
  2. 47 0
      wal/util.go

+ 27 - 5
etcdserver/server.go

@@ -36,6 +36,7 @@ import (
 	"github.com/coreos/etcd/etcdserver/etcdhttp/httptypes"
 	"github.com/coreos/etcd/etcdserver/etcdhttp/httptypes"
 	pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
 	pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
 	"github.com/coreos/etcd/etcdserver/stats"
 	"github.com/coreos/etcd/etcdserver/stats"
+	"github.com/coreos/etcd/migrate"
 	"github.com/coreos/etcd/pkg/pbutil"
 	"github.com/coreos/etcd/pkg/pbutil"
 	"github.com/coreos/etcd/pkg/types"
 	"github.com/coreos/etcd/pkg/types"
 	"github.com/coreos/etcd/pkg/wait"
 	"github.com/coreos/etcd/pkg/wait"
@@ -190,18 +191,39 @@ type EtcdServer struct {
 	raftLead uint64
 	raftLead uint64
 }
 }
 
 
+// UpgradeWAL converts an older version of the EtcdServer data to the newest version.
+// It must ensure that, after upgrading, the most recent version is present.
+func UpgradeWAL(cfg *ServerConfig, ver wal.WalVersion) {
+	if ver == wal.WALv0_4 {
+		err := migrate.Migrate4To5(cfg.DataDir, cfg.Name)
+		if err != nil {
+			log.Fatalf("Failed migrating data-dir: %v", err)
+		}
+	}
+}
+
 // NewServer creates a new EtcdServer from the supplied configuration. The
 // NewServer creates a new EtcdServer from the supplied configuration. The
 // configuration is considered static for the lifetime of the EtcdServer.
 // configuration is considered static for the lifetime of the EtcdServer.
 func NewServer(cfg *ServerConfig) (*EtcdServer, error) {
 func NewServer(cfg *ServerConfig) (*EtcdServer, error) {
-	if err := os.MkdirAll(cfg.SnapDir(), privateDirMode); err != nil {
-		return nil, fmt.Errorf("cannot create snapshot directory: %v", err)
-	}
-	ss := snap.New(cfg.SnapDir())
 	st := store.New()
 	st := store.New()
 	var w *wal.WAL
 	var w *wal.WAL
 	var n raft.Node
 	var n raft.Node
 	var id types.ID
 	var id types.ID
-	haveWAL := wal.Exist(cfg.WALDir())
+	walVersion := wal.DetectVersion(cfg.DataDir)
+	if walVersion == wal.UnknownWAL {
+		return nil, fmt.Errorf("unknown wal version in data dir %s", cfg.DataDir)
+	}
+	haveWAL := walVersion != wal.NoWAL
+
+	if haveWAL && walVersion != wal.WALv0_5 {
+		UpgradeWAL(cfg, walVersion)
+	}
+
+	if err := os.MkdirAll(cfg.SnapDir(), privateDirMode); err != nil {
+		return nil, fmt.Errorf("cannot create snapshot directory: %v", err)
+	}
+	ss := snap.New(cfg.SnapDir())
+
 	switch {
 	switch {
 	case !haveWAL && !cfg.NewCluster:
 	case !haveWAL && !cfg.NewCluster:
 		us := getOtherPeerURLs(cfg.Cluster, cfg.Name)
 		us := getOtherPeerURLs(cfg.Cluster, cfg.Name)

+ 47 - 0
wal/util.go

@@ -20,8 +20,55 @@ import (
 	"fmt"
 	"fmt"
 	"log"
 	"log"
 	"os"
 	"os"
+	"path"
 )
 )
 
 
+type StringSlice []string
+
+func containsStrings(source, target []string) bool {
+	for _, t := range target {
+		ok := false
+		for _, s := range source {
+			if t == s {
+				ok = true
+			}
+		}
+		if !ok {
+			return false
+		}
+	}
+	return true
+}
+
+// WalVersion is an enum for versions of etcd logs.
+type WalVersion string
+
+const (
+	UnknownWAL WalVersion = "Unknown WAL"
+	NoWAL      WalVersion = "No WAL"
+	WALv0_4    WalVersion = "0.4.x"
+	WALv0_5    WalVersion = "0.5.x"
+)
+
+func DetectVersion(dirpath string) WalVersion {
+	names, err := readDir(dirpath)
+	if err != nil || len(names) == 0 {
+		return NoWAL
+	}
+	if containsStrings(names, []string{"snap", "wal"}) {
+		// .../wal cannot be empty to exist.
+		if Exist(path.Join(dirpath, "wal")) {
+			return WALv0_5
+		}
+		return NoWAL
+	}
+	if containsStrings(names, []string{"snapshot", "conf", "log"}) {
+		return WALv0_4
+	}
+
+	return UnknownWAL
+}
+
 func Exist(dirpath string) bool {
 func Exist(dirpath string) bool {
 	names, err := readDir(dirpath)
 	names, err := readDir(dirpath)
 	if err != nil {
 	if err != nil {