Apologies for the long post but being an HBase newbie I'd like a sanity check
from wiser, more experienced folks with regards to my findings, and how I've
fixed the issue I think I've found, before going down the path of submitting
a formal patch.

To re-create the problem I was seeing in my app I added the following code
to TestIndexTable,

import org.apache.hadoop.hbase.client.RowLock;

  private void assertRowUpdated(int updatedRow, int expectedRowValue)
      throws IndexNotFoundException, IOException {
    ResultScanner scanner = table.getIndexedScanner(INDEX_COL_A, null, null,
        null, null, null);
    byte[] persistedRowValue = null;
    for (Result rowResult : scanner) {
      byte[] row = rowResult.getRow();
      byte[] value = rowResult.getValue(COL_A);
      if
(Bytes.toString(row).equals(Bytes.toString(PerformanceEvaluation.format(updatedRow))))
{        
        persistedRowValue = value;
        LOG.info("update found: row [" + Bytes.toString(row)
          + "] value [" + Bytes.toString(value) + "]");
      }
      else
        LOG.info("updated index scan : row [" + Bytes.toString(row)
          + "] value [" + Bytes.toString(value) + "]");
    }
    scanner.close();

   
Assert.assertEquals(Bytes.toString(PerformanceEvaluation.format(expectedRowValue)),
  
                                    Bytes.toString(persistedRowValue));
  }

  private void updateRow(int row, int newValue) throws IOException {
      Put update = new Put(PerformanceEvaluation.format(row));
      byte[] valueA = PerformanceEvaluation.format(newValue);
      update.add(FAMILY, QUAL_A, valueA);
      table.put(update);
      LOG.info("Updated row [" + Bytes.toString(update.getRow()) + "] val:
["
          + Bytes.toString(valueA) + "]");
  }

  private void updateLockedRow(int row, int newValue) throws IOException {
      RowLock lock = table.lockRow(PerformanceEvaluation.format(row));
      Put update = new Put(PerformanceEvaluation.format(row), lock);
      byte[] valueA = PerformanceEvaluation.format(newValue);
      update.add(FAMILY, QUAL_A, valueA);
      LOG.info("Updating row [" + Bytes.toString(update.getRow()) + "] val:
["
          + Bytes.toString(valueA) + "]");
      table.put(update);
      LOG.info("Updated row [" + Bytes.toString(update.getRow()) + "] val:
["
          + Bytes.toString(valueA) + "]");
      table.unlockRow(lock);
  }
  
  public void testRowUpdate() throws IOException {
    writeInitalRows();
    int row = NUM_ROWS - 2;
    int value = MAX_VAL + 111;
    updateRow(row, value);
    assertRowUpdated(row, value);
  }

  public void testLockedRowUpdate() throws IOException {
    writeInitalRows();
    int row = NUM_ROWS - 2;
    int value = MAX_VAL + 111;
    updateLockedRow(row, value);
    assertRowUpdated(row, value);
  }

As I expected from the behavior of my own app the test testRowUpdate() was
successful but the test testLockedRowUpdate() had an error as follows,

    [junit] java.io.IOException: java.io.IOException: Invalid row lock
    [junit]     at
org.apache.hadoop.hbase.regionserver.HRegion.getLock(HRegion.java:1640)
    [junit]     at
org.apache.hadoop.hbase.regionserver.HRegion.put(HRegion.java:1244)
    [junit]     at
org.apache.hadoop.hbase.regionserver.tableindexed.IndexedRegion.put(IndexedRegion.java:97)
    [junit]     at
org.apache.hadoop.hbase.regionserver.HRegion.put(HRegion.java:1216)
    [junit]     at
org.apache.hadoop.hbase.regionserver.HRegionServer.put(HRegionServer.java:1818)
    [junit]     at sun.reflect.GeneratedMethodAccessor23.invoke(Unknown Source)
    [junit]     at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    [junit]     at java.lang.reflect.Method.invoke(Method.java:597)
    [junit]     at
org.apache.hadoop.hbase.ipc.HBaseRPC$Server.call(HBaseRPC.java:650)
    [junit]     at
org.apache.hadoop.hbase.ipc.HBaseServer$Handler.run(HBaseServer.java:915)

NOTE: Line numbers in stacktrace may not make sense because I've been
hacking in loads of debug info. 

To fix the error I made three changes to IndexedRegion.java. The changes are
on lines marked *KST* below and in summary all they do is propagate the
lockid.

  public void put(Put put, Integer lockId, boolean writeToWAL)
      throws IOException {
    updateIndexes(put, lockId); // Do this first because will want to see
the old row *KST*
    super.put(put, lockId, writeToWAL);
  }

  private void updateIndexes(Put put, Integer lockId) throws IOException {
// *KST*
    List<IndexSpecification> indexesToUpdate = new
LinkedList<IndexSpecification>();

    // Find the indexes we need to update
    for (IndexSpecification index : getIndexes()) {
      if (possiblyAppliesToIndex(index, put)) {
        indexesToUpdate.add(index);
      }
    }

    if (indexesToUpdate.size() == 0) {
      return;
    }

    NavigableSet<byte[]> neededColumns =
getColumnsForIndexes(indexesToUpdate);
    NavigableMap<byte[], byte[]> newColumnValues = getColumnsFromPut(put);

    Get oldGet = new Get(put.getRow());
    for (byte [] neededCol : neededColumns) {
      oldGet.addColumn(neededCol);  
    }
    
    Result oldResult = super.get(oldGet, lockId); // *KST*

Feedback as to how I should proceed with these findings would be great. e.g.
should I submit a formal patch, have I made a silly coding error in my test
or in IndexedRegion? Also, maybe the test are insufficient. I have al sorts
of variations I have tried with autoflush turned off, maybe I should include
those tests too?
-- 
View this message in context: 
http://www.nabble.com/Row-lock-issues-with-Indexed-Tables-tp25442355p25442355.html
Sent from the HBase User mailing list archive at Nabble.com.

Reply via email to