From f803a9ff0efe98926148e5f5c320339ceea6f104 Mon Sep 17 00:00:00 2001 From: Kostas Christidis Date: Thu, 2 Mar 2017 01:37:19 -0500 Subject: [PATCH] [FAB-2591] Introduce file-ledger option https://jira.hyperledger.org/browse/FAB-2591 This changeset allows the user to choose the file ledger, introduced in a previous changeset. Change-Id: Id518961af10fddb4954291592cf53b12f1e3d1fa Signed-off-by: Kostas Christidis --- orderer/main.go | 47 +----------------- orderer/orderer.yaml | 2 +- orderer/util.go | 110 +++++++++++++++++++++++++++++++++++++++++++ orderer/util_test.go | 106 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 218 insertions(+), 47 deletions(-) create mode 100644 orderer/util.go create mode 100644 orderer/util_test.go diff --git a/orderer/main.go b/orderer/main.go index ec8fcb42528..4c7cec0702c 100644 --- a/orderer/main.go +++ b/orderer/main.go @@ -18,7 +18,6 @@ package main import ( "fmt" - "io/ioutil" "log" "net" "net/http" @@ -31,15 +30,9 @@ import ( "github.com/hyperledger/fabric/core/comm" "github.com/hyperledger/fabric/orderer/common/bootstrap/file" "github.com/hyperledger/fabric/orderer/kafka" - "github.com/hyperledger/fabric/orderer/ledger" - jsonledger "github.com/hyperledger/fabric/orderer/ledger/json" - ramledger "github.com/hyperledger/fabric/orderer/ledger/ram" "github.com/hyperledger/fabric/orderer/localconfig" "github.com/hyperledger/fabric/orderer/multichain" "github.com/hyperledger/fabric/orderer/sbft" - "github.com/hyperledger/fabric/orderer/sbft/backend" - sbftcrypto "github.com/hyperledger/fabric/orderer/sbft/crypto" - "github.com/hyperledger/fabric/orderer/sbft/simplebft" "github.com/hyperledger/fabric/orderer/solo" cb "github.com/hyperledger/fabric/protos/common" ab "github.com/hyperledger/fabric/protos/orderer" @@ -93,26 +86,7 @@ func main() { logger.Panic("Failed to initialize local MSP:", err) } - var lf ledger.Factory - switch conf.General.LedgerType { - case "file": - // just use the json ledger type for now - fallthrough - case "json": - location := conf.FileLedger.Location - if location == "" { - var err error - location, err = ioutil.TempDir("", conf.FileLedger.Prefix) - if err != nil { - logger.Panic("Error creating temp dir:", err) - } - } - lf = jsonledger.New(location) - case "ram": - fallthrough - default: - lf = ramledger.New(int(conf.RAMLedger.HistorySize)) - } + lf, _ := createLedgerFactory(conf) // Are we bootstrapping? if len(lf.ChainIDs()) == 0 { @@ -166,22 +140,3 @@ func main() { logger.Info("Beginning to serve requests") grpcServer.Start() } - -func makeSbftConsensusConfig(conf *config.TopLevel) *sbft.ConsensusConfig { - cfg := simplebft.Config{N: conf.Genesis.SbftShared.N, F: conf.Genesis.SbftShared.F, - BatchDurationNsec: uint64(conf.Genesis.DeprecatedBatchTimeout), - BatchSizeBytes: uint64(conf.Genesis.DeprecatedBatchSize), - RequestTimeoutNsec: conf.Genesis.SbftShared.RequestTimeoutNsec} - peers := make(map[string][]byte) - for addr, cert := range conf.Genesis.SbftShared.Peers { - peers[addr], _ = sbftcrypto.ParseCertPEM(cert) - } - return &sbft.ConsensusConfig{Consensus: &cfg, Peers: peers} -} - -func makeSbftStackConfig(conf *config.TopLevel) *backend.StackConfig { - return &backend.StackConfig{ListenAddr: conf.SbftLocal.PeerCommAddr, - CertFile: conf.SbftLocal.CertFile, - KeyFile: conf.SbftLocal.KeyFile, - DataDir: conf.SbftLocal.DataDir} -} diff --git a/orderer/orderer.yaml b/orderer/orderer.yaml index 5c3ed70ef70..f31cc3bf760 100644 --- a/orderer/orderer.yaml +++ b/orderer/orderer.yaml @@ -33,7 +33,7 @@ General: # Log Level: The level at which to log. This accepts logging specifications # per: fabric/docs/Setup/logging-control.md - LogLevel: debug + LogLevel: info # Genesis method: The method by which to retrieve/generate the genesis # block. Available values are "provisional", "file". Provisional utilizes diff --git a/orderer/util.go b/orderer/util.go new file mode 100644 index 00000000000..99231886b8f --- /dev/null +++ b/orderer/util.go @@ -0,0 +1,110 @@ +/* +Copyright IBM Corp. 2017 All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "io/ioutil" + "os" + "path/filepath" + + "github.com/hyperledger/fabric/common/ledger/blkstorage/fsblkstorage" + "github.com/hyperledger/fabric/orderer/ledger" + fileledger "github.com/hyperledger/fabric/orderer/ledger/file" + jsonledger "github.com/hyperledger/fabric/orderer/ledger/json" + ramledger "github.com/hyperledger/fabric/orderer/ledger/ram" + config "github.com/hyperledger/fabric/orderer/localconfig" + "github.com/hyperledger/fabric/orderer/sbft" + "github.com/hyperledger/fabric/orderer/sbft/backend" + sbftcrypto "github.com/hyperledger/fabric/orderer/sbft/crypto" + "github.com/hyperledger/fabric/orderer/sbft/simplebft" +) + +func createLedgerFactory(conf *config.TopLevel) (ledger.Factory, string) { + var lf ledger.Factory + var ld string + switch conf.General.LedgerType { + case "file": + ld = conf.FileLedger.Location + if ld == "" { + ld = createTempDir(conf.FileLedger.Prefix) + } + logger.Debug("Ledger dir:", ld) + lf = fileledger.New(ld) + // The file-based ledger stores the blocks for each channel + // in a fsblkstorage.ChainsDir sub-directory that we have + // to create separately. Otherwise the call to the ledger + // Factory's ChainIDs below will fail (dir won't exist). + createSubDir(ld, fsblkstorage.ChainsDir) + case "json": + ld = conf.FileLedger.Location + if ld == "" { + ld = createTempDir(conf.FileLedger.Prefix) + } + logger.Debug("Ledger dir:", ld) + lf = jsonledger.New(ld) + case "ram": + fallthrough + default: + lf = ramledger.New(int(conf.RAMLedger.HistorySize)) + } + return lf, ld +} + +func createTempDir(dirPrefix string) string { + dirPath, err := ioutil.TempDir("", dirPrefix) + if err != nil { + logger.Panic("Error creating temp dir:", err) + } + return dirPath +} + +func createSubDir(parentDirPath string, subDir string) (string, bool) { + var created bool + subDirPath := filepath.Join(parentDirPath, subDir) + if _, err := os.Stat(subDirPath); err != nil { + if os.IsNotExist(err) { + if err = os.Mkdir(subDirPath, 0755); err != nil { + logger.Panic("Error creating sub dir:", err) + } + created = true + } else { + logger.Debugf("Found %s sub-dir and using it", fsblkstorage.ChainsDir) + } + } + return subDirPath, created +} + +// XXX The functions below need to be moved to the SBFT package ASAP + +func makeSbftConsensusConfig(conf *config.TopLevel) *sbft.ConsensusConfig { + cfg := simplebft.Config{N: conf.Genesis.SbftShared.N, F: conf.Genesis.SbftShared.F, + BatchDurationNsec: uint64(conf.Genesis.DeprecatedBatchTimeout), + BatchSizeBytes: uint64(conf.Genesis.DeprecatedBatchSize), + RequestTimeoutNsec: conf.Genesis.SbftShared.RequestTimeoutNsec} + peers := make(map[string][]byte) + for addr, cert := range conf.Genesis.SbftShared.Peers { + peers[addr], _ = sbftcrypto.ParseCertPEM(cert) + } + return &sbft.ConsensusConfig{Consensus: &cfg, Peers: peers} +} + +func makeSbftStackConfig(conf *config.TopLevel) *backend.StackConfig { + return &backend.StackConfig{ListenAddr: conf.SbftLocal.PeerCommAddr, + CertFile: conf.SbftLocal.CertFile, + KeyFile: conf.SbftLocal.KeyFile, + DataDir: conf.SbftLocal.DataDir} +} diff --git a/orderer/util_test.go b/orderer/util_test.go new file mode 100644 index 00000000000..54aa06c7a0b --- /dev/null +++ b/orderer/util_test.go @@ -0,0 +1,106 @@ +/* +Copyright IBM Corp. 2017 All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "os" + "testing" + + config "github.com/hyperledger/fabric/orderer/localconfig" +) + +func TestCreateLedgerFactory(t *testing.T) { + testCases := []struct { + name string + ledgerType string + ledgerDir string + ledgerDirPrefix string + expectPanic bool + }{ + {"RAM", "ram", "", "", false}, + {"JSONwithPathSet", "json", "test-dir", "", false}, + {"JSONwithPathUnset", "json", "", "test-prefix", false}, + {"FilewithPathSet", "file", "test-dir", "", false}, + {"FilewithPathUnset", "file", "", "test-prefix", false}, + } + + conf := config.Load() + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + defer func() { + r := recover() + if tc.expectPanic && r == nil { + t.Fatal("Should have panicked") + } + if !tc.expectPanic && r != nil { + t.Fatal("Should not have panicked") + } + }() + + conf.General.LedgerType = tc.ledgerType + conf.FileLedger.Location = tc.ledgerDir + conf.FileLedger.Prefix = tc.ledgerDirPrefix + lf, ld := createLedgerFactory(conf) + + defer func() { + if ld != "" { + os.RemoveAll(ld) + t.Log("Removed temp dir:", ld) + } + }() + lf.ChainIDs() + }) + } +} + +func TestCreateSubDir(t *testing.T) { + testCases := []struct { + name string + count int + expectCreated bool + expectPanic bool + }{ + {"CleanDir", 1, true, false}, + {"HasSubDir", 2, false, false}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + defer func() { + r := recover() + if tc.expectPanic && r == nil { + t.Fatal("Should have panicked") + } + if !tc.expectPanic && r != nil { + t.Fatal("Should not have panicked") + } + }() + + parentDirPath := createTempDir("test-dir") + + var created bool + for i := 0; i < tc.count; i++ { + _, created = createSubDir(parentDirPath, "test-sub-dir") + } + + if created != tc.expectCreated { + t.Fatalf("Sub dir created = %v, but expectation was = %v", created, tc.expectCreated) + } + }) + } +}