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

Refactoring DiskSpaceAllocator to support dynamically add/remove store #1210

Merged
merged 3 commits into from
Jul 30, 2019

Conversation

jsjtzyy
Copy link
Contributor

@jsjtzyy jsjtzyy commented Jul 6, 2019

This PR allows disk allocator to add or delete segments for a certain
store without re-initializing entire reserve pool. The changes include:

  1. Each store has its own reserve file directory.
  2. All stores on the same disk share reserved swap segments.
  3. Changed addRequiredSegments() and deleteExtraSegments() to support
    segments addition/removal.

@codecov-io
Copy link

codecov-io commented Jul 6, 2019

Codecov Report

Merging #1210 into master will increase coverage by 0.05%.
The diff coverage is 87.42%.

Impacted file tree graph

@@             Coverage Diff              @@
##             master    #1210      +/-   ##
============================================
+ Coverage     69.49%   69.54%   +0.05%     
- Complexity     5516     5551      +35     
============================================
  Files           432      432              
  Lines         33844    33943      +99     
  Branches       4312     4342      +30     
============================================
+ Hits          23520    23606      +86     
- Misses         9137     9140       +3     
- Partials       1187     1197      +10
Impacted Files Coverage Δ Complexity Δ
...ava/com.github.ambry.store/BlobStoreCompactor.java 91.97% <ø> (ø) 154 <0> (ø) ⬇️
...tore/src/main/java/com.github.ambry.store/Log.java 98.55% <100%> (+0.02%) 60 <0> (+1) ⬆️
.../com.github.ambry.store/DiskSpaceRequirements.java 100% <100%> (+9.09%) 9 <5> (+2) ⬆️
...rc/main/java/com.github.ambry.store/BlobStore.java 88.3% <100%> (+0.02%) 89 <0> (ø) ⬇️
...ava/com.github.ambry.store/DiskSpaceAllocator.java 89.84% <85.61%> (-3.33%) 68 <42> (+30)
.../main/java/com.github.ambry.store/ScanResults.java 81.25% <0%> (-1.57%) 16% <0%> (-1%)
.../src/main/java/com.github.ambry.store/Journal.java 90.76% <0%> (-1.54%) 24% <0%> (-1%)
...in/java/com.github.ambry.store/BlobStoreStats.java 71.34% <0%> (-1.24%) 103% <0%> (-2%)
...va/com.github.ambry.router/TtlUpdateOperation.java 86.52% <0%> (-1.15%) 48% <0%> (-3%)
...src/main/java/com.github.ambry.commons/BlobId.java 93.18% <0%> (-0.36%) 71% <0%> (-1%)
... and 10 more

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 80c32e7...2664d0d. Read the comment docs.

@jsjtzyy jsjtzyy force-pushed the disk-allocator branch 2 times, most recently from 25f0c83 to f7ffab5 Compare July 6, 2019 22:49
@jsjtzyy jsjtzyy self-assigned this Jul 6, 2019
@jsjtzyy jsjtzyy marked this pull request as ready for review July 8, 2019 16:29
@jsjtzyy jsjtzyy requested review from cgtz and zzmao July 8, 2019 22:10
@jsjtzyy
Copy link
Contributor Author

jsjtzyy commented Jul 9, 2019

./gradlew build && ./gradlew test succeeded
The new hierarchy of reserve pool is as follows:

   * --- reserve_pool
   *       |--- reserve_store_1
   *       |              |--- reserve_size_2147483648
   *       |
   *       |--- reserve_store_2
   *                      |--- reserve_size_2147483648
   *       ...
   *       |--- reserve_store_n
   *       |              |--- reserve_size_2147483648
   *       |
   *       |--- reserve_swap
   *                      |--- reserve_size_2147483648
   *                      |--- reserve_size_8589934592

@@ -256,6 +256,7 @@ A single compaction job could be performed across multiple compaction cycles (if
* @return the number of temporary log segment files this compactor is currently using.
*/
int getSwapSegmentsInUse() throws StoreException {
// TODO: use this method to return swap segment to pool when removing store
Copy link
Contributor

Choose a reason for hiding this comment

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

address this TODO?

Copy link
Contributor Author

@jsjtzyy jsjtzyy Jul 19, 2019

Choose a reason for hiding this comment

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

This TODO is just a reminder that future PR (dynamically remove store) could invoke this method to swap segment in use and return it to pool. For current PR, no extra changes are needed. I will remove this comment in "remove store" PR :)

private static final FileFilter RESERVE_FILE_FILTER =
private static final String RESERVE_FILE_PREFIX = "reserve_";
static final String STORE_DIR_PREFIX = "reserve_store_";
static final FileFilter RESERVE_FILE_FILTER =
Copy link
Contributor

Choose a reason for hiding this comment

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

the two filters seem like they can be private

Copy link
Contributor Author

Choose a reason for hiding this comment

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

changed

*/
DiskSpaceAllocator(boolean enablePooling, File reserveDir, long requiredSwapSegmentsPerSize,
StorageManagerMetrics metrics) {
this.enablePooling = enablePooling;
this.reserveDir = reserveDir;
swapReserveDir = new File(reserveDir, SWAP_DIR_NAME);
Copy link
Contributor

Choose a reason for hiding this comment

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

What is the rollout strategy for this? Is it better to manually delete the old directories or have the code detect the old format and do it automatically. We could automatically delete any folders in reserveDir that start with "reserve_size_". This could help to avoid a complicated deployment where we have to disable the diskspaceallocator, then delete the files, and then redeploy with the new version.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

True. I will add some logic to correctly identify stale files/directories and delete them automatically.

Copy link
Contributor Author

@jsjtzyy jsjtzyy Jul 20, 2019

Choose a reason for hiding this comment

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

Actually, after second look, my code will clean up the directories that are neither store reserve directory nor swap segment directory. (following piece of code is in inventoryExistingReserveFiles method)

      } else {
        // if it is neither store reserved segment directory nor swap segment directory, then delete it.
        if (!file.delete()) {
          throw new IOException("Could not delete the following reserve file or directory: " + file.getAbsolutePath());
        }
      }

I will ensure there is a test to verify this.

// attempt to get segment from corresponding store reserve directory
if (storeReserveFiles.containsKey(storeId)) {
reserveFile = storeReserveFiles.get(storeId).remove(sizeInBytes);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

add logging if storeId not found?

if (storeReserveFiles.containsKey(storeId)) {
reserveFile = storeReserveFiles.get(storeId).remove(sizeInBytes);
}
}
}
if (reserveFile == null) {
if (enablePooling) {
Copy link
Contributor

Choose a reason for hiding this comment

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

or it might be good to edit all these log message to include info about storeID and isSwapSegment

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good point, will do.

@jsjtzyy
Copy link
Contributor Author

jsjtzyy commented Jul 22, 2019

added unit test to verify inventory can delete invalid directories/files.
./gradlew build && ./gradlew test succeeded

Copy link
Contributor

@zzmao zzmao left a comment

Choose a reason for hiding this comment

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

PROD code looks good. I can merge it now since this change blocks @jsjtzyy .

jsjtzyy added 2 commits July 26, 2019 10:17
This PR allows disk allocator to add or delete segments for a certain
store without re-initializing entire reserve pool. The changes include:
1. Each store has its own reserve file directory.
2. All stores on the same disk share reserved swap segments.
3. Changed addRequiredSegments() and deleteExtraSegments() to support
segments addition/removal.
}
} finally {
long elapsedTime = System.currentTimeMillis() - startTime;
logger.debug("free took {} ms", elapsedTime);
logger.debug("free took {} ms for {}", elapsedTime, "store[" + storeId + "]");
Copy link
Contributor

Choose a reason for hiding this comment

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

to avoid the cost of string concat when debug logging is off:

logger.debug("free took {} ms for store[{}]", elapsedTime, storeId);

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.

4 participants