Search in sources :

Example 51 with StaticBuffer

use of org.janusgraph.diskstorage.StaticBuffer in project janusgraph by JanusGraph.

the class LogTest method testFuzzMessagesSerial.

@Test
@Tag(LogTest.requiresOrderPreserving)
public void testFuzzMessagesSerial() throws Exception {
    final int maxLen = 1024 * 4;
    final int rounds = 32;
    StoringReader reader = new StoringReader(rounds);
    final List<StaticBuffer> expected = new ArrayList<>(rounds);
    Log l = manager.openLog("fuzz");
    l.registerReader(ReadMarker.fromNow(), reader);
    Random rand = new Random();
    for (int i = 0; i < rounds; i++) {
        // int len = rand.nextInt(maxLen + 1);
        int len = maxLen;
        if (0 == len)
            // 0 would throw IllegalArgumentException
            len = 1;
        byte[] raw = new byte[len];
        rand.nextBytes(raw);
        StaticBuffer sb = StaticArrayBuffer.of(raw);
        l.add(sb);
        expected.add(sb);
        Thread.sleep(100L);
    }
    reader.await(TIMEOUT_MS);
    assertEquals(rounds, reader.msgCount);
    assertEquals(expected, reader.messages);
}
Also used : Random(java.util.Random) ArrayList(java.util.ArrayList) StaticBuffer(org.janusgraph.diskstorage.StaticBuffer) RepeatedIfExceptionsTest(io.github.artsok.RepeatedIfExceptionsTest) Test(org.junit.jupiter.api.Test) Tag(org.junit.jupiter.api.Tag)

Example 52 with StaticBuffer

use of org.janusgraph.diskstorage.StaticBuffer in project janusgraph by JanusGraph.

the class HBaseStoreManager method convertToCommands.

/**
 * Convert JanusGraph internal Mutation representation into HBase native commands.
 *
 * @param mutations    Mutations to convert into HBase commands.
 * @param putTimestamp The timestamp to use for Put commands.
 * @param delTimestamp The timestamp to use for Delete commands.
 * @return Commands sorted by key converted from JanusGraph internal representation.
 * @throws org.janusgraph.diskstorage.PermanentBackendException
 */
