@Test public void reserveTest() throws Exception { // Reserve on top tier long blockId = 100; BlockStoreLocation tier0 = BlockStoreLocation.anyDirInTier(StorageLevelAlias.MEM.getValue()); for (int i = 0; i < 3; i++) { TieredBlockStoreTestUtils.cache(SESSION_ID, blockId++, BLOCK_SIZE, mBlockStore, tier0); } CommonUtils.sleepMs( WorkerContext.getConf().getLong(Constants.WORKER_SPACE_RESERVER_INTERVAL_MS)); BlockStoreMeta storeMeta = mBlockStore.getBlockStoreMeta(); Assert.assertEquals(3 * BLOCK_SIZE, storeMeta.getUsedBytes()); List<Long> usedBytesOnTiers = storeMeta.getUsedBytesOnTiers(); Assert.assertEquals( 2 * BLOCK_SIZE, (long) usedBytesOnTiers.get(StorageLevelAlias.MEM.getValue() - 1)); Assert.assertEquals( BLOCK_SIZE, (long) usedBytesOnTiers.get(StorageLevelAlias.HDD.getValue() - 1)); // Reserve on under tier for (int i = 0; i < 7; i++) { TieredBlockStoreTestUtils.cache(SESSION_ID, blockId++, BLOCK_SIZE, mBlockStore, tier0); } CommonUtils.sleepMs( WorkerContext.getConf().getLong(Constants.WORKER_SPACE_RESERVER_INTERVAL_MS)); storeMeta = mBlockStore.getBlockStoreMeta(); Assert.assertEquals(9 * BLOCK_SIZE, storeMeta.getUsedBytes()); usedBytesOnTiers = storeMeta.getUsedBytesOnTiers(); Assert.assertEquals( 2 * BLOCK_SIZE, (long) usedBytesOnTiers.get(StorageLevelAlias.MEM.getValue() - 1)); Assert.assertEquals( 7 * BLOCK_SIZE, (long) usedBytesOnTiers.get(StorageLevelAlias.HDD.getValue() - 1)); }
/** Reads into the block. */ public void read() throws IOException { if (_state.get().isValid()) { return; } synchronized (this) { if (_state.get().isValid()) { } else if (_state.get().isDestroyed()) { throw new IllegalStateException(toString()); } else if (_store.getBlockManager().copyDirtyBlock(this)) { // clearDirty(); // toValid(); } else { if (log.isLoggable(Level.ALL)) log.log(Level.ALL, "read db-block " + this); _isLoad = true; BlockReadWrite readWrite = _store.getReadWrite(); clearDirty(); readWrite.readBlock( _blockId & BlockStore.BLOCK_MASK, getBuffer(), 0, BlockStore.BLOCK_SIZE); toValid(); } } }
private synchronized boolean add(Block block, boolean tryConnecting) throws BlockStoreException, VerificationException, ScriptException { if (System.currentTimeMillis() - statsLastTime > 1000) { // More than a second passed since last stats logging. log.info("{} blocks per second", statsBlocksAdded); statsLastTime = System.currentTimeMillis(); statsBlocksAdded = 0; } // We check only the chain head for double adds here to avoid potentially expensive block chain // misses. if (block.equals(chainHead.getHeader())) { // Duplicate add of the block at the top of the chain, can be a natural artifact of the // download process. return true; } // Prove the block is internally valid: hash is lower than target, merkle root is correct and so // on. try { block.verify(); } catch (VerificationException e) { log.error("Failed to verify block:", e); log.error(block.toString()); throw e; } // Try linking it to a place in the currently known blocks. StoredBlock storedPrev = blockStore.get(block.getPrevBlockHash()); if (storedPrev == null) { // We can't find the previous block. Probably we are still in the process of downloading the // chain and a // block was solved whilst we were doing it. We put it to one side and try to connect it later // when we // have more blocks. log.warn("Block does not connect: {}", block.getHashAsString()); unconnectedBlocks.add(block); return false; } else { // It connects to somewhere on the chain. Not necessarily the top of the best known chain. // // Create a new StoredBlock from this block. It will throw away the transaction data so when // block goes // out of scope we will reclaim the used memory. StoredBlock newStoredBlock = storedPrev.build(block); checkDifficultyTransitions(storedPrev, newStoredBlock); blockStore.put(newStoredBlock); // block.transactions may be null here if we received only a header and not a full block. This // does not // happen currently but might in future if getheaders is implemented. connectBlock(newStoredBlock, storedPrev, block.transactions); } if (tryConnecting) tryConnectingUnconnected(); statsBlocksAdded++; return true; }
public void flush() { Iterator<BlockPayload> iterator = dirty.values().iterator(); while (iterator.hasNext()) { BlockPayload block = iterator.next(); iterator.remove(); store.write(block); } store.flush(); }
public void validateIsIndex() { long blockIndex = BlockStore.blockIdToIndex(getBlockId()); int allocCode = getStore().getAllocation(blockIndex); if (allocCode != BlockStore.ALLOC_INDEX) { RuntimeException exn; exn = new IllegalStateException(L.l("block {0} is not an index code={1}", this, allocCode)); exn.fillInStackTrace(); throw exn; /* if (_isValidation) { log.warning(exn.toString())); } else { log.log(Level.WARNING, exn.toString(), exn); ShutdownSystem.shutdownActive(ExitCode.HEALTH, L.l("Internal database issue: forcing restart {0}", exn.toString())); } */ } }
/** * For each block in unconnectedBlocks, see if we can now fit it on top of the chain and if so, do * so. */ private void tryConnectingUnconnected() throws VerificationException, ScriptException, BlockStoreException { // For each block in our unconnected list, try and fit it onto the head of the chain. If we // succeed remove it // from the list and keep going. If we changed the head of the list at the end of the round try // again until // we can't fit anything else on the top. int blocksConnectedThisRound; do { blocksConnectedThisRound = 0; Iterator<Block> iter = unconnectedBlocks.iterator(); while (iter.hasNext()) { Block block = iter.next(); // Look up the blocks previous. StoredBlock prev = blockStore.get(block.getPrevBlockHash()); if (prev == null) { // This is still an unconnected/orphan block. continue; } // Otherwise we can connect it now. // False here ensures we don't recurse infinitely downwards when connecting huge chains. add(block, false); iter.remove(); blocksConnectedThisRound++; } if (blocksConnectedThisRound > 0) { log.info("Connected {} floating blocks.", blocksConnectedThisRound); } } while (blocksConnectedThisRound > 0); }
private void setChainHead(StoredBlock chainHead) { this.chainHead = chainHead; try { blockStore.setChainHead(chainHead); } catch (BlockStoreException e) { throw new RuntimeException(e); } }
/** * Creates a BlockDataManager based on the configuration values. * * @param workerSource object for collecting the worker metrics * @param workerBlockMasterClient the block Tachyon master client for worker * @param workerFileSystemMasterClient the file system Tachyon master client for worker * @param blockStore the block store manager * @throws IOException if fail to connect to under filesystem */ public BlockDataManager( WorkerSource workerSource, WorkerBlockMasterClient workerBlockMasterClient, WorkerFileSystemMasterClient workerFileSystemMasterClient, BlockStore blockStore) throws IOException { mHeartbeatReporter = new BlockHeartbeatReporter(); mBlockStore = blockStore; mWorkerSource = workerSource; mMetricsReporter = new BlockMetricsReporter(mWorkerSource); mBlockMasterClient = workerBlockMasterClient; mFileSystemMasterClient = workerFileSystemMasterClient; // Register the heartbeat reporter so it can record block store changes mBlockStore.registerBlockStoreEventListener(mHeartbeatReporter); mBlockStore.registerBlockStoreEventListener(mMetricsReporter); }
private static void shutdown() { try { if (peers == null) return; // setup() never called so nothing to do. peers.stopAndWait(); saveWallet(walletFile); store.close(); wallet = null; } catch (BlockStoreException e) { throw new RuntimeException(e); } }
Block(BlockStore store, long blockId) { store.validateBlockId(blockId); _store = store; _blockId = blockId; // _lock = new Lock("block:" + store.getName() + ":" + Long.toHexString(_blockId)); // ReadWriteLock rwLock = new ReentrantReadWriteLock(); _rwLock = allocateReadWriteLock(); _readLock = _rwLock.readLock(); _writeLock = _rwLock.writeLock(); _isFlushDirtyOnCommit = _store.isFlushDirtyBlocksOnCommit(); _buffer = allocateBuffer(); if (log.isLoggable(Level.ALL)) log.log(Level.ALL, this + " create"); }
/** Forces a write of the data. */ public boolean save() { if (_dirtyRange.get() == INIT_DIRTY) { return false; } if (toWriteQueued()) { _store.getWriter().addDirtyBlock(this); } return true; }
/** * Constructs a BlockChain connected to the given wallet and store. To obtain a {@link Wallet} you * can construct one from scratch, or you can deserialize a saved wallet from disk using {@link * Wallet#loadFromFile(java.io.File)} * * <p>For the store you can use a {@link MemoryBlockStore} if you don't care about saving the * downloaded data, or a {@link BoundedOverheadBlockStore} if you'd like to ensure fast startup * the next time you run the program. */ public BlockChain(NetworkParameters params, Wallet wallet, BlockStore blockStore) { try { this.blockStore = blockStore; chainHead = blockStore.getChainHead(); log.info("chain head is:\n{}", chainHead.getHeader()); } catch (BlockStoreException e) { throw new RuntimeException(e); } this.params = params; this.wallet = wallet; }
public <T extends BlockPayload> T read(BlockPointer pos, Class<T> payloadType) { T block = payloadType.cast(dirty.get(pos)); if (block != null) { return block; } block = payloadType.cast(indexBlockCache.get(pos)); if (block != null) { return block; } block = store.read(pos, payloadType); maybeCache(block); return block; }
/** * Commits a block to Tachyon managed space. The block must be temporary. The block is persisted * after {@link BlockStore#commitBlock(long, long)}. The block will not be accessible until {@link * WorkerBlockMasterClient#commitBlock} succeeds. * * @param sessionId The id of the client * @param blockId The id of the block to commit * @throws BlockAlreadyExistsException if blockId already exists in committed blocks * @throws BlockDoesNotExistException if the temporary block cannot be found * @throws InvalidWorkerStateException if blockId does not belong to sessionId * @throws IOException if the block cannot be moved from temporary path to committed path * @throws WorkerOutOfSpaceException if there is no more space left to hold the block */ public void commitBlock(long sessionId, long blockId) throws BlockAlreadyExistsException, BlockDoesNotExistException, InvalidWorkerStateException, IOException, WorkerOutOfSpaceException { mBlockStore.commitBlock(sessionId, blockId); // TODO(calvin): Reconsider how to do this without heavy locking. // Block successfully committed, update master with new block metadata Long lockId = mBlockStore.lockBlock(sessionId, blockId); try { BlockMeta meta = mBlockStore.getBlockMeta(sessionId, blockId, lockId); BlockStoreLocation loc = meta.getBlockLocation(); Long length = meta.getBlockSize(); BlockStoreMeta storeMeta = mBlockStore.getBlockStoreMeta(); Long bytesUsedOnTier = storeMeta.getUsedBytesOnTiers().get(loc.tierAlias()); mBlockMasterClient.commitBlock( WorkerIdRegistry.getWorkerId(), bytesUsedOnTier, loc.tierAlias(), blockId, length); } catch (IOException ioe) { throw new IOException("Failed to commit block to master.", ioe); } finally { mBlockStore.unlockBlock(lockId); } }
/** * Frees a block from Tachyon managed space. * * @param sessionId The id of the client * @param blockId The id of the block to be freed * @throws InvalidWorkerStateException if blockId has not been committed * @throws BlockDoesNotExistException if block cannot be found * @throws IOException if block cannot be removed from current path */ public void removeBlock(long sessionId, long blockId) throws InvalidWorkerStateException, BlockDoesNotExistException, IOException { mBlockStore.removeBlock(sessionId, blockId); }
/** * Gets the path to the block file in local storage. The block must be a permanent block, and the * caller must first obtain the lock on the block. * * @param sessionId The id of the client * @param blockId The id of the block to read * @param lockId The id of the lock on this block * @return a string representing the path to this block in local storage * @throws BlockDoesNotExistException if the blockId cannot be found in committed blocks or lockId * cannot be found * @throws InvalidWorkerStateException if sessionId or blockId is not the same as that in the * LockRecord of lockId */ public String readBlock(long sessionId, long blockId, long lockId) throws BlockDoesNotExistException, InvalidWorkerStateException { BlockMeta meta = mBlockStore.getBlockMeta(sessionId, blockId, lockId); return meta.getPath(); }
/** * Gets the block reader for the block. This method is only called by a data server. * * @param sessionId The id of the client * @param blockId The id of the block to read * @param lockId The id of the lock on this block * @return the block reader for the block * @throws BlockDoesNotExistException if lockId is not found * @throws InvalidWorkerStateException if sessionId or blockId is not the same as that in the * LockRecord of lockId * @throws IOException if block cannot be read */ public BlockReader readBlockRemote(long sessionId, long blockId, long lockId) throws BlockDoesNotExistException, InvalidWorkerStateException, IOException { return mBlockStore.getBlockReader(sessionId, blockId, lockId); }
/** * Obtains a read lock the block. * * @param sessionId The id of the client * @param blockId The id of the block to be locked * @return the lockId that uniquely identifies the lock obtained * @throws BlockDoesNotExistException if blockId cannot be found, for example, evicted already */ public long lockBlock(long sessionId, long blockId) throws BlockDoesNotExistException { return mBlockStore.lockBlock(sessionId, blockId); }
/** * Moves a block from its current location to a target location, currently only tier level moves * are supported * * @param sessionId The id of the client * @param blockId The id of the block to move * @param tierAlias The alias of the tier to move the block to * @throws IllegalArgumentException if tierAlias is out of range of tiered storage * @throws BlockDoesNotExistException if blockId cannot be found * @throws BlockAlreadyExistsException if blockId already exists in committed blocks of the * newLocation * @throws InvalidWorkerStateException if blockId has not been committed * @throws WorkerOutOfSpaceException if newLocation does not have enough extra space to hold the * block * @throws IOException if block cannot be moved from current location to newLocation */ public void moveBlock(long sessionId, long blockId, String tierAlias) throws BlockDoesNotExistException, BlockAlreadyExistsException, InvalidWorkerStateException, WorkerOutOfSpaceException, IOException { BlockStoreLocation dst = BlockStoreLocation.anyDirInTier(tierAlias); mBlockStore.moveBlock(sessionId, blockId, dst); }
/** * Checks if the storage has a given block. * * @param blockId the block ID * @return true if the block is contained, false otherwise */ public boolean hasBlockMeta(long blockId) { return mBlockStore.hasBlockMeta(blockId); }
/** * Gets the metadata of a block given its blockId or throws IOException. This method does not * require a lock ID so the block is possible to be moved or removed after it returns. * * @param blockId the block ID * @return metadata of the block * @throws BlockDoesNotExistException if no BlockMeta for this blockId is found */ public BlockMeta getVolatileBlockMeta(long blockId) throws BlockDoesNotExistException { return mBlockStore.getVolatileBlockMeta(blockId); }
/** * Gets the metadata for the entire block store. Contains the block mapping per storage dir and * the total capacity and used capacity of each tier. * * @return the block store metadata */ public BlockStoreMeta getStoreMeta() { return mBlockStore.getBlockStoreMeta(); }
/** * Request an amount of space for a block in its storage directory. The block must be a temporary * block. * * @param sessionId The id of the client * @param blockId The id of the block to allocate space to * @param additionalBytes The amount of bytes to allocate * @throws BlockDoesNotExistException if blockId can not be found, or some block in eviction plan * cannot be found * @throws WorkerOutOfSpaceException if requested space can not be satisfied * @throws IOException if blocks in {@link tachyon.worker.block.evictor.EvictionPlan} fail to be * moved or deleted on file system */ public void requestSpace(long sessionId, long blockId, long additionalBytes) throws BlockDoesNotExistException, WorkerOutOfSpaceException, IOException { mBlockStore.requestSpace(sessionId, blockId, additionalBytes); }
// TODO(calvin): Remove when lock and reads are separate operations. public void unlockBlock(long sessionId, long blockId) throws BlockDoesNotExistException { mBlockStore.unlockBlock(sessionId, blockId); }
/** * Relinquishes the lock with the specified lock id. * * @param lockId The id of the lock to relinquish * @throws BlockDoesNotExistException if lockId cannot be found */ public void unlockBlock(long lockId) throws BlockDoesNotExistException { mBlockStore.unlockBlock(lockId); }
/** * Creates a block. This method is only called from a data server. * * <p>Call {@link #getTempBlockWriterRemote(long, long)} to get a writer for writing to the block. * * @param sessionId The id of the client * @param blockId The id of the block to be created * @param tierAlias The alias of the tier to place the new block in * @param initialBytes The initial amount of bytes to be allocated * @throws IllegalArgumentException if location does not belong to tiered storage * @throws BlockAlreadyExistsException if blockId already exists, either temporary or committed, * or block in eviction plan already exists * @throws WorkerOutOfSpaceException if this Store has no more space than the initialBlockSize * @throws IOException if blocks in eviction plan fail to be moved or deleted */ public void createBlockRemote(long sessionId, long blockId, String tierAlias, long initialBytes) throws BlockAlreadyExistsException, WorkerOutOfSpaceException, IOException { BlockStoreLocation loc = BlockStoreLocation.anyDirInTier(tierAlias); TempBlockMeta createdBlock = mBlockStore.createBlockMeta(sessionId, blockId, loc, initialBytes); FileUtils.createBlockPath(createdBlock.getPath()); }
/** * Set the pinlist for the underlying blockstore. Typically called by PinListSync. * * @param pinnedInodes a set of pinned inodes */ public void updatePinList(Set<Long> pinnedInodes) { mBlockStore.updatePinnedInodes(pinnedInodes); }
/** * Frees space to make a specific amount of bytes available in the tier. * * @param sessionId the session ID * @param availableBytes the amount of free space in bytes * @param tierAlias the alias of the tier to free space * @throws WorkerOutOfSpaceException if there is not enough space * @throws BlockDoesNotExistException if blocks can not be found * @throws IOException if blocks fail to be moved or deleted on file system * @throws BlockAlreadyExistsException if blocks to move already exists in destination location * @throws InvalidWorkerStateException if blocks to move/evict is uncommitted */ public void freeSpace(long sessionId, long availableBytes, String tierAlias) throws WorkerOutOfSpaceException, BlockDoesNotExistException, IOException, BlockAlreadyExistsException, InvalidWorkerStateException { BlockStoreLocation location = BlockStoreLocation.anyDirInTier(tierAlias); mBlockStore.freeSpace(sessionId, availableBytes, location); }
/** * Aborts the temporary block created by the session. * * @param sessionId The id of the client * @param blockId The id of the block to be aborted * @throws BlockAlreadyExistsException if blockId already exists in committed blocks * @throws BlockDoesNotExistException if the temporary block cannot be found * @throws InvalidWorkerStateException if blockId does not belong to sessionId * @throws IOException if temporary block cannot be deleted */ public void abortBlock(long sessionId, long blockId) throws BlockAlreadyExistsException, BlockDoesNotExistException, InvalidWorkerStateException, IOException { mBlockStore.abortBlock(sessionId, blockId); }
/** * Opens a {@link BlockWriter} for an existing temporary block. This method is only called from a * data server. * * <p>The temporary block must already exist with {@link #createBlockRemote(long, long, String, * long)}. * * @param sessionId The id of the client * @param blockId The id of the block to be opened for writing * @return the block writer for the local block file * @throws BlockDoesNotExistException if the block cannot be found * @throws IOException if block cannot be created */ public BlockWriter getTempBlockWriterRemote(long sessionId, long blockId) throws BlockDoesNotExistException, IOException { return mBlockStore.getBlockWriter(sessionId, blockId); }