All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.datarouter.filesystem.snapshot.reader.block.ScanningBlockReader Maven / Gradle / Ivy

The newest version!
/*
 * Copyright © 2009 HotPads ([email protected])
 *
 * 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 io.datarouter.filesystem.snapshot.reader.block;

import java.util.function.Function;

import io.datarouter.filesystem.snapshot.block.BlockKey;
import io.datarouter.filesystem.snapshot.block.branch.BranchBlock;
import io.datarouter.filesystem.snapshot.block.leaf.LeafBlock;
import io.datarouter.filesystem.snapshot.block.root.RootBlock;
import io.datarouter.filesystem.snapshot.key.SnapshotKey;
import io.datarouter.scanner.Scanner;
import io.datarouter.scanner.Threads;

/**
 * Thread-safe
 *
 * The parallel operations perform the potentially high-latency block fetches
 *
 * The blocks are passed to the parent scanner which parses them.  The parsing could potentially be done in the parallel
 * section, but it would result in more objects being allocated at the same time.  The parsing of the blocks is pretty
 * inexpensive, so this version leaves that for the parent reader thread.
 */
public class ScanningBlockReader{

	private final SnapshotKey snapshotKey;
	private final Threads threads;
	private final int numBlocks;
	private final BlockLoader blockLoader;
	private final RootBlock rootBlock;

	public ScanningBlockReader(
			SnapshotKey snapshotKey,
			Threads threads,
			int numBlocks,
			BlockLoader blockLoader){
		this.snapshotKey = snapshotKey;
		this.threads = threads;
		this.numBlocks = numBlocks;
		this.blockLoader = blockLoader;
		this.rootBlock = blockLoader.root(BlockKey.root(snapshotKey));
	}

	public Scanner scanLeafBlocks(long fromRecordIdInclusive){
		return scanLeafBlockKeys(fromRecordIdInclusive)
				.apply(leafBlockKeys -> LeafBlockRangeLoader.splitByFileAndBatch(leafBlockKeys, numBlocks))
				.parallelOrdered(threads)
				.map(blockLoader::leafRange)
				.concat(Function.identity());
	}

	private Scanner scanLeafBlockKeys(long fromRecordIdInclusive){
		BlockKey topBranchBlockKey = rootBlock.rootBranchBlockKey(snapshotKey);
		BranchBlock topBranchBlock = blockLoader.branch(topBranchBlockKey);
		return scanDescendantBranchBlocks(topBranchBlock, fromRecordIdInclusive)
				.include(branchBlock -> branchBlock.level() == 0)
				.concat(branchBlock -> Scanner.iterate(0, i -> i + 1)
						.limit(branchBlock.numRecords())
						.include(index -> branchBlock.recordId(index) >= fromRecordIdInclusive)
						.map(branchBlock::childBlock)
						.map(leafBlockId -> branchBlock.leafBlockKey(
								snapshotKey,
								leafBlockId)));
	}

	private Scanner scanDescendantBranchBlocks(BranchBlock branchBlock, long fromRecordIdInclusive){
		if(branchBlock.level() == 0){
			return Scanner.of(branchBlock);
		}
		return branchBlock.childBlockIds()
				.map(childBlockId -> branchBlock.childBranchBlockKey(
						snapshotKey,
						childBlockId))
				.parallelOrdered(threads)
				.map(blockLoader::branch)
				.include(childBranchBlock -> childBranchBlock.lastRecordId() >= fromRecordIdInclusive)
				.concat(childBranchBlock -> scanDescendantBranchBlocks(childBranchBlock, fromRecordIdInclusive));
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy