blob: d358ffbec2ecadef0e7becc4ff3f28d96ec4b982 [file] [log] [blame]
package org.apache.bookkeeper.meta;
/**
* 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.
*/
import java.io.IOException;
import org.apache.bookkeeper.util.BookKeeperConstants;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class encapsulates ledger layout information that is persistently stored
* in zookeeper. It provides parsing and serialization methods of such information.
*
*/
class LedgerLayout {
static final Logger LOG = LoggerFactory.getLogger(LedgerLayout.class);
// version of compability layout version
public static final int LAYOUT_MIN_COMPAT_VERSION = 1;
// version of ledger layout metadata
public static final int LAYOUT_FORMAT_VERSION = 2;
/**
* Read ledger layout from zookeeper
*
* @param zk ZooKeeper Client
* @param ledgersRoot Root of the ledger namespace to check
* @return ledger layout, or null if none set in zookeeper
*/
public static LedgerLayout readLayout(final ZooKeeper zk, final String ledgersRoot)
throws IOException, KeeperException {
String ledgersLayout = ledgersRoot + "/" + BookKeeperConstants.LAYOUT_ZNODE;
try {
LedgerLayout layout;
try {
byte[] layoutData = zk.getData(ledgersLayout, false, null);
layout = parseLayout(layoutData);
} catch (KeeperException.NoNodeException nne) {
return null;
}
return layout;
} catch (InterruptedException ie) {
throw new IOException(ie);
}
}
static final String splitter = ":";
static final String lSplitter = "\n";
// ledger manager factory class
private String managerFactoryCls;
// ledger manager version
private int managerVersion;
// layout version of how to store layout information
private int layoutFormatVersion = LAYOUT_FORMAT_VERSION;
/**
* Ledger Layout Constructor
*
* @param managerFactoryCls
* Ledger Manager Factory Class
* @param managerVersion
* Ledger Manager Version
* @param layoutFormatVersion
* Ledger Layout Format Version
*/
public LedgerLayout(String managerFactoryCls, int managerVersion) {
this(managerFactoryCls, managerVersion, LAYOUT_FORMAT_VERSION);
}
LedgerLayout(String managerFactoryCls, int managerVersion,
int layoutVersion) {
this.managerFactoryCls = managerFactoryCls;
this.managerVersion = managerVersion;
this.layoutFormatVersion = layoutVersion;
}
/**
* Get Ledger Manager Type
*
* @return ledger manager type
* @deprecated replaced by {@link #getManagerFactoryClass()}
*/
@Deprecated
public String getManagerType() {
// pre V2 layout store as manager type
return this.managerFactoryCls;
}
/**
* Get ledger manager factory class
*
* @return ledger manager factory class
*/
public String getManagerFactoryClass() {
return this.managerFactoryCls;
}
public int getManagerVersion() {
return this.managerVersion;
}
/**
* Return layout format version
*
* @return layout format version
*/
public int getLayoutFormatVersion() {
return this.layoutFormatVersion;
}
/**
* Store the ledger layout into zookeeper
*/
public void store(final ZooKeeper zk, String ledgersRoot)
throws IOException, KeeperException, InterruptedException {
String ledgersLayout = ledgersRoot + "/"
+ BookKeeperConstants.LAYOUT_ZNODE;
zk.create(ledgersLayout, serialize(), Ids.OPEN_ACL_UNSAFE,
CreateMode.PERSISTENT);
}
/**
* Delete the LAYOUT from zookeeper
*/
public void delete(final ZooKeeper zk, String ledgersRoot)
throws KeeperException, InterruptedException {
String ledgersLayout = ledgersRoot + "/"
+ BookKeeperConstants.LAYOUT_ZNODE;
zk.delete(ledgersLayout, -1);
}
/**
* Generates a byte array based on the LedgerLayout object.
*
* @return byte[]
*/
private byte[] serialize() throws IOException {
String s =
new StringBuilder().append(layoutFormatVersion).append(lSplitter)
.append(managerFactoryCls).append(splitter).append(managerVersion).toString();
LOG.debug("Serialized layout info: {}", s);
return s.getBytes("UTF-8");
}
/**
* Parses a given byte array and transforms into a LedgerLayout object
*
* @param bytes
* byte array to parse
* @param znodeVersion
* version of znode
* @return LedgerLayout
* @throws IOException
* if the given byte[] cannot be parsed
*/
private static LedgerLayout parseLayout(byte[] bytes) throws IOException {
String layout = new String(bytes, "UTF-8");
LOG.debug("Parsing Layout: {}", layout);
String lines[] = layout.split(lSplitter);
try {
int layoutFormatVersion = new Integer(lines[0]);
if (LAYOUT_FORMAT_VERSION < layoutFormatVersion ||
LAYOUT_MIN_COMPAT_VERSION > layoutFormatVersion) {
throw new IOException("Metadata version not compatible. Expected "
+ LAYOUT_FORMAT_VERSION + ", but got " + layoutFormatVersion);
}
if (lines.length < 2) {
throw new IOException("Ledger manager and its version absent from layout: " + layout);
}
String[] parts = lines[1].split(splitter);
if (parts.length != 2) {
throw new IOException("Invalid Ledger Manager defined in layout : " + layout);
}
// ledger manager factory class
String managerFactoryCls = parts[0];
// ledger manager version
int managerVersion = new Integer(parts[1]);
return new LedgerLayout(managerFactoryCls, managerVersion, layoutFormatVersion);
} catch (NumberFormatException e) {
throw new IOException("Could not parse layout '" + layout + "'", e);
}
}
@Override
public boolean equals(Object obj) {
if (null == obj) {
return false;
}
if (!(obj instanceof LedgerLayout)) {
return false;
}
LedgerLayout other = (LedgerLayout)obj;
return managerFactoryCls.equals(other.managerFactoryCls)
&& managerVersion == other.managerVersion;
}
@Override
public int hashCode() {
return (managerFactoryCls + managerVersion).hashCode();
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("LV").append(layoutFormatVersion).append(":")
.append(",Type:").append(managerFactoryCls).append(":")
.append(managerVersion);
return sb.toString();
}
}