code: public Buffer pin(BlockId blk) {
  		// Try to find out if this block has been pinned by this transaction
  		PinnedBuffer pinnedBuff = pinnedBuffers.get(blk);
  		if (pinnedBuff != null) {
  			pinnedBuff.pinnedCount++;
  			return pinnedBuff.buffer;
  		}
  		
  		// This transaction has pinned too many buffers
  		if (pinnedBuffers.size() == BUFFER_POOL_SIZE)
  			throw new BufferAbortException();
  		
  		// Pinning process
  		try {
  			Buffer buff;
  			long timestamp = System.currentTimeMillis();
  			boolean waitedBeforeGotBuffer = false;
  
  			// Try to pin a buffer or the pinned buffer for the given BlockId
  			buff = bufferPool.pin(blk);
  
  			// If there is no such buffer or no available buffer,
  			// wait for it
  			if (buff == null) {
  				waitedBeforeGotBuffer = true;
  				synchronized (bufferPool) {
  					waitingThreads.add(Thread.currentThread());
  
  					while (buff == null && !waitingTooLong(timestamp)) {
  						bufferPool.wait(MAX_TIME);
  						if (waitingThreads.get(0).equals(Thread.currentThread()))
  							buff = bufferPool.pin(blk);
  					}
  
  					waitingThreads.remove(Thread.currentThread());
  				}
  			}
  
  			// If it still has no buffer after a long wait,
  			// release and re-pin all buffers it has
  			if (buff == null) {
  				repin();
  				buff = pin(blk);
  			} else {
  				pinnedBuffers.put(buff.block(), new PinnedBuffer(buff));
  			}
  
  			// TODO: Add some comment here
  			if (waitedBeforeGotBuffer) {
  				synchronized (bufferPool) {
  					bufferPool.notifyAll();
  				}
  			}
  
  			return buff;
  		} catch (InterruptedException e) {
  			throw new BufferAbortException();
  		}
  	}
docs: Pins a buffer to the specified block, potentially waiting until a buffer
  becomes available. If no buffer becomes available within a fixed time
  period, then repins all currently holding blocks.
  
  @param blk
  a block ID
  @return the buffer pinned to that block