mirror of
https://github.com/hyperledger/fabric-samples.git
synced 2026-06-18 07:55:10 +00:00
Add store interface and implement with offChainStore struct. Decompose storing into small chunks and keep state around storing writes and failure count. Move environment variables used for store setup into the setup phase of the listen function. Signed-off-by: Stanislav Jakuschevskij <stas@two-giants.com>
93 lines
1.8 KiB
Go
93 lines
1.8 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
)
|
|
|
|
var errExpected = errors.New("expected error: simulated write failure")
|
|
|
|
type offChainStore struct {
|
|
writes, path string
|
|
simulatedFailureCount, transactionCount uint
|
|
}
|
|
|
|
func newOffChainStore(path string, simulatedFailureCount uint) *offChainStore {
|
|
return &offChainStore{
|
|
"",
|
|
path,
|
|
uint(simulatedFailureCount),
|
|
0,
|
|
}
|
|
}
|
|
|
|
// Apply writes for a given transaction to off-chain data store, ideally in a single operation for fault tolerance.
|
|
// This implementation just writes to a file.
|
|
func (ocs *offChainStore) write(data ledgerUpdate) error {
|
|
if err := ocs.simulateFailureIfRequired(); err != nil {
|
|
return err
|
|
}
|
|
|
|
ocs.clearLastWrites()
|
|
|
|
if err := ocs.marshal(data.Writes); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := ocs.persist(); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (ocs *offChainStore) simulateFailureIfRequired() error {
|
|
if ocs.simulatedFailureCount > 0 && ocs.transactionCount >= ocs.simulatedFailureCount {
|
|
ocs.transactionCount = 0
|
|
return errExpected
|
|
}
|
|
|
|
ocs.transactionCount += 1
|
|
|
|
return nil
|
|
}
|
|
|
|
func (ocs *offChainStore) clearLastWrites() {
|
|
ocs.writes = ""
|
|
}
|
|
|
|
func (ocs *offChainStore) marshal(writes []write) error {
|
|
for _, write := range writes {
|
|
marshaled, err := json.Marshal(write)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
ocs.writes += string(marshaled) + "\n"
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (ocs *offChainStore) persist() error {
|
|
f, err := os.OpenFile(ocs.path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if _, writeErr := f.Write([]byte(ocs.writes)); writeErr != nil {
|
|
if closeErr := f.Close(); closeErr != nil {
|
|
return fmt.Errorf("write error: %v, close error: %v", writeErr, closeErr)
|
|
}
|
|
|
|
return writeErr
|
|
}
|
|
|
|
if err := f.Close(); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|