use of io.trino.spi.block.DictionaryId in project trino by trinodb.
the class TestPage method testCompactDictionaryBlocks.
@Test
public void testCompactDictionaryBlocks() {
int positionCount = 100;
// Create 2 dictionary blocks with the same source id
DictionaryId commonSourceId = randomDictionaryId();
int commonDictionaryUsedPositions = 20;
int[] commonDictionaryIds = getDictionaryIds(positionCount, commonDictionaryUsedPositions);
// first dictionary contains "varbinary" values
Slice[] dictionaryValues1 = createExpectedValues(50);
Block dictionary1 = createSlicesBlock(dictionaryValues1);
DictionaryBlock commonSourceIdBlock1 = new DictionaryBlock(positionCount, dictionary1, commonDictionaryIds, commonSourceId);
// second dictionary block is "length(firstColumn)"
BlockBuilder dictionary2 = BIGINT.createBlockBuilder(null, dictionary1.getPositionCount());
for (Slice expectedValue : dictionaryValues1) {
BIGINT.writeLong(dictionary2, expectedValue.length());
}
DictionaryBlock commonSourceIdBlock2 = new DictionaryBlock(positionCount, dictionary2.build(), commonDictionaryIds, commonSourceId);
// Create block with a different source id, dictionary size, used
int otherDictionaryUsedPositions = 30;
int[] otherDictionaryIds = getDictionaryIds(positionCount, otherDictionaryUsedPositions);
Block dictionary3 = createSlicesBlock(createExpectedValues(70));
DictionaryBlock randomSourceIdBlock = new DictionaryBlock(dictionary3, otherDictionaryIds);
Page page = new Page(commonSourceIdBlock1, randomSourceIdBlock, commonSourceIdBlock2);
page.compact();
// dictionary blocks should all be compact
assertTrue(((DictionaryBlock) page.getBlock(0)).isCompact());
assertTrue(((DictionaryBlock) page.getBlock(1)).isCompact());
assertTrue(((DictionaryBlock) page.getBlock(2)).isCompact());
assertEquals(((DictionaryBlock) page.getBlock(0)).getDictionary().getPositionCount(), commonDictionaryUsedPositions);
assertEquals(((DictionaryBlock) page.getBlock(1)).getDictionary().getPositionCount(), otherDictionaryUsedPositions);
assertEquals(((DictionaryBlock) page.getBlock(2)).getDictionary().getPositionCount(), commonDictionaryUsedPositions);
// Blocks that had the same source id before compacting page should have the same source id after compacting page
assertNotEquals(((DictionaryBlock) page.getBlock(0)).getDictionarySourceId(), ((DictionaryBlock) page.getBlock(1)).getDictionarySourceId());
assertEquals(((DictionaryBlock) page.getBlock(0)).getDictionarySourceId(), ((DictionaryBlock) page.getBlock(2)).getDictionarySourceId());
}
use of io.trino.spi.block.DictionaryId in project trino by trinodb.
the class TestDictionaryBlock method testBasicGetPositions.
@Test
public void testBasicGetPositions() {
Slice[] expectedValues = createExpectedValues(10);
Block dictionaryBlock = new DictionaryBlock(createSlicesBlock(expectedValues), new int[] { 0, 1, 2, 3, 4, 5 });
assertBlock(dictionaryBlock, TestDictionaryBlock::createBlockBuilder, new Slice[] { expectedValues[0], expectedValues[1], expectedValues[2], expectedValues[3], expectedValues[4], expectedValues[5] });
DictionaryId dictionaryId = ((DictionaryBlock) dictionaryBlock).getDictionarySourceId();
// first getPositions
dictionaryBlock = dictionaryBlock.getPositions(new int[] { 0, 8, 1, 2, 4, 5, 7, 9 }, 2, 4);
assertBlock(dictionaryBlock, TestDictionaryBlock::createBlockBuilder, new Slice[] { expectedValues[1], expectedValues[2], expectedValues[4], expectedValues[5] });
assertEquals(((DictionaryBlock) dictionaryBlock).getDictionarySourceId(), dictionaryId);
// second getPositions
dictionaryBlock = dictionaryBlock.getPositions(new int[] { 0, 1, 3, 0, 0 }, 0, 3);
assertBlock(dictionaryBlock, TestDictionaryBlock::createBlockBuilder, new Slice[] { expectedValues[1], expectedValues[2], expectedValues[5] });
assertEquals(((DictionaryBlock) dictionaryBlock).getDictionarySourceId(), dictionaryId);
// third getPositions; we do not validate if -1 is an invalid position
dictionaryBlock = dictionaryBlock.getPositions(new int[] { -1, -1, 0, 1, 2 }, 2, 3);
assertBlock(dictionaryBlock, TestDictionaryBlock::createBlockBuilder, new Slice[] { expectedValues[1], expectedValues[2], expectedValues[5] });
assertEquals(((DictionaryBlock) dictionaryBlock).getDictionarySourceId(), dictionaryId);
// mixed getPositions
dictionaryBlock = dictionaryBlock.getPositions(new int[] { 0, 2, 2 }, 0, 3);
assertBlock(dictionaryBlock, TestDictionaryBlock::createBlockBuilder, new Slice[] { expectedValues[1], expectedValues[5], expectedValues[5] });
assertEquals(((DictionaryBlock) dictionaryBlock).getDictionarySourceId(), dictionaryId);
// duplicated getPositions
dictionaryBlock = dictionaryBlock.getPositions(new int[] { 1, 1, 1, 1, 1 }, 0, 5);
assertBlock(dictionaryBlock, TestDictionaryBlock::createBlockBuilder, new Slice[] { expectedValues[5], expectedValues[5], expectedValues[5], expectedValues[5], expectedValues[5] });
assertEquals(((DictionaryBlock) dictionaryBlock).getDictionarySourceId(), dictionaryId);
// out of range
final Block finalDictionaryBlock = dictionaryBlock;
for (int position : ImmutableList.of(-1, 6)) {
assertThatThrownBy(() -> finalDictionaryBlock.getPositions(new int[] { position }, 0, 1)).isInstanceOf(IllegalArgumentException.class).hasMessage("Invalid position %d in block with %d positions", position, finalDictionaryBlock.getPositionCount());
}
for (int offset : ImmutableList.of(-1, 6)) {
assertThatThrownBy(() -> finalDictionaryBlock.getPositions(new int[] { 0 }, offset, 1)).isInstanceOf(IndexOutOfBoundsException.class).hasMessage("Invalid offset %d and length 1 in array with 1 elements", offset);
}
for (int length : ImmutableList.of(-1, 6)) {
assertThatThrownBy(() -> finalDictionaryBlock.getPositions(new int[] { 0 }, 0, length)).isInstanceOf(IndexOutOfBoundsException.class).hasMessage("Invalid offset 0 and length %d in array with 1 elements", length);
}
}
use of io.trino.spi.block.DictionaryId in project trino by trinodb.
the class TestGroupByHash method testMemoryReservationYieldWithDictionary.
@Test
public void testMemoryReservationYieldWithDictionary() {
// Create a page with positionCount >> expected size of groupByHash
int dictionaryLength = 1_000;
int length = 2_000_000;
int[] ids = IntStream.range(0, dictionaryLength).toArray();
DictionaryId dictionaryId = randomDictionaryId();
Block valuesBlock = new DictionaryBlock(dictionaryLength, createStringSequenceBlock(0, length), ids, dictionaryId);
Block hashBlock = new DictionaryBlock(dictionaryLength, getHashBlock(ImmutableList.of(VARCHAR), valuesBlock), ids, dictionaryId);
Page page = new Page(valuesBlock, hashBlock);
AtomicInteger currentQuota = new AtomicInteger(0);
AtomicInteger allowedQuota = new AtomicInteger(3);
UpdateMemory updateMemory = () -> {
if (currentQuota.get() < allowedQuota.get()) {
currentQuota.getAndIncrement();
return true;
}
return false;
};
int yields = 0;
// test addPage
GroupByHash groupByHash = createGroupByHash(ImmutableList.of(VARCHAR), new int[] { 0 }, Optional.of(1), 1, true, JOIN_COMPILER, TYPE_OPERATOR_FACTORY, updateMemory);
boolean finish = false;
Work<?> addPageWork = groupByHash.addPage(page);
while (!finish) {
finish = addPageWork.process();
if (!finish) {
assertEquals(currentQuota.get(), allowedQuota.get());
// assert if we are blocked, we are going to be blocked again without changing allowedQuota
assertFalse(addPageWork.process());
assertEquals(currentQuota.get(), allowedQuota.get());
yields++;
allowedQuota.getAndAdd(3);
}
}
// assert there is not anything missing
assertEquals(dictionaryLength, groupByHash.getGroupCount());
// assert we yield for every 3 rehashes
// currentQuota is essentially the count we have successfully rehashed
// the rehash count is 10 = log(1_000 / 0.75)
assertEquals(currentQuota.get(), 10);
assertEquals(currentQuota.get() / 3, yields);
// test getGroupIds
currentQuota.set(0);
allowedQuota.set(3);
yields = 0;
groupByHash = createGroupByHash(ImmutableList.of(VARCHAR), new int[] { 0 }, Optional.of(1), 1, true, JOIN_COMPILER, TYPE_OPERATOR_FACTORY, updateMemory);
finish = false;
Work<GroupByIdBlock> getGroupIdsWork = groupByHash.getGroupIds(page);
while (!finish) {
finish = getGroupIdsWork.process();
if (!finish) {
assertEquals(currentQuota.get(), allowedQuota.get());
// assert if we are blocked, we are going to be blocked again without changing allowedQuota
assertFalse(getGroupIdsWork.process());
assertEquals(currentQuota.get(), allowedQuota.get());
yields++;
allowedQuota.getAndAdd(3);
}
}
// assert there is not anything missing
assertEquals(dictionaryLength, groupByHash.getGroupCount());
assertEquals(dictionaryLength, getGroupIdsWork.getResult().getPositionCount());
// assert we yield for every 3 rehashes
// currentQuota is essentially the count we have successfully rehashed
// the rehash count is 10 = log2(1_000 / 0.75)
assertEquals(currentQuota.get(), 10);
assertEquals(currentQuota.get() / 3, yields);
}
use of io.trino.spi.block.DictionaryId in project trino by trinodb.
the class Page method getRelatedDictionaryBlocks.
private Map<DictionaryId, DictionaryBlockIndexes> getRelatedDictionaryBlocks() {
Map<DictionaryId, DictionaryBlockIndexes> relatedDictionaryBlocks = new HashMap<>();
for (int i = 0; i < blocks.length; i++) {
Block block = blocks[i];
if (block instanceof DictionaryBlock) {
DictionaryBlock dictionaryBlock = (DictionaryBlock) block;
relatedDictionaryBlocks.computeIfAbsent(dictionaryBlock.getDictionarySourceId(), id -> new DictionaryBlockIndexes()).addBlock(dictionaryBlock, i);
}
}
return relatedDictionaryBlocks;
}
use of io.trino.spi.block.DictionaryId in project trino by trinodb.
the class Page method compact.
public void compact() {
if (getRetainedSizeInBytes() <= getSizeInBytes()) {
return;
}
for (int i = 0; i < blocks.length; i++) {
Block block = blocks[i];
if (block instanceof DictionaryBlock) {
continue;
}
// Compact the block
blocks[i] = block.copyRegion(0, block.getPositionCount());
}
Map<DictionaryId, DictionaryBlockIndexes> dictionaryBlocks = getRelatedDictionaryBlocks();
for (DictionaryBlockIndexes blockIndexes : dictionaryBlocks.values()) {
List<DictionaryBlock> compactBlocks = compactRelatedBlocks(blockIndexes.getBlocks());
List<Integer> indexes = blockIndexes.getIndexes();
for (int i = 0; i < compactBlocks.size(); i++) {
blocks[indexes.get(i)] = compactBlocks.get(i);
}
}
updateRetainedSize();
}
Aggregations