Search in sources :

Example 1 with DictionaryId

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());
}
Also used : DictionaryId(io.trino.spi.block.DictionaryId) DictionaryId.randomDictionaryId(io.trino.spi.block.DictionaryId.randomDictionaryId) Slice(io.airlift.slice.Slice) DictionaryBlock(io.trino.spi.block.DictionaryBlock) DictionaryBlock(io.trino.spi.block.DictionaryBlock) LazyBlock(io.trino.spi.block.LazyBlock) Block(io.trino.spi.block.Block) BlockBuilder(io.trino.spi.block.BlockBuilder) Test(org.testng.annotations.Test)

Example 2 with DictionaryId

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);
    }
}
Also used : Slice(io.airlift.slice.Slice) DictionaryId(io.trino.spi.block.DictionaryId) DictionaryBlock(io.trino.spi.block.DictionaryBlock) BlockAssertions.createSlicesBlock(io.trino.block.BlockAssertions.createSlicesBlock) VariableWidthBlock(io.trino.spi.block.VariableWidthBlock) DictionaryBlock(io.trino.spi.block.DictionaryBlock) IntArrayBlock(io.trino.spi.block.IntArrayBlock) Block(io.trino.spi.block.Block) Test(org.testng.annotations.Test)

Example 3 with DictionaryId

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);
}
Also used : DictionaryId(io.trino.spi.block.DictionaryId) DictionaryId.randomDictionaryId(io.trino.spi.block.DictionaryId.randomDictionaryId) DictionaryBlock(io.trino.spi.block.DictionaryBlock) Page(io.trino.spi.Page) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) GroupByHash.createGroupByHash(io.trino.operator.GroupByHash.createGroupByHash) TypeTestUtils.getHashBlock(io.trino.type.TypeTestUtils.getHashBlock) BlockAssertions.createLongSequenceBlock(io.trino.block.BlockAssertions.createLongSequenceBlock) DictionaryBlock(io.trino.spi.block.DictionaryBlock) BlockAssertions.createStringSequenceBlock(io.trino.block.BlockAssertions.createStringSequenceBlock) Block(io.trino.spi.block.Block) RunLengthEncodedBlock(io.trino.spi.block.RunLengthEncodedBlock) VariableWidthBlock(io.trino.spi.block.VariableWidthBlock) BlockAssertions.createLongsBlock(io.trino.block.BlockAssertions.createLongsBlock) Test(org.testng.annotations.Test)

Example 4 with DictionaryId

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;
}
Also used : Arrays(java.util.Arrays) HashMap(java.util.HashMap) Math.min(java.lang.Math.min) String.format(java.lang.String.format) ArrayList(java.util.ArrayList) DictionaryBlock(io.trino.spi.block.DictionaryBlock) DictionaryId(io.trino.spi.block.DictionaryId) List(java.util.List) ClassLayout(org.openjdk.jol.info.ClassLayout) SizeOf.sizeOf(io.airlift.slice.SizeOf.sizeOf) Block(io.trino.spi.block.Block) Map(java.util.Map) Objects.requireNonNull(java.util.Objects.requireNonNull) DictionaryId.randomDictionaryId(io.trino.spi.block.DictionaryId.randomDictionaryId) HashMap(java.util.HashMap) DictionaryId(io.trino.spi.block.DictionaryId) DictionaryId.randomDictionaryId(io.trino.spi.block.DictionaryId.randomDictionaryId) DictionaryBlock(io.trino.spi.block.DictionaryBlock) DictionaryBlock(io.trino.spi.block.DictionaryBlock) Block(io.trino.spi.block.Block)

Example 5 with DictionaryId

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();
}
Also used : DictionaryId(io.trino.spi.block.DictionaryId) DictionaryId.randomDictionaryId(io.trino.spi.block.DictionaryId.randomDictionaryId) DictionaryBlock(io.trino.spi.block.DictionaryBlock) DictionaryBlock(io.trino.spi.block.DictionaryBlock) Block(io.trino.spi.block.Block)

Aggregations

Block (io.trino.spi.block.Block)6 DictionaryBlock (io.trino.spi.block.DictionaryBlock)6 DictionaryId (io.trino.spi.block.DictionaryId)6 DictionaryId.randomDictionaryId (io.trino.spi.block.DictionaryId.randomDictionaryId)5 Test (org.testng.annotations.Test)3 Slice (io.airlift.slice.Slice)2 VariableWidthBlock (io.trino.spi.block.VariableWidthBlock)2 ArrayList (java.util.ArrayList)2 SizeOf.sizeOf (io.airlift.slice.SizeOf.sizeOf)1 BlockAssertions.createLongSequenceBlock (io.trino.block.BlockAssertions.createLongSequenceBlock)1 BlockAssertions.createLongsBlock (io.trino.block.BlockAssertions.createLongsBlock)1 BlockAssertions.createSlicesBlock (io.trino.block.BlockAssertions.createSlicesBlock)1 BlockAssertions.createStringSequenceBlock (io.trino.block.BlockAssertions.createStringSequenceBlock)1 GroupByHash.createGroupByHash (io.trino.operator.GroupByHash.createGroupByHash)1 Page (io.trino.spi.Page)1 BlockBuilder (io.trino.spi.block.BlockBuilder)1 IntArrayBlock (io.trino.spi.block.IntArrayBlock)1 LazyBlock (io.trino.spi.block.LazyBlock)1 RunLengthEncodedBlock (io.trino.spi.block.RunLengthEncodedBlock)1 TypeTestUtils.getHashBlock (io.trino.type.TypeTestUtils.getHashBlock)1