From 55d57b7d9f075c275e4fe30d29577a5b914f05db Mon Sep 17 00:00:00 2001 From: "Brian S. O'Neill" Date: Thu, 5 Nov 2009 23:58:22 +0000 Subject: Add support for compressed records. --- .../java/com/amazon/carbonado/layout/Layout.java | 37 +++++- .../com/amazon/carbonado/layout/LayoutFactory.java | 37 +++++- .../com/amazon/carbonado/layout/LayoutOptions.java | 131 +++++++++++++++++++++ .../com/amazon/carbonado/layout/StoredLayout.java | 8 -- .../carbonado/layout/StoredLayoutProperty.java | 11 -- 5 files changed, 200 insertions(+), 24 deletions(-) create mode 100644 src/main/java/com/amazon/carbonado/layout/LayoutOptions.java (limited to 'src/main/java/com/amazon/carbonado/layout') diff --git a/src/main/java/com/amazon/carbonado/layout/Layout.java b/src/main/java/com/amazon/carbonado/layout/Layout.java index b6c6c0d..7aea758 100644 --- a/src/main/java/com/amazon/carbonado/layout/Layout.java +++ b/src/main/java/com/amazon/carbonado/layout/Layout.java @@ -18,6 +18,7 @@ package com.amazon.carbonado.layout; +import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.ArrayList; @@ -32,6 +33,7 @@ import org.apache.commons.logging.LogFactory; import org.cojen.util.SoftValuedHashMap; +import com.amazon.carbonado.CorruptEncodingException; import com.amazon.carbonado.Cursor; import com.amazon.carbonado.FetchException; import com.amazon.carbonado.FetchNoneException; @@ -131,22 +133,36 @@ public class Layout { private final LayoutFactory mLayoutFactory; private final StoredLayout mStoredLayout; + private final LayoutOptions mOptions; private transient List mAllProperties; /** * Creates a Layout around an existing storable. */ - Layout(LayoutFactory factory, StoredLayout storedLayout) { + Layout(LayoutFactory factory, StoredLayout storedLayout) throws CorruptEncodingException { mLayoutFactory = factory; mStoredLayout = storedLayout; + + byte[] extra = storedLayout.getExtraData(); + if (extra == null) { + mOptions = null; + } else { + mOptions = new LayoutOptions(); + try { + mOptions.decode(extra); + } catch (IOException e) { + throw new CorruptEncodingException(e); + } + mOptions.readOnly(); + } } /** * Copies layout information into freshly prepared storables. Call insert * (on this class) to persist them. */ - Layout(LayoutFactory factory, StorableInfo info, long layoutID) { + Layout(LayoutFactory factory, StorableInfo info, LayoutOptions options, long layoutID) { mLayoutFactory = factory; StoredLayout storedLayout = factory.mLayoutStorage.prepare(); @@ -168,6 +184,14 @@ public class Layout { // Can't get host, no big deal. } + if (options == null) { + mOptions = null; + } else { + options.readOnly(); + storedLayout.setExtraData(options.encode()); + mOptions = options; + } + Collection> properties = info.getAllProperties().values(); List list = new ArrayList(properties.size()); int ordinal = 0; @@ -268,6 +292,15 @@ public class Layout { return mStoredLayout.getCreationHost(); } + /** + * Returns additional options, or null if none. + * + * @return read-only object or null + */ + public LayoutOptions getOptions() { + return mOptions; + } + /** * Returns the layout for a particular generation of this layout's type. * diff --git a/src/main/java/com/amazon/carbonado/layout/LayoutFactory.java b/src/main/java/com/amazon/carbonado/layout/LayoutFactory.java index 1b2f0fc..54b6933 100644 --- a/src/main/java/com/amazon/carbonado/layout/LayoutFactory.java +++ b/src/main/java/com/amazon/carbonado/layout/LayoutFactory.java @@ -87,6 +87,23 @@ public class LayoutFactory implements LayoutCapability { public Layout layoutFor(Class type) throws FetchException, PersistException { + return layoutFor(type, null); + } + + /** + * Returns the layout matching the current definition of the given type. + * + * @throws PersistException if type represents a new generation, but + * persisting this information failed + */ + public Layout layoutFor(Class type, LayoutOptions options) + throws FetchException, PersistException + { + if (options != null) { + // Make side-effect consistently applied. + options.readOnly(); + } + synchronized (this) { if (mReconstructed != null) { Layout layout = mReconstructed.get(type); @@ -120,10 +137,10 @@ public class LayoutFactory implements LayoutCapability { for (int i=0; i info, int multiplier) { + private long mixInHash(long hash, StorableInfo info, LayoutOptions options, int multiplier) + { hash = mixInHash(hash, info.getStorableType().getName(), multiplier); + hash = mixInHash(hash, options, multiplier); for (StorableProperty property : info.getAllProperties().values()) { if (!property.isJoin()) { @@ -314,6 +333,18 @@ public class LayoutFactory implements LayoutCapability { return hash; } + private long mixInHash(long hash, LayoutOptions options, int multiplier) { + if (options != null) { + byte[] data = options.encode(); + if (data != null) { + for (int b : data) { + hash = hash * multiplier + (b & 0xff); + } + } + } + return hash; + } + /** * Returns an annotation hash code using a algorithm similar to the * default. The difference is in the handling of class and enum values. The diff --git a/src/main/java/com/amazon/carbonado/layout/LayoutOptions.java b/src/main/java/com/amazon/carbonado/layout/LayoutOptions.java new file mode 100644 index 0000000..1e57407 --- /dev/null +++ b/src/main/java/com/amazon/carbonado/layout/LayoutOptions.java @@ -0,0 +1,131 @@ +/* + * Copyright 2009 Amazon Technologies, Inc. or its affiliates. + * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks + * of Amazon Technologies, Inc. or its affiliates. All rights reserved. + * + * Licensed 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 com.amazon.carbonado.layout; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import java.util.HashMap; +import java.util.Map; + +/** + * Extra options encoded with a Storable layout. + * + * @author Brian S O'Neill + */ +public class LayoutOptions { + /** + * Data is compression algorithm name, encoded by DataOutput.writeUTF. + */ + static final byte COMPRESSION_TYPE = 1; + + private final Map mData; + + private boolean mReadOnly; + + public LayoutOptions() { + mData = new HashMap(1); + } + + /** + * @return null if not compressed + */ + public synchronized String getCompressionType() { + return (String) mData.get(COMPRESSION_TYPE); + } + + /** + * @param type null if not compressed + */ + public void setCompressionType(String type) { + put(COMPRESSION_TYPE, type); + } + + private synchronized void put(byte op, Object value) { + if (mReadOnly) { + throw new IllegalStateException("Options are read only"); + } + if (value == null) { + mData.remove(op); + } else { + mData.put(op, value); + } + } + + synchronized void readOnly() { + mReadOnly = true; + } + + /** + * @return null if empty + */ + synchronized byte[] encode() { + if (mData.isEmpty()) { + return null; + } + + try { + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + DataOutputStream dout = new DataOutputStream(bout); + + for (Map.Entry entry : mData.entrySet()) { + switch (entry.getKey()) { + default: + break; + case COMPRESSION_TYPE: + dout.write(COMPRESSION_TYPE); + dout.writeUTF((String) entry.getValue()); + } + } + + dout.close(); + return bout.toByteArray(); + } catch (IOException e) { + throw new AssertionError(e); + } + } + + /** + * @param source can be null if empty + */ + synchronized void decode(byte[] source) throws IOException { + mData.clear(); + + if (source == null || source.length == 0) { + return; + } + + ByteArrayInputStream bin = new ByteArrayInputStream(source); + DataInputStream din = new DataInputStream(bin); + + while (bin.available() > 0) { + byte op = din.readByte(); + switch (op) { + default: + throw new IOException("Unknown extra data type: " + op); + case COMPRESSION_TYPE: + mData.put(COMPRESSION_TYPE, din.readUTF()); + break; + } + } + } +} diff --git a/src/main/java/com/amazon/carbonado/layout/StoredLayout.java b/src/main/java/com/amazon/carbonado/layout/StoredLayout.java index ea3c1ec..0ed8ffa 100644 --- a/src/main/java/com/amazon/carbonado/layout/StoredLayout.java +++ b/src/main/java/com/amazon/carbonado/layout/StoredLayout.java @@ -42,21 +42,18 @@ import com.amazon.carbonado.Version; @Alias("CARBONADO_LAYOUT") public interface StoredLayout extends Storable, Unevolvable { long getLayoutID(); - void setLayoutID(long typeID); /** * Storable type name is a fully qualified Java class name. */ String getStorableTypeName(); - void setStorableTypeName(String typeName); /** * Generation of storable, where 0 represents the first generation. */ int getGeneration(); - void setGeneration(int generation); /** @@ -64,7 +61,6 @@ public interface StoredLayout extends Storable, Unevolvable { * created. */ long getCreationTimestamp(); - void setCreationTimestamp(long timestamp); /** @@ -72,7 +68,6 @@ public interface StoredLayout extends Storable, Unevolvable { */ @Nullable String getCreationUser(); - void setCreationUser(String user); /** @@ -80,7 +75,6 @@ public interface StoredLayout extends Storable, Unevolvable { */ @Nullable String getCreationHost(); - void setCreationHost(String host); /** @@ -89,7 +83,6 @@ public interface StoredLayout extends Storable, Unevolvable { */ @Version int getVersionNumber(); - void setVersionNumber(int version); /** @@ -100,6 +93,5 @@ public interface StoredLayout extends Storable, Unevolvable { */ @Nullable byte[] getExtraData(); - void setExtraData(byte[] data); } diff --git a/src/main/java/com/amazon/carbonado/layout/StoredLayoutProperty.java b/src/main/java/com/amazon/carbonado/layout/StoredLayoutProperty.java index 0777f10..b98a2a7 100644 --- a/src/main/java/com/amazon/carbonado/layout/StoredLayoutProperty.java +++ b/src/main/java/com/amazon/carbonado/layout/StoredLayoutProperty.java @@ -42,7 +42,6 @@ import com.amazon.carbonado.Version; @Alias("CARBONADO_LAYOUT_PROPERTY") public interface StoredLayoutProperty extends Storable, Unevolvable { long getLayoutID(); - void setLayoutID(long typeID); /** @@ -50,32 +49,27 @@ public interface StoredLayoutProperty extends Storable, Un * layout. */ int getOrdinal(); - void setOrdinal(int ordinal); String getPropertyName(); - void setPropertyName(String name); /** * Property type descriptor is a Java type descriptor. */ String getPropertyTypeDescriptor(); - void setPropertyTypeDescriptor(String type); /** * Returns true of property value can be set to null. */ boolean isNullable(); - void setNullable(boolean nullable); /** * Returns true if property is a member of the primary key. */ boolean isPrimaryKeyMember(); - void setPrimaryKeyMember(boolean pk); /** @@ -83,7 +77,6 @@ public interface StoredLayoutProperty extends Storable, Un * Storable. */ boolean isVersion(); - void setVersion(boolean version); /** @@ -92,7 +85,6 @@ public interface StoredLayoutProperty extends Storable, Un */ @Nullable String getAdapterTypeName(); - void setAdapterTypeName(String name); /** @@ -100,7 +92,6 @@ public interface StoredLayoutProperty extends Storable, Un */ @Nullable String getAdapterParams(); - void setAdapterParams(String params); /** @@ -109,7 +100,6 @@ public interface StoredLayoutProperty extends Storable, Un */ @Version int getVersionNumber(); - void setVersionNumber(int version); /** @@ -120,6 +110,5 @@ public interface StoredLayoutProperty extends Storable, Un */ @Nullable byte[] getExtraData(); - void setExtraData(byte[] data); } -- cgit v1.2.3