Search in sources :

Example 1 with ParallelScannerContext

use of io.datarouter.scanner.ParallelScannerContext in project datarouter by hotpads.

the class LoadTestGetHandler method get.

@Handler(defaultHandler = true)
private Mav get(@Param(P_num) OptionalString num, @Param(P_max) OptionalString max, @Param(P_numThreads) OptionalString numThreads, @Param(P_batchSize) OptionalString batchSize, @Param(P_logPeriod) OptionalString logPeriod, @Param(P_submitAction) OptionalString submitAction) {
    var form = new HtmlForm().withMethod("post");
    form.addTextField().withDisplay("Num").withName(P_num).withPlaceholder("100,000").withValue(num.orElse(null));
    form.addTextField().withDisplay("Max").withName(P_max).withPlaceholder("10").withValue(max.orElse(null));
    form.addTextField().withDisplay("Num Threads").withName(P_numThreads).withPlaceholder("10").withValue(numThreads.orElse(null));
    form.addTextField().withDisplay("Batch Size").withName(P_batchSize).withPlaceholder("100").withValue(batchSize.orElse(null));
    form.addTextField().withDisplay("Log Period").withName(P_logPeriod).withPlaceholder("1,0000").withValue(logPeriod.orElse(null));
    form.addButton().withDisplay("Run Get").withValue("anything");
    if (submitAction.isEmpty() || form.hasErrors()) {
        return pageFactory.startBuilder(request).withTitle("Load Test - Get").withContent(Html.makeContent(form)).buildMav();
    }
    PhaseTimer timer = new PhaseTimer("get");
    // params
    int pNum = num.map(StringTool::nullIfEmpty).map(number -> number.replaceAll(",", "")).map(Integer::valueOf).orElse(DEFAULT_NUM);
    int pMax = max.map(StringTool::nullIfEmpty).map(number -> number.replaceAll(",", "")).map(Integer::valueOf).orElse(pNum);
    int pNumThreads = numThreads.map(StringTool::nullIfEmpty).map(number -> number.replaceAll(",", "")).map(Integer::valueOf).orElse(DEFAULT_NUM_THREADS);
    int pBatchSize = batchSize.map(StringTool::nullIfEmpty).map(number -> number.replaceAll(",", "")).map(Integer::valueOf).orElse(DEFAULT_BATCH_SIZE);
    int pLogPeriod = logPeriod.map(StringTool::nullIfEmpty).map(number -> number.replaceAll(",", "")).map(Integer::valueOf).orElse(DEFAULT_LOG_PERIOD);
    // tracking
    AtomicInteger rowCounter = new AtomicInteger(0);
    AtomicLong lastBatchFinished = new AtomicLong(System.nanoTime());
    // execute
    int numBatches = LoadTestTool.numBatches(pNum, pBatchSize);
    ExecutorService executor = Executors.newFixedThreadPool(pNumThreads);
    Scanner.of(IntStream.range(0, numBatches).mapToObj(Integer::valueOf)).map(batchId -> LoadTestTool.makeRandomIdBatch(pNum, pMax, pBatchSize, batchId)).map(ids -> new GetBatchCallable(dao.getReaderNode(), ids, pLogPeriod, rowCounter, lastBatchFinished)).parallel(new ParallelScannerContext(executor, pNumThreads, true)).forEach(CallableTool::callUnchecked);
    ExecutorServiceTool.shutdown(executor, Duration.ofSeconds(5));
    timer.add("got " + rowCounter.get());
    var message = div(h2("Load Test Get Results"), div(h3("Results"), dl(dt("Total Time"), dd(timer.getElapsedString()), dt("Rows per second"), dd(timer.getItemsPerSecond(rowCounter.get()) + ""))), div(h3("Params"), dl(dt("Num"), dd(pNum + ""), dt("Max"), dd(pMax + ""), dt("Num Threads"), dd(pNumThreads + ""), dt("Batch Size"), dd(pBatchSize + ""), dt("Log Period"), dd(pLogPeriod + "")))).withClass("container");
    logger.warn("total={}, rps={}, num={}, max={}, numThreads={} batchSize={}, logPeriod={}", timer.getElapsedString(), timer.getItemsPerSecond(rowCounter.get()), pNum, pMax, pNumThreads, pBatchSize, pLogPeriod);
    return pageFactory.message(request, message);
}
Also used : IntStream(java.util.stream.IntStream) Scanner(io.datarouter.scanner.Scanner) ParallelScannerContext(io.datarouter.scanner.ParallelScannerContext) TagCreator.dd(j2html.TagCreator.dd) LoggerFactory(org.slf4j.LoggerFactory) TagCreator.h3(j2html.TagCreator.h3) Callable(java.util.concurrent.Callable) OptionalString(io.datarouter.web.handler.types.optional.OptionalString) TagCreator.h2(j2html.TagCreator.h2) TagCreator.dl(j2html.TagCreator.dl) Inject(javax.inject.Inject) NumberFormatter(io.datarouter.util.number.NumberFormatter) ExecutorServiceTool(io.datarouter.util.concurrent.ExecutorServiceTool) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) TagCreator.br(j2html.TagCreator.br) TagCreator.dt(j2html.TagCreator.dt) Duration(java.time.Duration) Param(io.datarouter.web.handler.types.Param) Bootstrap4FormHtml(io.datarouter.web.html.j2html.bootstrap4.Bootstrap4FormHtml) ExecutorService(java.util.concurrent.ExecutorService) PhaseTimer(io.datarouter.util.timer.PhaseTimer) Logger(org.slf4j.Logger) Mav(io.datarouter.web.handler.mav.Mav) RandomValue(io.datarouter.loadtest.storage.RandomValue) StringTool(io.datarouter.util.string.StringTool) Executors(java.util.concurrent.Executors) ContainerTag(j2html.tags.ContainerTag) AtomicLong(java.util.concurrent.atomic.AtomicLong) List(java.util.List) LoadTestTool(io.datarouter.loadtest.util.LoadTestTool) HtmlForm(io.datarouter.web.html.form.HtmlForm) BaseHandler(io.datarouter.web.handler.BaseHandler) LoadTestGetDao(io.datarouter.loadtest.service.LoadTestGetDao) CallableTool(io.datarouter.util.concurrent.CallableTool) Bootstrap4PageFactory(io.datarouter.web.html.j2html.bootstrap4.Bootstrap4PageFactory) RandomValueKey(io.datarouter.loadtest.storage.RandomValueKey) TagCreator.div(j2html.TagCreator.div) MapStorageReader(io.datarouter.storage.node.op.raw.read.MapStorageReader) AtomicLong(java.util.concurrent.atomic.AtomicLong) PhaseTimer(io.datarouter.util.timer.PhaseTimer) HtmlForm(io.datarouter.web.html.form.HtmlForm) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) ParallelScannerContext(io.datarouter.scanner.ParallelScannerContext) CallableTool(io.datarouter.util.concurrent.CallableTool) ExecutorService(java.util.concurrent.ExecutorService) BaseHandler(io.datarouter.web.handler.BaseHandler)

