jetbrains.exodus.gc.GarbageCollectorTestInMemory.java Source code

Java tutorial

Introduction

Here is the source code for jetbrains.exodus.gc.GarbageCollectorTestInMemory.java

Source

/**
 * Copyright 2010 - 2015 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package jetbrains.exodus.gc;

import jetbrains.exodus.ArrayByteIterable;
import jetbrains.exodus.bindings.IntegerBinding;
import jetbrains.exodus.core.dataStructures.Pair;
import jetbrains.exodus.core.execution.Job;
import jetbrains.exodus.core.execution.JobProcessor;
import jetbrains.exodus.core.execution.ThreadJobProcessorPool;
import jetbrains.exodus.env.Cursor;
import jetbrains.exodus.env.Store;
import jetbrains.exodus.env.Transaction;
import jetbrains.exodus.env.TransactionalExecutable;
import jetbrains.exodus.io.DataReader;
import jetbrains.exodus.io.DataWriter;
import jetbrains.exodus.io.inMemory.Memory;
import jetbrains.exodus.io.inMemory.MemoryDataReader;
import jetbrains.exodus.io.inMemory.MemoryDataWriter;
import jetbrains.exodus.util.Random;
import org.apache.commons.logging.LogFactory;
import org.jetbrains.annotations.NotNull;
import org.junit.Assert;
import org.junit.Test;

import java.io.File;
import java.io.IOException;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class GarbageCollectorTestInMemory extends GarbageCollectorTest {

    private static final org.apache.commons.logging.Log logging = LogFactory
            .getLog(GarbageCollectorTestInMemory.class);
    private static final int TEST_DURATION = 1000 * 30;

    private final Random rnd = new Random();
    private Memory memory;

    @Override
    protected Pair<DataReader, DataWriter> createRW() throws IOException {
        memory = new Memory();
        return new Pair<DataReader, DataWriter>(new MemoryDataReader(memory), new MemoryDataWriter(memory));
    }

    @Override
    protected void deleteRW() {
        reader = null;
        writer = null;
        memory = null;
    }

    @Test
    public void testTextIndexLike() {
        testTextIndexLike(true);
    }

    @Test
    public void testTextIndexLikeWithoutExpirationChecker() {
        testTextIndexLike(false);
    }

    @Test
    public void testTextIndexLikeWithDeletions() {
        testTextIndexLikeWithDeletions(true);
    }

    @Test
    public void testTextIndexLikeWithDeletionsWithoutExpirationChecker() {
        testTextIndexLikeWithDeletions(false);
    }

    @Test
    public void testTextIndexLikeWithDeletionsAndConcurrentReading()
            throws InterruptedException, BrokenBarrierException {
        final long started = System.currentTimeMillis();
        prepare();
        final Transaction txn = env.beginTransaction();
        final Store store = env.openStore("store", getStoreConfig(false), txn);
        final Store storeDups = env.openStore("storeDups", getStoreConfig(true), txn);
        txn.commit();
        final Throwable[] throwable = { null };
        final JobProcessor[] processors = new JobProcessor[10];
        for (int i = 0; i < processors.length; ++i) {
            processors[i] = ThreadJobProcessorPool.getOrCreateJobProcessor("test processor" + i);
            processors[i].start();
        }
        final CyclicBarrier barrier = new CyclicBarrier(processors.length + 1);
        processors[0].queue(new Job() {
            @Override
            protected void execute() throws Throwable {
                barrier.await();
                try {
                    while (System.currentTimeMillis() - started < TEST_DURATION) {
                        env.executeInTransaction(new TransactionalExecutable() {
                            @Override
                            public void execute(@NotNull final Transaction txn) {
                                int randomInt = rnd.nextInt() & 0x3fffffff;
                                final int count = 4 + (randomInt) & 0x1f;
                                for (int j = 0; j < count; randomInt += ++j) {
                                    final int intKey = randomInt & 0x3fff;
                                    final ArrayByteIterable key = IntegerBinding.intToCompressedEntry(intKey);
                                    final int valueLength = 50 + (randomInt % 100);
                                    store.put(txn, key, new ArrayByteIterable(new byte[valueLength]));
                                    storeDups.put(txn, key, IntegerBinding.intToEntry(randomInt % 32));
                                }
                                randomInt = (randomInt * randomInt) & 0x3fffffff;
                                for (int j = 0; j < count; randomInt += ++j) {
                                    final int intKey = randomInt & 0x3fff;
                                    final ArrayByteIterable key = IntegerBinding.intToCompressedEntry(intKey);
                                    store.delete(txn, key);
                                    try (Cursor cursor = storeDups.openCursor(txn)) {
                                        if (cursor.getSearchBoth(key, IntegerBinding.intToEntry(randomInt % 32))) {
                                            cursor.deleteCurrent();
                                        }
                                    }
                                }
                            }
                        });
                        Thread.sleep(0);
                    }
                } catch (Throwable t) {
                    throwable[0] = t;
                }
            }
        });
        for (int i = 1; i < processors.length; ++i) {
            processors[i].queue(new Job() {
                @Override
                protected void execute() throws Throwable {
                    try {
                        barrier.await();
                        while (System.currentTimeMillis() - started < TEST_DURATION) {
                            int randomInt = rnd.nextInt() & 0x3fffffff;
                            for (int j = 0; j < 100; randomInt += ++j) {
                                final int intKey = randomInt & 0x3fff;
                                final ArrayByteIterable key = IntegerBinding.intToCompressedEntry(intKey);
                                getAutoCommit(store, key);
                                getAutoCommit(storeDups, key);
                                Thread.sleep(0);
                            }
                            Thread.sleep(50);
                        }
                    } catch (Throwable t) {
                        throwable[0] = t;
                    }
                }
            });
        }
        barrier.await();
        for (final JobProcessor processor : processors) {
            processor.finish();
        }
        final Throwable t = throwable[0];
        if (t != null) {
            memory.dump(new File(System.getProperty("user.home"), "dump"));
            logging.error("User code exception: ", t);
            Assert.assertTrue(false);
        }
    }

    private void testTextIndexLike(boolean useExpirationChecker) {
        final long started = System.currentTimeMillis();
        prepare(useExpirationChecker);
        final Transaction txn = env.beginTransaction();
        final Store store = env.openStore("store", getStoreConfig(false), txn);
        final Store storeDups = env.openStore("storeDups", getStoreConfig(true), txn);
        txn.commit();
        try {
            while (System.currentTimeMillis() - started < TEST_DURATION) {
                env.executeInTransaction(new TransactionalExecutable() {
                    @Override
                    public void execute(@NotNull final Transaction txn) {
                        int randomInt = rnd.nextInt() & 0x3fffffff;
                        final int count = 4 + (randomInt) & 0x1f;
                        for (int j = 0; j < count; randomInt += ++j) {
                            final int intKey = randomInt & 0x3fff;
                            final ArrayByteIterable key = IntegerBinding.intToCompressedEntry(intKey);
                            final int valueLength = 50 + (randomInt % 100);
                            store.put(txn, key, new ArrayByteIterable(new byte[valueLength]));
                            storeDups.put(txn, key, IntegerBinding.intToEntry(randomInt % 32));
                        }
                    }
                });
                Thread.sleep(0);
            }
        } catch (Throwable t) {
            memory.dump(new File(System.getProperty("user.home"), "dump"));
            logging.error("User code exception: ", t);
            Assert.assertTrue(false);
        }
    }

    private void testTextIndexLikeWithDeletions(boolean useExpirationChecker) {
        final long started = System.currentTimeMillis();
        prepare(useExpirationChecker);
        final Transaction txn = env.beginTransaction();
        final Store store = env.openStore("store", getStoreConfig(false), txn);
        final Store storeDups = env.openStore("storeDups", getStoreConfig(true), txn);
        txn.commit();
        try {
            while (System.currentTimeMillis() - started < TEST_DURATION) {
                env.executeInTransaction(new TransactionalExecutable() {
                    @Override
                    public void execute(@NotNull final Transaction txn) {
                        int randomInt = rnd.nextInt() & 0x3fffffff;
                        final int count = 4 + (randomInt) & 0x1f;
                        for (int j = 0; j < count; randomInt += ++j) {
                            final int intKey = randomInt & 0x3fff;
                            final ArrayByteIterable key = IntegerBinding.intToCompressedEntry(intKey);
                            final int valueLength = 50 + (randomInt % 100);
                            store.put(txn, key, new ArrayByteIterable(new byte[valueLength]));
                            storeDups.put(txn, key, IntegerBinding.intToEntry(randomInt % 32));
                        }
                        randomInt = (randomInt * randomInt) & 0x3fffffff;
                        for (int j = 0; j < count / 2; randomInt += ++j) {
                            final int intKey = randomInt & 0x3fff;
                            final ArrayByteIterable key = IntegerBinding.intToCompressedEntry(intKey);
                            store.delete(txn, key);
                            try (Cursor cursor = storeDups.openCursor(txn)) {
                                if (cursor.getSearchBoth(key, IntegerBinding.intToEntry(randomInt % 32))) {
                                    cursor.deleteCurrent();
                                }
                            }
                        }

                    }
                });
                Thread.sleep(0);
            }
        } catch (Throwable t) {
            memory.dump(new File(System.getProperty("user.home"), "dump"));
            logging.error("User code exception: ", t);
            Assert.assertTrue(false);
        }
    }

    private void prepare() {
        prepare(true);
    }

    private void prepare(boolean useExpirationChecker) {
        setLogFileSize(2);
        env.getEnvironmentConfig().setTreeMaxPageSize(16);
        env.getEnvironmentConfig().setGcUseExpirationChecker(useExpirationChecker);
        reopenEnvironment();
    }
}