Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.apache.bookkeeper.client.LedgerCreateOp Maven / Gradle / Ivy
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.apache.bookkeeper.client;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.security.GeneralSecurityException;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.apache.bookkeeper.client.AsyncCallback.CreateCallback;
import org.apache.bookkeeper.client.BKException.BKNotEnoughBookiesException;
import org.apache.bookkeeper.client.BookKeeper.DigestType;
import org.apache.bookkeeper.client.SyncCallbackUtils.SyncCreateAdvCallback;
import org.apache.bookkeeper.client.SyncCallbackUtils.SyncCreateCallback;
import org.apache.bookkeeper.client.api.CreateAdvBuilder;
import org.apache.bookkeeper.client.api.CreateBuilder;
import org.apache.bookkeeper.client.api.LedgerMetadata;
import org.apache.bookkeeper.client.api.WriteAdvHandle;
import org.apache.bookkeeper.client.api.WriteFlag;
import org.apache.bookkeeper.client.api.WriteHandle;
import org.apache.bookkeeper.meta.LedgerIdGenerator;
import org.apache.bookkeeper.net.BookieId;
import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.GenericCallback;
import org.apache.bookkeeper.stats.OpStatsLogger;
import org.apache.bookkeeper.util.MathUtils;
import org.apache.bookkeeper.versioning.Versioned;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Encapsulates asynchronous ledger create operation.
*
*/
class LedgerCreateOp {
static final Logger LOG = LoggerFactory.getLogger(LedgerCreateOp.class);
final CreateCallback cb;
LedgerMetadata metadata;
LedgerHandle lh;
long ledgerId = -1L;
final Object ctx;
final int ensembleSize;
final int writeQuorumSize;
final int ackQuorumSize;
final Map customMetadata;
final int metadataFormatVersion;
final byte[] passwd;
final BookKeeper bk;
final DigestType digestType;
final EnumSet writeFlags;
final long startTime;
final OpStatsLogger createOpLogger;
final BookKeeperClientStats clientStats;
boolean adv = false;
boolean generateLedgerId = true;
/**
* Constructor.
*
* @param bk
* BookKeeper object
* @param ensembleSize
* ensemble size
* @param writeQuorumSize
* write quorum size
* @param ackQuorumSize
* ack quorum size
* @param digestType
* digest type, either MAC or CRC32
* @param passwd
* password
* @param cb
* callback implementation
* @param ctx
* optional control object
* @param customMetadata
* A map of user specified custom metadata about the ledger to be persisted; will not try to
* preserve the order(e.g. sortedMap) upon later retireval.
*/
LedgerCreateOp(
BookKeeper bk, int ensembleSize, int writeQuorumSize, int ackQuorumSize, DigestType digestType,
byte[] passwd, CreateCallback cb, Object ctx, final Map customMetadata,
EnumSet writeFlags,
BookKeeperClientStats clientStats) {
this.bk = bk;
this.metadataFormatVersion = bk.getConf().getLedgerMetadataFormatVersion();
this.ensembleSize = ensembleSize;
this.writeQuorumSize = writeQuorumSize;
this.ackQuorumSize = ackQuorumSize;
this.digestType = digestType;
this.customMetadata = customMetadata;
this.writeFlags = writeFlags;
this.passwd = passwd;
this.cb = cb;
this.ctx = ctx;
this.startTime = MathUtils.nowInNano();
this.createOpLogger = clientStats.getCreateOpLogger();
this.clientStats = clientStats;
}
/**
* Initiates the operation.
*/
public void initiate() {
int actualEnsembleSize = ensembleSize;
List ensemble = null;
// select bookies for first ensemble
if (bk.getConf().getOpportunisticStriping()) {
BKNotEnoughBookiesException lastError = null;
// we would like to select ensembleSize bookies, but
// we can settle to writeQuorumSize
while (actualEnsembleSize >= writeQuorumSize) {
try {
ensemble = bk.getBookieWatcher()
.newEnsemble(actualEnsembleSize, writeQuorumSize, ackQuorumSize, customMetadata);
lastError = null;
break;
} catch (BKNotEnoughBookiesException e) {
if (actualEnsembleSize >= writeQuorumSize + 1) {
LOG.info("Not enough bookies to create ledger with ensembleSize={},"
+ " writeQuorumSize={} and ackQuorumSize={}, opportusticStriping enabled, try again",
actualEnsembleSize, writeQuorumSize, ackQuorumSize);
}
lastError = e;
actualEnsembleSize--;
}
}
if (lastError != null) {
LOG.error("Not enough bookies to create ledger with ensembleSize={},"
+ " writeQuorumSize={} and ackQuorumSize={}",
actualEnsembleSize, writeQuorumSize, ackQuorumSize);
createComplete(lastError.getCode(), null);
return;
}
} else {
try {
ensemble = bk.getBookieWatcher()
.newEnsemble(actualEnsembleSize, writeQuorumSize, ackQuorumSize, customMetadata);
} catch (BKNotEnoughBookiesException e) {
LOG.error("Not enough bookies to create ledger with ensembleSize={},"
+ " writeQuorumSize={} and ackQuorumSize={}",
actualEnsembleSize, writeQuorumSize, ackQuorumSize);
createComplete(e.getCode(), null);
return;
}
}
LedgerMetadataBuilder metadataBuilder = LedgerMetadataBuilder.create()
.withEnsembleSize(actualEnsembleSize).withWriteQuorumSize(writeQuorumSize).withAckQuorumSize(ackQuorumSize)
.withDigestType(digestType.toApiDigestType()).withPassword(passwd);
metadataBuilder.newEnsembleEntry(0L, ensemble);
if (customMetadata != null) {
metadataBuilder.withCustomMetadata(customMetadata);
}
metadataBuilder.withMetadataFormatVersion(metadataFormatVersion);
if (bk.getConf().getStoreSystemtimeAsLedgerCreationTime()) {
metadataBuilder.withCreationTime(System.currentTimeMillis()).storingCreationTime(true);
}
if (this.generateLedgerId) {
generateLedgerIdAndCreateLedger(metadataBuilder);
} else {
this.metadata = metadataBuilder.withId(ledgerId).build();
// Create ledger with supplied ledgerId
bk.getLedgerManager().createLedgerMetadata(ledgerId, metadata)
.whenComplete((written, exception) -> metadataCallback(written, exception, metadataBuilder));
}
}
void generateLedgerIdAndCreateLedger(LedgerMetadataBuilder metadataBuilder) {
// generate a ledgerId
final LedgerIdGenerator ledgerIdGenerator = bk.getLedgerIdGenerator();
ledgerIdGenerator.generateLedgerId(new GenericCallback() {
@Override
public void operationComplete(int rc, Long ledgerId) {
if (BKException.Code.OK != rc) {
createComplete(rc, null);
return;
}
LedgerCreateOp.this.ledgerId = ledgerId;
LedgerCreateOp.this.metadata = metadataBuilder.withId(ledgerId).build();
// create a ledger with metadata
bk.getLedgerManager().createLedgerMetadata(ledgerId, metadata)
.whenComplete((written, exception) -> metadataCallback(written, exception, metadataBuilder));
}
});
}
/**
* Initiates the operation to return LedgerHandleAdv.
*/
public void initiateAdv(final long ledgerId) {
this.adv = true;
this.ledgerId = ledgerId;
if (this.ledgerId != -1L) {
this.generateLedgerId = false;
}
initiate();
}
/**
* Callback when metadata store has responded.
*/
private void metadataCallback(Versioned writtenMetadata,
Throwable exception, LedgerMetadataBuilder metadataBuilder) {
if (exception != null) {
if (this.generateLedgerId
&& (BKException.getExceptionCode(exception) == BKException.Code.LedgerExistException)) {
// retry to generate a new ledger id
generateLedgerIdAndCreateLedger(metadataBuilder);
} else {
createComplete(BKException.getExceptionCode(exception), null);
}
} else {
try {
if (adv) {
lh = new LedgerHandleAdv(bk.getClientCtx(), ledgerId, writtenMetadata,
digestType, passwd, writeFlags);
} else {
lh = new LedgerHandle(bk.getClientCtx(), ledgerId, writtenMetadata, digestType, passwd, writeFlags);
}
} catch (GeneralSecurityException e) {
LOG.error("Security exception while creating ledger: " + ledgerId, e);
createComplete(BKException.Code.DigestNotInitializedException, null);
return;
} catch (NumberFormatException e) {
LOG.error("Incorrectly entered parameter throttle: " + bk.getConf().getThrottleValue(), e);
createComplete(BKException.Code.IncorrectParameterException, null);
return;
}
List curEns = lh.getLedgerMetadata().getEnsembleAt(0L);
LOG.info("Ensemble: {} for ledger: {}", curEns, lh.getId());
for (BookieId bsa : curEns) {
clientStats.getEnsembleBookieDistributionCounter(bsa.toString()).inc();
}
// return the ledger handle back
createComplete(BKException.Code.OK, lh);
}
}
private void createComplete(int rc, LedgerHandle lh) {
// Opened a new ledger
if (BKException.Code.OK != rc) {
createOpLogger.registerFailedEvent(MathUtils.elapsedNanos(startTime), TimeUnit.NANOSECONDS);
} else {
createOpLogger.registerSuccessfulEvent(MathUtils.elapsedNanos(startTime), TimeUnit.NANOSECONDS);
}
if (lh != null) { // lh is null in case of errors
lh.executeOrdered(() -> cb.createComplete(rc, lh, ctx));
} else {
cb.createComplete(rc, null, ctx);
}
}
public static class CreateBuilderImpl implements CreateBuilder {
private final BookKeeper bk;
private int builderEnsembleSize = 3;
private int builderAckQuorumSize = 2;
private int builderWriteQuorumSize = 2;
private byte[] builderPassword;
private EnumSet builderWriteFlags = WriteFlag.NONE;
private org.apache.bookkeeper.client.api.DigestType builderDigestType =
org.apache.bookkeeper.client.api.DigestType.CRC32;
private Map builderCustomMetadata = Collections.emptyMap();
CreateBuilderImpl(BookKeeper bk) {
this.bk = bk;
}
@Override
public CreateBuilder withEnsembleSize(int ensembleSize) {
this.builderEnsembleSize = ensembleSize;
return this;
}
@Override
public CreateBuilder withWriteFlags(EnumSet writeFlags) {
this.builderWriteFlags = writeFlags;
return this;
}
@Override
public CreateBuilder withWriteQuorumSize(int writeQuorumSize) {
this.builderWriteQuorumSize = writeQuorumSize;
return this;
}
@Override
public CreateBuilder withAckQuorumSize(int ackQuorumSize) {
this.builderAckQuorumSize = ackQuorumSize;
return this;
}
@SuppressFBWarnings("EI_EXPOSE_REP2")
@Override
public CreateBuilder withPassword(byte[] password) {
this.builderPassword = password;
return this;
}
@Override
public CreateBuilder withCustomMetadata(Map customMetadata) {
this.builderCustomMetadata = customMetadata;
return this;
}
@Override
public CreateBuilder withDigestType(org.apache.bookkeeper.client.api.DigestType digestType) {
this.builderDigestType = digestType;
return this;
}
@Override
public CreateAdvBuilder makeAdv() {
return new CreateAdvBuilderImpl(this);
}
private boolean validate() {
if (builderWriteFlags == null) {
LOG.error("invalid null writeFlags");
return false;
}
if (builderWriteQuorumSize > builderEnsembleSize) {
LOG.error("invalid writeQuorumSize {} > ensembleSize {}", builderWriteQuorumSize, builderEnsembleSize);
return false;
}
if (builderAckQuorumSize > builderWriteQuorumSize) {
LOG.error("invalid ackQuorumSize {} > writeQuorumSize {}", builderAckQuorumSize,
builderWriteQuorumSize);
return false;
}
if (builderAckQuorumSize <= 0) {
LOG.error("invalid ackQuorumSize {} <= 0", builderAckQuorumSize);
return false;
}
if (builderPassword == null) {
LOG.error("invalid null password");
return false;
}
if (builderDigestType == null) {
LOG.error("invalid null digestType");
return false;
}
if (builderCustomMetadata == null) {
LOG.error("invalid null customMetadata");
return false;
}
return true;
}
@Override
public CompletableFuture execute() {
CompletableFuture future = new CompletableFuture<>();
SyncCreateCallback callback = new SyncCreateCallback(future);
create(callback);
return future;
}
private void create(CreateCallback cb) {
if (!validate()) {
cb.createComplete(BKException.Code.IncorrectParameterException, null, null);
return;
}
LedgerCreateOp op = new LedgerCreateOp(bk, builderEnsembleSize,
builderWriteQuorumSize, builderAckQuorumSize, DigestType.fromApiDigestType(builderDigestType),
builderPassword, cb, null, builderCustomMetadata, builderWriteFlags,
bk.getClientCtx().getClientStats());
ReentrantReadWriteLock closeLock = bk.getCloseLock();
closeLock.readLock().lock();
try {
if (bk.isClosed()) {
cb.createComplete(BKException.Code.ClientClosedException, null, null);
return;
}
op.initiate();
} finally {
closeLock.readLock().unlock();
}
}
}
private static class CreateAdvBuilderImpl implements CreateAdvBuilder {
private Long builderLedgerId;
private final CreateBuilderImpl parent;
private CreateAdvBuilderImpl(CreateBuilderImpl parent) {
this.parent = parent;
}
@Override
public CreateAdvBuilder withLedgerId(long ledgerId) {
builderLedgerId = ledgerId;
return this;
}
@Override
public CompletableFuture execute() {
CompletableFuture future = new CompletableFuture<>();
SyncCreateAdvCallback callback = new SyncCreateAdvCallback(future);
create(callback);
return future;
}
private boolean validate() {
if (!parent.validate()) {
return false;
}
if (builderLedgerId != null && builderLedgerId < 0) {
LOG.error("invalid ledgerId {} < 0. Do not set en explicit value if you want automatic generation",
builderLedgerId);
return false;
}
return true;
}
private void create(CreateCallback cb) {
if (!validate()) {
cb.createComplete(BKException.Code.IncorrectParameterException, null, null);
return;
}
LedgerCreateOp op = new LedgerCreateOp(parent.bk, parent.builderEnsembleSize,
parent.builderWriteQuorumSize, parent.builderAckQuorumSize,
DigestType.fromApiDigestType(parent.builderDigestType),
parent.builderPassword, cb, null, parent.builderCustomMetadata,
parent.builderWriteFlags,
parent.bk.getClientCtx().getClientStats());
ReentrantReadWriteLock closeLock = parent.bk.getCloseLock();
closeLock.readLock().lock();
try {
if (parent.bk.isClosed()) {
cb.createComplete(BKException.Code.ClientClosedException, null, null);
return;
}
op.initiateAdv(builderLedgerId == null ? -1L : builderLedgerId);
} finally {
closeLock.readLock().unlock();
}
}
}
}