You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by dp...@apache.org on 2007/01/11 15:40:01 UTC
svn commit: r495239 [2/2] -
/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/FileRecordLog.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/FileRecordLog.java?view=diff&rev=495239&r1=495238&r2=495239
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/FileRecordLog.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/FileRecordLog.java Thu Jan 11 06:40:00 2007
@@ -16,6 +16,9 @@
*/
package org.apache.jackrabbit.core.cluster;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import java.io.File;
import java.io.DataInputStream;
import java.io.IOException;
@@ -23,14 +26,43 @@
import java.io.BufferedInputStream;
import java.io.DataOutputStream;
import java.io.FileOutputStream;
+import java.io.InputStream;
/**
- * A file record log is a file containing {@link FileRecord}s. Internally,
- * the first 8 bytes contain the revision this log starts with.
+ * A file record log is a file containing {@link FileRecord}s. Physically,
+ * the first 4 bytes contain a signature, followed by a major and minor version
+ * (2 bytes each). The next 8 bytes contain the revision this log starts with.
+ * After this, zero or more <code>FileRecord</code>s follow.
*/
class FileRecordLog {
/**
+ * Logger.
+ */
+ private static Logger log = LoggerFactory.getLogger(FileRecordLog.class);
+
+ /**
+ * Record log signature.
+ */
+ private static final byte[] SIGNATURE = { 'J', 'L', 'O', 'G' };
+
+ /**
+ * Known major version.
+ */
+ private static final short MAJOR_VERSION = 1;
+
+ /**
+ * Known minor version.
+ */
+ private static final short MINOR_VERSION = 0;
+
+ /**
+ * Header size. This is the size of {@link #SIGNATURE}, {@link #MAJOR_VERSION},
+ * {@link #MINOR_VERSION} and first revision (8 bytes).
+ */
+ private static final int HEADER_SIZE = 4 + 2 + 2 + 8;
+
+ /**
* Underlying file.
*/
private File file;
@@ -68,8 +100,9 @@
DataInputStream in = new DataInputStream(new FileInputStream(file));
try {
+ readHeader(in);
minRevision = in.readLong();
- maxRevision = minRevision + file.length() - 8;
+ maxRevision = minRevision + file.length() - HEADER_SIZE;
} finally {
in.close();
}
@@ -117,12 +150,23 @@
*/
public void seek(long revision) throws IOException {
if (in != null) {
- String msg = "Seek allowed exactly once.";
+ String msg = "Stream already open: seek() only allowed once.";
throw new IllegalStateException(msg);
}
- open();
+ in = new DataInputStream(new BufferedInputStream(
+ new FileInputStream(file)));
+ skip(revision - minRevision + HEADER_SIZE);
+ }
- long skiplen = revision - minRevision + 8;
+ /**
+ * Skip exactly <code>n</code> bytes. Throws if less bytes are skipped.
+ *
+ * @param n bytes to skip
+ * @throws IOException if an I/O error occurs, or less that <code>n</code> bytes
+ * were skipped.
+ */
+ private void skip(long n) throws IOException {
+ long skiplen = n;
while (skiplen > 0) {
long skipped = in.skip(skiplen);
if (skipped <= 0) {
@@ -137,54 +181,143 @@
}
/**
- * Append a record to this log.
+ * Read the file record at the current seek position.
+ *
+ * @return file record
+ * @throws IOException if an I/O error occurs
+ */
+ public FileRecord read() throws IOException {
+ byte[] creator = new byte[in.readUnsignedShort()];
+ in.readFully(creator);
+ int length = in.readInt();
+ return new FileRecord(creator, length, in);
+ }
+
+ /**
+ * Append a record to this log. Returns the revision following this record.
*
* @param record record to add
+ * @return next available revision
* @throws IOException if an I/O error occurs
*/
- public void append(FileRecord record) throws IOException {
+ public long append(long revision, byte[] creator, File record) throws IOException {
DataOutputStream out = new DataOutputStream(new FileOutputStream(file, true));
try {
+ int recordLength = (int) record.length();
if (isNew) {
- out.writeLong(record.getRevision());
+ writeHeader(out);
+ out.writeLong(revision);
}
- record.append(out);
+ out.writeShort(creator.length);
+ out.write(creator);
+ out.writeInt(recordLength);
+ append(record, out);
+ return revision + getRecordSize(creator, recordLength);
} finally {
out.close();
}
}
/**
- * Open this log.
- *
- * @throws IOException if an I/O error occurs
+ * Close this log.
*/
- private void open() throws IOException {
- in = new DataInputStream(new BufferedInputStream(
- new FileInputStream(file)));
+ public void close() {
+ try {
+ if (in != null) {
+ in.close();
+ }
+ } catch (IOException e) {
+ String msg = "Error while closing record log: " + e.getMessage();
+ log.warn(msg);
+ }
}
/**
- * Return the underlying input stream.
+ * Return the size of a stored record . A stored record's size is the size of
+ * the length-prefixed creator string plus the size of the length-prefixed data.
*
- * @return underlying input stream
+ * @param creator creator string
+ * @param length data length
+ * @return size of a stored record
*/
- protected DataInputStream getInputStream() {
- if (in == null) {
- String msg = "Input stream not open.";
- throw new IllegalStateException(msg);
+ public static int getRecordSize(byte[] creator, int length) {
+ return 2 + creator.length + 4 + length;
+ }
+
+ /**
+ * Read signature and major/minor version of file and verify.
+ *
+ * @param in input stream
+ * @throws IOException if an I/O error occurs or the file does
+ * not have a valid header.
+ */
+ private void readHeader(DataInputStream in) throws IOException {
+ byte[] signature = new byte[SIGNATURE.length];
+ in.readFully(signature);
+
+ for (int i = 0; i < SIGNATURE.length; i++) {
+ if (signature[i] != SIGNATURE[i]) {
+ String msg = "Record log '" + file.getPath() +
+ "' has wrong signature: " + toHexString(signature);
+ throw new IOException(msg);
+ }
+ }
+
+ short major = in.readShort();
+ in.readShort(); // minor version not used yet
+
+ if (major > MAJOR_VERSION) {
+ String msg = "Record log '" + file.getPath() +
+ "' has incompatible major version: " + major;
+ throw new IOException(msg);
}
- return in;
}
/**
- * Close this log.
+ * Write signature and major/minor.
*
- * @throws IOException if an I/O error occurs
+ * @param out input stream
+ * @throws IOException if an I/O error occurs.
*/
- public void close() throws IOException {
- if (in != null) {
+ private void writeHeader(DataOutputStream out) throws IOException {
+ out.write(SIGNATURE);
+ out.writeShort(MAJOR_VERSION);
+ out.writeShort(MINOR_VERSION);
+ }
+
+ /**
+ * Append a record to this log's output stream.
+ *
+ * @param record record to append
+ * @param out where to append to
+ */
+ private static void append(File record, DataOutputStream out) throws IOException {
+ byte[] buffer = new byte[8192];
+ int len;
+
+ InputStream in = new BufferedInputStream(new FileInputStream(record));
+ try {
+ while ((len = in.read(buffer)) > 0) {
+ out.write(buffer, 0, len);
+ }
+ out.flush();
+ } finally {
in.close();
}
+ }
+
+ /**
+ * Convert a byte array to its hexadecimal string representation.
+ */
+ private static String toHexString(byte[] b) {
+ StringBuffer buf = new StringBuffer();
+ for (int i = 0; i < b.length; i++) {
+ String s = Integer.toHexString(b[i] & 0xff).toUpperCase();
+ if (s.length() == 1) {
+ buf.append('0');
+ }
+ buf.append(s);
+ }
+ return buf.toString();
}
}
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/FileRevision.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/FileRevision.java?view=diff&rev=495239&r1=495238&r2=495239
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/FileRevision.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/FileRevision.java Thu Jan 11 06:40:00 2007
@@ -133,7 +133,7 @@
lock(true);
try {
- long value = 0;
+ long value = 0L;
if (raf.length() > 0) {
raf.seek(0L);
value = raf.readLong();
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/Record.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/Record.java?view=auto&rev=495239
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/Record.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/Record.java Thu Jan 11 06:40:00 2007
@@ -0,0 +1,34 @@
+/*
+ * 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.jackrabbit.core.cluster;
+
+/**
+ * Contains definitions common to both <code>RecordInput</code> and
+ * <code>RecordOutput</code>.
+ */
+interface Record {
+
+ /**
+ * Indicator for a literal UUID.
+ */
+ public static final byte UUID_LITERAL = 'L';
+
+ /**
+ * Indicator for a UUID index.
+ */
+ public static final byte UUID_INDEX = 'I';
+}
\ No newline at end of file
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/RecordInput.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/RecordInput.java?view=auto&rev=495239
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/RecordInput.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/RecordInput.java Thu Jan 11 06:40:00 2007
@@ -0,0 +1,266 @@
+/*
+ * 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.jackrabbit.core.cluster;
+
+import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.core.PropertyId;
+import org.apache.jackrabbit.core.nodetype.NodeTypeDef;
+import org.apache.jackrabbit.core.nodetype.compact.CompactNodeTypeDefReader;
+import org.apache.jackrabbit.core.nodetype.compact.ParseException;
+import org.apache.jackrabbit.name.NameException;
+import org.apache.jackrabbit.name.NamespaceResolver;
+import org.apache.jackrabbit.name.QName;
+import org.apache.jackrabbit.name.NameFormat;
+import org.apache.jackrabbit.name.Path;
+import org.apache.jackrabbit.name.PathFormat;
+import org.apache.jackrabbit.name.MalformedPathException;
+import org.apache.jackrabbit.uuid.Constants;
+import org.apache.jackrabbit.uuid.UUID;
+
+import java.io.IOException;
+import java.io.DataInputStream;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Allows reading data from a <code>DataInputStream</code>.
+ */
+class RecordInput {
+
+ /**
+ * Underlying input stream.
+ */
+ private final DataInputStream in;
+
+ /**
+ * Name resolver.
+ */
+ private final NamespaceResolver resolver;
+
+ /**
+ * UUID index.
+ */
+ private final ArrayList uuidIndex = new ArrayList();
+
+ /**
+ * Flag indicating whether this input is closed.
+ */
+ private boolean closed;
+
+ /**
+ * Open an existing file record.
+ *
+ * @param in underlying input stream
+ * @param resolver namespace resolver
+ */
+ public RecordInput(DataInputStream in, NamespaceResolver resolver) {
+ this.in = in;
+ this.resolver = resolver;
+ }
+
+ /**
+ * Read a byte from the underlying stream.
+ *
+ * @return byte
+ * @throws IOException if an I/O error occurs
+ */
+ public byte readByte() throws IOException {
+ checkOpen();
+
+ return in.readByte();
+ }
+
+ /**
+ * Read a character from the underlying stream.
+ *
+ * @return character
+ * @throws IOException if an I/O error occurs
+ */
+ public char readChar() throws IOException {
+ checkOpen();
+
+ return in.readChar();
+ }
+
+ /**
+ * Read a boolean from the underlying stream.
+ *
+ * @return boolean
+ * @throws IOException if an I/O error occurs
+ */
+ public boolean readBoolean() throws IOException {
+ checkOpen();
+
+ return in.readBoolean();
+ }
+
+ /**
+ * Read an integer from the underlying stream.
+ *
+ * @return integer
+ * @throws IOException if an I/O error occurs
+ */
+ public int readInt() throws IOException {
+ checkOpen();
+
+ return in.readInt();
+ }
+
+ /**
+ * Read a string from the underlying stream.
+ *
+ * @return string or <code>null</code>
+ * @throws IOException if an I/O error occurs
+ */
+ public String readString() throws IOException {
+ checkOpen();
+
+ boolean isNull = in.readBoolean();
+ if (isNull) {
+ return null;
+ } else {
+ return in.readUTF();
+ }
+ }
+
+ /**
+ * Read a <code>QName</code>.
+ *
+ * @return name
+ * @throws IOException if an I/O error occurs
+ * @throws NameException if the name retrieved is illegal
+ */
+ public QName readQName() throws IOException, NameException {
+ checkOpen();
+
+ return NameFormat.parse(readString(), resolver);
+ }
+
+ /**
+ * Read a <code>PathElement</code>.
+ *
+ * @return path element
+ * @throws IOException if an I/O error occurs
+ * @throws NameException if the name retrieved is illegal
+ */
+ public Path.PathElement readPathElement() throws IOException, NameException {
+ checkOpen();
+
+ QName name = NameFormat.parse(readString(), resolver);
+ int index = readInt();
+ if (index != 0) {
+ return Path.PathElement.create(name, index);
+ } else {
+ return Path.PathElement.create(name);
+ }
+ }
+
+ /**
+ * Read a <code>Path</code>.
+ *
+ * @return path
+ * @throws IOException if an I/O error occurs
+ * @throws MalformedPathException if the path is malformed
+ */
+ public Path readPath() throws IOException, MalformedPathException {
+ checkOpen();
+
+ return PathFormat.parse(readString(), resolver);
+ }
+
+ /**
+ * Read a <code>NodeId</code>
+ *
+ * @return node id
+ * @throws IOException if an I/O error occurs
+ */
+ public NodeId readNodeId() throws IOException {
+ checkOpen();
+
+ byte uuidType = readByte();
+ if (uuidType == Record.UUID_INDEX) {
+ int index = readInt();
+ if (index == -1) {
+ return null;
+ } else {
+ return (NodeId) uuidIndex.get(index);
+ }
+ } else if (uuidType == Record.UUID_LITERAL) {
+ byte[] b = new byte[Constants.UUID_BYTE_LENGTH];
+ in.readFully(b);
+ NodeId nodeId = new NodeId(new UUID(b));
+ uuidIndex.add(nodeId);
+ return nodeId;
+ } else {
+ String msg = "UUID type unknown: " + uuidType;
+ throw new IOException(msg);
+ }
+ }
+
+ /**
+ * Read a <code>PropertyId</code>
+ *
+ * @return property id
+ * @throws IOException if an I/O error occurs
+ * @throws NameException if the name retrieved is illegal
+ */
+ public PropertyId readPropertyId() throws IOException, NameException {
+ checkOpen();
+
+ return new PropertyId(readNodeId(), readQName());
+ }
+
+ /**
+ * Read a <code>NodeTypeDef</code>
+ */
+ public NodeTypeDef readNodeTypeDef() throws IOException, ParseException {
+ checkOpen();
+
+ StringReader sr = new StringReader(readString());
+
+ CompactNodeTypeDefReader reader = new CompactNodeTypeDefReader(sr, "(internal)");
+ List ntds = reader.getNodeTypeDefs();
+ if (ntds.size() != 1) {
+ throw new IOException("Expected one node type definition: got " + ntds.size());
+ }
+ return (NodeTypeDef) ntds.get(0);
+ }
+
+
+
+ /**
+ * Close this input. Does not close underlying stream as this is a shared resource.
+ */
+ public void close() {
+ checkOpen();
+
+ closed = true;
+ }
+
+ /**
+ * Check that this input is open, throw otherwise.
+ *
+ * @throws IllegalStateException if input is closed.
+ */
+ private void checkOpen() throws IllegalStateException {
+ if (closed) {
+ throw new IllegalStateException("Input closed.");
+ }
+ }
+
+}
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/RecordOutput.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/RecordOutput.java?view=auto&rev=495239
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/RecordOutput.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/RecordOutput.java Thu Jan 11 06:40:00 2007
@@ -0,0 +1,269 @@
+/*
+ * 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.jackrabbit.core.cluster;
+
+import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.core.PropertyId;
+import org.apache.jackrabbit.core.nodetype.NodeTypeDef;
+import org.apache.jackrabbit.core.nodetype.compact.CompactNodeTypeDefWriter;
+import org.apache.jackrabbit.name.NamespaceResolver;
+import org.apache.jackrabbit.name.QName;
+import org.apache.jackrabbit.name.NameFormat;
+import org.apache.jackrabbit.name.Path;
+import org.apache.jackrabbit.name.PathFormat;
+import org.apache.jackrabbit.name.NoPrefixDeclaredException;
+
+import java.io.IOException;
+import java.io.DataOutputStream;
+import java.io.StringWriter;
+import java.util.ArrayList;
+
+/**
+ * Allows writing data to a <code>DataOutputStream</code>.
+ */
+class RecordOutput {
+
+ /**
+ * Underlying output stream.
+ */
+ private final DataOutputStream out;
+
+ /**
+ * Name resolver.
+ */
+ private final NamespaceResolver resolver;
+
+ /**
+ * UUID index.
+ */
+ private final ArrayList uuidIndex = new ArrayList();
+
+ /**
+ * Flag indicating whether this output is closed.
+ */
+ private boolean closed;
+
+ /**
+ * Create a new file record.
+ *
+ * @param out outputstream to write to
+ * @param resolver namespace resolver
+ */
+ public RecordOutput(DataOutputStream out, NamespaceResolver resolver) {
+ this.out = out;
+ this.resolver = resolver;
+ }
+
+ /**
+ * Write a byte to the underlying stream.
+ *
+ * @param n byte
+ * @throws IOException if an I/O error occurs
+ */
+ public void writeByte(int n) throws IOException {
+ checkOpen();
+
+ out.writeByte(n);
+ }
+
+ /**
+ * Write a character to the underlying stream.
+ *
+ * @param c character
+ * @throws IOException if an I/O error occurs
+ */
+ public void writeChar(char c) throws IOException {
+ checkOpen();
+
+ out.writeChar(c);
+ }
+
+ /**
+ * Write a boolean from the underlying stream.
+ *
+ * @param b boolean
+ * @throws IOException if an I/O error occurs
+ */
+ public void writeBoolean(boolean b) throws IOException {
+ checkOpen();
+
+ out.writeBoolean(b);
+ }
+
+ /**
+ * Write an integer to the underlying stream.
+ *
+ * @param n integer
+ * @throws IOException if an I/O error occurs
+ */
+ public void writeInt(int n) throws IOException {
+ checkOpen();
+
+ out.writeInt(n);
+ }
+
+ /**
+ * Write a string from the underlying stream.
+ *
+ * @param s string, may be <code>null</code>
+ * @throws IOException if an I/O error occurs
+ */
+ public void writeString(String s) throws IOException {
+ checkOpen();
+
+ if (s == null) {
+ out.writeBoolean(true);
+ } else {
+ out.writeBoolean(false);
+ out.writeUTF(s);
+ }
+ }
+
+ /**
+ * Write a <code>QName</code>.
+ *
+ * @param name name
+ * @throws IOException if an I/O error occurs
+ * @throws NoPrefixDeclaredException if the prefix is not declared
+ */
+ public void writeQName(QName name) throws IOException, NoPrefixDeclaredException {
+ checkOpen();
+
+ writeString(NameFormat.format(name, resolver));
+ }
+
+ /**
+ * Write a <code>PathElement</code>.
+ *
+ * @param element path element
+ * @throws IOException if an I/O error occurs
+ * @throws NoPrefixDeclaredException if the prefix is not declared
+ */
+ public void writePathElement(Path.PathElement element) throws IOException, NoPrefixDeclaredException {
+ checkOpen();
+
+ writeQName(element.getName());
+ writeInt(element.getIndex());
+ }
+
+ /**
+ * Write a <code>Path</code>.
+ *
+ * @param path path
+ * @throws IOException if an I/O error occurs
+ * @throws NoPrefixDeclaredException if the prefix is not declared
+ */
+ public void writePath(Path path) throws IOException, NoPrefixDeclaredException {
+ checkOpen();
+
+ writeString(PathFormat.format(path, resolver));
+ }
+
+ /**
+ * Write a <code>NodeId</code>. Since the same node ids are likely to appear multiple times,
+ * only the first one will actually be literally appended, while all other reference the
+ * previous entry's index.
+ *
+ * @param nodeId node id
+ * @throws IOException if an I/O error occurs
+ */
+ public void writeNodeId(NodeId nodeId) throws IOException {
+ checkOpen();
+
+ if (nodeId == null) {
+ writeByte(Record.UUID_INDEX);
+ writeInt(-1);
+ } else {
+ int index = getOrCreateIndex(nodeId);
+ if (index != -1) {
+ writeByte(Record.UUID_INDEX);
+ writeInt(index);
+ } else {
+ writeByte(Record.UUID_LITERAL);
+ out.write(nodeId.getUUID().getRawBytes());
+ }
+ }
+ }
+
+ /**
+ * Write a <code>PropertyId</code>
+ *
+ * @param propertyId property id
+ * @throws IOException if an I/O error occurs
+ * @throws NoPrefixDeclaredException if the prefix is not declared
+ */
+ public void writePropertyId(PropertyId propertyId) throws IOException, NoPrefixDeclaredException {
+ checkOpen();
+
+ writeNodeId(propertyId.getParentId());
+ writeQName(propertyId.getName());
+ }
+
+ /**
+ * Write a <code>NodeTypeDef</code>
+ */
+ public void writeNodeTypeDef(NodeTypeDef ntd) throws IOException {
+ checkOpen();
+
+ StringWriter sw = new StringWriter();
+ CompactNodeTypeDefWriter writer = new CompactNodeTypeDefWriter(sw, resolver, true);
+ writer.write(ntd);
+ writer.close();
+
+ writeString(sw.toString());
+ }
+
+ /**
+ * Close this output.
+ *
+ * @throws IOException if an I/O error occurs
+ */
+ public void close() throws IOException {
+ checkOpen();
+
+ try {
+ out.close();
+ } finally {
+ closed = true;
+ }
+ }
+
+ /**
+ * Get a <code>NodeId</code>'s existing cache index, creating a new entry if necesary.
+ *
+ * @param nodeId nodeId to lookup
+ * @return cache index of existing entry or <code>-1</code> to indicate the entry was added
+ */
+ private int getOrCreateIndex(NodeId nodeId) {
+ int index = uuidIndex.indexOf(nodeId);
+ if (index == -1) {
+ uuidIndex.add(nodeId);
+ }
+ return index;
+ }
+
+ /**
+ * Check that this output is open, throw otherwise.
+ *
+ * @throws IllegalStateException if output is closed.
+ */
+ private void checkOpen() throws IllegalStateException {
+ if (closed) {
+ throw new IllegalStateException("Output closed.");
+ }
+ }
+}
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/default.ddl
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/default.ddl?view=auto&rev=495239
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/default.ddl (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/default.ddl Thu Jan 11 06:40:00 2007
@@ -0,0 +1,21 @@
+# 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.
+create table ${schemaObjectPrefix}JOURNAL (REVISION_ID BIGINT NOT NULL, REVISION_CREATOR varchar(255), REVISION_DATA varbinary)
+create unique index ${schemaObjectPrefix}JOURNAL_IDX on ${schemaObjectPrefix}JOURNAL (REVISION_ID)
+create table ${schemaObjectPrefix}GLOBAL_REVISION (REVISION_ID BIGINT NOT NULL)
+create unique index ${schemaObjectPrefix}GLOBAL_REVISION_IDX on ${schemaObjectPrefix}GLOBAL_REVISION (REVISION_ID)
+
+# Inserting the one and only revision counter record now helps avoiding race conditions
+insert into ${schemaObjectPrefix}GLOBAL_REVISION VALUES(0)
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/derby.ddl
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/derby.ddl?view=auto&rev=495239
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/derby.ddl (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/derby.ddl Thu Jan 11 06:40:00 2007
@@ -0,0 +1,21 @@
+# 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.
+create table ${schemaObjectPrefix}JOURNAL (REVISION_ID BIGINT NOT NULL, REVISION_CREATOR varchar(255), REVISION_DATA blob)
+create unique index ${schemaObjectPrefix}JOURNAL_IDX on ${schemaObjectPrefix}JOURNAL (REVISION_ID)
+create table ${schemaObjectPrefix}GLOBAL_REVISION (REVISION_ID BIGINT NOT NULL)
+create unique index ${schemaObjectPrefix}GLOBAL_REVISION_IDX on ${schemaObjectPrefix}GLOBAL_REVISION (REVISION_ID)
+
+# Inserting the one and only revision counter record now helps avoiding race conditions
+insert into ${schemaObjectPrefix}GLOBAL_REVISION VALUES(0)
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/h2.ddl
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/h2.ddl?view=auto&rev=495239
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/h2.ddl (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/h2.ddl Thu Jan 11 06:40:00 2007
@@ -0,0 +1,23 @@
+# 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.
+#
+# DDL script for the H2 database engine (http://www.h2database.com)
+#
+set max_length_inplace_lob 4096
+create table ${schemaObjectPrefix}JOURNAL (REVISION_ID bigint primary key, REVISION_CREATOR varchar(255), REVISION_DATA blob)
+create table ${schemaObjectPrefix}GLOBAL_REVISION (REVISION_ID bigint primary key)
+
+# Inserting the one and only revision counter record now helps avoiding race conditions
+insert into ${schemaObjectPrefix}GLOBAL_REVISION VALUES(0)
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/oracle.ddl
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/oracle.ddl?view=auto&rev=495239
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/oracle.ddl (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/oracle.ddl Thu Jan 11 06:40:00 2007
@@ -0,0 +1,21 @@
+# 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.
+create table ${schemaObjectPrefix}JOURNAL (REVISION_ID number(20,0) NOT NULL, REVISION_CREATOR varchar(255), REVISION_DATA blob)
+create unique index ${schemaObjectPrefix}JOURNAL_IDX on ${schemaObjectPrefix}JOURNAL (REVISION_ID)
+create table ${schemaObjectPrefix}GLOBAL_REVISION (REVISION_ID number(20,0) NOT NULL)
+create unique index ${schemaObjectPrefix}GLOBAL_REVISION_IDX on ${schemaObjectPrefix}GLOBAL_REVISION (REVISION_ID)
+
+# Inserting the one and only revision counter record now helps avoiding race conditions
+insert into ${schemaObjectPrefix}GLOBAL_REVISION VALUES(0)