Moved databases to sdcard.

Added InMemoryBlockStore android implementation.
This commit is contained in:
Adrian Tiberius 2015-06-12 04:20:53 +02:00
parent 232b25eb85
commit 7481fcc816
7 changed files with 240 additions and 5 deletions

View File

@ -61,7 +61,7 @@ public class LevelDbDataSource implements KeyValueDataSource {
options.logger(logger1); options.logger(logger1);
try { try {
logger.debug("Opening database"); logger.debug("Opening database");
File dbLocation = context.getDir(SystemProperties.CONFIG.databaseDir(), 0); File dbLocation = new File(SystemProperties.CONFIG.databaseDir());
File fileLocation = new File(dbLocation, name); File fileLocation = new File(dbLocation, name);
if (SystemProperties.CONFIG.databaseReset()) { if (SystemProperties.CONFIG.databaseReset()) {

View File

@ -31,4 +31,6 @@ public interface BlockStoreDatabase {
public void save(TransactionReceiptVO transactionReceiptVO); public void save(TransactionReceiptVO transactionReceiptVO);
public TransactionReceipt getTransactionReceiptByHash(byte[] hash); public TransactionReceipt getTransactionReceiptByHash(byte[] hash);
public boolean flush(List<Block> blocks);
} }

View File

@ -28,7 +28,6 @@ public class BlockStoreImpl implements BlockStore {
public Block getBlockByNumber(long blockNumber) { public Block getBlockByNumber(long blockNumber) {
List result = database.getByNumber(blockNumber); List result = database.getByNumber(blockNumber);
if (result.size() == 0) return null; if (result.size() == 0) return null;
BlockVO vo = (BlockVO) result.get(0); BlockVO vo = (BlockVO) result.get(0);

View File

@ -0,0 +1,205 @@
package org.ethereum.android.db;
import org.ethereum.core.Block;
import org.ethereum.core.TransactionReceipt;
import org.ethereum.db.BlockStore;
import org.ethereum.db.ByteArrayWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static java.math.BigInteger.ZERO;
import static org.ethereum.util.ByteUtil.wrap;
public class InMemoryBlockStore implements BlockStore {
private static final Logger logger = LoggerFactory.getLogger("general");
Map<ByteArrayWrapper, Block> hashIndex = new HashMap<>();
Map<Long, Block> numberIndex = new HashMap<>();
List<Block> blocks = new ArrayList<>();
private BlockStoreDatabase database;
BigInteger totalDifficulty = ZERO;
public InMemoryBlockStore(BlockStoreDatabase database) {
this.database = database;
}
@Override
public byte[] getBlockHashByNumber(long blockNumber) {
Block block = numberIndex.get(blockNumber);
if (block == null)
return dbGetBlockHashByNumber(blockNumber);
else
return block.getHash();
}
@Override
public Block getBlockByNumber(long blockNumber) {
Block block = numberIndex.get(blockNumber);
if (block == null)
return dbGetBlockByNumber(blockNumber);
else
return block;
}
@Override
public Block getBlockByHash(byte[] hash) {
Block block = hashIndex.get(wrap(hash));
if (block == null)
return dbGetBlockByHash(hash);
else
return block;
}
@Override
public List<byte[]> getListOfHashesStartFrom(byte[] hash, int qty) {
Block startBlock = hashIndex.get(wrap(hash));
long endIndex = startBlock.getNumber() + qty;
endIndex = getBestBlock().getNumber() < endIndex ? getBestBlock().getNumber() : endIndex;
List<byte[]> hashes = new ArrayList<>();
for (long i = startBlock.getNumber(); i <= endIndex; ++i){
Block block = getBlockByNumber(i);
hashes.add(block.getHash() );
}
return hashes;
}
@Override
public void deleteBlocksSince(long number) {
// todo: delete blocks sinse
}
@Override
public void saveBlock(Block block, List<TransactionReceipt> receipts) {
ByteArrayWrapper wHash = wrap(block.getHash());
blocks.add(block);
hashIndex.put(wHash, block);
numberIndex.put(block.getNumber(), block);
totalDifficulty = totalDifficulty.add(block.getCumulativeDifficulty());
}
@Override
public BigInteger getTotalDifficultySince(long number) {
// todo calculate from db + from cache
throw new UnsupportedOperationException();
}
@Override
public BigInteger getTotalDifficulty() {
return totalDifficulty;
}
@Override
public Block getBestBlock() {
if (blocks.size() == 0) return null;
return blocks.get(blocks.size() - 1);
}
@Override
public List<Block> getAllBlocks() {
return blocks;
}
@Override
public void reset() {
blocks.clear();
hashIndex.clear();
numberIndex.clear();
}
@Override
public TransactionReceipt getTransactionReceiptByHash(byte[] hash) {
return null;
}
// FIXME: wrap from here in to db class
public byte[] dbGetBlockHashByNumber(long blockNumber) {
Block block = getBlockByNumber(blockNumber);
if (block != null) return block.getHash();
return null;
}
public Block dbGetBlockByNumber(long blockNumber) {
List result = database.getByNumber(blockNumber);
if (result.size() == 0) return null;
BlockVO vo = (BlockVO) result.get(0);
return new Block(vo.rlp);
}
public Block dbGetBlockByHash(byte[] hash) {
List result = database.getByHash(hash);
if (result.size() == 0) return null;
BlockVO vo = (BlockVO) result.get(0);
return new Block(vo.rlp);
}
@Override
public void flush(){
long t_ = System.nanoTime();
database.flush(blocks);
Block block = getBestBlock();
blocks.clear();
hashIndex.clear();
numberIndex.clear();
saveBlock(block, null);
long t__ = System.nanoTime();
logger.info("Flush block store in: {} ms", ((float) (t__ - t_) / 1_000_000));
totalDifficulty = (BigInteger) database.getTotalDifficulty();
}
public void load(){
logger.info("loading db");
long t = System.nanoTime();
Block bestBlock = database.getBestBlock();
if (bestBlock == null) return;
saveBlock(bestBlock, null);
totalDifficulty = database.getTotalDifficulty();
long t_ = System.nanoTime();
logger.info("Loaded db in: {} ms", ((float)(t_ - t) / 1_000_000));
}
}

View File

@ -2,11 +2,13 @@ package org.ethereum.android.db;
import android.content.Context; import android.content.Context;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import android.os.Environment;
import android.util.Log; import android.util.Log;
import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper; import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper;
import com.j256.ormlite.dao.Dao; import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.dao.GenericRawResults; import com.j256.ormlite.dao.GenericRawResults;
import com.j256.ormlite.misc.TransactionManager;
import com.j256.ormlite.stmt.DeleteBuilder; import com.j256.ormlite.stmt.DeleteBuilder;
import com.j256.ormlite.support.ConnectionSource; import com.j256.ormlite.support.ConnectionSource;
import com.j256.ormlite.table.TableUtils; import com.j256.ormlite.table.TableUtils;
@ -14,10 +16,12 @@ import com.j256.ormlite.table.TableUtils;
import org.ethereum.core.Block; import org.ethereum.core.Block;
import org.ethereum.core.TransactionReceipt; import org.ethereum.core.TransactionReceipt;
import java.io.File;
import java.math.BigInteger; import java.math.BigInteger;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.Callable;
public class OrmLiteBlockStoreDatabase extends OrmLiteSqliteOpenHelper implements BlockStoreDatabase { public class OrmLiteBlockStoreDatabase extends OrmLiteSqliteOpenHelper implements BlockStoreDatabase {
@ -28,7 +32,8 @@ public class OrmLiteBlockStoreDatabase extends OrmLiteSqliteOpenHelper implement
private Dao<TransactionReceiptVO, Integer> transactionDao = null; private Dao<TransactionReceiptVO, Integer> transactionDao = null;
public OrmLiteBlockStoreDatabase(Context context) { public OrmLiteBlockStoreDatabase(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION); super(context, Environment.getExternalStorageDirectory().getAbsolutePath()
+ File.separator + DATABASE_NAME, null, DATABASE_VERSION);
} }
/** /**
@ -252,4 +257,27 @@ public class OrmLiteBlockStoreDatabase extends OrmLiteSqliteOpenHelper implement
return new TransactionReceipt(vo.rlp); return new TransactionReceipt(vo.rlp);
} }
public boolean flush(final List<Block> blocks) {
try {
TransactionManager.callInTransaction(getBlockDao().getConnectionSource(),
new Callable<Void>() {
public Void call() throws Exception {
for (Block block : blocks) {
BlockVO blockVO = new BlockVO(block.getNumber(), block.getHash(), block.getEncoded(), block.getCumulativeDifficulty());
save(blockVO);
}
// you could pass back an object here
return null;
}
});
return true;
} catch(java.sql.SQLException e) {
Log.e(OrmLiteBlockStoreDatabase.class.getName(), "Error querying for hash", e);
return false;
}
}
} }

View File

@ -5,6 +5,7 @@ import android.content.Context;
import com.j256.ormlite.android.apptools.OpenHelperManager; import com.j256.ormlite.android.apptools.OpenHelperManager;
import org.ethereum.android.datasource.LevelDbDataSource; import org.ethereum.android.datasource.LevelDbDataSource;
import org.ethereum.android.db.InMemoryBlockStore;
import org.ethereum.android.db.OrmLiteBlockStoreDatabase; import org.ethereum.android.db.OrmLiteBlockStoreDatabase;
import org.ethereum.android.db.BlockStoreImpl; import org.ethereum.android.db.BlockStoreImpl;
import org.ethereum.config.SystemProperties; import org.ethereum.config.SystemProperties;
@ -76,7 +77,7 @@ public class EthereumModule {
@Singleton @Singleton
BlockStore provideBlockStore() { BlockStore provideBlockStore() {
OrmLiteBlockStoreDatabase database = OpenHelperManager.getHelper(context, OrmLiteBlockStoreDatabase.class); OrmLiteBlockStoreDatabase database = OpenHelperManager.getHelper(context, OrmLiteBlockStoreDatabase.class);
return new BlockStoreImpl(database); return new InMemoryBlockStore(database);
} }
@Provides @Provides

View File

@ -90,7 +90,7 @@ samples.dir = samples
database.reset = false database.reset = false
# place to save physical storage files # place to save physical storage files
database.dir = database database.dir = /mnt/sdcard
# this string is computed # this string is computed
# to be eventually the address # to be eventually the address