Example 2 with ParallelScannerContext

use of io.datarouter.scanner.ParallelScannerContext in project datarouter by hotpads.

the class BaseDatarouterServletContextListener method processListeners.

private void processListeners(OnAction onAction, boolean executeAllListenersSynchronously) {
    ThreadFactory factory = new NamedThreadFactory("datarouterListenerExecutor", false);
    ExecutorService executor = Executors.newFixedThreadPool(allListeners.size(), factory);
    var timer = new PhaseTimer();
    long shutdownStartMillis = System.currentTimeMillis();
    for (Pair<ExecutionMode, List<DatarouterAppListener>> listenersByShutdownMode : listenersByExecutionMods) {
        List<DatarouterAppListener> listeners = listenersByShutdownMode.getRight();
        ExecutionMode executionMode = executeAllListenersSynchronously ? ExecutionMode.SYNCHRONOUS : listenersByShutdownMode.getLeft();
        logger.warn("{} {}: [{}", onAction.display, executionMode.display, listeners.stream().map(listener -> listener.getClass().getSimpleName()).collect(Collectors.joining(", ")) + "]");
        if (executionMode == ExecutionMode.SYNCHRONOUS) {
            Scanner.of(listeners).map(executeOnAction(onAction)).forEach(timer::add);
        } else if (executionMode == ExecutionMode.PARALLEL) {
            long shutdownParallelStartMillis = System.currentTimeMillis();
            Scanner.of(listeners).parallel(new ParallelScannerContext(executor, listeners.size(), true)).map(executeOnAction(onAction)).forEach(timer::add);
            logger.info("Parallel {} total={}", onAction.display, System.currentTimeMillis() - shutdownParallelStartMillis);
        }
    }
    logger.warn(String.format("%s [total=%d][%s]", onAction, System.currentTimeMillis() - shutdownStartMillis, timer.getPhaseNamesAndTimes().stream().map(pair -> pair.getLeft() + "=" + pair.getRight()).collect(Collectors.joining("]["))));
    ExecutorServiceTool.shutdown(executor, Duration.ofSeconds(2));
}
Also used : DatarouterInjector(io.datarouter.inject.DatarouterInjector) Scanner(io.datarouter.scanner.Scanner) Logger(org.slf4j.Logger) ParallelScannerContext(io.datarouter.scanner.ParallelScannerContext) LoggerFactory(org.slf4j.LoggerFactory) Function(java.util.function.Function) Collectors(java.util.stream.Collectors) Executors(java.util.concurrent.Executors) ArrayList(java.util.ArrayList) NamedThreadFactory(io.datarouter.util.concurrent.NamedThreadFactory) List(java.util.List) ServletContextEvent(javax.servlet.ServletContextEvent) ExecutorServiceTool(io.datarouter.util.concurrent.ExecutorServiceTool) InjectorRetriever(io.datarouter.web.inject.InjectorRetriever) Duration(java.time.Duration) ThreadFactory(java.util.concurrent.ThreadFactory) Pair(io.datarouter.util.tuple.Pair) Collections(java.util.Collections) ServletContextListener(javax.servlet.ServletContextListener) ExecutorService(java.util.concurrent.ExecutorService) PhaseTimer(io.datarouter.util.timer.PhaseTimer) NamedThreadFactory(io.datarouter.util.concurrent.NamedThreadFactory) ThreadFactory(java.util.concurrent.ThreadFactory) PhaseTimer(io.datarouter.util.timer.PhaseTimer) NamedThreadFactory(io.datarouter.util.concurrent.NamedThreadFactory) ParallelScannerContext(io.datarouter.scanner.ParallelScannerContext) ExecutorService(java.util.concurrent.ExecutorService) ArrayList(java.util.ArrayList) List(java.util.List)

Example 3 with ParallelScannerContext

use of io.datarouter.scanner.ParallelScannerContext in project datarouter by hotpads.

the class BaseSnapshotTests method testSearches.

@Test
public void testSearches() {
    if (!ENABLED_TESTS.contains(TestId.SEARCHES)) {
        return;
    }
    BlockLoader blockLoader = makeBlockLoader(useMemoryCache(), shareMemoryCache());
    var reader = new ScanningSnapshotReader(snapshotKey, exec, getNumThreads(), blockLoader, SCAN_NUM_BLOCKS);
    int step = 1000;
    int limit = 1000;
    Scanner.iterate(0, fromId -> fromId += step).advanceWhile(fromId -> fromId < sortedInputs.size() - limit).parallel(new ParallelScannerContext(scanExec, getNumThreads(), true)).forEach(fromId -> {
        var idReader = new SnapshotIdReader(snapshotKey, blockLoader);
        // known first key inclusive
        byte[] searchKey = idReader.getRecord(fromId).key;
        List<SnapshotLeafRecord> outputsInclusive = reader.scanLeafRecords(searchKey, true).limit(limit).list();
        for (int i = 0; i < limit; ++i) {
            Input input = sortedInputs.get(fromId + i);
            SnapshotLeafRecord output = outputsInclusive.get(i);
            Assert.assertEquals(fromId + i, output.id);
            Assert.assertEquals(new Bytes(input.entry.key()), new Bytes(output.key));
        }
        // known first key exclusive
        List<SnapshotLeafRecord> outputsExclusive = reader.scanLeafRecords(searchKey, false).limit(limit).list();
        for (int i = 0; i < limit; ++i) {
            // plus one because exclusive
            Input input = sortedInputs.get(fromId + i + 1);
            SnapshotLeafRecord output = outputsExclusive.get(i);
            Assert.assertEquals(input.id, output.id);
            Assert.assertEquals(new Bytes(input.entry.key()), new Bytes(output.key));
        }
        // fake first key (should act like exclusive)
        byte[] nonExistentKey = ByteTool.concat(searchKey, new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0 });
        List<SnapshotLeafRecord> outputsNonExistentKey = reader.scanLeafRecords(nonExistentKey, true).limit(limit).list();
        for (int i = 0; i < limit; ++i) {
            // plus one because the first key didn't exist
            Input input = sortedInputs.get(fromId + i + 1);
            SnapshotLeafRecord output = outputsNonExistentKey.get(i);
            Assert.assertEquals(input.id, output.id);
            Assert.assertEquals(new Bytes(input.entry.key()), new Bytes(output.key));
        }
    });
}
Also used : ScanningSnapshotReader(io.datarouter.filesystem.snapshot.reader.ScanningSnapshotReader) IntStream(java.util.stream.IntStream) SnapshotRecord(io.datarouter.filesystem.snapshot.reader.record.SnapshotRecord) Scanner(io.datarouter.scanner.Scanner) Arrays(java.util.Arrays) SnapshotKeyReader(io.datarouter.filesystem.snapshot.reader.SnapshotKeyReader) ByteTool(io.datarouter.bytes.ByteTool) BlockKey(io.datarouter.filesystem.snapshot.block.BlockKey) ParallelScannerContext(io.datarouter.scanner.ParallelScannerContext) LoggerFactory(org.slf4j.LoggerFactory) Test(org.testng.annotations.Test) Bytes(io.datarouter.bytes.Bytes) GzipBlockCompressor(io.datarouter.filesystem.snapshot.compress.GzipBlockCompressor) SnapshotWriterConfig(io.datarouter.filesystem.snapshot.writer.SnapshotWriterConfig) NumberFormatter(io.datarouter.util.number.NumberFormatter) SnapshotWriteResult(io.datarouter.filesystem.snapshot.group.dto.SnapshotWriteResult) Assert(org.testng.Assert) ScanningSnapshotReader(io.datarouter.filesystem.snapshot.reader.ScanningSnapshotReader) BlockLoader(io.datarouter.filesystem.snapshot.reader.block.BlockLoader) DatarouterFilesystemModuleFactory(io.datarouter.filesystem.DatarouterFilesystemModuleFactory) SnapshotLeafRecord(io.datarouter.filesystem.snapshot.reader.record.SnapshotLeafRecord) SnapshotWriterConfigBuilder(io.datarouter.filesystem.snapshot.writer.SnapshotWriterConfigBuilder) ExecutorService(java.util.concurrent.ExecutorService) PhaseTimer(io.datarouter.util.timer.PhaseTimer) SnapshotIdReader(io.datarouter.filesystem.snapshot.reader.SnapshotIdReader) AfterClass(org.testng.annotations.AfterClass) Logger(org.slf4j.Logger) BeforeClass(org.testng.annotations.BeforeClass) SnapshotGroup(io.datarouter.filesystem.snapshot.group.SnapshotGroup) Set(java.util.Set) MemoryBlockCache(io.datarouter.filesystem.snapshot.cache.MemoryBlockCache) SnapshotEntry(io.datarouter.filesystem.snapshot.entry.SnapshotEntry) StandardCharsets(java.nio.charset.StandardCharsets) Executors(java.util.concurrent.Executors) Guice(org.testng.annotations.Guice) AtomicLong(java.util.concurrent.atomic.AtomicLong) List(java.util.List) Optional(java.util.Optional) SnapshotKey(io.datarouter.filesystem.snapshot.key.SnapshotKey) ListTool(io.datarouter.util.collection.ListTool) Require(io.datarouter.util.Require) Bytes(io.datarouter.bytes.Bytes) SnapshotLeafRecord(io.datarouter.filesystem.snapshot.reader.record.SnapshotLeafRecord) ParallelScannerContext(io.datarouter.scanner.ParallelScannerContext) BlockLoader(io.datarouter.filesystem.snapshot.reader.block.BlockLoader) SnapshotIdReader(io.datarouter.filesystem.snapshot.reader.SnapshotIdReader) Test(org.testng.annotations.Test)

Example 4 with ParallelScannerContext

use of io.datarouter.scanner.ParallelScannerContext in project datarouter by hotpads.

the class BaseSnapshotTests method testOperationInternal.

private void testOperationInternal(BlockLoader threadSafeBlockLoader, boolean random, boolean multiThreaded, Operation operation) {
    List<Input> searchKeys = random ? randomInputs : sortedInputs;
    int batchSize = 10_000;
    var parallelScannerContext = new ParallelScannerContext(exec, getNumThreads(), true, multiThreaded);
    var count = new AtomicLong();
    Scanner.of(searchKeys).batch(batchSize).parallel(parallelScannerContext).forEach(batch -> {
        var idReader = new SnapshotIdReader(snapshotKey, threadSafeBlockLoader);
        var keyReader = new SnapshotKeyReader(snapshotKey, threadSafeBlockLoader);
        for (int i = 0; i < batch.size(); ++i) {
            Input input = batch.get(i);
            long id = input.id;
            byte[] key = input.entry.key();
            byte[] value = input.entry.value();
            if (Operation.GET_LEAF_RECORD == operation) {
                SnapshotLeafRecord leafRecord = idReader.leafRecord(id);
                if (!Arrays.equals(key, leafRecord.key)) {
                    String message = String.format("%s, expected=%s, actual=%s", id, utf8(key), utf8(leafRecord.key));
                    throw new RuntimeException(message);
                }
                if (!Arrays.equals(value, leafRecord.value)) {
                    String message = String.format("%s, expected=%s, actual=%s", id, utf8(value), utf8(leafRecord.value));
                    throw new RuntimeException(message);
                }
            } else if (Operation.GET_RECORD == operation) {
                SnapshotRecord result = idReader.getRecord(id);
                if (id != result.id) {
                    String message = String.format("%s, expected=%s, actual=%s", id, id, result.id);
                    throw new RuntimeException(message);
                }
                if (!Arrays.equals(key, result.key)) {
                    String message = String.format("%s, expected=%s, actual=%s", id, utf8(key), utf8(result.key));
                    throw new RuntimeException(message);
                }
                if (!SnapshotEntry.equal(input.entry, result.entry())) {
                    String message = String.format("%s, expected=%s, actual=%s", i, // TODO print more than column 0
                    utf8(input.entry.columnValues[0]), utf8(result.columnValues[0]));
                    throw new RuntimeException(message);
                }
            } else if (Operation.FIND_ID == operation) {
                if (keyReader.findRecordId(key).isEmpty()) {
                    String message = String.format("%s, %s not found", i, utf8(key));
                    throw new RuntimeException(message);
                }
                if (id != keyReader.findRecordId(key).get().longValue()) {
                    String message = String.format("%s, %s not found", i, utf8(key));
                    throw new RuntimeException(message);
                }
            } else if (Operation.FIND_RECORD == operation) {
                Optional<SnapshotRecord> output = keyReader.findRecord(key);
                if (output.isEmpty()) {
                    String message = String.format("%s, %s not found", i, utf8(key));
                    throw new RuntimeException(message);
                }
                if (!SnapshotEntry.equal(input.entry, output.get().entry())) {
                    String message = String.format("%s, expected=%s, actual=%s", i, // TODO print more than column 0
                    utf8(batch.get(i).entry.columnValues[0]), utf8(output.get().columnValues[0]));
                    throw new RuntimeException(message);
                }
            }
        }
        count.addAndGet(batch.size());
        logger.warn("{}, {}, {} for {}/{} {}", random ? "random" : "sorted", multiThreaded ? "multi" : "single", operation.toString().toLowerCase(), NumberFormatter.addCommas(count.get()), NumberFormatter.addCommas(searchKeys.size()), utf8(ListTool.getLast(batch).entry.key()));
    });
}
Also used : SnapshotLeafRecord(io.datarouter.filesystem.snapshot.reader.record.SnapshotLeafRecord) Optional(java.util.Optional) ParallelScannerContext(io.datarouter.scanner.ParallelScannerContext) SnapshotRecord(io.datarouter.filesystem.snapshot.reader.record.SnapshotRecord) SnapshotIdReader(io.datarouter.filesystem.snapshot.reader.SnapshotIdReader) AtomicLong(java.util.concurrent.atomic.AtomicLong) SnapshotKeyReader(io.datarouter.filesystem.snapshot.reader.SnapshotKeyReader)

Example 5 with ParallelScannerContext

use of io.datarouter.scanner.ParallelScannerContext in project datarouter by hotpads.

the class DatarouterSnapshotGroupsHandler method buildGroupList.

private ContainerTag<?> buildGroupList() {
    var thead = thead(tr(th("ID"), th("numSnapshots")));
    var table = table().withClasses("sortable table table-sm table-striped my-4 border").with(thead);
    groups.scanIds().sort().parallel(new ParallelScannerContext(exec, exec.getMaximumPoolSize(), false)).map(id -> {
        String href = new URIBuilder().setPath(request.getContextPath() + snapshotPaths.datarouter.snapshot.group.listSnapshots.toSlashedString()).addParameter(P_groupId, id).toString();
        var anchor = a(id).withHref(href);
        String numSnapshots = groups.getGroup(id).keyReadOps(false).scanSnapshotKeys().count() + "";
        return tr(TagCreator.td(anchor), TagCreator.td(numSnapshots));
    }).forEach(table::with);
    var header = h4("Snapshot Groups");
    return div(header, table).withClass("container-fluid my-4").withStyle("padding-left: 0px");
}
Also used : TagCreator.table(j2html.TagCreator.table) URIBuilder(org.apache.http.client.utils.URIBuilder) ParallelScannerContext(io.datarouter.scanner.ParallelScannerContext) Mav(io.datarouter.web.handler.mav.Mav) TagCreator.h4(j2html.TagCreator.h4) TagCreator.a(j2html.TagCreator.a) DatarouterSnapshotWebExecutor(io.datarouter.filesystem.snapshot.web.DatarouterSnapshotExecutors.DatarouterSnapshotWebExecutor) ContainerTag(j2html.tags.ContainerTag) Inject(javax.inject.Inject) DatarouterWebRequireJsV2(io.datarouter.web.requirejs.DatarouterWebRequireJsV2) TagCreator.th(j2html.TagCreator.th) SnapshotGroups(io.datarouter.filesystem.snapshot.group.SnapshotGroups) BaseHandler(io.datarouter.web.handler.BaseHandler) TagCreator.tr(j2html.TagCreator.tr) Bootstrap4PageFactory(io.datarouter.web.html.j2html.bootstrap4.Bootstrap4PageFactory) TagCreator.div(j2html.TagCreator.div) TagCreator(j2html.TagCreator) TagCreator.thead(j2html.TagCreator.thead) ParallelScannerContext(io.datarouter.scanner.ParallelScannerContext) TagCreator.table(j2html.TagCreator.table) URIBuilder(org.apache.http.client.utils.URIBuilder)