@VisibleForTesting
Map<StaticBuffer, Pair<List<Put>, Delete>> convertToCommands(Map<String, Map<StaticBuffer, KCVMutation>> mutations, final Long putTimestamp, final Long delTimestamp) throws PermanentBackendException {
    // A map of rowkey to commands (list of Puts, Delete)
    final Map<StaticBuffer, Pair<List<Put>, Delete>> commandsPerKey = new HashMap<>();
    for (Map.Entry<String, Map<StaticBuffer, KCVMutation>> entry : mutations.entrySet()) {
        String cfString = getCfNameForStoreName(entry.getKey());
        byte[] cfName = Bytes.toBytes(cfString);
        for (Map.Entry<StaticBuffer, KCVMutation> m : entry.getValue().entrySet()) {
            final byte[] key = m.getKey().as(StaticBuffer.ARRAY_FACTORY);
            KCVMutation mutation = m.getValue();
            Pair<List<Put>, Delete> commands = commandsPerKey.get(m.getKey());
            // create the holder for a particular rowkey
            if (commands == null) {
                commands = new Pair<>();
                // List of all the Puts for this rowkey, including the ones without TTL and with TTL.
                final List<Put> putList = new ArrayList<>();
                commands.setFirst(putList);
                commandsPerKey.put(m.getKey(), commands);
            }
            if (mutation.hasDeletions()) {
                if (commands.getSecond() == null) {
                    Delete d = new Delete(key);
                    if (delTimestamp != null) {
                        d.setTimestamp(delTimestamp);
                    }
                    commands.setSecond(d);
                }
                for (StaticBuffer b : mutation.getDeletions()) {
                    // commands.getSecond() is a Delete for this rowkey.
                    addColumnToDelete(commands.getSecond(), cfName, b.as(StaticBuffer.ARRAY_FACTORY), delTimestamp);
                }
            }
            if (mutation.hasAdditions()) {
                // All the entries (column cells) with the rowkey use this one Put, except the ones with TTL.
                final Put putColumnsWithoutTtl = putTimestamp != null ? new Put(key, putTimestamp) : new Put(key);
                // that have TTL set.
                for (Entry e : mutation.getAdditions()) {
                    // Deal with TTL within the entry (column cell) first
                    // HBase cell level TTL is actually set at the Mutation/Put level.
                    // Therefore we need to construct a new Put for each entry (column cell) with TTL.
                    // We can not combine them because column cells within the same rowkey may:
                    // 1. have no TTL
                    // 2. have TTL
                    // 3. have different TTL
                    final Integer ttl = (Integer) e.getMetaData().get(EntryMetaData.TTL);
                    if (null != ttl && ttl > 0) {
                        // Create a new Put
                        Put putColumnWithTtl = putTimestamp != null ? new Put(key, putTimestamp) : new Put(key);
                        addColumnToPut(putColumnWithTtl, cfName, putTimestamp, e);
                        // Convert ttl from second (JanusGraph TTL) to milliseconds (HBase TTL)
                        // @see JanusGraphManagement#setTTL(JanusGraphSchemaType, Duration)
                        // HBase supports cell-level TTL for versions 0.98.6 and above.
                        (putColumnWithTtl).setTTL(TimeUnit.SECONDS.toMillis((long) ttl));
                        // commands.getFirst() is the list of Puts for this rowkey. Add this
                        // Put column with TTL to the list.
                        commands.getFirst().add(putColumnWithTtl);
                    } else {
                        addColumnToPut(putColumnsWithoutTtl, cfName, putTimestamp, e);
                    }
                }
                // If there were any mutations without TTL set, add them to commands.getFirst()
                if (!putColumnsWithoutTtl.isEmpty()) {
                    commands.getFirst().add(putColumnsWithoutTtl);
                }
            }
        }
    }
    return commandsPerKey;
}
Also used : Delete(org.apache.hadoop.hbase.client.Delete) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) Put(org.apache.hadoop.hbase.client.Put) KCVMutation(org.janusgraph.diskstorage.keycolumnvalue.KCVMutation) Entry(org.janusgraph.diskstorage.Entry) StaticBuffer(org.janusgraph.diskstorage.StaticBuffer) List(java.util.List) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) Map(java.util.Map) BiMap(com.google.common.collect.BiMap) ImmutableMap(com.google.common.collect.ImmutableMap) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) ConcurrentMap(java.util.concurrent.ConcurrentMap) ImmutableBiMap(com.google.common.collect.ImmutableBiMap) Pair(org.apache.hadoop.hbase.util.Pair) VisibleForTesting(com.google.common.annotations.VisibleForTesting)

Example 53 with StaticBuffer

use of org.janusgraph.diskstorage.StaticBuffer in project janusgraph by JanusGraph.

the class HBaseStoreManager method mutateMany.

@Override
public void mutateMany(Map<String, Map<StaticBuffer, KCVMutation>> mutations, StoreTransaction txh) throws BackendException {
    Long putTimestamp = null;
    Long delTimestamp = null;
    MaskedTimestamp commitTime = null;
    if (assignTimestamp) {
        commitTime = new MaskedTimestamp(txh);
        putTimestamp = commitTime.getAdditionTime(times);
        delTimestamp = commitTime.getDeletionTime(times);
    }
    // In case of an addition and deletion with identical timestamps, the
    // deletion tombstone wins.
    // https://hbase.apache.org/book/versions.html#d244e4250
    final Map<StaticBuffer, Pair<List<Put>, Delete>> commandsPerKey = convertToCommands(mutations, putTimestamp, delTimestamp);
    // actual batch operation
    final List<Row> batch = new ArrayList<>(commandsPerKey.size());
    // convert sorted commands into representation required for 'batch' operation
    for (Pair<List<Put>, Delete> commands : commandsPerKey.values()) {
        if (commands.getFirst() != null && !commands.getFirst().isEmpty())
            batch.addAll(commands.getFirst());
        if (commands.getSecond() != null)
            batch.add(commands.getSecond());
    }
    try {
        Table table = null;
        try {
            table = cnx.getTable(tableName);
            table.batch(batch, new Object[batch.size()]);
        } finally {
            IOUtils.closeQuietly(table);
        }
    } catch (IOException | InterruptedException e) {
        throw new TemporaryBackendException(e);
    }
    if (commitTime != null) {
        sleepAfterWrite(commitTime);
    }
}
Also used : Delete(org.apache.hadoop.hbase.client.Delete) Table(org.apache.hadoop.hbase.client.Table) ArrayList(java.util.ArrayList) IOException(java.io.IOException) Put(org.apache.hadoop.hbase.client.Put) TemporaryBackendException(org.janusgraph.diskstorage.TemporaryBackendException) StaticBuffer(org.janusgraph.diskstorage.StaticBuffer) List(java.util.List) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) Row(org.apache.hadoop.hbase.client.Row) Pair(org.apache.hadoop.hbase.util.Pair)

