HBase1.0.0 source code analysis-request processing process analysis using the Put operation as an example (1), hbase1.0.0put
The following code shows a simple code instance for HBase Put operations. The Connection connection = ConnectionFactory in the Code is as follows. createConnection (conf), which describes the connection process and service information started in the previous Client startup connection process of bohbase1.0.0 source code analysis.
TableName tn = TableName.valueOf("test010"); try (Connection connection = ConnectionFactory.createConnection(conf)) { try (Table table = connection.getTable(tn)) { Put put = new Put("ROW1".getBytes()); put.addColumn("CF1".getBytes(),"column1".getBytes(),"value1".getBytes()); put.addColumn("CF2".getBytes(),"column1".getBytes(),"value1".getBytes()); table.put(put); System.out.println("done!"); } }
This article focuses on how put is sent to the server and called by the server step by step. First, we need to review the Connection type structure, as shown in: The HConnectionImplementation class is actually responsible for connecting to the server. To operate the table data, for example, in the put example, we first need to obtain an instance of a Table, which can be obtained from the connection,
public HTableInterface getTable(TableName tableName, ExecutorService pool) throws IOException { if (managed) { throw new NeedUnmanagedConnectionException(); } return new HTable(tableName, this, tableConfig, rpcCallerFactory, rpcControllerFactory, pool); }
Table is actually an operation interface. The real implementation class is HTable. HTable can perform data-level operations such as data insertion and deletion on a single HBase data Table, this class is currently only HBase Internal, and the external interface is Table. After obtaining the HTable instance, the operation is executed,
/** * {@inheritDoc} * @throws IOException */ @Override public void put(final Put put) throws IOException { getBufferedMutator().mutate(put); if (autoFlush) { flushCommits(); } }
The above code is the prototype of the HTable operation. A series of calls are made here. We analyze them one by one. The first is the getBufferedMutator () function,
This function returns an implemented instance BufferedMutatorImpl. This class is similar to HTable and is responsible for communicating with a single HBase table. However, it is batch for put operations and can be asynchronously executed.
Mutate calls the doMutate method internally:
private void doMutate(Mutation m) throws InterruptedIOException, RetriesExhaustedWithDetailsException { if (closed) { throw new IllegalStateException("Cannot put when the BufferedMutator is closed."); } if (!(m instanceof Put) && !(m instanceof Delete)) { throw new IllegalArgumentException("Pass a Delete or a Put"); } // This behavior is highly non-intuitive... it does not protect us against // 94-incompatible behavior, which is a timing issue because hasError, the below code // and setter of hasError are not synchronized. Perhaps it should be removed. if (ap.hasError()) { writeAsyncBuffer.add(m); backgroundFlushCommits(true); } if (m instanceof Put) { validatePut((Put) m); } currentWriteBufferSize += m.heapSize(); writeAsyncBuffer.add(m); while (currentWriteBufferSize > writeBufferSize) { backgroundFlushCommits(false); } }
Valid code: writeAsyncBuffer. add (m); in fact, it is to add this operation to an asynchronous buffer. After a single request, the flash will be executed when certain conditions are met. When a flash operation occurs, this operation will actually be executed. This is mainly to improve the throughput of the system. Let's take a look at the internal flush operation.
private void backgroundFlushCommits(boolean synchronous) throws InterruptedIOException, RetriesExhaustedWithDetailsException { try { if (!synchronous) { ap.submit(tableName, writeAsyncBuffer, true, null, false); if (ap.hasError()) { LOG.debug(tableName + ": One or more of the operations have failed -" + " waiting for all operation in progress to finish (successfully or not)"); } }
The refresh operation can be asynchronous or synchronous. In doMutate, the refresh operation is performed asynchronously by default. The ap here is an instance of the AsyncProcess class, this class uses multiple threads to Implement Asynchronous requests, and uses Future to obtain server-side data in the thread. The process here is also complicated. I will continue in the next article.