Migration guide: Java and Thrift clients¶
Documentation home · HappyBase migration · API reference
The driver uses native HBase RPC but is not a complete Java Client implementation. Familiar operation names do not guarantee identical defaults, result models, retry logic, or thread safety.
Start with a capability inventory¶
Before replacing a client, list the operations your application actually relies on:
- data reads/writes, scan boundaries, and column projections;
- cell timestamps, historical versions, and retention policies;
- counters, conditional operations, and cross-row assumptions;
- concurrent use, connection ownership, failover, and authentication;
- snapshots, administrative procedures, and recovery requirements.
Compare each requirement with current limitations. If a critical feature is not implemented end-to-end, keep that path on the existing client until there is a tested solution.
Java-style concepts, Python-specific calls¶
| Concept | Current Python interface | Migration caution |
|---|---|---|
| Configuration / connection | Client(dict) | Only implemented settings apply |
| Table identifier | TableName.value_of(namespace, qualifier) | Two byte-string arguments |
| Column-family descriptor | ColumnFamilyDescriptorBuilder(...).build() | Returns a protobuf schema |
| Put / Get / Delete | Operation object passed to Table method | Not every setter is chainable |
| Result | Row or None | No complete cells/timestamps/version-history model |
| ResultScanner | with table.scan(scan) | Explicit cleanup; no Java retry guarantee |
| Scan bounds | with_start_row / with_end_row | Both constructor bounds inclusive by default |
| BufferedMutator params | Instantiate then assign attributes | No constructor keyword parameters |
| Conditional mutation | CheckAndPut or Table.check_and_delete | Same-row condition; not a lock framework |
| Async admin procedure | Returned procedure ID | Must verify completion separately |
Use bytes directly or encode application strings explicitly. Passing arbitrary Java configuration keys into the dictionary does not implement their behavior.
Minimal target pattern¶
This example assumes an existing default:users table with cf:
import os
from hbasedriver.client.client import Client
from hbasedriver.hbase_constants import HConstants
from hbasedriver.operations.get import Get
from hbasedriver.operations.put import Put
config = {HConstants.ZOOKEEPER_QUORUM: os.getenv("HBASE_ZK", "127.0.0.1:2181")}
with Client(config) as client:
with client.get_table(b"default", b"users") as table:
table.put(Put(b"user:001").add_column(b"cf", b"name", b"Alice"))
row = table.get(Get(b"user:001").add_column(b"cf", b"name"))
name = None if row is None else row.get(b"cf", b"name")
print(name)
Client construction performs discovery. ZooKeeper, Master, and advertised RegionServers must be reachable. A Thrift endpoint is not a ZooKeeper endpoint.
Differences requiring application changes¶
Read shape and timestamps¶
Row maps one value to each family/qualifier. Requesting multiple versions does not produce a Java-style list of cells; timestamp information is lost. Current Get/Scan time-range paths are incomplete. Do not silently degrade an audit/history application to latest-value reads.
Batch results and failure boundaries¶
BatchGet returns a dictionary, not a positional array. BatchPut returns status booleans on success and can raise after earlier writes. Batch and BufferedMutator currently execute individual calls. They do not provide cross-row atomicity or Java Multi-request throughput characteristics.
Scans and pagination¶
Specify end exclusivity explicitly. Do not pass Java-style or invented keywords to the constructor. Use next_batch(n) for bounded consumption, and use exclusive resume keys for pagination. Preserve all predicates and bounds between pages. Reverse/cross-region behavior under splits needs separate testing.
Concurrency, retry, and resource ownership¶
Do not transfer Java Connection/Table thread-sharing assumptions without tests. Current cleanup and shared caches have limitations. A timeout can leave the write outcome unknown. Replaying Increment/Append is not safe without deduplication or reconciliation.
Administration¶
Use unique test resources. Table truncation currently deletes/recreates and does not preserve splits/full metadata. Snapshot restore/clone returns a procedure ID, not completed data. Cluster-wide changes need operational approval and verification.
A staged validation plan¶
| Stage | Required evidence |
|---|---|
| Schema/encoding comparison | Byte-for-byte agreement for known rows, empty values, and counters |
| Query comparison | Correct first/last boundaries, filters, missing rows, and pagination |
| Write comparison | Correct single-row results and tested conditional-failure path |
| Failure testing | Known handling of timeouts, partial batches, reconnects, and Region movement |
| Performance test | End-to-end completion time, latency distribution, errors, resource growth |
| Rollout | Limited traffic, monitoring, rollback ownership, no unsafe duplicate writes |
Start with the cookbook, then add application-specific integration tests. Documentation smoke tests are a foundation, not a migration acceptance test for every production workload.