From 2a4e5695948e87bca619741d347a3cd989754801 Mon Sep 17 00:00:00 2001 From: Mohamed Feddad Date: Sun, 8 Sep 2024 18:12:24 +0400 Subject: [PATCH 1/3] chore: refactor pointors, and remove percent counter --- safelock/core.go | 4 ++-- safelock/decrypt.go | 31 +++++++++++------------- safelock/encrypt.go | 48 ++++++++++++++------------------------ safelock/reader.go | 35 +++++++++++++-------------- safelock/readerWriter.go | 41 ++++++++++++++++++++------------ safelock/writer.go | 34 ++++++++++++--------------- utils/getExitSignals.go | 19 +++++++++++++++ utils/percentCalculator.go | 48 -------------------------------------- 8 files changed, 111 insertions(+), 149 deletions(-) create mode 100644 utils/getExitSignals.go delete mode 100644 utils/percentCalculator.go diff --git a/safelock/core.go b/safelock/core.go index 16c36cb..1369669 100644 --- a/safelock/core.go +++ b/safelock/core.go @@ -24,8 +24,8 @@ type asyncGcm struct { done chan bool } -func newAsyncGcm(pwd string, config EncryptionConfig, errs chan<- error) *asyncGcm { - ag := &asyncGcm{ +func newAsyncGcm(pwd string, config EncryptionConfig, errs chan<- error) asyncGcm { + ag := asyncGcm{ pwd: pwd, config: config, errs: errs, diff --git a/safelock/decrypt.go b/safelock/decrypt.go index 84af0cd..7f79eaf 100644 --- a/safelock/decrypt.go +++ b/safelock/decrypt.go @@ -16,9 +16,9 @@ import ( // and then outputs the content into `outputPath` which must be a valid path to an existing directory // // NOTE: `ctx` context is optional you can pass `nil` and the method will handle it -func (sl *Safelock) Decrypt(ctx context.Context, input InputReader, outputPath, password string) (err error) { +func (sl Safelock) Decrypt(ctx context.Context, input InputReader, outputPath, password string) (err error) { errs := make(chan error) - signals, closeSignals := sl.getExitSignals() + signals, closeSignals := utils.GetExitSignals() if ctx == nil { ctx = context.Background() @@ -33,27 +33,25 @@ func (sl *Safelock) Decrypt(ctx context.Context, input InputReader, outputPath, Trigger(StatusEnd.Str()) go func() { - var calc *utils.PercentCalculator - if err = sl.validateDecryptionPaths(outputPath); err != nil { errs <- fmt.Errorf("invalid decryption input > %w", err) return } - if calc, err = utils.NewSeekerCalculator(input, 1.0); err != nil { - errs <- fmt.Errorf("failed to read input paths > %w", err) + ctx, cancel := context.WithCancel(ctx) + reader := newReader(password, input, 1.0, cancel, sl.EncryptionConfig, errs) + + if err = reader.setInputSize(); err != nil { + errs <- fmt.Errorf("failed to read input > %w", err) return } - ctx, cancel := context.WithCancel(ctx) - rw := newReader(password, input, cancel, calc, sl.EncryptionConfig, errs) - - if err = rw.ReadHeader(); err != nil { - errs <- fmt.Errorf("failed to read input file header > %w", err) + if err = reader.ReadHeader(); err != nil { + errs <- fmt.Errorf("failed to read input header > %w", err) return } - if err = sl.decryptFiles(ctx, outputPath, rw, calc); err != nil { + if err = sl.decryptFiles(ctx, outputPath, reader); err != nil { errs <- fmt.Errorf("failed to extract archive file > %w", err) return } @@ -87,19 +85,18 @@ func (sl *Safelock) validateDecryptionPaths(outputPath string) (err error) { return } -func (sl *Safelock) decryptFiles( +func (sl Safelock) decryptFiles( ctx context.Context, outputPath string, - slReader *safelockReader, - calc *utils.PercentCalculator, + slReader safelockReader, ) (err error) { var reader io.ReadCloser - if reader, err = sl.Compression.OpenReader(slReader); err != nil { + if reader, err = sl.Compression.OpenReader(&slReader); err != nil { return fmt.Errorf("cannot read archive file > %w", err) } - go sl.updateProgressStatus(ctx, "Decrypting", calc) + go sl.updateProgressStatus(ctx, "Decrypting", slReader) fileHandler := getExtractFileHandler(outputPath) diff --git a/safelock/encrypt.go b/safelock/encrypt.go index fbe5eaa..d10b31e 100644 --- a/safelock/encrypt.go +++ b/safelock/encrypt.go @@ -5,8 +5,6 @@ import ( "fmt" "io" "os" - "os/signal" - "syscall" "time" "github.com/mholt/archiver/v4" @@ -18,9 +16,9 @@ import ( // outputs into an object `output` that implements [io.Writer] such as [io.File] // // NOTE: `ctx` context is optional you can pass `nil` and the method will handle it -func (sl *Safelock) Encrypt(ctx context.Context, inputPaths []string, output io.Writer, password string) (err error) { +func (sl Safelock) Encrypt(ctx context.Context, inputPaths []string, output io.Writer, password string) (err error) { errs := make(chan error) - signals, closeSignals := sl.getExitSignals() + signals, closeSignals := utils.GetExitSignals() if ctx == nil { ctx = context.Background() @@ -41,16 +39,16 @@ func (sl *Safelock) Encrypt(ctx context.Context, inputPaths []string, output io. } ctx, cancel := context.WithCancel(ctx) - calc := utils.NewPathsCalculator(20.0) - rw := newWriter(password, output, cancel, calc, sl.EncryptionConfig, errs) - rw.asyncGcm = newAsyncGcm(password, sl.EncryptionConfig, errs) + config := sl.EncryptionConfig + gcm := newAsyncGcm(password, config, errs) + writer := newWriter(password, output, 20.0, cancel, gcm, config, errs) - if err = sl.encryptFiles(ctx, inputPaths, rw, calc); err != nil { + if err = sl.encryptFiles(ctx, inputPaths, writer); err != nil { errs <- err return } - if err = rw.WriteHeader(); err != nil { + if err = writer.WriteHeader(); err != nil { errs <- fmt.Errorf("failed to create encrypted file header > %w", err) return } @@ -74,18 +72,7 @@ func (sl *Safelock) Encrypt(ctx context.Context, inputPaths []string, output io. } } -func (sl *Safelock) getExitSignals() (<-chan os.Signal, func()) { - signals := make(chan os.Signal, 2) - close := func() { - signal.Stop(signals) - close(signals) - } - - signal.Notify(signals, syscall.SIGTERM, syscall.SIGINT) - return signals, close -} - -func (sl *Safelock) validateEncryptionInputs(inputPaths []string, pwd string) (err error) { +func (sl Safelock) validateEncryptionInputs(inputPaths []string, pwd string) (err error) { sl.updateStatus("Validating inputs", 0.0) for _, path := range inputPaths { @@ -101,15 +88,14 @@ func (sl *Safelock) validateEncryptionInputs(inputPaths []string, pwd string) (e return } -func (sl *Safelock) encryptFiles( +func (sl Safelock) encryptFiles( ctx context.Context, inputPaths []string, - slWriter *safelockWriter, - calc *utils.PercentCalculator, + slWriter safelockWriter, ) (err error) { var files []archiver.File var filesMap = make(map[string]string, len(inputPaths)) - var cancelListingStatus = sl.updateListingStatus(ctx, 1.0, calc.Start) + var cancelListingStatus = sl.updateListingStatus(ctx, 1.0, slWriter.start) for _, path := range inputPaths { filesMap[path] = "" @@ -122,14 +108,14 @@ func (sl *Safelock) encryptFiles( go func() { for _, file := range files { - calc.InputSize += int(file.Size()) + slWriter.increaseInputSize(int(file.Size())) } cancelListingStatus() - sl.updateProgressStatus(ctx, "Encrypting", calc) + sl.updateProgressStatus(ctx, "Encrypting", slWriter) }() - if err = sl.archive(ctx, slWriter, files); err != nil { + if err = sl.archive(ctx, &slWriter, files); err != nil { err = fmt.Errorf("failed to create encrypted archive file > %w", err) return } @@ -138,7 +124,7 @@ func (sl *Safelock) encryptFiles( return } -func (sl *Safelock) updateListingStatus(ctx context.Context, start, end float64) (cancel context.CancelFunc) { +func (sl Safelock) updateListingStatus(ctx context.Context, start, end float64) (cancel context.CancelFunc) { ctx, cancel = context.WithCancel(ctx) go func() { @@ -161,13 +147,13 @@ func (sl *Safelock) updateListingStatus(ctx context.Context, start, end float64) return } -func (sl *Safelock) updateProgressStatus(ctx context.Context, act string, calc *utils.PercentCalculator) { +func (sl Safelock) updateProgressStatus(ctx context.Context, act string, rw getPercent) { for { select { case <-ctx.Done(): return default: - sl.updateStatus(fmt.Sprintf("%s files", act), calc.GetPercent()) + sl.updateStatus(fmt.Sprintf("%s files", act), rw.getCompletedPercent()) time.Sleep(time.Second / 5) } } diff --git a/safelock/reader.go b/safelock/reader.go index d360554..5e55e72 100644 --- a/safelock/reader.go +++ b/safelock/reader.go @@ -9,7 +9,6 @@ import ( "strings" "github.com/mrf345/safelock-cli/slErrs" - "github.com/mrf345/safelock-cli/utils" ) type InputReader interface { @@ -19,7 +18,7 @@ type InputReader interface { type safelockReader struct { io.Reader - safelockReaderWriterBase + *safelockReaderWriterBase reader InputReader overflow []byte } @@ -27,29 +26,36 @@ type safelockReader struct { func newReader( pwd string, reader InputReader, + start float64, cancel context.CancelFunc, - calc *utils.PercentCalculator, config EncryptionConfig, errs chan<- error, -) *safelockReader { - return &safelockReader{ +) safelockReader { + return safelockReader{ reader: reader, - safelockReaderWriterBase: safelockReaderWriterBase{ + safelockReaderWriterBase: &safelockReaderWriterBase{ pwd: pwd, - calc: calc, errs: errs, cancel: cancel, config: config, + start: start, + end: 100.0, }, } } -func (sr *safelockReader) ReadHeader() (err error) { - sr.setSize() +func (sr *safelockReader) setInputSize() (err error) { + size, err := sr.reader.Seek(0, io.SeekEnd) + sr.inputSize = int(size) + return +} - headerBytes := make([]byte, sr.headerSize) +func (sr *safelockReader) ReadHeader() (err error) { + headerSize := sr.config.getHeaderSizeOut(sr.inputSize) + sizeDiff := int64(sr.inputSize - headerSize) + headerBytes := make([]byte, headerSize) - if _, err = sr.reader.Seek(sr.diffSize(), io.SeekStart); err != nil { + if _, err = sr.reader.Seek(sizeDiff, io.SeekStart); err != nil { err = fmt.Errorf("can't seek header > %w", err) return sr.handleErr(err) } @@ -74,11 +80,6 @@ func (sr *safelockReader) ReadHeader() (err error) { return } -func (sr *safelockReader) setSize() { - sr.size = sr.calc.InputSize - sr.headerSize = sr.config.getHeaderSizeOut(sr.size) -} - func (sr *safelockReader) Read(chunk []byte) (read int, err error) { var blockSize int var block string @@ -115,7 +116,7 @@ func (sr *safelockReader) Read(chunk []byte) (read int, err error) { return read, sr.handleErr(err) } - sr.calc.OutputSize += len(decrypted) + sr.outputSize += len(decrypted) return sr.handleOverflowOut(&chunk, decrypted), nil } diff --git a/safelock/readerWriter.go b/safelock/readerWriter.go index b49ed12..d206925 100644 --- a/safelock/readerWriter.go +++ b/safelock/readerWriter.go @@ -2,30 +2,41 @@ package safelock import ( "context" - - "github.com/mrf345/safelock-cli/utils" ) -type safelockReaderWriterBase struct { - config EncryptionConfig - pwd string - errs chan<- error - cancel context.CancelFunc - calc *utils.PercentCalculator - - size int - headerSize int - blocks []string - err error +type getPercent interface { + getCompletedPercent() float64 } -func (srw *safelockReaderWriterBase) diffSize() int64 { - return int64(srw.size - srw.headerSize) +type safelockReaderWriterBase struct { + config EncryptionConfig + pwd string + errs chan<- error + cancel context.CancelFunc + blocks []string + err error + start, end float64 + inputSize, outputSize int } func (srw *safelockReaderWriterBase) handleErr(err error) error { + // panic(err) srw.err = err srw.errs <- err srw.cancel() return err } + +func (srw safelockReaderWriterBase) getCompletedPercent() float64 { + percent := srw.start + (float64(srw.outputSize) / float64(srw.inputSize) * srw.end) + + if srw.end > percent { + return percent + } + + return srw.end +} + +func (srw *safelockReaderWriterBase) increaseInputSize(increment int) { + srw.inputSize += increment +} diff --git a/safelock/writer.go b/safelock/writer.go index 3e65611..e7b400c 100644 --- a/safelock/writer.go +++ b/safelock/writer.go @@ -5,33 +5,34 @@ import ( "fmt" "io" "strings" - - "github.com/mrf345/safelock-cli/utils" ) type safelockWriter struct { io.Writer - safelockReaderWriterBase + *safelockReaderWriterBase writer io.Writer - asyncGcm *asyncGcm + asyncGcm asyncGcm } func newWriter( pwd string, writer io.Writer, + start float64, cancel context.CancelFunc, - calc *utils.PercentCalculator, + asyncGcm asyncGcm, config EncryptionConfig, errs chan<- error, -) *safelockWriter { - return &safelockWriter{ - writer: writer, - safelockReaderWriterBase: safelockReaderWriterBase{ +) safelockWriter { + return safelockWriter{ + writer: writer, + asyncGcm: asyncGcm, + safelockReaderWriterBase: &safelockReaderWriterBase{ pwd: pwd, - calc: calc, errs: errs, cancel: cancel, config: config, + start: start, + end: 100.0, }, } } @@ -44,7 +45,7 @@ func (sw *safelockWriter) Write(chunk []byte) (written int, err error) { return written, sw.handleErr(err) } - sw.calc.OutputSize += written + sw.outputSize += written sw.blocks = append(sw.blocks, fmt.Sprintf("%d", written)) return @@ -52,14 +53,14 @@ func (sw *safelockWriter) Write(chunk []byte) (written int, err error) { func (sw *safelockWriter) WriteHeader() (err error) { sw.asyncGcm.done <- true - sw.setSize() - if 0 >= sw.size { + if 0 >= sw.outputSize { return } header := "BS;" + strings.Join(sw.blocks, ";") - headerBytes := make([]byte, sw.headerSize) + headerSize := sw.config.getHeaderSizeIn(sw.outputSize) + headerBytes := make([]byte, headerSize) headerBytes = append([]byte(header), headerBytes[len(header):]...) if _, err = sw.writer.Write(headerBytes); err != nil { @@ -69,8 +70,3 @@ func (sw *safelockWriter) WriteHeader() (err error) { return } - -func (sw *safelockWriter) setSize() { - sw.size = sw.calc.OutputSize - sw.headerSize = sw.config.getHeaderSizeIn(sw.size) -} diff --git a/utils/getExitSignals.go b/utils/getExitSignals.go new file mode 100644 index 0000000..7e73744 --- /dev/null +++ b/utils/getExitSignals.go @@ -0,0 +1,19 @@ +package utils + +import ( + "os" + "os/signal" + "syscall" +) + +// get exit signal channel, and its closer function +func GetExitSignals() (<-chan os.Signal, func()) { + signals := make(chan os.Signal, 2) + close := func() { + signal.Stop(signals) + close(signals) + } + + signal.Notify(signals, syscall.SIGTERM, syscall.SIGINT) + return signals, close +} diff --git a/utils/percentCalculator.go b/utils/percentCalculator.go deleted file mode 100644 index 0e3ef65..0000000 --- a/utils/percentCalculator.go +++ /dev/null @@ -1,48 +0,0 @@ -package utils - -import ( - "io" -) - -// helps calculating file completion percentage -type PercentCalculator struct { - OutputSize int - InputSize int - Start float64 - End float64 -} - -// create new instance of [utils.PercentCalculator] for input paths -func NewPathsCalculator(start float64) *PercentCalculator { - return &PercentCalculator{ - Start: start, - End: 100.0, - } -} - -// create new instance of [utils.PercentCalculator] for [io.Seeker] -func NewSeekerCalculator(inputSeeker io.Seeker, start float64) (pc *PercentCalculator, err error) { - pc = &PercentCalculator{ - Start: start, - End: 100.0, - } - err = pc.setInputSeekerSize(inputSeeker) - return -} - -func (pc *PercentCalculator) setInputSeekerSize(seeker io.Seeker) (err error) { - size, err := seeker.Seek(0, io.SeekEnd) - pc.InputSize = int(size) - return -} - -// get current completion percentage -func (pc *PercentCalculator) GetPercent() float64 { - percent := pc.Start + (float64(pc.OutputSize) / float64(pc.InputSize) * pc.End) - - if pc.End > percent { - return percent - } - - return pc.End -} From 7dae1eadc3624c8256b74493589d3af28dd9c914 Mon Sep 17 00:00:00 2001 From: Mohamed Feddad Date: Sun, 8 Sep 2024 18:13:07 +0400 Subject: [PATCH 2/3] chore: update benchmarks and readme --- README.md | 3 +- benchmark/decryption-time.webp | Bin 7688 -> 7376 bytes benchmark/decryption.json | 100 ++++++++++++++++----------------- benchmark/encryption-time.webp | Bin 7418 -> 6960 bytes benchmark/encryption.json | 100 ++++++++++++++++----------------- benchmark/file-size.webp | Bin 7898 -> 7754 bytes 6 files changed, 102 insertions(+), 101 deletions(-) diff --git a/README.md b/README.md index 2899ee1..bb411f3 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,8 @@ You can find interactive examples of using it as a package to [encrypt](https:// ### Performance -With the default settings the encryption should be about **18.5** times faster than `gpgtar` and **8.8** times faster than `7zip` +- Encryption should be about **20.2** times faster than `gpgtar`, and the decryption **3.3** times. +- Encryption should be about **9.1** times faster than `7zip`, and the decryption **9.5** times. > [!NOTE] > You can reproduce the results by running [bench_and_plot.py](benchmark/bench_and_plot.py) (based on [Matplotlib](https://github.com/matplotlib/matplotlib) and [Hyperfine](https://github.com/sharkdp/hyperfine)) diff --git a/benchmark/decryption-time.webp b/benchmark/decryption-time.webp index bcfceab73d42aec4df65596cfba0fb6b66728d6b..8aedb9a29f8c0bb3062032800f9fda46ace80963 100644 GIT binary patch literal 7376 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 I9RdLSKSmpNX#fBK literal 7688 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 diff --git a/benchmark/decryption.json b/benchmark/decryption.json index 76f4041..c808168 100644 --- a/benchmark/decryption.json +++ b/benchmark/decryption.json @@ -2,17 +2,17 @@ "results": [ { "command": "echo \"123456789\" | ~/Projects/safelock-cli/safelock-cli decrypt test.sla safelock_dump --quiet", - "mean": 2.1050263989333335, - "stddev": 0.06409584697239645, - "median": 2.1340488396, - "user": 2.565836426666667, - "system": 1.86455084, - "min": 2.0315528936000002, - "max": 2.1494774636000002, + "mean": 2.1295176539933336, + "stddev": 0.03361454776096437, + "median": 2.13093239266, + "user": 2.5876522466666665, + "system": 1.88427306, + "min": 2.0952180726600003, + "max": 2.16240249666, "times": [ - 2.1494774636000002, - 2.1340488396, - 2.0315528936000002 + 2.16240249666, + 2.13093239266, + 2.0952180726600003 ], "exit_codes": [ 0, @@ -22,17 +22,17 @@ }, { "command": "echo \"123456789\" | ~/Projects/safelock-cli/safelock-cli decrypt test_sha256.sla safelock_dump --quiet --sha256", - "mean": 1.7911251366, - "stddev": 0.21521963683077622, - "median": 1.7543641936, - "user": 1.9575960933333334, - "system": 1.67062184, - "min": 1.5966536246, - "max": 2.0223575916, + "mean": 1.8789916449933333, + "stddev": 0.17816416646803604, + "median": 1.98184108566, + "user": 2.0644982466666666, + "system": 1.776121393333333, + "min": 1.67326538666, + "max": 1.9818684626599998, "times": [ - 1.7543641936, - 2.0223575916, - 1.5966536246 + 1.67326538666, + 1.98184108566, + 1.9818684626599998 ], "exit_codes": [ 0, @@ -42,17 +42,17 @@ }, { "command": "echo \"123456789\" | ~/Projects/safelock-cli/safelock-cli decrypt test_sha512.sla safelock_dump --quiet --sha512", - "mean": 2.268577597266667, - "stddev": 0.026547606953880087, - "median": 2.2732154626, - "user": 2.8112754266666666, - "system": 1.9018115066666663, - "min": 2.2400166546, - "max": 2.2925006746000003, + "mean": 2.123450407993334, + "stddev": 0.1763774710740607, + "median": 2.1136010126600002, + "user": 2.5975039133333335, + "system": 1.7468127266666666, + "min": 1.95220401166, + "max": 2.3045461996600003, "times": [ - 2.2732154626, - 2.2400166546, - 2.2925006746000003 + 2.3045461996600003, + 2.1136010126600002, + 1.95220401166 ], "exit_codes": [ 0, @@ -62,17 +62,17 @@ }, { "command": "7z e -y -p123456789 -mx1 test.7z -osafelock_dump", - "mean": 18.642169893266665, - "stddev": 1.1840904020013951, - "median": 17.9893611436, - "user": 20.570662093333336, - "system": 1.4070678399999998, - "min": 17.9281653906, - "max": 20.0089831456, + "mean": 17.944166026326666, + "stddev": 0.03535223844853417, + "median": 17.95858265166, + "user": 19.665792913333334, + "system": 1.4092493933333332, + "min": 17.90388353266, + "max": 17.97003189466, "times": [ - 20.0089831456, - 17.9281653906, - 17.9893611436 + 17.97003189466, + 17.90388353266, + 17.95858265166 ], "exit_codes": [ 0, @@ -82,17 +82,17 @@ }, { "command": "gpgtar -d --yes --batch --gpg-args \"--passphrase 123456789\" test.gpg", - "mean": 5.750362993933334, - "stddev": 0.2899378904750308, - "median": 5.6110951406, - "user": 0.1864430933333333, - "system": 1.3356181733333334, - "min": 5.5563355296, - "max": 6.0836583116, + "mean": 6.240754918993335, + "stddev": 0.18841334623779463, + "median": 6.18021860166, + "user": 0.17699391333333328, + "system": 1.4514090599999998, + "min": 6.09005041466, + "max": 6.45199574066, "times": [ - 6.0836583116, - 5.6110951406, - 5.5563355296 + 6.45199574066, + 6.18021860166, + 6.09005041466 ], "exit_codes": [ 0, diff --git a/benchmark/encryption-time.webp b/benchmark/encryption-time.webp index 6b09361932dd9260289e83f1217104b1291c7960..98b5e14dee09bcaaf9212c747f82cdfe96af5952 100644 GIT binary patch literal 6960 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 Y(S!m37@WcUdKw=Smd|-z{r|WB2Z&p?i~s-t literal 7898 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 From c38cfdb48f57eb2c5a9181af071652dbf1563f5d Mon Sep 17 00:00:00 2001 From: Mohamed Feddad Date: Sun, 8 Sep 2024 18:13:37 +0400 Subject: [PATCH 3/3] chore: cleanup, and bump version to 0.4.3 --- cmd/root.go | 2 +- safelock/readerWriter.go | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index d604b54..96551a1 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -16,7 +16,7 @@ var rootCmd = &cobra.Command{ Use: "safelock-cli", Short: "Simple tool to encrypt/decrypt files with AES encryption", Long: "Simple command-line tool to encrypt and decrypt files with AES encryption", - Version: "0.4.2", + Version: "0.4.3", CompletionOptions: cobra.CompletionOptions{ DisableDefaultCmd: true, }, diff --git a/safelock/readerWriter.go b/safelock/readerWriter.go index d206925..7482e5b 100644 --- a/safelock/readerWriter.go +++ b/safelock/readerWriter.go @@ -20,7 +20,6 @@ type safelockReaderWriterBase struct { } func (srw *safelockReaderWriterBase) handleErr(err error) error { - // panic(err) srw.err = err srw.errs <- err srw.cancel()