mirror of
https://github.com/bitcoinj/bitcoinj.git
synced 2025-02-22 14:22:45 +01:00
BlockFileLoader: refactor to use single-file Block iterator internally
* Replace iterator that iterates all blocks in a file list with iterator that iterates all blocks in a single file * Rewrite stream() to use flatMap() on a stream of blocks in a file (internally using BlockFileIterator) * Rewrite iterator() to use stream() This is a step towards a standalone capability to iterate/stream the blocks in a single .dat file. It also is a step towards higher-performance implementations that can use multiple threads.
This commit is contained in:
parent
18126e368b
commit
7776f7c907
1 changed files with 61 additions and 69 deletions
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012 Matt Corallo.
|
||||
* Copyright by the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -33,6 +33,8 @@ import java.util.LinkedList;
|
|||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Spliterator;
|
||||
import java.util.Spliterators;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
|
@ -43,7 +45,7 @@ import static org.bitcoinj.base.internal.Preconditions.checkArgument;
|
|||
* blocks together. Importing block data with this tool can be a lot faster than syncing over the network, if you
|
||||
* have the files available.</p>
|
||||
*
|
||||
* <p>In order to comply with {@link Iterable}, {@link BlockIterator} swallows a lot of {@link IOException}s, which may result in a few
|
||||
* <p>In order to comply with {@link Iterable}, {@link BlockFileIterator} swallows a lot of {@link IOException}s, which may result in a few
|
||||
* blocks being missed followed by a huge set of orphan blocks.</p>
|
||||
*
|
||||
* <p>To blindly import all files which can be found in Bitcoin Core (version 0.8 or higher) datadir automatically,
|
||||
|
@ -111,14 +113,17 @@ public class BlockFileLoader implements Iterable<Block> {
|
|||
}
|
||||
|
||||
|
||||
public class BlockIterator implements Iterator<Block> {
|
||||
private final Iterator<File> fileIt;
|
||||
private File file = null;
|
||||
private FileInputStream currentFileStream = null;
|
||||
private Block nextBlock = null;
|
||||
/**
|
||||
* Iterates all the blocks in a single block file.
|
||||
*/
|
||||
public class BlockFileIterator implements Iterator<Block> {
|
||||
private final File file;
|
||||
private final FileInputStream currentFileStream;
|
||||
private org.bitcoinj.core.Block nextBlock = null;
|
||||
|
||||
public BlockIterator(List<File> fileList) {
|
||||
this.fileIt = fileList.iterator();
|
||||
public BlockFileIterator(File blockFile) throws FileNotFoundException {
|
||||
this.file = blockFile;
|
||||
currentFileStream = new FileInputStream(blockFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -138,69 +143,41 @@ public class BlockFileLoader implements Iterable<Block> {
|
|||
}
|
||||
|
||||
private void loadNextBlock() {
|
||||
while (true) {
|
||||
try {
|
||||
if (!fileIt.hasNext() && (currentFileStream == null || currentFileStream.available() < 1))
|
||||
break;
|
||||
} catch (IOException e) {
|
||||
currentFileStream = null;
|
||||
if (!fileIt.hasNext())
|
||||
break;
|
||||
try {
|
||||
if (currentFileStream.available() < 1) {
|
||||
nextBlock = null;
|
||||
return;
|
||||
}
|
||||
while (true) {
|
||||
try {
|
||||
if (currentFileStream != null && currentFileStream.available() > 0)
|
||||
break;
|
||||
} catch (IOException e1) {
|
||||
currentFileStream = null;
|
||||
}
|
||||
if (!fileIt.hasNext()) {
|
||||
nextBlock = null;
|
||||
currentFileStream = null;
|
||||
return;
|
||||
}
|
||||
file = fileIt.next();
|
||||
try {
|
||||
currentFileStream = new FileInputStream(file);
|
||||
} catch (FileNotFoundException e) {
|
||||
currentFileStream = null;
|
||||
}
|
||||
}
|
||||
try {
|
||||
int nextChar = currentFileStream.read();
|
||||
while (nextChar != -1) {
|
||||
if (nextChar != ((packetMagic >>> 24) & 0xff)) {
|
||||
nextChar = currentFileStream.read();
|
||||
continue;
|
||||
}
|
||||
int nextChar = currentFileStream.read();
|
||||
while (nextChar != -1) {
|
||||
if (nextChar != ((packetMagic >>> 24) & 0xff)) {
|
||||
nextChar = currentFileStream.read();
|
||||
if (nextChar != ((packetMagic >>> 16) & 0xff))
|
||||
continue;
|
||||
nextChar = currentFileStream.read();
|
||||
if (nextChar != ((packetMagic >>> 8) & 0xff))
|
||||
continue;
|
||||
nextChar = currentFileStream.read();
|
||||
if (nextChar == (packetMagic & 0xff))
|
||||
break;
|
||||
}
|
||||
byte[] bytes = new byte[4];
|
||||
currentFileStream.read(bytes, 0, 4);
|
||||
long size = ByteUtils.readUint32(bytes, 0);
|
||||
bytes = new byte[(int) size];
|
||||
currentFileStream.read(bytes, 0, (int) size);
|
||||
try {
|
||||
nextBlock = serializer.makeBlock(ByteBuffer.wrap(bytes));
|
||||
} catch (ProtocolException e) {
|
||||
nextBlock = null;
|
||||
continue;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("unexpected problem with block in " + file, e);
|
||||
}
|
||||
break;
|
||||
} catch (IOException e) {
|
||||
currentFileStream = null;
|
||||
continue;
|
||||
nextChar = currentFileStream.read();
|
||||
if (nextChar != ((packetMagic >>> 16) & 0xff))
|
||||
continue;
|
||||
nextChar = currentFileStream.read();
|
||||
if (nextChar != ((packetMagic >>> 8) & 0xff))
|
||||
continue;
|
||||
nextChar = currentFileStream.read();
|
||||
if (nextChar == (packetMagic & 0xff))
|
||||
break;
|
||||
}
|
||||
byte[] bytes = new byte[4];
|
||||
currentFileStream.read(bytes, 0, 4);
|
||||
long size = ByteUtils.readUint32(bytes, 0);
|
||||
bytes = new byte[(int) size];
|
||||
currentFileStream.read(bytes, 0, (int) size);
|
||||
try {
|
||||
nextBlock = serializer.makeBlock(ByteBuffer.wrap(bytes));
|
||||
} catch (ProtocolException e) {
|
||||
nextBlock = null;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("unexpected problem with block in " + file, e);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
nextBlock = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -212,10 +189,25 @@ public class BlockFileLoader implements Iterable<Block> {
|
|||
|
||||
@Override
|
||||
public Iterator<Block> iterator() {
|
||||
return new BlockIterator(files);
|
||||
return stream().iterator();
|
||||
}
|
||||
|
||||
public Stream<Block> stream() {
|
||||
return StreamSupport.stream(spliterator(), false);
|
||||
return files.stream()
|
||||
.flatMap(this::fileBlockStream);
|
||||
}
|
||||
|
||||
protected Stream<Block> fileBlockStream(File file) {
|
||||
return StreamSupport.stream(fileBlockSpliterator(file), false);
|
||||
}
|
||||
|
||||
protected Spliterator<Block> fileBlockSpliterator(File file) {
|
||||
try {
|
||||
Iterator<Block> iterator = new BlockFileIterator(file);
|
||||
int characteristics = Spliterator.DISTINCT | Spliterator.ORDERED;
|
||||
return Spliterators.spliteratorUnknownSize(iterator, characteristics);
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue