or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration.mdexceptions.mdexecution.mdexpressions.mdindex.mdjdbc.mdmapreduce.mdmonitoring.mdquery-compilation.mdschema-metadata.mdserver.mdtransactions.mdtypes.md

server.mddocs/

0

# Server-Side Components

1

2

Phoenix's server-side components run within HBase region servers as coprocessors, providing distributed query processing, metadata management, index maintenance, and caching operations. These components enable Phoenix's SQL capabilities while leveraging HBase's scalability.

3

4

## Core Imports

5

6

```java

7

import org.apache.phoenix.coprocessor.*;

8

import org.apache.phoenix.hbase.index.*;

9

import org.apache.hadoop.hbase.coprocessor.*;

10

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

11

import java.io.IOException;

12

```

13

14

## Coprocessor Framework

15

16

### PhoenixCoprocessor

17

18

Base interface for all Phoenix coprocessors providing common functionality and lifecycle management.

19

20

```java{ .api }

21

public interface PhoenixCoprocessor {

22

// Lifecycle methods

23

void start(CoprocessorEnvironment env) throws IOException

24

void stop(CoprocessorEnvironment env) throws IOException

25

26

// Configuration

27

Configuration getConfiguration()

28

HRegionInfo getRegionInfo()

29

30

// Error handling

31

void handleException(Exception e) throws IOException

32

}

33

```

34

35

### MetaDataEndpointImpl

36

37

Server-side metadata operations coprocessor handling schema changes and metadata queries.

38

39

```java{ .api }

40

public class MetaDataEndpointImpl extends BaseEndpointCoprocessor

41

implements PhoenixMetaDataCoprocessorProtocol {

42

// Table operations

43

public MetaDataMutationResult createTable(List<Mutation> tableMetadata) throws IOException

44

public MetaDataMutationResult dropTable(byte[] schemaName, byte[] tableName,

45

byte[] parentTableName, long timestamp) throws IOException

46

public MetaDataMutationResult addColumn(List<Mutation> tableMetadata) throws IOException

47

public MetaDataMutationResult dropColumn(List<Mutation> tableMetadata) throws IOException

48

49

// Index operations

50

public MetaDataMutationResult createIndex(List<Mutation> tableMetadata,

51

byte[] physicalIndexName) throws IOException

52

public MetaDataMutationResult dropIndex(List<Mutation> tableMetadata,

53

byte[] indexName) throws IOException

54

55

// Schema operations

56

public MetaDataMutationResult createSchema(List<Mutation> schemaMetadata) throws IOException

57

public MetaDataMutationResult dropSchema(List<Mutation> schemaMetadata) throws IOException

58

59

// Function operations

60

public MetaDataMutationResult createFunction(List<Mutation> functionMetadata) throws IOException

61

public MetaDataMutationResult dropFunction(List<Mutation> functionMetadata) throws IOException

62

63

// Metadata queries

64

public MetaDataResponse getTable(byte[] tenantId, byte[] schemaName,

65

byte[] tableName, long timestamp) throws IOException

66

public MetaDataResponse getFunctions(byte[] tenantId, List<byte[]> functionNames,

67

long timestamp) throws IOException

68

public MetaDataResponse getSchema(byte[] tenantId, byte[] schemaName,

69

long timestamp) throws IOException

70

}

71

```

72

73

**Usage:**

74

```java

75

// Server-side metadata operations are typically invoked through client connections

76

// but can be accessed programmatically in coprocessor contexts

77

78

// Example: Custom coprocessor extending MetaDataEndpointImpl

79

public class CustomMetaDataEndpoint extends MetaDataEndpointImpl {

80

@Override

81

public MetaDataMutationResult createTable(List<Mutation> tableMetadata) throws IOException {

82

// Custom logic before table creation

83

System.out.println("Creating table with " + tableMetadata.size() + " mutations");

84

85

// Perform additional validation

86

for (Mutation mutation : tableMetadata) {

87

if (mutation instanceof Put) {

88

Put put = (Put) mutation;

89

// Validate table metadata

90

validateTableMetadata(put);

91

}

92

}

93

94

// Call parent implementation

95

MetaDataMutationResult result = super.createTable(tableMetadata);

96

97

// Custom logic after table creation

98

if (result.getMutationCode() == MutationCode.TABLE_ALREADY_EXISTS) {

99

System.out.println("Table already exists");

100

} else {

101

System.out.println("Table created successfully");

102

}

103

104

return result;

105

}

106

107

private void validateTableMetadata(Put put) throws IOException {

108

// Custom table metadata validation logic

109

byte[] tableName = put.getRow();

110

// Validate table name patterns, quotas, etc.

111

}

112

}

113

```

114

115

### ServerCachingEndpointImpl

116

117

Server-side caching operations coprocessor for distributed cache management.

118

119

```java{ .api }

120

public class ServerCachingEndpointImpl extends BaseEndpointCoprocessor

121

implements ServerCachingProtocol {

122

// Cache operations

123

public boolean addServerCache(byte[] tenantId, byte[] cacheId, byte[] cachePtr,

124

byte[] txState, ServerCacheFactory cacheFactory) throws IOException

125

public boolean removeServerCache(byte[] tenantId, byte[] cacheId) throws IOException

126

127

// Cache queries

128

public ServerCache getServerCache(byte[] tenantId, byte[] cacheId) throws IOException

129

public long getSize(byte[] tenantId, byte[] cacheId) throws IOException

130

131

// Cache statistics

132

public ServerCacheStats getCacheStats() throws IOException

133

public void clearAllCache() throws IOException

134

}

135

```

136

137

**Usage:**

138

```java

139

// Server cache usage is typically handled internally by Phoenix

140

// but can be managed in custom coprocessors

141

142

// Example: Custom caching coprocessor

143

public class CustomCachingEndpoint extends ServerCachingEndpointImpl {

144

private static final Logger LOG = LoggerFactory.getLogger(CustomCachingEndpoint.class);

145

146

@Override

147

public boolean addServerCache(byte[] tenantId, byte[] cacheId, byte[] cachePtr,

148

byte[] txState, ServerCacheFactory cacheFactory) throws IOException {

149

LOG.info("Adding server cache: tenant={}, cacheId={}, size={}",

150

Bytes.toString(tenantId), Bytes.toString(cacheId), cachePtr.length);

151

152

// Custom cache validation or preprocessing

153

if (cachePtr.length > getMaxCacheSize()) {

154

throw new IOException("Cache size exceeds maximum allowed size");

155

}

156

157

boolean result = super.addServerCache(tenantId, cacheId, cachePtr, txState, cacheFactory);

158

159

if (result) {

160

LOG.info("Server cache added successfully");

161

} else {

162

LOG.warn("Failed to add server cache");

163

}

164

165

return result;

166

}

167

168

private int getMaxCacheSize() {

169

return getConfiguration().getInt("phoenix.cache.maxSize", 104857600); // 100MB default

170

}

171

}

172

```

173

174

## Index Management

175

176

### IndexBuilder

177

178

Interface for building index updates from primary table mutations.

179

180

```java{ .api }

181

public interface IndexBuilder {

182

// Index update building

183

Collection<Pair<Mutation, byte[]>> getIndexUpdate(Put put, IndexMetaData indexMetaData)

184

throws IOException

185

Collection<Pair<Mutation, byte[]>> getIndexUpdate(Delete delete, IndexMetaData indexMetaData)

186

throws IOException

187

Collection<Pair<Mutation, byte[]>> getIndexUpdateForFilteredRows(

188

Collection<KeyValue> filtered, IndexMetaData indexMetaData) throws IOException

189

190

// Builder lifecycle

191

void setup(RegionCoprocessorEnvironment env) throws IOException

192

void batchStarted(MiniBatchOperationInProgress<Mutation> miniBatchOp,

193

IndexMetaData context) throws IOException

194

void batchCompleted(MiniBatchOperationInProgress<Mutation> miniBatchOp)

195

}

196

```