Aggregations

ParallelScannerContext (io.datarouter.scanner.ParallelScannerContext)10 Scanner (io.datarouter.scanner.Scanner)8 List (java.util.List)7 ExecutorService (java.util.concurrent.ExecutorService)7 Logger (org.slf4j.Logger)7 LoggerFactory (org.slf4j.LoggerFactory)7 PhaseTimer (io.datarouter.util.timer.PhaseTimer)6 Executors (java.util.concurrent.Executors)6 Inject (javax.inject.Inject)6 NumberFormatter (io.datarouter.util.number.NumberFormatter)5 AtomicLong (java.util.concurrent.atomic.AtomicLong)5 SnapshotRecord (io.datarouter.filesystem.snapshot.reader.record.SnapshotRecord)4 Mav (io.datarouter.web.handler.mav.Mav)4 Bootstrap4PageFactory (io.datarouter.web.html.j2html.bootstrap4.Bootstrap4PageFactory)4 TagCreator.div (j2html.TagCreator.div)4 ContainerTag (j2html.tags.ContainerTag)4 IntStream (java.util.stream.IntStream)4 ByteTool (io.datarouter.bytes.ByteTool)3 DatarouterFilesystemModuleFactory (io.datarouter.filesystem.DatarouterFilesystemModuleFactory)3 BlockKey (io.datarouter.filesystem.snapshot.block.BlockKey)3