All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.bookkeeper.client.LedgerMetadataImpl Maven / Gradle / Ivy

There is a newer version: 4.17.1
Show newest version
/*
 * 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 static com.google.common.base.Preconditions.checkArgument;

import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import java.util.Arrays;
import java.util.Base64;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
import java.util.Optional;
import java.util.TreeMap;
import java.util.stream.Collectors;
import lombok.EqualsAndHashCode;
import org.apache.bookkeeper.client.api.DigestType;
import org.apache.bookkeeper.client.api.LedgerMetadata;
import org.apache.bookkeeper.client.api.LedgerMetadata.State;
import org.apache.bookkeeper.net.BookieId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * This class encapsulates all the ledger metadata that is persistently stored
 * in metadata store.
 *
 * 

It provides parsing and serialization methods of such metadata. */ @EqualsAndHashCode(exclude = "ledgerId" // ledgerId is not serialized inside ZK node data ) class LedgerMetadataImpl implements LedgerMetadata { static final Logger LOG = LoggerFactory.getLogger(LedgerMetadataImpl.class); private final long ledgerId; private final int metadataFormatVersion; private final int ensembleSize; private final int writeQuorumSize; private final int ackQuorumSize; private final State state; private final long length; private final long lastEntryId; private final long ctime; final boolean storeCtime; // non-private so builder can access for copy private final NavigableMap> ensembles; private final ImmutableList currentEnsemble; private final boolean hasPassword; private final DigestType digestType; private final byte[] password; private final Map customMetadata; private long cToken; LedgerMetadataImpl(long ledgerId, int metadataFormatVersion, int ensembleSize, int writeQuorumSize, int ackQuorumSize, State state, Optional lastEntryId, Optional length, Map> ensembles, Optional digestType, Optional password, long ctime, boolean storeCtime, long cToken, Map customMetadata) { checkArgument(ensembles.size() > 0, "There must be at least one ensemble in the ledger"); if (state == State.CLOSED) { checkArgument(length.isPresent(), "Closed ledger must have a length"); checkArgument(lastEntryId.isPresent(), "Closed ledger must have a last entry"); } else { checkArgument(!length.isPresent(), "Non-closed ledger must not have a length"); checkArgument(!lastEntryId.isPresent(), "Non-closed ledger must not have a last entry"); } checkArgument((digestType.isPresent() && password.isPresent()) || (!digestType.isPresent() && !password.isPresent()), "Either both password and digest type must be set, or neither"); this.ledgerId = ledgerId; this.metadataFormatVersion = metadataFormatVersion; this.ensembleSize = ensembleSize; this.writeQuorumSize = writeQuorumSize; this.ackQuorumSize = ackQuorumSize; this.state = state; this.lastEntryId = lastEntryId.orElse(LedgerHandle.INVALID_ENTRY_ID); this.length = length.orElse(0L); this.ensembles = Collections.unmodifiableNavigableMap( ensembles.entrySet().stream().collect(TreeMap::new, (m, e) -> m.put(e.getKey(), ImmutableList.copyOf(e.getValue())), TreeMap::putAll)); if (state != State.CLOSED) { currentEnsemble = this.ensembles.lastEntry().getValue(); } else { currentEnsemble = null; } if (password.isPresent()) { this.password = password.get(); this.digestType = digestType.get(); this.hasPassword = true; } else { this.password = null; this.hasPassword = false; this.digestType = null; } this.ctime = ctime; this.storeCtime = storeCtime; this.cToken = cToken; this.customMetadata = ImmutableMap.copyOf(customMetadata); } @Override public long getLedgerId() { return ledgerId; } @Override public NavigableMap> getAllEnsembles() { return ensembles; } @Override public int getEnsembleSize() { return ensembleSize; } @Override public int getWriteQuorumSize() { return writeQuorumSize; } @Override public int getAckQuorumSize() { return ackQuorumSize; } @Override public long getCtime() { return ctime; } /** * In versions 4.1.0 and below, the digest type and password were not * stored in the metadata. * * @return whether the password has been stored in the metadata */ @Override public boolean hasPassword() { return hasPassword; } @Override public byte[] getPassword() { if (!hasPassword()) { return new byte[0]; } else { return Arrays.copyOf(password, password.length); } } @Override public DigestType getDigestType() { if (!hasPassword()) { return null; } else { return digestType; } } @Override public long getLastEntryId() { return lastEntryId; } @Override public long getLength() { return length; } @Override public boolean isClosed() { return state == State.CLOSED; } @Override public State getState() { return state; } @Override public List getEnsembleAt(long entryId) { // the head map cannot be empty, since we insert an ensemble for // entry-id 0, right when we start return ensembles.get(ensembles.headMap(entryId + 1).lastKey()); } @Override public Map getCustomMetadata() { return this.customMetadata; } @Override public String toString() { return toStringRepresentation(true); } /** * Returns a string representation of this LedgerMetadata object by * filtering out the password field. * * @return a string representation of the object without password field in * it. */ @Override public String toSafeString() { return toStringRepresentation(false); } private String toStringRepresentation(boolean withPassword) { MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper("LedgerMetadata"); helper.add("formatVersion", metadataFormatVersion) .add("ensembleSize", ensembleSize) .add("writeQuorumSize", writeQuorumSize) .add("ackQuorumSize", ackQuorumSize) .add("state", state); if (state == State.CLOSED) { helper.add("length", length) .add("lastEntryId", lastEntryId); } if (hasPassword()) { helper.add("digestType", digestType); if (withPassword) { helper.add("password", "base64:" + Base64.getEncoder().encodeToString(password)); } else { helper.add("password", "OMITTED"); } } helper.add("ensembles", ensembles.toString()); helper.add("customMetadata", customMetadata.entrySet().stream().collect( Collectors.toMap(e -> e.getKey(), e -> "base64:" + Base64.getEncoder().encodeToString(e.getValue())))); return helper.toString(); } @Override public int getMetadataFormatVersion() { return metadataFormatVersion; } boolean shouldStoreCtime() { return storeCtime; } @Override public long getCToken() { return cToken; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy