Skip to content

Commit

Permalink
Utility methods for rounding to aligned size
Browse files Browse the repository at this point in the history
Add more utility methods for rounding to aligned size and use
these in computeRange and toPageAlignedSize.
  • Loading branch information
henningandersen committed Apr 25, 2024
1 parent a91564c commit 3c190d1
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,25 @@ public static int toIntBytes(long l) {
}

/**
* Rounds the length up so that it is aligned on the next page size (defined by SharedBytes.PAGE_SIZE). For example
* Round down the size to the nearest aligned size <= size.
*/
public static long roundDownToAlignedSize(long size, long alignment) {
return size / alignment * alignment;
}

/**
* Round up the size to the nearest aligned size >= size
*/
public static long roundUpToAlignedSize(long size, long alignment) {
return (((size - 1) / alignment) + 1) * alignment;
}

/**
* Rounds the length up so that it is aligned on the next page size (defined by SharedBytes.PAGE_SIZE).
*/
public static long toPageAlignedSize(long length) {
int remainder = (int) (length % SharedBytes.PAGE_SIZE);
if (remainder > 0L) {
return length + (SharedBytes.PAGE_SIZE - remainder);
}
return length;
int alignment = SharedBytes.PAGE_SIZE;
return roundUpToAlignedSize(length, alignment);
}

public static void throwEOF(long channelPos, long len) throws EOFException {
Expand All @@ -58,13 +69,13 @@ public static void ensureSeek(long pos, IndexInput input) throws IOException {

public static ByteRange computeRange(long rangeSize, long position, long size, long blobLength) {
return ByteRange.of(
(position / rangeSize) * rangeSize,
Math.min((((position + size - 1) / rangeSize) + 1) * rangeSize, blobLength)
roundDownToAlignedSize(position, rangeSize),
Math.min(roundUpToAlignedSize(position + size, rangeSize), blobLength)
);
}

public static ByteRange computeRange(long rangeSize, long position, long size) {
return ByteRange.of((position / rangeSize) * rangeSize, (((position + size - 1) / rangeSize) + 1) * rangeSize);
return ByteRange.of(roundDownToAlignedSize(position, rangeSize), roundUpToAlignedSize(position + size, rangeSize));
}

public static void ensureSlice(String sliceName, long sliceOffset, long sliceLength, IndexInput input) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@
*/
package org.elasticsearch.blobcache;

import org.elasticsearch.blobcache.common.ByteRange;
import org.elasticsearch.blobcache.shared.SharedBytes;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.test.ESTestCase;
import org.hamcrest.Matchers;

import java.io.EOFException;
import java.nio.ByteBuffer;

import static org.hamcrest.Matchers.equalTo;

public class BlobCacheUtilsTests extends ESTestCase {

public void testReadSafeThrows() {
Expand All @@ -25,6 +27,56 @@ public void testReadSafeThrows() {
public void testToPageAlignedSize() {
long value = randomLongBetween(0, Long.MAX_VALUE - SharedBytes.PAGE_SIZE);
long expected = ((value - 1) / SharedBytes.PAGE_SIZE + 1) * SharedBytes.PAGE_SIZE;
assertThat(BlobCacheUtils.toPageAlignedSize(value), Matchers.equalTo(expected));
assertThat(BlobCacheUtils.toPageAlignedSize(value), equalTo(expected));
assertThat(BlobCacheUtils.toPageAlignedSize(value), equalTo(roundUpUsingRemainder(value, SharedBytes.PAGE_SIZE)));
}

public void testRoundUpToAlignment() {
assertThat(BlobCacheUtils.roundUpToAlignedSize(8, 4), equalTo(8L));
assertThat(BlobCacheUtils.roundUpToAlignedSize(9, 4), equalTo(12L));
long alignment = randomLongBetween(1, Long.MAX_VALUE / 2);
long value = randomLongBetween(0, Long.MAX_VALUE - alignment);
assertThat(BlobCacheUtils.roundUpToAlignedSize(value, alignment), equalTo(roundUpUsingRemainder(value, alignment)));
}

public void testRoundDownToAlignment() {
assertThat(BlobCacheUtils.roundDownToAlignedSize(8, 4), equalTo(8L));
assertThat(BlobCacheUtils.roundDownToAlignedSize(9, 4), equalTo(8L));
long alignment = randomLongBetween(1, Long.MAX_VALUE / 2);
long value = randomLongBetween(0, Long.MAX_VALUE - alignment);
assertThat(BlobCacheUtils.roundDownToAlignedSize(value, alignment), equalTo(roundDownUsingRemainder(value, alignment)));
}

public void testComputeRange() {
assertThat(BlobCacheUtils.computeRange(8, 8, 8), equalTo(ByteRange.of(8, 16)));
assertThat(BlobCacheUtils.computeRange(8, 9, 8), equalTo(ByteRange.of(8, 24)));
assertThat(BlobCacheUtils.computeRange(8, 8, 9), equalTo(ByteRange.of(8, 24)));

long large = randomLongBetween(24, 64);
assertThat(BlobCacheUtils.computeRange(8, 8, 8, large), equalTo(ByteRange.of(8, 16)));
assertThat(BlobCacheUtils.computeRange(8, 9, 8, large), equalTo(ByteRange.of(8, 24)));
assertThat(BlobCacheUtils.computeRange(8, 8, 9, large), equalTo(ByteRange.of(8, 24)));

long small = randomLongBetween(8, 16);
assertThat(BlobCacheUtils.computeRange(8, 8, 8, small), equalTo(ByteRange.of(8, small)));
assertThat(BlobCacheUtils.computeRange(8, 9, 8, small), equalTo(ByteRange.of(8, small)));
assertThat(BlobCacheUtils.computeRange(8, 8, 9, small), equalTo(ByteRange.of(8, small)));
}

private static long roundUpUsingRemainder(long value, long alignment) {
long remainder = value % alignment;
if (remainder > 0L) {
return value + (alignment - remainder);
}
return value;
}

private static long roundDownUsingRemainder(long value, long alignment) {
long remainder = value % alignment;
if (remainder > 0L) {
return value - remainder;
}
return value;

}
}

0 comments on commit 3c190d1

Please sign in to comment.