/** * 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.ArrayList; import java.util.List; import java.util.SortedMap; import org.apache.bookkeeper.net.BookieSocketAddress; /** * Represents the entries of a segment of a ledger which are stored on a single * bookie in the segments bookie ensemble. * * Used for checking and recovery */ public class LedgerFragment { private final int bookieIndex; private final List<BookieSocketAddress> ensemble; private final long firstEntryId; private final long lastKnownEntryId; private final long ledgerId; private final DistributionSchedule schedule; private final boolean isLedgerClosed; LedgerFragment(LedgerHandle lh, long firstEntryId, long lastKnownEntryId, int bookieIndex) { this.ledgerId = lh.getId(); this.firstEntryId = firstEntryId; this.lastKnownEntryId = lastKnownEntryId; this.bookieIndex = bookieIndex; this.ensemble = lh.getLedgerMetadata().getEnsemble(firstEntryId); this.schedule = lh.getDistributionSchedule(); SortedMap<Long, ArrayList<BookieSocketAddress>> ensembles = lh .getLedgerMetadata().getEnsembles(); this.isLedgerClosed = lh.getLedgerMetadata().isClosed() || !ensemble.equals(ensembles.get(ensembles.lastKey())); } /** * Returns true, if and only if the ledger fragment will never be modified * by any of the clients in future, otherwise false. i.e, * <ol> * <li>If ledger is in closed state, then no other clients can modify this * fragment.</li> * <li>If ledger is not in closed state and the current fragment is not a * last fragment, then no one will modify this fragment.</li> * </ol> */ public boolean isClosed() { return isLedgerClosed; } long getLedgerId() { return ledgerId; } long getFirstEntryId() { return firstEntryId; } long getLastKnownEntryId() { return lastKnownEntryId; } /** * Gets the failedBookie address */ public BookieSocketAddress getAddress() { return ensemble.get(bookieIndex); } /** * Gets the failedBookie index */ public int getBookiesIndex() { return bookieIndex; } /** * Gets the first stored entry id of the fragment in failed bookie. * * @return entryId */ public long getFirstStoredEntryId() { 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 = 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; } /** * Gets the ensemble of fragment * * @return the ensemble for the segment which this fragment is a part of */ public List<BookieSocketAddress> getEnsemble() { return this.ensemble; } @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(), getAddress(), isLedgerClosed); } }