Example 54 with StaticBuffer

use of org.janusgraph.diskstorage.StaticBuffer in project janusgraph by JanusGraph.

the class MultiPageEntryBuffer method mutate.

@Override
public void mutate(Entry[] add, Entry[] del, int maxPageSize) {
    int pageHits = 0;
    int oldPageCount = pages.size();
    // if new page is going to hit max size - insert new one
    if (pages.size() == 0) {
        pages.add(buildFromEntryArray(new Entry[] {}, 0));
    }
    int iadd = 0;
    int idel = 0;
    // NOTE: if it finds min of first add/first delete via getPageIndex (binary search), jumps straight to that page
    // - could be better for big stores updated sparsely. However in practice it doesn't seem to be any noticeable bottleneck
    int currPageNo = 0;
    while (currPageNo < pages.size() && (iadd < add.length || idel < del.length)) {
        BufferPage currPage = pages.get(currPageNo);
        BufferPage nextPage = (currPageNo + 1 < pages.size()) ? pages.get(currPageNo + 1) : null;
        // assumes there will be no pages with zero entries - i.e. we will delete a page if it contains no data
        Preconditions.checkArgument(nextPage == null || nextPage.numEntries() > 0);
        StaticBuffer nextPageStart = nextPage == null ? null : nextPage.getNoCopy(0);
        boolean pageNeedsMerging = false;
        // Compare with additions
        if (// still have things to add
        iadd < add.length) {
            // if there's no next page then we definitely need to merge into this page
            pageNeedsMerging = nextPageStart == null;
            if (!pageNeedsMerging) {
                // if next page start is bigger than the key we need to add, this means we need to merge this page
                // if next page start is smaller, then we can skip this page - we will merge one of the next pages we see
                int compare = nextPageStart.compareTo(add[iadd]);
                pageNeedsMerging = compare >= 0;
            }
        }
        // Compare with deletions
        if (// still have things to delete, and still not sure if we need to merge this page
        !pageNeedsMerging && idel < del.length) {
            // if this page end is bigger than the key we need to delete, this means we need to merge this page
            // if it is smaller, then we won't find anything to delete in this page anyway
            StaticBuffer thisPageEnd = currPage.getNoCopy(currPage.numEntries() - 1);
            int compare = thisPageEnd.compareTo(del[idel]);
            pageNeedsMerging = compare >= 0;
        }
        if (pageNeedsMerging) {
            int addLimit;
            int delLimit;
            if (// this is the last page, everything we still need to add/delete applies to it
            nextPageStart == null) {
                addLimit = add.length;
                delLimit = del.length;
            } else // this is not the last page, we need to determine which adds/deletes go to this page, and which go to next page(s)
            {
                // NOTE: for long mutation lists, it could be better to do binary search here,
                // otherwise it could be up to maxPageSize linear comparisons.
                // However it was not seen as a bottleneck in practice so far
                addLimit = iadd;
                while (addLimit < add.length && nextPageStart.compareTo(add[addLimit]) > 0) {
                    addLimit++;
                }
                delLimit = idel;
                while (delLimit < del.length && nextPageStart.compareTo(del[delLimit]) > 0) {
                    delLimit++;
                }
            }
            List<BufferPage> mergedPages = currPage.merge(add, iadd, addLimit, del, idel, delLimit, maxPageSize);
            if (// there was no data left in the page as a result of merge - remove old page
            mergedPages.size() == 0) {
                pages.remove(currPageNo);
            // do NOT increase currPageNo here as the next page moved in to this place
            } else // there is at least one page as a result of merge - replace the current one and insert any additional overflow pages
            {
                // replace the currPage with the newly merged version
                pages.set(currPageNo, mergedPages.get(0));
                // move to next page
                currPageNo++;
                if (// more than one page as a result of merge - insert all additional ones
                mergedPages.size() > 1) {
                    mergedPages.remove(0);
                    pages.addAll(currPageNo, mergedPages);
                    // skip over the pages we just added as they cannot contain any work we might still need to do
                    currPageNo += mergedPages.size();
                    pageHits += mergedPages.size();
                }
            }
            iadd = addLimit;
            idel = delLimit;
            pageHits++;
        } else {
            currPageNo++;
        }
    }
    if (oldPageCount >= pages.size()) {
        // it grew before but not this time, assume it stopped growing for now and trim to size to save memory
        pages.trimToSize();
    }
}
Also used : Entry(org.janusgraph.diskstorage.Entry) StaticBuffer(org.janusgraph.diskstorage.StaticBuffer)

