Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[LEDGER] reduce #arguments in a few kvledger methods #1210

Merged

Conversation

cendhu
Copy link
Contributor

@cendhu cendhu commented May 4, 2020

Type of change

  • Improvement (improvement to code)

Description

As the number of arguments passed to newKVLedger(), initTxMgr(), and NewLockBasedTxMgr() is high, we reduce it by passing the initializer struct itself.

Additional details

In subsequent PRs, we would think of moving the BookeepingProvider and DB to the txmgr pkg and instead create a TxMgrProvider in the kvLedger to reduce the number of arguments further by 1. Moreover, it is natural to initiate structs that are directly used by kvLedger in the kvledger pkg. For now, the BookeepingProvider and DB are not directly used by the kvLedger.

Related issues

FAB-17683

@cendhu cendhu requested a review from a team as a code owner May 4, 2020 19:22
@manish-sethi
Copy link
Contributor

@cendhu - I don't think that this change is in the right direction. The dependencies were being passed explicitly, as is typically desired.

@lindluni
Copy link
Contributor

lindluni commented May 4, 2020

@cendhu - I don't think that this change is in the right direction. The dependencies were being passed explicitly, as is typically desired.

I don't have an extensive background on what is right or wrong here, but I tend to support this change. The simplification greatly reduced the complexity of following the code. The object being passed around (and it remains in the kvledger package, and in the same file) the same package until it is ultimately passed off to another package (the txmgr) where the necessary parameters are extracted from the object before being passed out of the package.

If I was tracing this code I have to track the same 5 parameters through multiple function calls, making it difficult to keep track of mentally. With Senthil's change I can simply follow the object until it's ultimately extracted within the current package and passed off for consumption to a single function. The context is much simpler.

It's also worth noting, that if you were to turn on the code smell feature of many of the most popular Golang linting tools, a function taking in this many number of arguments would NOT pass the smell tests as being unusually complicated and not being mentally digestible.

As is typically desired doesn't always mean mandatory. The reduction in complexity IMO is worth breaking from what might be typically desired.

customTxProcessors,
hasher,
); err != nil {
err := l.initTxMgr(versionedDB, lgrProvider.stateListeners, btlPolicy, lgrProvider)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you're already passing in the lgrProvider you can pull the lgrProvider.stateListeners off the object in the callee instead of passing it down explicitly.

@manish-sethi
Copy link
Contributor

manish-sethi commented May 4, 2020

@cendhu - I don't think that this change is in the right direction. The dependencies were being passed explicitly, as is typically desired.

I don't have an extensive background on what is right or wrong here, but I tend to support this change. The simplification greatly reduced the complexity of following the code. The object being passed around (and it remains in the kvledger package, and in the same file) the same package until it is ultimately passed off to another package (the txmgr) where the necessary parameters are extracted from the object before being passed out of the package.

If I was tracing this code I have to track the same 5 parameters through multiple function calls, making it difficult to keep track of mentally. With Senthil's change I can simply follow the object until it's ultimately extracted within the current package and passed off for consumption to a single function. The context is much simpler.

It's also worth noting, that if you were to turn on the code smell feature of many of the most popular Golang linting tools, a function taking in this many number of arguments would NOT pass the smell tests as being unusually complicated and not being mentally digestible.

As is typically desired doesn't always mean mandatory. The reduction in complexity IMO is worth breaking from what might be typically desired.

I am not against clubbing the parameters to reduce the number of parameters. My objection is to the way it is achieved here. i.e., pass down the provider instance much deeper in the code where we are supposed to have the code specific to one ledger instance. This is overusing the provider, which is not merely a holder of objects but has an associated behavior as well.
For instance, the same problem was there when passing the dependencies from peer to ledger and they were clubbed in this struct -

type Initializer struct {

@cendhu
Copy link
Contributor Author

cendhu commented May 5, 2020

@manish-sethi As @btl5037 mentioned, having too many arguments make the code readability a bit hard. I have faced it multiple times when adding/making changes to kvledger package. Let me share the thought process I had before submitting this PR.

  1. given that newKVLedger() uses many variables present in the Provider, I thought of moving newKVLedger() method under Provider struct itself and renaming it to initKVLedger() but that might break the current file organization and wasn't sure whether you would approve it. In the earlier days, kv_ledger_provider.go and kv_ledger.go confused me a lot and now I know about them. Anyway, I didn't want to do a bigger refactoring in this PR.
  2. when we call newKVLedger(), we do pass most of the arguments needed to construct the kvLedger struct but txmgr. Hence, I was thinking of directly creating kvLedger struct from the Provider and calling kvLedger.init() but again I wasn't sure whether newXXX only should create the sturct and hence, I dropped that option too. Moreover, we pass all needed items from Provider except txmgr which did not look correct to me. As can be seen in the PR description, I am planning to introduce something called txmgr provider.
  3. finally I was thinking of introducing a struct called ledgerConfig and txmgrConfig but I thought this might collide with the ledgerConfig passed from start.go.

I didn't think of the initializer struct. Are you suggesting to introduce something like kvLedgerInitializer struct and pass it to newKVLedger()? Similarly, we can introduce txmgrInitializer to reduce the number of arguments in initTxmgr()

@manish-sethi
Copy link
Contributor

  1. given that newKVLedger() uses many variables present in the Provider, I thought of moving newKVLedger() method under Provider struct itself and renaming it to initKVLedger()

I am fine with this approach, if you want to go that way.

Moreover, we pass all needed items from Provider except txmgr which did not look correct to me. As can be seen in the PR description, I am planning to introduce something called txmgr provider.

There is a difference between the other items that are passed in and the txmgr. The other items are either passed-in dependencies from other packages (e.g., DeployedChaincodeInfoProvider) or they are shared stores (e.g., leveldbs), whereas, the txmgr is just an internal struct which is constructed one for each ledger - and hence constructed internally.

I didn't think of the initializer struct. Are you suggesting to introduce something like kvLedgerInitializer struct and pass it to newKVLedger()? Similarly, we can introduce txmgrInitializer to reduce the number of arguments in initTxmgr()

Yes, that's what I meant.

So, either (or mix of both) of provider.newKVLedger() and txmgrInitializer works for me.

Finally, IMO, the bigger problem with this function is that some of the dependencies of initialization ordering needs a revisit... so, various init's can be removed

@mastersingh24
Copy link
Contributor

@manish-sethi is on to something here. I'd say that this is worthy of a bigger refactor (although I do see the value in reducing the number of parameters where possible).

We really need to define the hierarchy of structs here and try to avoid side effects as best as possible. For example, does a provider have multiple ledgers or do ledgers have a provider (where multiple ledgers can share a provider)

@cendhu
Copy link
Contributor Author

cendhu commented May 5, 2020

@mastersingh24 Yes, Manish was planning to refactor these dependencies ( some are ledger sub-packages and some are not) as part of validation refactoring epic (if I remember correctly). For now, we have decided to defer a few bigger refactoring work as we need to move to ledger checkpointing work. We would still do small refactoring while we code for the ledger checkpointing and defer the bigger refactoring which involves the following packages:

  1. mvcc validation pkg.
  2. kvledger pkg
  3. merge kvledger pkg with ledger pkg to reduce folder depth.
  4. merge lockbasedtxmgr pkg with the txmgr pkg.
  5. merge privacyenabledstate pkg with the lockbasedtxmgr pkg

and a few more.

@mastersingh24
Copy link
Contributor

@mastersingh24 Yes, Manish was planning to refactor these dependencies ( some are ledger sub-packages and some are not) as part of validation refactoring epic (if I remember correctly). For now, we have decided to defer a few bigger refactoring work as we need to move to ledger checkpointing work. We would still do small refactoring while we code for the ledger checkpointing and defer the bigger refactoring which involves the following packages:

  1. mvcc validation pkg.
  2. kvledger pkg
  3. merge kvledger pkg with ledger pkg to reduce folder depth.
  4. merge lockbasedtxmgr pkg with the txmgr pkg.
  5. merge privacyenabledstate pkg with the lockbasedtxmgr pkg

and a few more.

Got it - makes sense

@cendhu cendhu marked this pull request as draft May 6, 2020 07:47
@cendhu cendhu force-pushed the reduce-noarguments-kvledger branch 2 times, most recently from 8bcecd7 to c6f8a16 Compare May 8, 2020 13:37
@cendhu cendhu marked this pull request as ready for review May 8, 2020 13:40
As the number of arguments passed to newKVLedger(),
initTxMgr() is quite high, we reduce it by introducing
initializer struct.

FAB-17683

Signed-off-by: senthil <cendhu@gmail.com>
@cendhu cendhu force-pushed the reduce-noarguments-kvledger branch from c6f8a16 to 8020952 Compare May 8, 2020 13:54
if hasher == nil {
func NewLockBasedTxMgr(initializer *Initializer) (*LockBasedTxMgr, error) {

if initializer.Hasher == nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In isolation, without checking initializer for nil, this check seems a half job. Also, we check here only for Hasher and not for other parameters, seem odd. Though, the difference is that the hasher is an external ledger dependency that is passed from the peer. So, I guess that to make it clear, we should move this way up (directly when the ledger is initialized from outside). Not introduced in this PR, so can be done separately.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. At least we can move this check to kvledger package for now.

@manish-sethi manish-sethi merged commit 25e5c3e into hyperledger:master May 8, 2020
xhens added a commit to xhens/fabric that referenced this pull request May 8, 2020
* [FAB-17819] Discovery returns user friendly errors

Currently, the discovery service filters out peers that don't have the chaincode installed
early on in the computation, and as a result - the service cannot distinguish from a case
where there are not enough alive peers to satisfy the endorsement policy, or that there are
enough peers but the chaincode is not installed on enough of them.

This change set defers the chaincode filtering to the end of the computation, so
the layouts and peer group mapping is creating without taking into account if the peers
have the chaincode installed on them, and if there is no layout that can be satisfied
without taking into account the chaincodes - the error that is returned now
is "no peer combination can satisfy the endorsement policy",
instead of "cannot satisfy any principal combination".

Afterwards, the layouts are being inspected once again, and then the layouts
that cannot be satisfied are filtered out, when the error returned
when no layout can be satisfied is now: "required chaincodes are not installed on sufficient peers".

Change-Id: I74eb29b30aec1a87842d220414c73872cdbc8304
Signed-off-by: yacovm <yacovm@il.ibm.com>

* Fix docker network leak from RAFT integration test (hyperledger#1203)

Signed-off-by: Matthew Sykes <matthew.sykes@gmail.com>

* [FAB-17786] Update upgrade_dbs peer command to drop state couchdb (hyperledger#1187)

The existing upgrade_dbs command does not automatically drop state couchdbs
and therefore a separate step is required to drop couchdbs, This PR updates
the command to automatically drop state couchdbs.

In addition, it checks upgrade eligibility before upgrade so that it will not
drop databases if it is already the expected format.

Signed-off-by: Wenjian Qiao <wenjianq@gmail.com>

* [FAB-17774] support orderer restart without genesis block (hyperledger#1197)

* adding support for orderer restart without genesis block.

Signed-off-by: Chongxin Luo <Chongxin.Luo@ibm.com>

* Remove interface for block storage

- Removed the interface for better code navigation, as There is only a
 single implementation for block storage
- Merged the remaining code in the package blkstorgae with the
implementation in the package fsblkstorage and used the name
blkstorgae for the final package
- Moved the internal single proto message with in same package

Signed-off-by: manish <manish.sethi@gmail.com>

* [LEDGER] Move UpdatesBytesBuilder to txmgr pkg (hyperledger#1209)

- mv updateBatch bytes constructor to txmgr pkg
Currently, we create the bytes representation of updateBatch
to compute the hash of updateBatch which would be included in
the block along with the validation results. The utility for
converting a updateBatch to a deterministic bytes is present
in the privacyenabledstate pkg. However, this utility is
used only by the txmgr and hence, we move the utility
function to txmgr pkg from privacyenabledstate pkg.

- rename proto messages
In the updateBatch proto, we have defined proto messages such
as KVWriteProto and KVWriteBatchProto. As we shouldn't append
the keyword proto to messages, we rename KVWriteProto to KVWrite
and KVWriteBatchProto to Updates.

- rename function names
The function name such as buildForKeys(), buildForColls() are not
very explicit in what they do. When the buildForColls() calls
buildForKeys(), it adds even more confusion as the first-level
function, i.e., deterministicBytesForPubAndHashUpdates() is also
calling buildForKeys(). Hence, we have used the following function
names instead:
(1) genKVsFromNsUpdates()
(2) genKVsFromCollsUpdates()
(3) genKVs()

FAB-17830

Signed-off-by: senthil <cendhu@gmail.com>

* Update grpc-go to v1.29.1 (hyperledger#1213)

Signed-off-by: Gari Singh <gari.r.singh@gmail.com>

* [FAB-17831] Use generic constant/var names in dataformat.go (hyperledger#1212)

Currently Version1x and Version20 are defined in dataformat.go.
They should be renamed to more generic names such as
PreviousFormat and CurrentFormat.

The format values will change only when the data format is changed
in ledger. If a Fabric version does not introduce a new data format,
CurrentFormat will remain the same as the latest format prior to
the Fabric version.

Signed-off-by: Wenjian Qiao <wenjianq@gmail.com>

* [LEDGER] rm interface from pvtdatastorage pkg (hyperledger#1217)

rm pvtdatastorage interfaces

As we have only one implementation of the pvtdatastore and not
planning to any a new one, we can safely remove the interface.
This also helps in code navigation and to avoid type casting
such as s.(*store) in the test.

FAB-17843

Signed-off-by: senthil <cendhu@gmail.com>

* FAB-15710 Ch.Part.API: orderer config & hook into http server (hyperledger#1218)

- Expose a configuration object for channel participation at
  the top level (like Metrics). Even though the channel
  participation API shares the same endpoint and TLS config
  with operations, placing it at the top level will allow us
  to separate these APIs to different endpoints in the future
  without changing the config structure.

- Extend operations.System to be able to register a handler
  for additional APIs.

- Implement a skeleton handler for the channel participation API.

- Register the skeleton handler to the http server in
  operations.System during the server boot sequence.

Signed-off-by: Yoav Tock <tock@il.ibm.com>
Change-Id: I5cf15dffa29985cba60e5aaf31d189e755a3a1ef

* Update the vagrant dev environment

- Remove GOPATH in favor of modules
- Move to Ubuntu 20.04
- Remove docker-compose as it's unnecessary for build and test

Signed-off-by: Matthew Sykes <sykesmat@us.ibm.com>

* Add function in blockstore to export TxIDs

FAB-17837

Signed-off-by: manish <manish.sethi@gmail.com>

* reduce #arguments in a few kvledger methods (hyperledger#1210)

As the number of arguments passed to newKVLedger(),
initTxMgr() is quite high, we reduce it by introducing
initializer struct.

FAB-17683

Signed-off-by: senthil <cendhu@gmail.com>

Co-authored-by: yacovm <yacovm@il.ibm.com>
Co-authored-by: Matthew Sykes <sykesmat@us.ibm.com>
Co-authored-by: wen <wenjianq@gmail.com>
Co-authored-by: Dereck <Chongxin.Luo@ibm.com>
Co-authored-by: manish <manish.sethi@gmail.com>
Co-authored-by: Senthil Nathan N <cendhu@users.noreply.github.com>
Co-authored-by: Gari Singh <gari.r.singh@gmail.com>
Co-authored-by: Yoav Tock <tock@il.ibm.com>
xhens added a commit to xhens/fabric that referenced this pull request May 10, 2020
* [FAB-17819] Discovery returns user friendly errors

Currently, the discovery service filters out peers that don't have the chaincode installed
early on in the computation, and as a result - the service cannot distinguish from a case
where there are not enough alive peers to satisfy the endorsement policy, or that there are
enough peers but the chaincode is not installed on enough of them.

This change set defers the chaincode filtering to the end of the computation, so
the layouts and peer group mapping is creating without taking into account if the peers
have the chaincode installed on them, and if there is no layout that can be satisfied
without taking into account the chaincodes - the error that is returned now
is "no peer combination can satisfy the endorsement policy",
instead of "cannot satisfy any principal combination".

Afterwards, the layouts are being inspected once again, and then the layouts
that cannot be satisfied are filtered out, when the error returned
when no layout can be satisfied is now: "required chaincodes are not installed on sufficient peers".

Change-Id: I74eb29b30aec1a87842d220414c73872cdbc8304
Signed-off-by: yacovm <yacovm@il.ibm.com>

* Fix docker network leak from RAFT integration test (hyperledger#1203)

Signed-off-by: Matthew Sykes <matthew.sykes@gmail.com>

* [FAB-17786] Update upgrade_dbs peer command to drop state couchdb (hyperledger#1187)

The existing upgrade_dbs command does not automatically drop state couchdbs
and therefore a separate step is required to drop couchdbs, This PR updates
the command to automatically drop state couchdbs.

In addition, it checks upgrade eligibility before upgrade so that it will not
drop databases if it is already the expected format.

Signed-off-by: Wenjian Qiao <wenjianq@gmail.com>

* [FAB-17774] support orderer restart without genesis block (hyperledger#1197)

* adding support for orderer restart without genesis block.

Signed-off-by: Chongxin Luo <Chongxin.Luo@ibm.com>

* Remove interface for block storage

- Removed the interface for better code navigation, as There is only a
 single implementation for block storage
- Merged the remaining code in the package blkstorgae with the
implementation in the package fsblkstorage and used the name
blkstorgae for the final package
- Moved the internal single proto message with in same package

Signed-off-by: manish <manish.sethi@gmail.com>

* [LEDGER] Move UpdatesBytesBuilder to txmgr pkg (hyperledger#1209)

- mv updateBatch bytes constructor to txmgr pkg
Currently, we create the bytes representation of updateBatch
to compute the hash of updateBatch which would be included in
the block along with the validation results. The utility for
converting a updateBatch to a deterministic bytes is present
in the privacyenabledstate pkg. However, this utility is
used only by the txmgr and hence, we move the utility
function to txmgr pkg from privacyenabledstate pkg.

- rename proto messages
In the updateBatch proto, we have defined proto messages such
as KVWriteProto and KVWriteBatchProto. As we shouldn't append
the keyword proto to messages, we rename KVWriteProto to KVWrite
and KVWriteBatchProto to Updates.

- rename function names
The function name such as buildForKeys(), buildForColls() are not
very explicit in what they do. When the buildForColls() calls
buildForKeys(), it adds even more confusion as the first-level
function, i.e., deterministicBytesForPubAndHashUpdates() is also
calling buildForKeys(). Hence, we have used the following function
names instead:
(1) genKVsFromNsUpdates()
(2) genKVsFromCollsUpdates()
(3) genKVs()

FAB-17830

Signed-off-by: senthil <cendhu@gmail.com>

* Update grpc-go to v1.29.1 (hyperledger#1213)

Signed-off-by: Gari Singh <gari.r.singh@gmail.com>

* [FAB-17831] Use generic constant/var names in dataformat.go (hyperledger#1212)

Currently Version1x and Version20 are defined in dataformat.go.
They should be renamed to more generic names such as
PreviousFormat and CurrentFormat.

The format values will change only when the data format is changed
in ledger. If a Fabric version does not introduce a new data format,
CurrentFormat will remain the same as the latest format prior to
the Fabric version.

Signed-off-by: Wenjian Qiao <wenjianq@gmail.com>

* [LEDGER] rm interface from pvtdatastorage pkg (hyperledger#1217)

rm pvtdatastorage interfaces

As we have only one implementation of the pvtdatastore and not
planning to any a new one, we can safely remove the interface.
This also helps in code navigation and to avoid type casting
such as s.(*store) in the test.

FAB-17843

Signed-off-by: senthil <cendhu@gmail.com>

* FAB-15710 Ch.Part.API: orderer config & hook into http server (hyperledger#1218)

- Expose a configuration object for channel participation at
  the top level (like Metrics). Even though the channel
  participation API shares the same endpoint and TLS config
  with operations, placing it at the top level will allow us
  to separate these APIs to different endpoints in the future
  without changing the config structure.

- Extend operations.System to be able to register a handler
  for additional APIs.

- Implement a skeleton handler for the channel participation API.

- Register the skeleton handler to the http server in
  operations.System during the server boot sequence.

Signed-off-by: Yoav Tock <tock@il.ibm.com>
Change-Id: I5cf15dffa29985cba60e5aaf31d189e755a3a1ef

* Update the vagrant dev environment

- Remove GOPATH in favor of modules
- Move to Ubuntu 20.04
- Remove docker-compose as it's unnecessary for build and test

Signed-off-by: Matthew Sykes <sykesmat@us.ibm.com>

* Add function in blockstore to export TxIDs

FAB-17837

Signed-off-by: manish <manish.sethi@gmail.com>

* reduce #arguments in a few kvledger methods (hyperledger#1210)

As the number of arguments passed to newKVLedger(),
initTxMgr() is quite high, we reduce it by introducing
initializer struct.

FAB-17683

Signed-off-by: senthil <cendhu@gmail.com>

* Clarify the deliver access denied message (hyperledger#1224)

There are two scenarios where a deliver client could receive a
'FORBIDDEN' result when requesting blocks.  Either the client was not
authorized to connect to the channel initially, or, the client's
access was revoked after a successful connection by some later
configuration block.  In both cases, we log an identical error message
that "Client authorization revoked" when in fact, for the first case,
the client may never have had access, so claiming it was revoked is
misleading.

Signed-off-by: Jason Yellick <jyellick@us.ibm.com>

* Validate TLS certs during raft consenter addition (hyperledger#1223)

* raft membership_test.go cleanup

- For negative tests, test that expected error message is returned.
- For positive tests, switch the order so expected/actual match the
expected usage of "testify/require" package.

Signed-off-by: Will Lahti <wtlahti@us.ibm.com>

* Validate TLS certs during raft consenter addition

FAB-17733 #done

Signed-off-by: Will Lahti <wtlahti@us.ibm.com>

* [FAB-17640] Remove pkg/configtx and import as hyperledger/fabric-config

Signed-off-by: Danny Cao <dcao@us.ibm.com>

* Update CONTRIBUTING guide

Removed reference to Gerrit

Signed-off-by: Ry Jones <ry@linux.com>

Co-authored-by: yacovm <yacovm@il.ibm.com>
Co-authored-by: Matthew Sykes <sykesmat@us.ibm.com>
Co-authored-by: wen <wenjianq@gmail.com>
Co-authored-by: Dereck <Chongxin.Luo@ibm.com>
Co-authored-by: manish <manish.sethi@gmail.com>
Co-authored-by: Senthil Nathan N <cendhu@users.noreply.github.com>
Co-authored-by: Gari Singh <gari.r.singh@gmail.com>
Co-authored-by: Yoav Tock <tock@il.ibm.com>
Co-authored-by: Jason Yellick <jyellick@us.ibm.com>
Co-authored-by: Will Lahti <wtlahti@us.ibm.com>
Co-authored-by: Danny Cao <dcao@us.ibm.com>
Co-authored-by: Ry Jones <ry@linux.com>
@cendhu cendhu deleted the reduce-noarguments-kvledger branch May 12, 2020 13:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants