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

Implement helixAccountService with version history and blobs #1234

Merged
merged 12 commits into from
Aug 16, 2019

Conversation

justinlin-linkedin
Copy link
Collaborator

This is the first step of implementation for this design https://docs.google.com/document/d/1Lr30Uph1KL0AMHznTGEdC_JG3W6_d_NKNTa9FbBTTjI/edit

In this implementation, HelixAccountService has two separated implementation of AccountMetadataStore, which fetches account metadata and update it.

Old approach is still the default implementation and new approach would be enabled after.

The next step is to

  1. implement a function to copy the account metadata from the old path to ambry server and create that blob id list.
  2. limit the size of list by removing the blobs when the size of list exceeds the count in the config.

Notice that this implementation might end up with some blob leak.

@codecov-io
Copy link

codecov-io commented Aug 12, 2019

Codecov Report

Merging #1234 into master will decrease coverage by 3.07%.
The diff coverage is 81.79%.

Impacted file tree graph

@@             Coverage Diff              @@
##             master    #1234      +/-   ##
============================================
- Coverage     88.92%   85.84%   -3.08%     
- Complexity       60       76      +16     
============================================
  Files             6        9       +3     
  Lines           352      544     +192     
  Branches         37       56      +19     
============================================
+ Hits            313      467     +154     
- Misses           29       58      +29     
- Partials         10       19       +9
Impacted Files Coverage Δ Complexity Δ
...com/github/ambry/account/AccountMetadataStore.java 100% <100%> (ø) 5 <5> (?)
...om/github/ambry/account/AccountServiceMetrics.java 100% <100%> (ø) 1 <0> (ø) ⬇️
...ain/java/com/github/ambry/account/RouterStore.java 77.08% <77.08%> (ø) 11 <11> (?)
.../com/github/ambry/account/HelixAccountService.java 87.05% <80.61%> (-0.94%) 33 <7> (-5)
.../com/github/ambry/account/LegacyMetadataStore.java 86.79% <86.79%> (ø) 5 <5> (?)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update e5d6e7e...ce88e0b. Read the comment docs.

Copy link
Contributor

@lightningrob lightningrob left a comment

Choose a reason for hiding this comment

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

Left a few initial comments. I will re-review after HelixAccountService is refactored.

Copy link
Collaborator Author

@justinlin-linkedin justinlin-linkedin left a comment

Choose a reason for hiding this comment

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

updated

Copy link
Contributor

@lightningrob lightningrob left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Contributor

@jsjtzyy jsjtzyy left a comment

Choose a reason for hiding this comment

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

Some comments. Need to take a look at tests.

if (notifier != null) {
notifier.subscribe(ACCOUNT_METADATA_CHANGE_TOPIC, changeTopicListener);
} else {
logger.warn("Notifier is null. Account updates cannot be notified to other entities. Local account cache may not "
+ "be in sync with remote account data.");
accountServiceMetrics.nullNotifierCount.inc();
}
if (config.useNewZNodePath) {
accountMetadataStore = new RouterStore(this.accountServiceMetrics, backup, helixStore, router);
Copy link
Contributor

Choose a reason for hiding this comment

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

I understand this is first PR to improve account metadata and I believe setupRouter will be invoked in future PR, however, here router might not be initialized, can we do some proactive check in RouterStore?
Eventually, after transition is done, we should explicitly call setupRouter in RestServer.java

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

good idea, updated

* @param isCalledFromListener True is this function is invoked in the {@link TopicListener}.
*/
private synchronized void fetchAndUpdateCache(boolean isCalledFromListener) {
Map<String, String> accountMap = accountMetadataStore.fetchAccountMetadata();
Copy link
Contributor

Choose a reason for hiding this comment

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

Although this is synchronized method, there might be race condition when initialFetchAndSchedule is called before accountMetadataStore is instantiated. My suggestion is, if possible, move notifier.subscribe() to the end of constructor.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Good Idea, I move the notifier.subscribe into the initialFetchAndSchedule function so there will be no race condition here.

Copy link
Contributor

@jsjtzyy jsjtzyy left a comment

Choose a reason for hiding this comment

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

Looks good after minor comments are addressed.

ZNRecord znRecord = helixStore.get(znRecordPath, null, AccessOption.PERSISTENT);
logger.trace("Fetched ZNRecord from path={}, took time={} ms", znRecordPath, startTimeMs);
if (znRecord == null) {
logger.debug("The ZNRecord to read does not exist on path={}", znRecordPath);
Copy link
Contributor

Choose a reason for hiding this comment

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

minor: I think here can be warn

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

but it's not a warning message. ZNRecord can be null here. It's one of the legit state.

Copy link
Contributor

Choose a reason for hiding this comment

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

If not warn, I would suggest info because such info is supposed to be printed out (debug level is turned off by default). I feel like ZNRecord should exist in almost all cases, if not, it's actually a warning that either the ZNode is deleted or znRecordPath is incorrect.

}
List<String> accountBlobIDs = record.getListField(ACCOUNT_METADATA_BLOB_IDS_LIST_KEY);
if (accountBlobIDs == null || accountBlobIDs.size() == 0) {
logger.debug("ZNRecord={} to read on path={} does not have a simple list with key={}", record,
Copy link
Contributor

Choose a reason for hiding this comment

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

same here, maybe use warn?

throw new IllegalStateException(errorMessage, e);
} catch (Exception e) {
errorMessage =
String.format("Unexpected exception occurred when parsing the blob id list from {}", accountBlobIDs);
Copy link
Contributor

Choose a reason for hiding this comment

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

if you choose to String.format, can you change it to following style (basically replace {} with %s):

String.format("Unexpected exception occurred when parsing the blob id list from %s", accountBlobIDs);

Make change to all occurrences. This can pass intellij inspection.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

figured that string concatenation would just do the work.

@jsjtzyy jsjtzyy merged commit bbaf997 into linkedin:master Aug 16, 2019
@justinlin-linkedin justinlin-linkedin deleted the helixas branch August 16, 2019 20:50
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.

5 participants