Example 55 with StaticBuffer

use of org.janusgraph.diskstorage.StaticBuffer in project janusgraph by JanusGraph.

the class InMemoryStoreManager method mutateMany.

@Override
public void mutateMany(Map<String, Map<StaticBuffer, KCVMutation>> mutations, StoreTransaction txh) throws BackendException {
    for (Map.Entry<String, Map<StaticBuffer, KCVMutation>> storeMut : mutations.entrySet()) {
        KeyColumnValueStore store = stores.get(storeMut.getKey());
        Preconditions.checkNotNull(store);
        for (Map.Entry<StaticBuffer, KCVMutation> keyMut : storeMut.getValue().entrySet()) {
            store.mutate(keyMut.getKey(), keyMut.getValue().getAdditions(), keyMut.getValue().getDeletions(), txh);
        }
    }
}
Also used : KeyColumnValueStore(org.janusgraph.diskstorage.keycolumnvalue.KeyColumnValueStore) StaticBuffer(org.janusgraph.diskstorage.StaticBuffer) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) KCVMutation(org.janusgraph.diskstorage.keycolumnvalue.KCVMutation)

Aggregations

StaticBuffer (org.janusgraph.diskstorage.StaticBuffer)101 Entry (org.janusgraph.diskstorage.Entry)36 Test (org.junit.jupiter.api.Test)36 ArrayList (java.util.ArrayList)27 HashMap (java.util.HashMap)20 Map (java.util.Map)19 StoreTransaction (org.janusgraph.diskstorage.keycolumnvalue.StoreTransaction)17 KeySliceQuery (org.janusgraph.diskstorage.keycolumnvalue.KeySliceQuery)16 StaticArrayEntry (org.janusgraph.diskstorage.util.StaticArrayEntry)16 BackendException (org.janusgraph.diskstorage.BackendException)15 List (java.util.List)14 EntryList (org.janusgraph.diskstorage.EntryList)14 TemporaryBackendException (org.janusgraph.diskstorage.TemporaryBackendException)14 KCVMutation (org.janusgraph.diskstorage.keycolumnvalue.KCVMutation)13 PermanentBackendException (org.janusgraph.diskstorage.PermanentBackendException)12 Instant (java.time.Instant)11 DataOutput (org.janusgraph.graphdb.database.serialize.DataOutput)10 ReadBuffer (org.janusgraph.diskstorage.ReadBuffer)8 ConsistentKeyLockStatus (org.janusgraph.diskstorage.locking.consistentkey.ConsistentKeyLockStatus)7 BackendOperation (org.janusgraph.diskstorage.util.BackendOperation)7