197

198

### PhoenixIndexBuilder

199

200

Phoenix-specific implementation of IndexBuilder with support for covered columns and functional indexes.

201

202

```java{ .api }

203

public class PhoenixIndexBuilder implements IndexBuilder {

204

// Index update generation

205

public Collection<Pair<Mutation, byte[]>> getIndexUpdate(Put put, IndexMetaData indexMetaData)

206

throws IOException

207

public Collection<Pair<Mutation, byte[]>> getIndexUpdate(Delete delete, IndexMetaData indexMetaData)

208

throws IOException

209

210

// Phoenix-specific functionality

211

public Collection<Pair<Mutation, byte[]>> getIndexUpdatesForFilteredRows(

212

Collection<KeyValue> filtered, IndexMetaData indexMetaData) throws IOException

213

214

// Configuration

215

public void setup(RegionCoprocessorEnvironment env) throws IOException

216

public boolean isEnabled(Mutation m) throws IOException

217

}

218

```

219

220

### IndexWriter

221

222

Interface for writing index updates with support for different writing strategies.

223

224

```java{ .api }

225

public interface IndexWriter {

226

// Index writing

227

void write(Collection<Pair<Mutation, byte[]>> indexUpdates) throws IOException

228

void write(Pair<Mutation, byte[]> indexUpdate, boolean allowLocalUpdates) throws IOException

229

230

// Writer lifecycle

231

void setup(RegionCoprocessorEnvironment env) throws IOException

232

void stop(String why) throws IOException

233

234

// Error handling

235

void handleFailure(Collection<Pair<Mutation, byte[]>> attempted,

236

Exception cause) throws IOException

237

}

238

```

239

240

### ParallelWriterIndexCommitter

241

242

Parallel index writer implementation for high-throughput index maintenance.

243

244

```java{ .api }

245

public class ParallelWriterIndexCommitter implements IndexWriter {

246

// Parallel writing configuration

247

public ParallelWriterIndexCommitter(int numThreads)

248

public ParallelWriterIndexCommitter(ThreadPoolExecutor pool)

249

250

// Index writing implementation

251

public void write(Collection<Pair<Mutation, byte[]>> indexUpdates) throws IOException

252

public void write(Pair<Mutation, byte[]> indexUpdate, boolean allowLocalUpdates) throws IOException

253

254

// Performance monitoring

255

public IndexWriterStats getStats()

256

public void resetStats()

257

}

258

```

259

260

**Usage:**

261

```java

262

// Custom index builder for specialized indexing logic

263

public class CustomIndexBuilder extends PhoenixIndexBuilder {

264

@Override

265

public Collection<Pair<Mutation, byte[]>> getIndexUpdate(Put put, IndexMetaData indexMetaData)

266

throws IOException {

267

Collection<Pair<Mutation, byte[]>> updates = super.getIndexUpdate(put, indexMetaData);

268

269

// Add custom index logic

270

for (Pair<Mutation, byte[]> update : updates) {

271

Mutation indexMutation = update.getFirst();

272

byte[] indexTableName = update.getSecond();

273

274

// Custom processing for specific indexes

275

if (Bytes.toString(indexTableName).endsWith("_CUSTOM_IDX")) {

276

enhanceIndexMutation(indexMutation, put);

277

}

278

}

279

280

return updates;

281

}

282

283

private void enhanceIndexMutation(Mutation indexMutation, Put originalPut) {

284

// Add computed columns, derived values, etc.

285

if (indexMutation instanceof Put) {

286

Put indexPut = (Put) indexMutation;

287

// Add computed timestamp

288

indexPut.addColumn(Bytes.toBytes("cf"), Bytes.toBytes("computed_ts"),

289

Bytes.toBytes(System.currentTimeMillis()));

290

}

291

}

292

}

293

294

// Custom index writer with retry logic

295

public class RetryableIndexWriter extends ParallelWriterIndexCommitter {

296

private final int maxRetries;

297

private final long retryDelayMs;

298

299

public RetryableIndexWriter(int numThreads, int maxRetries, long retryDelayMs) {

300

super(numThreads);

301

this.maxRetries = maxRetries;

302

this.retryDelayMs = retryDelayMs;

303

}

304

305

@Override

306

public void write(Collection<Pair<Mutation, byte[]>> indexUpdates) throws IOException {

307

int attempts = 0;

308

IOException lastException = null;

309

310

while (attempts < maxRetries) {

311

try {

312

super.write(indexUpdates);

313

return; // Success

314

} catch (IOException e) {

315

lastException = e;

316

attempts++;

317

318

if (attempts < maxRetries) {

319

try {

320

Thread.sleep(retryDelayMs);

321

} catch (InterruptedException ie) {

322

Thread.currentThread().interrupt();

323

throw new IOException("Interrupted during retry", ie);

324

}

325

}

326

}

327

}

328

329

throw new IOException("Failed to write index updates after " + maxRetries + " attempts",

330

lastException);

331

}

332

}

333

```

334

335

## Region Observer Integration

336

337

### PhoenixRegionObserver

338

339

Phoenix region observer that integrates with HBase region lifecycle for SQL operations.

340

341

```java{ .api }

342

public class PhoenixRegionObserver implements RegionObserver, RegionCoprocessor {

343

// Region lifecycle

344

public void start(CoprocessorEnvironment e) throws IOException

345

public void stop(CoprocessorEnvironment e) throws IOException

346

347

// Mutation interception

348

public void preBatchMutate(ObserverContext<RegionCoprocessorEnvironment> c,

349

MiniBatchOperationInProgress<Mutation> miniBatchOp) throws IOException

350

public void postBatchMutate(ObserverContext<RegionCoprocessorEnvironment> c,

351

MiniBatchOperationInProgress<Mutation> miniBatchOp) throws IOException

352

353

// Scan interception

354

public RegionScanner preScannerOpen(ObserverContext<RegionCoprocessorEnvironment> c,

355

Scan scan, RegionScanner s) throws IOException

356

public boolean preScannerNext(ObserverContext<RegionCoprocessorEnvironment> c,

357

InternalScanner s, List<Result> result,

358

int limit, boolean hasNext) throws IOException

359

360

// Region split/merge handling

361

public void preSplit(ObserverContext<RegionCoprocessorEnvironment> c,

362

byte[] splitRow) throws IOException

363

public void postSplit(ObserverContext<RegionCoprocessorEnvironment> c,

364

Region l, Region r) throws IOException

365

}

366

```

367

368

**Usage:**

369

