Re: Private: Re: [Hyperledger Fabric] [FAB-17598] Improve the efficiency of viperutil.EnhancedExactUnmarshal

Nicholas Basker

Matt, All:

As discussed in the thread below, I have raised a draft PR to decouple "viper" from getKeysRecursive() function. Attached below the test results and improved times. 
The PR as it stands is raised to show the changes and get review comments. The code in "execmode := os.Getenv("SKIP_VIPER")" is the changes. The yaml.Unmarshal data could be reused instead of going through viper.Get() which does further recursive calls to viper.searchMap(). Furthermore the entire viper library can be skipped.

Have tested internal/configtxgen/genesisconfig, orderer/common/localconfig and common/viperutil (which are unit tests for viperutil.go). 

At this time, the viper references are not cleaned up as it enables me to compare and measure. Based on review, if this change is aligning with the thought of viper-removal, then shall update the PR with full cleanup by removing viper references from these files.

go test -race -count 1 -v -run Test | tail -2


ok        10.481s

SKIP_VIPER=yes go test -race -count 1 -v -run Test | tail -2


ok        5.922s

go test -race -count 1 -v -run Test | tail -2


ok        5.639s

SKIP_VIPER=orderer go test -race -count 1 -v -run Test | tail -2


ok        5.418s

go test -race -count 1 -v -run Test | tail -2


ok  5.544s

SKIP_VIPER=viperutil go test -race -count 1 -v -run Test | tail -2


ok  5.558s


On Sun, May 31, 2020 at 10:28 PM Nicholas Basker <nbasker@...> wrote:

Investigated the code and able to see that as you had mentioned getKeysRecursively() and the "viper.ReadInConfig()" have an over-lap. The viper.ReadInConfig() internally uses yaml ( or json utilities respectively to read the config and give it to getKeysRecursively() which again does a recursive-depth-walk to construct "TopLevel struct". 

Its possible to come up with a change to avoid viper, instead use yaml or json to read the file and directly pass to getKeysRecursively() to avoid on recursive-depth-walk. I can make the change.
The getKeysRecursively() function is only used by "EnhancedExactUnmarshal()" which in turn is used only in the following two places.

// EnhancedExactUnmarshal. Cache key is the path of the configuration file that was used.

                err := viperutil.EnhancedExactUnmarshal(config, conf)


// EnhancedExactUnmarshal. Cache key is the path of the configuration file that was used.

                err := viperutil.EnhancedExactUnmarshal(config, &uconf)


Is the objective to clean the above to avoid two recursive-depth-walk?
There are other places where viper is referenced but not used along with getKeysRecursively(), so there is no repetition. Is there clean up needed in these as well. (there are a lot of places where viper is used, clearing that seems like a fairly lot of change)


On Thu, May 21, 2020 at 11:58 PM Matthew Sykes <matthew.sykes@...> wrote:
The test I pointed to will exercise the code. If you're trying to observe what I mean when I say the bug is now the feature:

$ go get # upgrade to a current version of viper
$ go mod vendor
$ go test -race -count 1 -run TestLoadProfile

That test will now fail with a panic because "SampleDevModeKafka" is not present in the "Profiles" map associated with the config. This is related to bug fixes that went into viper in back in October of 2016. [1] if you're asking about the multi-pass nature, you should look at the implementation of `getKeysRecursively` and the viper implementation. There's quite a bit of overlap between the two.

Having said that, the ultimate goal is to remove viper from Fabric. While viper is a fine library, it does a lot of things we don't need and its property based model gets in the way as often as it doesn't - especially given how many of our components are populating value structures for config. So, if you want to pull on that thread, I think it would be a welcome effort.


Join to automatically receive all group messages.