com.h3c.util.persistence.cassandra.index

## Class IndexEntryHandler<K extends Serializable>

- java.lang.Object
- - com.h3c.util.persistence.cassandra.index.IndexEntryHandler<K>

- Type Parameters:
    `K` - type of the row key in the main column family.
  All Implemented Interfaces:
    ColumnFamilyHandler

      public class IndexEntryHandler<K extends Serializable>
      extends Object
      implements ColumnFamilyHandler

  Column family to keep indexes values to facilitate updating custom secondary indexes.

  Reading is easy with secondary indexes using regular column range operations. However updates are harder because the old index value needs to be removed before inserting the new one (Read before write).

  This class offers a method to update the manual secondary indexes column families.

  For example, in a users by location indexing the following clilumn families would be needed:

  - Users: To keep users information.
  - Users by location: To index users by location. Row key would be the location and columns would represent the users.
  - Users index entries: To keep previous values of users locations used to update "Users by Location" column family (and other indexes) after users updates. This same column family can be used to update multiple column families representing indexes. IndexEntryHandler is an utility class to maintain this table.

  IndexEntriesColumnFamily:

  - Row key (Key validation: K): The same row key from the main column family.
  - Column value (default validation: Bytes): Index value.
  - Column name (comparator: ): Composite column name with the attribute name or indexed column name ("Location" for the example above) and the update timestamp.

       column_family_name {
           "row_key_in_main_column_family": {
               <attr 1, timestamp 1>: old value for attr 1,
               <attr 1, timestamp 2>: old value for attr 1,
               <attr 2, timestamp 3>: old value for attr 2,
               ...
               <attr n, timestamp m>: old value for attr n,
           }
       }

  We read previous index values from IndexEntryHandler rather than the main column family (or source data column family) to deal with concurrency. The timestamp is used to avoid locking for concurrent updates; old values are not override so they are deleted from the index column families.

  Note: A unique id is actually used rather than a timestamp to guarantee uniqueness and avoid overriding values.

  Steps to update a row in the main column family:

  1. Using range query read all columns related to the attribute to update from IndexEntryHandler (All values of "Location" in the example above, or all values of "attr 1" in the column family structure example above).
  2. Delete all the read entries (attribute's old values) from all index column families (For example: Users by location column family).
  3. Delete all the read entries (attribute's old values) from IndexEntryHandler.
  4. Insert into IndexEntryHandler the new attribute's value (For example: The new location value).
  5. Insert into all index column families the new attribute's value (For example: Users by location column family).
  6. Update the row in the main column family with the new attribute's value (For example: users column family).

  Some points to notice

  - This method works for multi-threading environments without the need of implementing any locking (nor local nor distributed) as long as update operations remain idempotent (inserts normally are in Cassandra). Indexes will be eventually consistent.
  - If something goes wrong the same operation can be applied as many times as needed until it completes since it is idempotent.
  - It is possible to get a false positive because updates are being made in flight. You could get a result that is not present while the index column families are being updated. If this is a problem use filter on read rather than locking.

- - ### Nested Class Summary

    Nested Classes
    Modifier and Type | Class and Description
    --- | ---
    `static class` | `IndexEntryHandler.IndexEntry` Composite column name to keep the indexed attribute (or column name in the main column family) and a field to make the indexed value unique to avoid overriding previous values.

  - ### Constructor Summary

    Constructors
    Constructor and Description
    `IndexEntryHandler(String columnFamilyName, CassDataTypes rowKeyDataType, com.netflix.astyanax.Serializer<K> rowKeySerializer)` Creates a column family to keep previous values of indexes.

  - ### Method Summary

    Methods
    Modifier and Type | Method and Description
    --- | ---
    `void` | `addIndexedValue(K rowKey, Column<String,?> indexedColumn, DataStoreContext context)` Adds an indexed value.
    `<D> void` | `deleteIndexedValues(K rowKey, Collection<Column<IndexEntryHandler.IndexEntry,D>> indexedValues, DataStoreContext context)` Deletes the given indexed values (old values).
    `Collection<ColumnFamilyDefinition<?,?>>` | `getColumnFamilyDefinitions()` Gets the definition of all column families this handler reads from and writes into.
    `<D> Collection<Column<IndexEntryHandler.IndexEntry,D>>` | `getIndexedValues(K rowKey, ColumnName<String,?> indexedColumnName, ColumnDecoder<IndexEntryHandler.IndexEntry,D> decoder, DataStoreContext context)` Gets the indexed values (old values).

    - ### Methods inherited from class java.lang.Object

      `clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

- - ### Constructor Detail

    - #### IndexEntryHandler

          public IndexEntryHandler(String columnFamilyName,
                           CassDataTypes rowKeyDataType,
                           com.netflix.astyanax.Serializer<K> rowKeySerializer)

      Creates a column family to keep previous values of indexes.
      Parameters:
        `columnFamilyName` - name for the column family.
        `rowKeyDataType` - type of the row key in the main column family.
        `rowKeySerializer` - row key serializer.

  - ### Method Detail

    - #### getColumnFamilyDefinitions

          public Collection<ColumnFamilyDefinition<?,?>> getColumnFamilyDefinitions()

      Description copied from interface: `ColumnFamilyHandler`
      Gets the definition of all column families this handler reads from and writes into.
      Specified by:
        `getColumnFamilyDefinitions` in interface `ColumnFamilyHandler`
      Returns:
        column family definitions.

    - #### addIndexedValue

          public void addIndexedValue(K rowKey,
                             Column<String,?> indexedColumn,
                             DataStoreContext context)

      Adds an indexed value.
      Parameters:
        `rowKey` - row key.
        `indexedColumn` - indexed column.
        `context` - data store context.

    - #### getIndexedValues

          public <D> Collection<Column<IndexEntryHandler.IndexEntry,D>> getIndexedValues(K rowKey,
                                                                                ColumnName<String,?> indexedColumnName,
                                                                                ColumnDecoder<IndexEntryHandler.IndexEntry,D> decoder,
                                                                                DataStoreContext context)
                                                                              throws ClassCastException

      Gets the indexed values (old values).
      Parameters:
        `rowKey` - row key.
        `indexedColumnName` - name of the indexed column to retrieve index values (old values) for.
        `decoder` - value decoder.
        `context` - data store context.
      Returns:
        current indexed values.
      Throws:
        `ClassCastException` - id the type of the indexed column is not the same than the one the given decoder produces.

    - #### deleteIndexedValues

          public <D> void deleteIndexedValues(K rowKey,
                                     Collection<Column<IndexEntryHandler.IndexEntry,D>> indexedValues,
                                     DataStoreContext context)

      Deletes the given indexed values (old values).
      Parameters:
        `rowKey` - row key.
        `indexedValues` - indexed values to delete.
        `context` - data store context.

Copyright © 2014. All Rights Reserved.