```java

370

// Custom Phoenix region observer for monitoring and custom logic

371

public class CustomPhoenixRegionObserver extends PhoenixRegionObserver {

372

private static final Logger LOG = LoggerFactory.getLogger(CustomPhoenixRegionObserver.class);

373

private Timer mutationTimer;

374

375

@Override

376

public void start(CoprocessorEnvironment e) throws IOException {

377

super.start(e);

378

mutationTimer = new Timer("MutationTimer", true);

379

LOG.info("Custom Phoenix Region Observer started");

380

}

381

382

@Override

383

public void preBatchMutate(ObserverContext<RegionCoprocessorEnvironment> c,

384

MiniBatchOperationInProgress<Mutation> miniBatchOp) throws IOException {

385

long startTime = System.currentTimeMillis();

386

387

// Log large batches

388

if (miniBatchOp.size() > 1000) {

389

LOG.info("Processing large batch of {} mutations", miniBatchOp.size());

390

}

391

392

// Custom validation or preprocessing

393

for (int i = 0; i < miniBatchOp.size(); i++) {

394

Mutation mutation = miniBatchOp.getOperation(i);

395

if (mutation instanceof Put) {

396

validatePutMutation((Put) mutation);

397

}

398

}

399

400

// Store timing information

401

c.getEnvironment().getRegion().getRegionInfo().setEndKey(

402

Bytes.toBytes(String.valueOf(startTime))

403

);

404

405

super.preBatchMutate(c, miniBatchOp);

406

}

407

408

@Override

409

public void postBatchMutate(ObserverContext<RegionCoprocessorEnvironment> c,

410

MiniBatchOperationInProgress<Mutation> miniBatchOp) throws IOException {

411

super.postBatchMutate(c, miniBatchOp);

412

413

// Calculate and log timing

414

long duration = System.currentTimeMillis() - extractStartTime(c);

415

if (duration > 5000) { // Log slow operations

416

LOG.warn("Slow batch mutation: {} mutations took {}ms",

417

miniBatchOp.size(), duration);

418

}

419

}

420

421

private void validatePutMutation(Put put) throws IOException {

422

// Custom validation logic

423

NavigableMap<byte[], List<Cell>> familyMap = put.getFamilyCellMap();

424

for (List<Cell> cells : familyMap.values()) {

425

for (Cell cell : cells) {

426

if (cell.getValueLength() > getMaxCellSize()) {

427

throw new IOException("Cell value too large: " + cell.getValueLength());

428

}

429

}

430

}

431

}

432

433

private long extractStartTime(ObserverContext<RegionCoprocessorEnvironment> c) {

434

byte[] endKey = c.getEnvironment().getRegion().getRegionInfo().getEndKey();

435

return Long.parseLong(Bytes.toString(endKey));

436

}

437

438

private int getMaxCellSize() {

439

return getConfiguration().getInt("phoenix.custom.maxCellSize", 10485760); // 10MB

440

}

441

442

@Override

443

public void stop(CoprocessorEnvironment e) throws IOException {

444

if (mutationTimer != null) {

445

mutationTimer.cancel();

446

}

447

super.stop(e);

448

LOG.info("Custom Phoenix Region Observer stopped");

449

}

450

}

451

```

452

453

## Server-Side Query Processing

454

455

### AggregateClient

456

457

Client interface for server-side aggregation operations.

458

459

```java{ .api }

460

public class AggregateClient {

461

// Aggregation execution

462

public <T> T aggregate(Scan scan, RowProcessor<T> rowProcessor) throws IOException

463

public Result[] getRows(Scan scan, int numberOfRows) throws IOException

464

465

// Aggregate functions

466

public long rowCount(Scan scan) throws IOException

467

public <R, S> R median(Scan scan, ColumnInterpreter<R, S, P, Q, W> ci,

468

byte[] colFamily, byte[] qualifier) throws IOException

469

public <R, S> S sum(Scan scan, ColumnInterpreter<R, S, P, Q, W> ci,

470

byte[] colFamily, byte[] qualifier) throws IOException

471

public <R, S> R max(Scan scan, ColumnInterpreter<R, S, P, Q, W> ci,

472

byte[] colFamily, byte[] qualifier) throws IOException

473

public <R, S> R min(Scan scan, ColumnInterpreter<R, S, P, Q, W> ci,

474

byte[] colFamily, byte[] qualifier) throws IOException

475

}

476

```

477

478

### HashJoinRegionScanner

479

480

Server-side scanner for hash join operations.

481

482

```java{ .api }

483

public class HashJoinRegionScanner extends BaseRegionScanner {

484

public HashJoinRegionScanner(RegionScanner scanner, List<Expression> expressions,

485

Expression postJoinFilterExpression,

486

List<HashJoinInfo> joinInfos, TupleProjector projector)

487

488

// Scanner implementation

489

public boolean next(List<Cell> results) throws IOException

490

public boolean next(List<Cell> results, ScannerContext scannerContext) throws IOException

491

public void close() throws IOException

492

493

// Join-specific methods

494

public long getMaxResultSize()

495

public RegionInfo getRegionInfo()

496

}

497

```

498

499

**Usage:**

500

```java

501

// Server-side aggregation example

502

public class ServerAggregationExample {

503

public void performServerAggregation(Connection connection, String tableName) throws IOException, SQLException {

504

PhoenixConnection phoenixConn = connection.unwrap(PhoenixConnection.class);

505

ConnectionQueryServices queryServices = phoenixConn.getQueryServices();

506

507

// Create scan for aggregation

508

Scan scan = new Scan();

509

scan.addFamily(Bytes.toBytes("cf"));

510

511

// Custom row processor for aggregation

512

RowProcessor<AggregationResult> processor = new RowProcessor<AggregationResult>() {

513

private long count = 0;

514

private long sum = 0;

515

516

@Override

517

public void process(Result result) {

518

count++;

519

Cell[] cells = result.rawCells();

520

for (Cell cell : cells) {

521

if (Bytes.equals(CellUtil.cloneQualifier(cell), Bytes.toBytes("salary"))) {

522

sum += Bytes.toLong(CellUtil.cloneValue(cell));

523

}

524

}

525

}

526

527

@Override

528

public AggregationResult getResult() {

529

return new AggregationResult(count, sum, sum / (double) count);

530

}

531

};

532

533

// Execute server-side aggregation

534

AggregateClient client = new AggregateClient();

535

Table table = queryServices.getTable(Bytes.toBytes(tableName));

536

AggregationResult result = client.aggregate(scan, processor);

537

538

System.out.println("Count: " + result.getCount());

539

System.out.println("Sum: " + result.getSum());

540

System.out.println("Average: " + result.getAverage());

541

}

542

}

543

```

544

545

## Custom Coprocessor Development

546

547

### Custom Phoenix Coprocessor Template

548

549

```java

550

// Template for developing custom Phoenix coprocessors

551

public abstract class CustomPhoenixCoprocessor implements RegionObserver, RegionCoprocessor {

552

protected Configuration configuration;

553

protected RegionCoprocessorEnvironment environment;

554

555

@Override

556

public void start(CoprocessorEnvironment env) throws IOException {

557

if (env instanceof RegionCoprocessorEnvironment) {

558

this.environment = (RegionCoprocessorEnvironment) env;

559

this.configuration = env.getConfiguration();

560

onStart();

561

}

562

}

563

564

@Override

565

public void stop(CoprocessorEnvironment env) throws IOException {

566

onStop();

567

}

568

569

// Template methods for subclasses

570

protected abstract void onStart() throws IOException;

571

protected abstract void onStop() throws IOException;

572

573

// Utility methods

574

protected Table getPhoenixTable(String tableName) throws IOException {

575

return environment.getConnection().getTable(TableName.valueOf(tableName));

576

}

577

578

protected void logInfo(String message, Object... args) {

579

System.out.println(String.format("[CustomCoprocessor] " + message, args));

580

}

581

582

protected void logError(String message, Throwable t) {

583

System.err.println("[CustomCoprocessor] ERROR: " + message);

584

if (t != null) {

585

t.printStackTrace();

586

}

587

}

588

}

589

590

// Example implementation

591

public class AuditTrailCoprocessor extends CustomPhoenixCoprocessor {

592

private Table auditTable;

593

594

@Override

595

protected void onStart() throws IOException {

596

auditTable = getPhoenixTable("AUDIT_TRAIL");

597

logInfo("Audit trail coprocessor started");

598

}

599

600

@Override

601

protected void onStop() throws IOException {

602

if (auditTable != null) {

603

auditTable.close();

604

}

605

logInfo("Audit trail coprocessor stopped");

606

}

607

608

@Override

609

public void postBatchMutate(ObserverContext<RegionCoprocessorEnvironment> c,

610

MiniBatchOperationInProgress<Mutation> miniBatchOp) throws IOException {

611

try {

612

// Record audit information

613

for (int i = 0; i < miniBatchOp.size(); i++) {

614

Mutation mutation = miniBatchOp.getOperation(i);

615

recordAuditEntry(mutation);

616

}

617

} catch (Exception e) {

618

logError("Failed to record audit entry", e);

619

// Don't fail the original operation

620

}

621

}

622

623

private void recordAuditEntry(Mutation mutation) throws IOException {

624

Put auditPut = new Put(generateAuditRowKey());

625

auditPut.addColumn(Bytes.toBytes("cf"), Bytes.toBytes("operation_type"),

626

Bytes.toBytes(mutation.getClass().getSimpleName()));

627

auditPut.addColumn(Bytes.toBytes("cf"), Bytes.toBytes("row_key"),

628

mutation.getRow());

629

auditPut.addColumn(Bytes.toBytes("cf"), Bytes.toBytes("timestamp"),

630

Bytes.toBytes(System.currentTimeMillis()));

631

632

auditTable.put(auditPut);

633

}

634

635

private byte[] generateAuditRowKey() {

636

return Bytes.toBytes(UUID.randomUUID().toString());

637

}

638

}

639

```

