org.apache.bookkeeper.client.LedgerFragment 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 java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.SortedMap;
import org.apache.bookkeeper.net.BookieId;
/**
* Represents the entries of a segment of a ledger which are stored on subset of
* bookies in the segments bookie ensemble.
*
* Used for checking and recovery
*/
public class LedgerFragment {
private final Set bookieIndexes;
private final List ensemble;
private final long firstEntryId;
private final long lastKnownEntryId;
private final long ledgerId;
private final DistributionSchedule schedule;
private final boolean isLedgerClosed;
private ReplicateType replicateType = ReplicateType.DATA_LOSS;
public LedgerFragment(LedgerHandle lh,
long firstEntryId,
long lastKnownEntryId,
Set bookieIndexes) {
this.ledgerId = lh.getId();
this.firstEntryId = firstEntryId;
this.lastKnownEntryId = lastKnownEntryId;
this.bookieIndexes = bookieIndexes;
this.ensemble = lh.getLedgerMetadata().getEnsembleAt(firstEntryId);
this.schedule = lh.getDistributionSchedule();
SortedMap> ensembles = lh
.getLedgerMetadata().getAllEnsembles();
// Check if the ledger fragment is closed has two conditions
// 1. The ledger is closed
// 2. This fragment is not the last fragment and this ledger's lastAddConfirm >= ensembles.lastKey() - 1.
// This case happens when the ledger's last ensemble is empty
this.isLedgerClosed = lh.getLedgerMetadata().isClosed()
|| (!ensemble.equals(ensembles.get(ensembles.lastKey()))
&& lh.getLastAddConfirmed() >= ensembles.lastKey() - 1);
}
public LedgerFragment(LedgerFragment lf, Set subset) {
this.ledgerId = lf.ledgerId;
this.firstEntryId = lf.firstEntryId;
this.lastKnownEntryId = lf.lastKnownEntryId;
this.bookieIndexes = subset;
this.ensemble = lf.ensemble;
this.schedule = lf.schedule;
this.isLedgerClosed = lf.isLedgerClosed;
}
/**
* Return a ledger fragment contains subset of bookies.
*
* @param subset
* subset of bookies.
* @return ledger fragment contains subset of bookies
*/
public LedgerFragment subset(Set subset) {
return new LedgerFragment(this, subset);
}
/**
* Returns true, if and only if the ledger fragment will never be modified
* by any of the clients in future, otherwise false. i.e,
*
* - If ledger is in closed state, then no other clients can modify this
* fragment.
* - If ledger is not in closed state and the current fragment is not a
* last fragment, then no one will modify this fragment.
*
*/
public boolean isClosed() {
return isLedgerClosed;
}
public long getLedgerId() {
return ledgerId;
}
public long getFirstEntryId() {
return firstEntryId;
}
public long getLastKnownEntryId() {
return lastKnownEntryId;
}
/**
* Gets the failedBookie address.
*/
public BookieId getAddress(int bookieIndex) {
return ensemble.get(bookieIndex);
}
public Set getAddresses() {
Set addresses = new HashSet();
for (int bookieIndex : bookieIndexes) {
addresses.add(ensemble.get(bookieIndex));
}
return addresses;
}
/**
* Gets the failedBookie index.
*/
public Set getBookiesIndexes() {
return bookieIndexes;
}
/**
* Gets the first stored entry id of the fragment in failed bookies.
*
* @return entryId
*/
public long getFirstStoredEntryId() {
long firstEntry = LedgerHandle.INVALID_ENTRY_ID;
for (int bookieIndex : bookieIndexes) {
Long firstStoredEntryForBookie = getFirstStoredEntryId(bookieIndex);
if (firstStoredEntryForBookie != LedgerHandle.INVALID_ENTRY_ID) {
if (firstEntry == LedgerHandle.INVALID_ENTRY_ID) {
firstEntry = firstStoredEntryForBookie;
} else {
firstEntry = Math.min(firstEntry, firstStoredEntryForBookie);
}
}
}
return firstEntry;
}
/**
* Get the first stored entry id of the fragment in the given failed bookies.
*
* @param bookieIndex
* the bookie index in the ensemble.
* @return first stored entry id on the bookie.
*/
public Long getFirstStoredEntryId(int bookieIndex) {
long firstEntry = firstEntryId;
for (int i = 0; i < ensemble.size() && firstEntry <= lastKnownEntryId; i++) {
if (schedule.hasEntry(firstEntry, bookieIndex)) {
return firstEntry;
} else {
firstEntry++;
}
}
return LedgerHandle.INVALID_ENTRY_ID;
}
/**
* Gets the last stored entry id of the fragment in failed bookie.
*
* @return entryId
*/
public long getLastStoredEntryId() {
long lastEntry = LedgerHandle.INVALID_ENTRY_ID;
for (int bookieIndex : bookieIndexes) {
Long lastStoredEntryIdForBookie = getLastStoredEntryId(bookieIndex);
if (lastStoredEntryIdForBookie != LedgerHandle.INVALID_ENTRY_ID) {
if (lastEntry == LedgerHandle.INVALID_ENTRY_ID) {
lastEntry = lastStoredEntryIdForBookie;
} else {
lastEntry = Math.max(lastEntry, lastStoredEntryIdForBookie);
}
}
}
return lastEntry;
}
/**
* Get the last stored entry id of the fragment in the given failed bookie.
*
* @param bookieIndex
* the bookie index in the ensemble.
* @return first stored entry id on the bookie.
*/
public Long getLastStoredEntryId(int bookieIndex) {
long lastEntry = lastKnownEntryId;
for (int i = 0; i < ensemble.size() && lastEntry >= firstEntryId; i++) {
if (schedule.hasEntry(lastEntry, bookieIndex)) {
return lastEntry;
} else {
lastEntry--;
}
}
return LedgerHandle.INVALID_ENTRY_ID;
}
public boolean isStoredEntryId(long entryId, int bookieIndex) {
return schedule.hasEntry(entryId, bookieIndex);
}
/**
* Gets the ensemble of fragment.
*
* @return the ensemble for the segment which this fragment is a part of
*/
public List getEnsemble() {
return this.ensemble;
}
public ReplicateType getReplicateType() {
return replicateType;
}
public void setReplicateType(ReplicateType replicateType) {
this.replicateType = replicateType;
}
@Override
public String toString() {
return String.format("Fragment(LedgerID: %d, FirstEntryID: %d[%d], "
+ "LastKnownEntryID: %d[%d], Host: %s, Closed: %s)", ledgerId, firstEntryId,
getFirstStoredEntryId(), lastKnownEntryId, getLastStoredEntryId(),
getAddresses(), isLedgerClosed);
}
/**
* ReplicateType.
*/
public enum ReplicateType {
DATA_LOSS,
DATA_NOT_ADHERING_PLACEMENT
}
}