Currently IsDirEmpty returns true, err if it encounters
any error after trying to os.Open the directory.
I noticed this while studying the code and recalled a bug
from an earlier project in which doing the exact same thing
on code without permissions would trip out and falsely report
that the directory was empty.
Given demo.go in https://play.golang.org/p/vhTPU2RiCJ
* Demo:
```shell
$ mkdir -p sample-demo/1 && touch sample-demo/2
$ echo "1st round" && go run demo.go sample-demo
$ sudo chown root sample-demo && sudo chmod 0700 sample-demo
$ echo "2nd round" && go run demo.go sample-demo
```
That then prints out
```shell
1st round
original:: empty: false err: <nil>
updated:: empty: false err: <nil>
2nd round
original:: empty: true err: open data/: permission denied
updated:: empty: false err: open data/: permission denied
```
where in "2nd round", the original code falsely reports that
the directory is empty but that's a permission error.
I could write a code test for it, but that test requires me to change
users and switch to root as a Go user so no point in complicating our
tests, but otherwise it is a 1-to-1 translation between shell and Go.
Found common http utils that were being multiply duplicated across
many libraries and since am moving things in basecoin/unstable to
add for more functionality, it's better to put them in one
place.
Utilities and tests added:
- [X] FparseJSON
- [X] FparseAndValidateJSON
- [X] ParseRequestJSON
- [X] ParseAndValidateRequestJSON
- [X] WriteCode
- [X] WriteError
- [X] WriteSuccess
- [X] ErrorResponse
During review from @ethanfrey, made updates:
* Removed tt.want since it was a distraction/artifact that made
the reviewer think the tests weren't testing for both failed
and passed results.
* Added ErrorWithCode as WithCode is a common options pattern
in Go that could cause confusion:
ErrorWithCode(error, int) ErrorResponse
* Using json.NewDecoder(io.Reader) error instead of
ioutil.ReadAll(io.Reader) to slurp all the bytes.
* Added more test scenarios to achieve 100% coverage of http.go
Add a godoc reference to delegate indexing and references
to that service, thus keeping our library and usages upto date,
instead of relying on generated markdown that goes stale
especially for changing API signatures, and becomes tedious
where someone has to remember to always regenerate the README
markdown and then commit it.
Fixes#24
* Optimized ReverseBytes to:
a) Minimally allocate --> 60.0% reduction in the number of allocations
b) Only walk halfway the length of the string thus performing
byte swaps from left to right. Improves the performance as well.
Complexity is O(n/2) instead of O(n) which is still O(n) but
benchmarks show the new time is in deed 1/2 of the original time.
* Added unit tests and some common cases to ensure correctness.
* Benchmark shoot out results:
```shell
name old time/op new time/op delta
ReverseBytes-4 554ns ± 4% 242ns ± 3% -56.20% (p=0.000 n=10+10)
name old alloc/op new alloc/op delta
ReverseBytes-4 208B ± 0% 114B ± 0% -45.19% (p=0.000 n=10+10)
name old allocs/op new allocs/op delta
ReverseBytes-4 10.0 ± 0% 4.0 ± 0% -60.00% (p=0.000 n=10+10)
```
We use WriteFileAtomic in two places:
```
p2p/addrbook.go
338: err = cmn.WriteFileAtomic(filePath, jsonBytes, 0644)
types/priv_validator.go
162: err = WriteFileAtomic(privVal.filePath, jsonBytes, 0600)
```
and we don't need .bak in any of the above. We save priv_validator every
10ms and addrbook every 2 min.