640

641

## Deployment and Configuration

642

643

### Coprocessor Registration

644

645

```java

646

// Programmatic coprocessor registration

647

public class CoprocessorManager {

648

public static void registerCustomCoprocessors(Admin admin, String tableName) throws IOException {

649

TableDescriptor tableDescriptor = admin.getTableDescriptor(TableName.valueOf(tableName));

650

TableDescriptorBuilder builder = TableDescriptorBuilder.newBuilder(tableDescriptor);

651

652

// Add custom coprocessors

653

builder.setCoprocessor(CustomPhoenixRegionObserver.class.getName());

654

builder.setCoprocessor(AuditTrailCoprocessor.class.getName());

655

656

// Update table

657

admin.modifyTable(builder.build());

658

System.out.println("Custom coprocessors registered for table: " + tableName);

659

}

660

661

public static void unregisterCoprocessors(Admin admin, String tableName) throws IOException {

662

TableDescriptor tableDescriptor = admin.getTableDescriptor(TableName.valueOf(tableName));

663

TableDescriptorBuilder builder = TableDescriptorBuilder.newBuilder(tableDescriptor);

664

665

// Remove coprocessors

666

builder.removeCoprocessor(CustomPhoenixRegionObserver.class.getName());

667

builder.removeCoprocessor(AuditTrailCoprocessor.class.getName());

668

669

admin.modifyTable(builder.build());

670

System.out.println("Coprocessors unregistered for table: " + tableName);

671

}

672

}

673

674

// Usage

675

ConnectionQueryServices queryServices = connection.getQueryServices();

676

Admin admin = queryServices.getAdmin();

677

678

CoprocessorManager.registerCustomCoprocessors(admin, "users");

679

```

680

681

### Configuration Properties

682

683

```xml

684

<!-- hbase-site.xml configuration for Phoenix coprocessors -->

685

<configuration>

686

<!-- Enable Phoenix coprocessors -->

687

<property>

688

<name>hbase.coprocessor.region.classes</name>

689

<value>org.apache.phoenix.coprocessor.PhoenixRegionObserver</value>

690

</property>

691

692

<!-- Phoenix index coprocessors -->

693

<property>

694

<name>hbase.coprocessor.wal.classes</name>

695

<value>org.apache.phoenix.hbase.index.wal.IndexedWALEditCodec</value>

696

</property>

697

698

<!-- Custom coprocessor configuration -->

699

<property>

700

<name>phoenix.custom.maxCellSize</name>

701

<value>10485760</value>

702

</property>

703

704

<property>

705

<name>phoenix.cache.maxSize</name>

706

<value>104857600</value>

707

</property>

708

</configuration>

709

```