You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@labs.apache.org by ka...@apache.org on 2009/03/17 11:14:04 UTC
svn commit: r755179 [2/3] - in /labs/bananadb/trunk: ./
src/main/java/org/apache/labs/bananadb/entity/
src/main/java/org/apache/labs/bananadb/entity/isolation/
src/main/java/org/apache/labs/bananadb/entity/serialization/
src/main/java/org/apache/labs/b...
Added: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Accessor.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Accessor.java?rev=755179&view=auto
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Accessor.java (added)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Accessor.java Tue Mar 17 10:14:03 2009
@@ -0,0 +1,364 @@
+package org.apache.labs.bananadb.store;
+
+/*
+ * 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 org.apache.labs.bananadb.store.lock.Lock;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.HashMap;
+
+/**
+ * This class is not thread safe. I.e. you'll need to instantiate one per thread!
+ *
+ * @author kalle
+ * @see org.apache.labs.bananadb.store.Store#createAccessor(boolean)
+ * @since 2009-mar-16 14:20:33
+ */
+public class Accessor {
+
+ private static final Log log = new Log(Accessor.class);
+
+ private Store store;
+ private String access;
+
+ private Lock writeLock;
+
+ private Metadata metadata;
+ private Hashtable hashtable;
+ private Map<Integer, HashCodesPartition> hashCodesPartitions = new HashMap<Integer, HashCodesPartition>();
+ private Map<Integer, KeysPartition> keyPartitions = new HashMap<Integer, KeysPartition>();
+ private Map<Integer, ValuesPartition> valuePartitions = new HashMap<Integer, ValuesPartition>();
+
+ Accessor(final Store store, boolean readOnly) throws IOException {
+ this.store = store;
+ access = readOnly ? "r" : "rw";
+ writeLock = store.getConfiguration().getLockFactory().makeLock("lock");
+ metadata = new Metadata(store.getConfiguration().getDataPath(), access);
+
+ if (metadata.getFile().exists()) {
+ metadata.open();
+ } else {
+
+ long ms = System.currentTimeMillis();
+
+ if (readOnly) {
+ throw new IOException("Can not create a new store when accessor is in read only mode");
+ }
+
+ log.info("Creating new store..");
+
+ Lock.With width = new Lock.With(writeLock, store.getConfiguration().getLockWaitTimeoutMilliseconds()) {
+ protected Object doBody() throws IOException {
+ if (!metadata.getFile().exists()) {
+
+ metadata.format(metadata.getHeaderByteSize());
+ metadata.open();
+ Metadata.Header mdh = new Metadata.Header();
+ mdh.setFileFormatVersion(0);
+ mdh.setCommitVersion(0);
+ mdh.setCurrentHashtableId(0);
+ mdh.setCurrentHashCodesPartition(0);
+ mdh.setCurrentKeysPartition(0);
+ mdh.setValuePostingsCount(0);
+ metadata.writeHeader(mdh);
+
+ hashtable = new Hashtable(store.getConfiguration().getDataPath(), 0, access);
+ hashtable.format((store.getConfiguration().getInitialCapacity() * Hashtable.Posting.POSTING_BYTE_SIZE) + hashtable.getHeaderByteSize());
+ hashtable.open();
+ Hashtable.Header hth = new Hashtable.Header();
+ hth.setPostingsCapacity(store.getConfiguration().getInitialCapacity());
+ hashtable.writeHeader(hth);
+
+ }
+ return null;
+ }
+ };
+ width.run();
+
+ // these could be opened lazy, but let's do it now.
+ getHashCodesPartition(0);
+ getKeysPartition(0);
+ getValuesPartition(0);
+
+ ms = System.currentTimeMillis() - ms;
+ log.info("New store has been created. Took " + ms + " milliseconds.");
+
+ }
+ }
+
+ public void close() throws IOException {
+ metadata.close();
+ hashtable.close();
+ for (FileHandler fileHandler : hashCodesPartitions.values()) {
+ fileHandler.close();
+ }
+ for (FileHandler fileHandler : keyPartitions.values()) {
+ fileHandler.close();
+ }
+ for (FileHandler fileHandler : valuePartitions.values()) {
+ fileHandler.close();
+ }
+ metadata = null;
+ hashtable = null;
+ hashCodesPartitions = null;
+ keyPartitions = null;
+ valuePartitions = null;
+
+ store.getAccessors().remove(this);
+ }
+
+
+ public Metadata getMetadata() throws IOException {
+ return metadata;
+ }
+
+
+ public Hashtable getHashtable() throws IOException {
+ Metadata.Header metadataHeader = new Metadata.Header();
+ metadata.readHeader(metadataHeader);
+ if (hashtable == null || metadataHeader.getCurrentHashtableId() != hashtable.getVersionId()) {
+ if (hashtable != null) {
+ hashtable.getRAF().close();
+ }
+ hashtable = new Hashtable(store.getConfiguration().getDataPath(), metadataHeader.getCurrentHashtableId(), access);
+ hashtable.open();
+ }
+ return hashtable;
+ }
+
+ public HashCodesPartition getHashCodesPartition(int partitionId) throws IOException {
+ HashCodesPartition partition = hashCodesPartitions.get(partitionId);
+ if (partition == null) {
+ partition = new HashCodesPartition(store.getConfiguration().getDataPath(), partitionId, access);
+ if (!partition.getFile().exists()) {
+ final HashCodesPartition p = partition;
+ Lock.With with = new Lock.With(writeLock, store.getConfiguration().getLockWaitTimeoutMilliseconds()) {
+ protected Object doBody() throws IOException {
+ if (!p.getFile().exists()) {
+ p.format(store.getConfiguration().getHashCodesPartitionByteSize());
+ p.open();
+ HashCodesPartition.Header hch = new HashCodesPartition.Header();
+ hch.setNextPostingOffset(p.getHeaderByteSize());
+ hch.setBytesLeft(store.getConfiguration().getHashCodesPartitionByteSize() - p.getHeaderByteSize());
+ p.writeHeader(hch);
+ }
+ return null;
+ }
+ };
+ with.run();
+ } else {
+ partition.open();
+ }
+ hashCodesPartitions.put(partitionId, partition);
+ }
+ return partition;
+ }
+
+ public KeysPartition getKeysPartition(int partitionId) throws IOException {
+ KeysPartition partition = keyPartitions.get(partitionId);
+ if (partition == null) {
+ partition = new KeysPartition(store.getConfiguration().getDataPath(), partitionId, access);
+ if (!partition.getFile().exists()) {
+ final KeysPartition p = partition;
+ Lock.With with = new Lock.With(writeLock, store.getConfiguration().getLockWaitTimeoutMilliseconds()) {
+ protected Object doBody() throws IOException {
+ if (!p.getFile().exists()) {
+ p.format(store.getConfiguration().getKeysPartitionByteSize());
+ p.open();
+ KeysPartition.Header kh = new KeysPartition.Header();
+ kh.setNextPostingOffset(p.getHeaderByteSize());
+ kh.setBytesLeft(store.getConfiguration().getKeysPartitionByteSize() - p.getHeaderByteSize());
+ p.writeHeader(kh);
+ }
+ return null;
+ }
+ };
+ with.run();
+ } else {
+ partition.open();
+ }
+ keyPartitions.put(partitionId, partition);
+ }
+ return partition;
+ }
+
+ public ValuesPartition getValuesPartition(int partitionId) throws IOException {
+ ValuesPartition partition = valuePartitions.get(partitionId);
+ if (partition == null) {
+ partition = new ValuesPartition(store.getConfiguration().getDataPath(), partitionId, access);
+ if (!partition.getFile().exists()) {
+ final ValuesPartition p = partition;
+ Lock.With with = new Lock.With(writeLock, store.getConfiguration().getLockWaitTimeoutMilliseconds()) {
+ protected Object doBody() throws IOException {
+ if (!p.getFile().exists()) {
+ p.format(store.getConfiguration().getValuesPartitionByteSize());
+ p.open();
+ ValuesPartition.Header vh = new ValuesPartition.Header();
+ vh.setNextPostingOffset(p.getHeaderByteSize());
+ vh.setBytesLeft(store.getConfiguration().getValuesPartitionByteSize() - p.getHeaderByteSize());
+ p.writeHeader(vh);
+ }
+ return null;
+ }
+ };
+ with.run();
+ } else {
+ partition.open();
+ }
+ valuePartitions.put(partitionId, partition);
+ }
+ return partition;
+ }
+
+ /**
+ * Require write lock!
+ *
+ * @param posting
+ * @return
+ * @throws IOException
+ */
+ public RequestPartitionWriterResponse<ValuesPartition> requestValueWrite(ValuesPartition.Posting posting) throws IOException {
+
+ int requestedBytes = posting.getPostingByteSize();
+
+ Metadata.Header mdh = new Metadata.Header();
+ metadata.readHeader(mdh);
+
+ ValuesPartition vp = getValuesPartition(mdh.getCurrentValuesPartition());
+ ValuesPartition.Header vph = new ValuesPartition.Header();
+
+ vp.readHeader(vph);
+ if (vph.getBytesLeft() < requestedBytes) {
+ mdh.setCurrentValuesPartition(mdh.getCurrentValuesPartition() + 1);
+ metadata.writeHeader(mdh);
+
+ vp = getValuesPartition(mdh.getCurrentValuesPartition());
+ vp.readHeader(vph);
+ }
+
+ RequestPartitionWriterResponse<ValuesPartition> response = new RequestPartitionWriterResponse<ValuesPartition>();
+
+ response.fileHandler = vp;
+ response.startOffset = vph.getNextPostingOffset();
+
+ vph.setBytesLeft(vph.getBytesLeft() - requestedBytes);
+ vph.setNextPostingOffset(vph.getNextPostingOffset() + requestedBytes);
+ vp.writeHeader(vph);
+
+ return response;
+ }
+
+ /**
+ * Require write lock!
+ *
+ * @param posting
+ * @return
+ * @throws IOException
+ */
+ public RequestPartitionWriterResponse<KeysPartition> requestValueWrite(KeysPartition.Posting posting) throws IOException {
+
+ int requestedBytes = posting.getPostingByteSize();
+
+ Metadata.Header mdh = new Metadata.Header();
+ metadata.readHeader(mdh);
+
+ KeysPartition kp = getKeysPartition(mdh.getCurrentKeysPartition());
+ KeysPartition.Header kh = new KeysPartition.Header();
+
+ kp.readHeader(kh);
+ if (kh.getBytesLeft() < requestedBytes) {
+ mdh.setCurrentValuesPartition(mdh.getCurrentKeysPartition() + 1);
+ metadata.writeHeader(mdh);
+
+ kp = getKeysPartition(mdh.getCurrentKeysPartition());
+ kp.readHeader(kh);
+ }
+
+ RequestPartitionWriterResponse<KeysPartition> response = new RequestPartitionWriterResponse<KeysPartition>();
+
+ response.fileHandler = kp;
+ response.startOffset = kh.getNextPostingOffset();
+
+ kh.setBytesLeft(kh.getBytesLeft() - requestedBytes);
+ kh.setNextPostingOffset(kh.getNextPostingOffset() + requestedBytes);
+ kp.writeHeader(kh);
+
+ return response;
+ }
+
+ /**
+ * Require write lock!
+ *
+ * @param posting
+ * @return
+ * @throws IOException
+ */
+ public RequestPartitionWriterResponse<HashCodesPartition> requestValueWrite(HashCodesPartition.Posting posting) throws IOException {
+
+ int requestedBytes = posting.getPostingByteSize();
+
+ Metadata.Header mdh = new Metadata.Header();
+ metadata.readHeader(mdh);
+
+ HashCodesPartition hcp = getHashCodesPartition(mdh.getCurrentHashCodesPartition());
+ HashCodesPartition.Header hch = new HashCodesPartition.Header();
+
+ hcp.readHeader(hch);
+ if (hch.getBytesLeft() < requestedBytes) {
+ mdh.setCurrentValuesPartition(mdh.getCurrentHashCodesPartition() + 1);
+ metadata.writeHeader(mdh);
+
+ hcp = getHashCodesPartition(mdh.getCurrentHashCodesPartition());
+ hcp.readHeader(hch);
+ }
+
+ RequestPartitionWriterResponse<HashCodesPartition> response = new RequestPartitionWriterResponse<HashCodesPartition>();
+
+ response.fileHandler = hcp;
+ response.startOffset = hch.getNextPostingOffset();
+
+ hch.setBytesLeft(hch.getBytesLeft() - requestedBytes);
+ hch.setNextPostingOffset(hch.getNextPostingOffset() + requestedBytes);
+ hcp.writeHeader(hch);
+
+ return response;
+ }
+
+ public static class RequestPartitionWriterResponse<T extends FileHandler> {
+ private T fileHandler;
+ private int startOffset;
+
+ public T getFileHandler() {
+ return fileHandler;
+ }
+
+ public int getStartOffset() {
+ return startOffset;
+ }
+ }
+
+ public Lock getWriteLock() {
+ return writeLock;
+ }
+
+ public Store getStore() {
+ return store;
+ }
+}
Added: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Configuration.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Configuration.java?rev=755179&view=auto
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Configuration.java (added)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Configuration.java Tue Mar 17 10:14:03 2009
@@ -0,0 +1,150 @@
+package org.apache.labs.bananadb.store;
+
+/*
+ * 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 org.apache.labs.bananadb.store.lock.LockFactory;
+import org.apache.labs.bananadb.store.lock.NativeFSLockFactory;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * @author kalle
+ * @since 2009-mar-16 15:53:03
+ */
+public class Configuration {
+
+ /**
+ * Location of directory containing the data files.
+ * Only one hashtable can exist in a path.
+ */
+ private File dataPath;
+
+ public Configuration(File dataPath) throws IOException {
+ this.dataPath = dataPath;
+ lockFactory = new NativeFSLockFactory(dataPath);
+ }
+
+ /**
+ * Number of items you want to fit in the hashtable from the start.
+ */
+ private int initialCapacity = 800000;
+
+ /**
+ * The factor of which to grow the capacity on rehash.
+ */
+ private double automaticRehashCapacityGrowFactor = 1.7d;
+
+ /**
+ * Ratio of available key posting left required to trigger a rehash at put()-time.
+ * <p/>
+ * The default identified sweetspot
+ * is to have at least 8x greater capacity than items in the hashtable.
+ * <p/>
+ * In order to automatically rehash so you never fill the hashtable to more than 1/8
+ * you have set this value to 1/8 (0.125).
+ *
+ * A number greater than 0 and less than 1.
+ */
+ private double automaticRehashThreadshold = 0.125d;
+
+
+ private LockFactory lockFactory;
+
+ private long lockWaitTimeoutMilliseconds = 60000;
+
+ public static final int megaByte = 1024 * 1024;
+
+ private int valuesPartitionByteSize = 100 * megaByte;
+ private int keysPartitionByteSize = 10 * megaByte;
+ private int hashCodesPartitionByteSize = 10 * megaByte;
+
+
+ public int getInitialCapacity() {
+ return initialCapacity;
+ }
+
+ public void setInitialCapacity(int initialCapacity) {
+ this.initialCapacity = initialCapacity;
+ }
+
+ public double getAutomaticRehashCapacityGrowFactor() {
+ return automaticRehashCapacityGrowFactor;
+ }
+
+ public void setAutomaticRehashCapacityGrowFactor(double automaticRehashCapacityGrowFactor) {
+ this.automaticRehashCapacityGrowFactor = automaticRehashCapacityGrowFactor;
+ }
+
+ public double getAutomaticRehashThreadshold() {
+ return automaticRehashThreadshold;
+ }
+
+ public void setAutomaticRehashThreadshold(double automaticRehashThreadshold) {
+ this.automaticRehashThreadshold = automaticRehashThreadshold;
+ }
+
+ public LockFactory getLockFactory() {
+ return lockFactory;
+ }
+
+ public void setLockFactory(LockFactory lockFactory) {
+ this.lockFactory = lockFactory;
+ }
+
+ public long getLockWaitTimeoutMilliseconds() {
+ return lockWaitTimeoutMilliseconds;
+ }
+
+ public void setLockWaitTimeoutMilliseconds(long lockWaitTimeoutMilliseconds) {
+ this.lockWaitTimeoutMilliseconds = lockWaitTimeoutMilliseconds;
+ }
+
+ public int getValuesPartitionByteSize() {
+ return valuesPartitionByteSize;
+ }
+
+ public void setValuesPartitionByteSize(int valuesPartitionByteSize) {
+ this.valuesPartitionByteSize = valuesPartitionByteSize;
+ }
+
+ public int getKeysPartitionByteSize() {
+ return keysPartitionByteSize;
+ }
+
+ public void setKeysPartitionByteSize(int keysPartitionByteSize) {
+ this.keysPartitionByteSize = keysPartitionByteSize;
+ }
+
+ public int getHashCodesPartitionByteSize() {
+ return hashCodesPartitionByteSize;
+ }
+
+ public void setHashCodesPartitionByteSize(int hashCodesPartitionByteSize) {
+ this.hashCodesPartitionByteSize = hashCodesPartitionByteSize;
+ }
+
+ public File getDataPath() {
+ return dataPath;
+ }
+
+ public void setDataPath(File dataPath) {
+ this.dataPath = dataPath;
+ }
+}
Added: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Cursor.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Cursor.java?rev=755179&view=auto
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Cursor.java (added)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Cursor.java Tue Mar 17 10:14:03 2009
@@ -0,0 +1,32 @@
+package org.apache.labs.bananadb.store;
+
+/*
+ * 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.
+ */
+
+
+/**
+ * Cursor implementations must be thread safe!!!
+ * The easiet way is to synchronize the next() method
+ *
+ * @author kalle
+ * @since 2009-mar-16 15:37:56
+ */
+public interface Cursor {
+
+ public abstract byte[] next(Accessor accessor);
+
+}
Added: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/FileHandler.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/FileHandler.java?rev=755179&view=auto
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/FileHandler.java (added)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/FileHandler.java Tue Mar 17 10:14:03 2009
@@ -0,0 +1,180 @@
+package org.apache.labs.bananadb.store;
+
+/*
+ * 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.File;
+import java.io.RandomAccessFile;
+import java.io.IOException;
+import java.io.FileOutputStream;
+import java.util.Arrays;
+
+/**
+ * @author kalle
+ * @since 2009-mar-16 15:28:29
+ */
+public abstract class FileHandler<H extends FileHandler.Header, P extends FileHandler.Posting> {
+
+ private static final Log log = new Log(FileHandler.class);
+
+ private File file;
+ private RandomAccessFile RAF;
+ private String access;
+
+ protected FileHandler(File directory, int id, String suffix, String access) throws IOException {
+ StringBuilder sb = new StringBuilder(15);
+ sb.append(String.valueOf(id));
+ while (sb.length() < 8) {
+ sb.insert(0, "0");
+ }
+ sb.append(".");
+ sb.append(suffix);
+ this.file = new File(directory, sb.toString());
+ this.access = access;
+ }
+
+ public void format(long size) throws IOException {
+ format(size, (byte) 0);
+ }
+
+ public void format(long size, byte defaultValue) throws IOException {
+ log.info("Formatting " + file.getAbsolutePath() + "..");
+
+ long ms = System.currentTimeMillis();
+
+ long leftToWrite = size;
+
+ FileOutputStream fos = new FileOutputStream(file);
+ int bufSize = Math.min(1024 * 1024, (int)(size / 5));
+ byte[] bytes = new byte[bufSize];
+ Arrays.fill(bytes, defaultValue);
+ while (leftToWrite >= bytes.length) {
+ fos.write(bytes);
+ leftToWrite -= bytes.length;
+ }
+ if (leftToWrite > 0) {
+ fos.write(bytes, defaultValue, (int) leftToWrite);
+ }
+ fos.close();
+
+ log.info("It took " + (System.currentTimeMillis() - ms) + " milliseconds to format " + file.getAbsolutePath());
+ }
+
+ public void open() throws IOException {
+ if (RAF != null) {
+ throw new IOException("Already open");
+ }
+ this.RAF = new RandomAccessFile(file, access);
+ }
+
+ public void close() throws IOException {
+ if (RAF == null) {
+ throw new IOException("Already closed");
+ }
+ RAF.close();
+ }
+
+ public abstract int getHeaderByteSize();
+
+ public File getFile() {
+ return file;
+ }
+
+ public RandomAccessFile getRAF() {
+ return RAF;
+ }
+
+ public static abstract class Header {
+ }
+
+ public static abstract class Posting {
+ public abstract int getPostingByteSize();
+ }
+
+// public void writePosting(P posting) throws IOException {
+// writePosting(posting, getRAF());
+// }
+
+ /**
+ * Marks the posting at the start offset as deleted
+ * @param startOffset
+ * @throws IOException
+ */
+ public void deletePosting(int startOffset) throws IOException {
+ deletePosting(startOffset, RAF);
+ }
+
+ public abstract void deletePosting(int startOffset, RandomAccessFile RAF) throws IOException;
+
+ public void writePosting(P posting, int startOffset) throws IOException {
+ writePosting(posting, startOffset, getRAF());
+ }
+
+ public void writePosting(P posting, int startOffset, RandomAccessFile RAF) throws IOException {
+ RAF.seek(startOffset);
+ writePosting(posting, RAF);
+ }
+
+ public abstract void writePosting(P posting, RandomAccessFile RAF) throws IOException;
+
+// public void readPosting(P posting) throws IOException {
+// readPosting(posting, getRAF());
+// }
+
+ public void readPosting(P posting, int startOffset) throws IOException {
+ readPosting(posting, startOffset, getRAF());
+ }
+
+ public void readPosting(P posting, int startOffset, RandomAccessFile RAF) throws IOException {
+ RAF.seek(startOffset);
+ readPosting(posting, RAF);
+ }
+
+ public abstract void readPosting(P posting, RandomAccessFile RAF) throws IOException;
+
+
+ public void writeHeader(H header) throws IOException {
+ writeHeader(header, 0, getRAF());
+ }
+
+ public void writeHeader(H header, int startOffset) throws IOException {
+ writeHeader(header, startOffset, getRAF());
+ }
+
+ public void writeHeader(H header, int startOffset, RandomAccessFile RAF) throws IOException {
+ RAF.seek(startOffset);
+ writeHeader(header, RAF);
+ }
+
+ public abstract void writeHeader(H header, RandomAccessFile RAF) throws IOException;
+
+ public void readHeader(H header) throws IOException {
+ readHeader(header, 0, RAF);
+ }
+
+ public void readHeader(H header, int startOffset) throws IOException {
+ readHeader(header, startOffset, getRAF());
+ }
+
+ public void readHeader(H header, int startOffset, RandomAccessFile RAF) throws IOException {
+ RAF.seek(startOffset);
+ readHeader(header, RAF);
+ }
+
+ public abstract void readHeader(H header, RandomAccessFile RAF) throws IOException;
+}
Added: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/HashCodesPartition.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/HashCodesPartition.java?rev=755179&view=auto
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/HashCodesPartition.java (added)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/HashCodesPartition.java Tue Mar 17 10:14:03 2009
@@ -0,0 +1,212 @@
+package org.apache.labs.bananadb.store;
+
+/*
+ * 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.RandomAccessFile;
+import java.io.IOException;
+import java.io.File;
+
+/**
+ * Hash code postings partition file.
+ * <p/>
+ * Chained postings. Each postings has a unique hash code value and points at how to find
+ * the key posting for this hash code.
+ * <p/>
+ * This file is affected by rehashing.
+ *
+ * @author kalle
+ * @since 2009-mar-16 14:00:37
+ */
+public class HashCodesPartition extends FileHandler<HashCodesPartition.Header, HashCodesPartition.Posting> {
+
+ private int partitionId;
+
+ public HashCodesPartition(File directory, int partitionId, String access) throws IOException {
+ super(directory, partitionId, "hc", access);
+ this.partitionId = partitionId;
+ }
+
+ public int getPartitionId() {
+ return partitionId;
+ }
+
+ public static final int HEADER_BYTE_SIZE = 1024;
+ public int getHeaderByteSize() {
+ return HEADER_BYTE_SIZE;
+ }
+
+ public static class Header extends FileHandler.Header {
+
+ /**
+ * Offset in this partition for next new posting.
+ */
+ private int nextPostingOffset;
+ /**
+ * Bytes left for use in this partition.
+ */
+ private int bytesLeft;
+
+ public void update(Posting posting) {
+ nextPostingOffset += POSTING_BYTE_SIZE;
+ bytesLeft -= POSTING_BYTE_SIZE;
+ }
+
+ public int getNextPostingOffset() {
+ return nextPostingOffset;
+ }
+
+ public void setNextPostingOffset(int nextPostingOffset) {
+ this.nextPostingOffset = nextPostingOffset;
+ }
+
+ public int getBytesLeft() {
+ return bytesLeft;
+ }
+
+ public void setBytesLeft(int bytesLeft) {
+ this.bytesLeft = bytesLeft;
+ }
+
+
+ }
+
+ public static final int POSTING_BYTE_SIZE = 1 + 8 + 4 + 4 + 4 + 4;
+
+ public static class Posting extends FileHandler.Posting {
+
+ public int getPostingByteSize() {
+ return POSTING_BYTE_SIZE;
+ }
+
+ /**
+ * 0 = never used
+ * 1 = in use
+ * 2 = deleted
+ */
+ private byte flag;
+
+ /**
+ * Key hash code.
+ */
+ private long keyHashCode;
+
+ /**
+ * Partition id of next hash code posting with the same hashtable posting position.
+ * -1 == no more hash code postings in chain
+ */
+ private int nextPostingPartition;
+
+ /**
+ * Offset in above hash code postings partition.
+ */
+ private int nextPostingPartitionOffset;
+
+
+ /**
+ * Partition id of first key posting with this hash code.
+ */
+ private int firstKeyPostingPartition;
+
+ /**
+ * Offset in above key postings partition.
+ */
+ private int firstKeyPostingPartitionOffset;
+
+ public byte getFlag() {
+ return flag;
+ }
+
+ public void setFlag(byte flag) {
+ this.flag = flag;
+ }
+
+ public long getKeyHashCode() {
+ return keyHashCode;
+ }
+
+ public void setKeyHashCode(long keyHashCode) {
+ this.keyHashCode = keyHashCode;
+ }
+
+ public int getNextPostingPartition() {
+ return nextPostingPartition;
+ }
+
+ public void setNextPostingPartition(int nextPostingPartition) {
+ this.nextPostingPartition = nextPostingPartition;
+ }
+
+ public int getNextPostingPartitionOffset() {
+ return nextPostingPartitionOffset;
+ }
+
+ public void setNextPostingPartitionOffset(int nextPostingPartitionOffset) {
+ this.nextPostingPartitionOffset = nextPostingPartitionOffset;
+ }
+
+ public int getFirstKeyPostingPartition() {
+ return firstKeyPostingPartition;
+ }
+
+ public void setFirstKeyPostingPartition(int firstKeyPostingPartition) {
+ this.firstKeyPostingPartition = firstKeyPostingPartition;
+ }
+
+ public int getFirstKeyPostingPartitionOffset() {
+ return firstKeyPostingPartitionOffset;
+ }
+
+ public void setFirstKeyPostingPartitionOffset(int firstKeyPostingPartitionOffset) {
+ this.firstKeyPostingPartitionOffset = firstKeyPostingPartitionOffset;
+ }
+ }
+
+ public void readHeader(Header header, RandomAccessFile RAF) throws IOException {
+ header.nextPostingOffset = RAF.readInt();
+ header.bytesLeft = RAF.readInt();
+ }
+
+ public void writeHeader(Header header, RandomAccessFile RAF) throws IOException {
+ RAF.writeInt(header.nextPostingOffset);
+ RAF.writeInt(header.bytesLeft);
+ }
+
+
+ public void readPosting(Posting posting, RandomAccessFile RAF) throws IOException {
+ posting.flag = RAF.readByte();
+ posting.keyHashCode = RAF.readLong();
+ posting.nextPostingPartition = RAF.readInt();
+ posting.nextPostingPartitionOffset = RAF.readInt();
+ posting.firstKeyPostingPartition = RAF.readInt();
+ posting.firstKeyPostingPartitionOffset = RAF.readInt();
+ }
+
+ public void writePosting(Posting posting, RandomAccessFile RAF) throws IOException {
+ RAF.writeByte(posting.flag);
+ RAF.writeLong(posting.keyHashCode);
+ RAF.writeInt(posting.nextPostingPartition);
+ RAF.writeInt(posting.nextPostingPartitionOffset);
+ RAF.writeInt(posting.firstKeyPostingPartition);
+ RAF.writeInt(posting.firstKeyPostingPartitionOffset);
+ }
+
+ public void deletePosting(int startOffset, RandomAccessFile RAF) throws IOException {
+ RAF.seek(startOffset);
+ RAF.writeByte((byte)2);
+ }
+}
Added: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Hashtable.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Hashtable.java?rev=755179&view=auto
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Hashtable.java (added)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Hashtable.java Tue Mar 17 10:14:03 2009
@@ -0,0 +1,162 @@
+package org.apache.labs.bananadb.store;
+
+/*
+ * 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.RandomAccessFile;
+import java.io.IOException;
+import java.io.File;
+
+/**
+ * Hashtable file. There is never more than one of these that are valid at any given time.
+ * <p/>
+ * The position in the hashtable for a given hash code is calculated as (hash & (capacity - 1)).
+ * At this position there is a posting that points at the first known hash code posting.
+ * <p/>
+ * This file is affected by rehashing.
+ *
+ * @author kalle
+ * @since 2009-mar-16 14:00:56
+ */
+public class Hashtable extends FileHandler<Hashtable.Header, Hashtable.Posting> {
+
+
+ private int versionId;
+
+ /**
+ * header as when file was openend. used only to read capacity. but that is also all the header contains..
+ */
+ private Header header;
+
+ public Hashtable(File directory, int versionId, String access) throws IOException {
+ super(directory, versionId, "ht", access);
+ this.versionId = versionId;
+ }
+
+ @Override
+ public void open() throws IOException {
+ super.open();
+ readHeader(header = new Header());
+ }
+
+ public int getVersionId() {
+ return versionId;
+ }
+
+ public static final int HEADER_BYTE_SIZE = 1024;
+ public int getHeaderByteSize() {
+ return HEADER_BYTE_SIZE;
+ }
+
+ public static class Header extends FileHandler.Header {
+ /**
+ * This hashtable postings file capacity.
+ */
+ private int postingsCapacity;
+
+ public int getPostingsCapacity() {
+ return postingsCapacity;
+ }
+
+ public void setPostingsCapacity(int postingsCapacity) {
+ this.postingsCapacity = postingsCapacity;
+ }
+ }
+
+
+
+
+ public static class Posting extends FileHandler.Posting {
+
+ public static final int POSTING_BYTE_SIZE = 1+ 4 + 4;
+ public int getPostingByteSize() {
+ return POSTING_BYTE_SIZE;
+ }
+
+ /**
+ * 0 = never used
+ * 1 = in use
+ * 2 = deleted
+ */
+ private byte flag;
+
+ /**
+ * Partition id of first hash code posting with this hashtable position. -1 == null
+ */
+ private int hashCodePostingPartition;
+
+ /**
+ * Offset in above hash code postings partition.
+ */
+ private int hashCodePostingPartitionOffset;
+
+ public byte getFlag() {
+ return flag;
+ }
+
+ public void setFlag(byte flag) {
+ this.flag = flag;
+ }
+
+ public int getHashCodePostingPartition() {
+ return hashCodePostingPartition;
+ }
+
+ public void setHashCodePostingPartition(int hashCodePostingPartition) {
+ this.hashCodePostingPartition = hashCodePostingPartition;
+ }
+
+ public int getHashCodePostingPartitionOffset() {
+ return hashCodePostingPartitionOffset;
+ }
+
+ public void setHashCodePostingPartitionOffset(int hashCodePostingPartitionOffset) {
+ this.hashCodePostingPartitionOffset = hashCodePostingPartitionOffset;
+ }
+ }
+
+ public void readHeader(Header header, RandomAccessFile RAF) throws IOException {
+ header.postingsCapacity = RAF.readInt();
+ }
+
+ public void writeHeader(Header header, RandomAccessFile RAF) throws IOException {
+ RAF.writeInt(header.postingsCapacity);
+ }
+
+ public int calculateHashCodePostingOffset(long hashCode) {
+ return (int) (HEADER_BYTE_SIZE + (Posting.POSTING_BYTE_SIZE * (hashCode & (header.postingsCapacity - 1))));
+ }
+
+ public void readPosting(Posting posting, RandomAccessFile RAF) throws IOException {
+ posting.flag = RAF.readByte();
+ posting.hashCodePostingPartition = RAF.readInt();
+ posting.hashCodePostingPartitionOffset = RAF.readInt();
+ }
+
+ public void writePosting(Posting posting, RandomAccessFile RAF) throws IOException {
+ RAF.writeByte(posting.flag);
+ RAF.writeInt(posting.hashCodePostingPartition);
+ RAF.writeInt(posting.hashCodePostingPartitionOffset);
+ }
+
+ public void deletePosting(int startOffset, RandomAccessFile RAF) throws IOException {
+ RAF.seek(startOffset);
+ RAF.writeByte((byte)2);
+ }
+
+}
Added: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/KeysPartition.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/KeysPartition.java?rev=755179&view=auto
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/KeysPartition.java (added)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/KeysPartition.java Tue Mar 17 10:14:03 2009
@@ -0,0 +1,251 @@
+package org.apache.labs.bananadb.store;
+
+/*
+ * 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 java.io.File;
+import java.io.RandomAccessFile;
+
+/**
+ * Key postings partition file.
+ * <p/>
+ * Chained postings. Each posting contains a unique key value and points at how to
+ * find the value associated with this key.
+ * <p/>
+ * This file is NOT affected by rehashing.
+ *
+ * @author kalle
+ * @since 2009-mar-16 14:00:22
+ */
+public class KeysPartition extends FileHandler<KeysPartition.Header, KeysPartition.Posting> {
+
+ private int partitionId;
+
+ public KeysPartition(File directory, int partitionId, String access) throws IOException {
+ super(directory, partitionId, "k", access);
+ this.partitionId = partitionId;
+ }
+
+ public static final int HEADER_BYTE_SIZE = 1024;
+
+ public int getHeaderByteSize() {
+ return HEADER_BYTE_SIZE;
+ }
+
+ public int getPartitionId() {
+ return partitionId;
+ }
+
+ public static class Header extends FileHandler.Header {
+
+ /**
+ * Offset in this partition for next new posting.
+ */
+ private int nextPostingOffset;
+ /**
+ * Bytes left for use in this partition.
+ */
+ private int bytesLeft;
+
+ public void update(Posting posting) {
+ int postingByteSize = posting.getPostingByteSize();
+ nextPostingOffset += postingByteSize;
+ bytesLeft -= postingByteSize;
+ }
+
+ public int getNextPostingOffset() {
+ return nextPostingOffset;
+ }
+
+ public void setNextPostingOffset(int nextPostingOffset) {
+ this.nextPostingOffset = nextPostingOffset;
+ }
+
+ public int getBytesLeft() {
+ return bytesLeft;
+ }
+
+ public void setBytesLeft(int bytesLeft) {
+ this.bytesLeft = bytesLeft;
+ }
+ }
+
+ public static class Posting extends FileHandler.Posting {
+
+
+ /**
+ * 0 = never used
+ * 1 = in use
+ * 2 = deleted
+ */
+ private byte flag;
+
+
+ /**
+ * Partition id of next key posting with the same hash code.
+ * -1 == end of keys chain
+ * -2 == deleted key
+ */
+ private int nextKeyPostingPartition;
+ /**
+ * Offset in above key postings partition.
+ */
+ private int nextKeyPostingPartitionOffset;
+
+ /**
+ * Key hash code
+ */
+ private long keyHashCode;
+
+ /**
+ * Paritition id of value posting. -1 == null
+ */
+ private int valuePostingPartition;
+ /**
+ * Offset in above value postings partition.
+ */
+ private int valuePostingPartitionOffset;
+
+ /**
+ * Length in bytes of serialized key.
+ */
+ private int bytesLength;
+ /**
+ * Serialized key
+ */
+ private byte[] bytes;
+
+ public int getPostingByteSize() {
+ return 1 + 4 + 4 + 8 + 4 + 4 + 4 + bytesLength;
+ }
+
+ public byte getFlag() {
+ return flag;
+ }
+
+ public void setFlag(byte flag) {
+ this.flag = flag;
+ }
+
+ public int getNextKeyPostingPartition() {
+ return nextKeyPostingPartition;
+ }
+
+ public void setNextKeyPostingPartition(int nextKeyPostingPartition) {
+ this.nextKeyPostingPartition = nextKeyPostingPartition;
+ }
+
+ public int getNextKeyPostingPartitionOffset() {
+ return nextKeyPostingPartitionOffset;
+ }
+
+ public void setNextKeyPostingPartitionOffset(int nextKeyPostingPartitionOffset) {
+ this.nextKeyPostingPartitionOffset = nextKeyPostingPartitionOffset;
+ }
+
+ public long getKeyHashCode() {
+ return keyHashCode;
+ }
+
+ public void setKeyHashCode(long keyHashCode) {
+ this.keyHashCode = keyHashCode;
+ }
+
+ public int getValuePostingPartition() {
+ return valuePostingPartition;
+ }
+
+ public void setValuePostingPartition(int valuePostingPartition) {
+ this.valuePostingPartition = valuePostingPartition;
+ }
+
+ public int getValuePostingPartitionOffset() {
+ return valuePostingPartitionOffset;
+ }
+
+ public void setValuePostingPartitionOffset(int valuePostingPartitionOffset) {
+ this.valuePostingPartitionOffset = valuePostingPartitionOffset;
+ }
+
+ public int getBytesLength() {
+ return bytesLength;
+ }
+
+ public void setBytesLength(int bytesLength) {
+ this.bytesLength = bytesLength;
+ }
+
+ public byte[] getBytes() {
+ return bytes;
+ }
+
+ public void setBytes(byte[] bytes) {
+ this.bytes = bytes;
+ }
+ }
+
+ public void readHeader(Header header, RandomAccessFile RAF) throws IOException {
+ header.nextPostingOffset = RAF.readInt();
+ header.bytesLeft = RAF.readInt();
+ }
+
+ public void writeHeader(Header header, RandomAccessFile RAF) throws IOException {
+ RAF.writeInt(header.nextPostingOffset);
+ RAF.writeInt(header.bytesLeft);
+ }
+
+ public void readPosting(Posting posting, RandomAccessFile RAF) throws IOException {
+ posting.flag = RAF.readByte();
+ posting.nextKeyPostingPartition = RAF.readInt();
+ posting.nextKeyPostingPartitionOffset = RAF.readInt();
+ posting.keyHashCode = RAF.readLong();
+ posting.valuePostingPartition = RAF.readInt();
+ posting.valuePostingPartitionOffset = RAF.readInt();
+ posting.bytesLength = RAF.readInt();
+ if (posting.bytesLength > 0) {
+ if (posting.bytes == null || posting.bytes.length != posting.bytesLength) {
+ posting.bytes = new byte[posting.bytesLength];
+ }
+ int read = RAF.read(posting.bytes, 0, posting.bytesLength);
+ if (read != posting.bytesLength) {
+ throw new IOException("Unexcpected EOF");
+ }
+ }
+ }
+
+ public void writePosting(Posting posting, RandomAccessFile RAF) throws IOException {
+ RAF.writeByte(posting.flag);
+ RAF.writeInt(posting.nextKeyPostingPartition);
+ RAF.writeInt(posting.nextKeyPostingPartitionOffset);
+ RAF.writeLong(posting.keyHashCode);
+ RAF.writeInt(posting.valuePostingPartition);
+ RAF.writeInt(posting.valuePostingPartitionOffset);
+ RAF.writeInt(posting.bytesLength);
+ if (posting.bytesLength > 0) {
+ RAF.write(posting.bytes, 0, posting.bytesLength);
+ }
+ }
+
+ public void deletePosting(int startOffset, RandomAccessFile RAF) throws IOException {
+ RAF.seek(startOffset);
+ RAF.writeByte((byte)2);
+ }
+
+
+}
Added: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Log.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Log.java?rev=755179&view=auto
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Log.java (added)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Log.java Tue Mar 17 10:14:03 2009
@@ -0,0 +1,144 @@
+package org.apache.labs.bananadb.store;
+
+/*
+ * 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.PrintWriter;
+
+/**
+ * BananaDB has very little debug output.
+ * This class avoids dependencies.
+ *
+ * @author kalle
+ * @since 2009-mar-16 23:32:14
+ */
+public class Log {
+
+ private static enum Level {
+ DEBUG(0), INFO(1), WARNING(2), ERROR(3);
+
+ private int intValue;
+
+ private Level(int intValue) {
+ this.intValue = intValue;
+ }
+
+ public int getIntValue() {
+ return intValue;
+ }
+ }
+
+ private Level level;
+
+ private String name;
+
+ public Log(String name) {
+ this(name, Level.INFO);
+ }
+
+ public Log(Class owner) {
+ this(owner.getName());
+ }
+
+ public Log(Class owner, Level level) {
+ this(owner.getName(), level);
+ }
+
+ public Log(String name, Level level) {
+ this.name = name;
+ this.level = level;
+ }
+
+ public boolean isDebug() {
+ return level.intValue <= Level.DEBUG.intValue;
+ }
+
+ public void debug(String text) {
+ if (isDebug()) {
+ log("DEBUG", text);
+ }
+ }
+
+ public boolean isInfo() {
+ return level.intValue <= Level.INFO.intValue;
+ }
+
+ public void info(String text) {
+ if (isInfo()) {
+ log("INFO", text);
+ }
+ }
+
+ public boolean isWarn() {
+ return level.intValue <= Level.WARNING.intValue;
+ }
+
+ public void warn(String text) {
+ if (isWarn()) {
+ log("WARNING", text);
+ }
+ }
+
+ public void warn(String text, Throwable throwable) {
+ if (isWarn()) {
+ log("WARNING", text, throwable);
+ }
+ }
+
+ public boolean isError() {
+ return level.intValue <= Level.ERROR.intValue;
+ }
+
+ public void error(Throwable throwable) {
+ if (isError()) {
+ log("ERROR", "", throwable);
+ }
+ }
+
+ public void error(String text, Throwable throwable) {
+ if (isError()) {
+ log("ERROR", text, throwable);
+ }
+ }
+
+ private void log(String type, String text) {
+ log(type, text, null);
+ }
+
+ private void log(String type, String text, Throwable throwable) {
+ out.print(String.valueOf(System.currentTimeMillis()));
+ out.print(" ");
+ out.print(name);
+ out.print(" ");
+ out.print(type);
+ out.print(": ");
+ out.print(text);
+ out.print("\n");
+ if (throwable != null) {
+ throwable.printStackTrace(out);
+ }
+ out.flush();
+ }
+
+ private PrintWriter out = new PrintWriter(System.err);
+
+ public void setOut(PrintWriter out) {
+ this.out = out;
+ }
+
+}
Added: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Metadata.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Metadata.java?rev=755179&view=auto
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Metadata.java (added)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Metadata.java Tue Mar 17 10:14:03 2009
@@ -0,0 +1,172 @@
+package org.apache.labs.bananadb.store;
+
+/*
+ * 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.RandomAccessFile;
+import java.io.IOException;
+import java.io.File;
+
+/**
+ * @author kalle
+ * @since 2009-mar-16 14:16:39
+ */
+public class Metadata extends FileHandler<Metadata.Header, FileHandler.Posting> {
+
+ public Metadata(File directory, String access) throws IOException {
+ super(directory, 0, "md", access);
+ }
+
+ public static final int HEADER_BYTE_SIZE = 1024;
+ public int getHeaderByteSize() {
+ return HEADER_BYTE_SIZE;
+ }
+
+ public static class Header extends FileHandler.Header {
+ /**
+ * File format version.
+ */
+ private int fileFormatVersion;
+
+ /**
+ * Current hashtable file id. -- will change after rehash.
+ */
+ private int currentHashtableId;
+
+ /** Current hash codes partition used for appending new postings */
+ private int currentHashCodesPartition;
+
+ /** Current keys partition used for appending new postings */
+ private int currentKeysPartition;
+
+ /** Current values partition used for appending new postings */
+ private int currentValuesPartition;
+
+ /**
+ * Total number of value postings.
+ */
+ private long valuePostingsCount;
+
+ /**
+ * Commit version, will increase by one after each modification to the database.
+ */
+ private long commitVersion;
+
+ public int getCurrentHashCodesPartition() {
+ return currentHashCodesPartition;
+ }
+
+ public void setCurrentHashCodesPartition(int currentHashCodesPartition) {
+ this.currentHashCodesPartition = currentHashCodesPartition;
+ }
+
+ public int getCurrentKeysPartition() {
+ return currentKeysPartition;
+ }
+
+ public void setCurrentKeysPartition(int currentKeysPartition) {
+ this.currentKeysPartition = currentKeysPartition;
+ }
+
+ public int getCurrentValuesPartition() {
+ return currentValuesPartition;
+ }
+
+ public void setCurrentValuesPartition(int currentValuesPartition) {
+ this.currentValuesPartition = currentValuesPartition;
+ }
+
+ public int getFileFormatVersion() {
+ return fileFormatVersion;
+ }
+
+ public void setFileFormatVersion(int fileFormatVersion) {
+ this.fileFormatVersion = fileFormatVersion;
+ }
+
+ public int getCurrentHashtableId() {
+ return currentHashtableId;
+ }
+
+ public void setCurrentHashtableId(int currentHashtableId) {
+ this.currentHashtableId = currentHashtableId;
+ }
+
+ public long getValuePostingsCount() {
+ return valuePostingsCount;
+ }
+
+ public void setValuePostingsCount(long valuePostingsCount) {
+ this.valuePostingsCount = valuePostingsCount;
+ }
+
+ public long getCommitVersion() {
+ return commitVersion;
+ }
+
+ public void setCommitVersion(long commitVersion) {
+ this.commitVersion = commitVersion;
+ }
+
+ public long increaseCommitVersion(long value) {
+ return commitVersion += value;
+ }
+
+ public long increaseValuePostingsCount(long value) {
+ return valuePostingsCount += value;
+ }
+
+ public long decreaseValuePostingsCount(long value) {
+ return valuePostingsCount -= value;
+ }
+
+ }
+
+ public void readHeader(Header header, RandomAccessFile RAF) throws IOException {
+ header.fileFormatVersion = RAF.readInt();
+ header.commitVersion = RAF.readLong();
+ header.currentHashtableId = RAF.readInt();
+ header.currentHashCodesPartition = RAF.readInt();
+ header.currentKeysPartition = RAF.readInt();
+ header.currentValuesPartition = RAF.readInt();
+ header.valuePostingsCount = RAF.readLong();
+
+ }
+
+ public void writeHeader(Header header, RandomAccessFile RAF) throws IOException {
+ RAF.writeInt(header.fileFormatVersion);
+ RAF.writeLong(header.commitVersion);
+ RAF.writeInt(header.currentHashtableId);
+ RAF.writeInt(header.currentHashCodesPartition);
+ RAF.writeInt(header.currentKeysPartition);
+ RAF.writeInt(header.currentValuesPartition);
+ RAF.writeLong(header.valuePostingsCount);
+ }
+
+ public void writePosting(Posting posting, RandomAccessFile RAF) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void readPosting(Posting posting, RandomAccessFile RAF) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void deletePosting(int startOffset, RandomAccessFile RAF) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+}
Added: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Store.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Store.java?rev=755179&view=auto
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Store.java (added)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Store.java Tue Mar 17 10:14:03 2009
@@ -0,0 +1,687 @@
+package org.apache.labs.bananadb.store;
+
+
+/*
+ * 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 org.apache.labs.bananadb.store.lock.Lock;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+/**
+ * @author kalle
+ * @since 2009-mar-16 15:34:56
+ */
+public class Store {
+
+ private static final Log log = new Log(Store.class);
+
+ private Configuration configuration;
+
+ public Store(Configuration configuration) {
+ this.configuration = configuration;
+ }
+
+
+ public void open() throws IOException {
+ if (!getConfiguration().getDataPath().exists()) {
+ if (log.isInfo()) {
+ log.info("Creating directory " + getConfiguration().getDataPath().getAbsolutePath());
+ }
+ if (!getConfiguration().getDataPath().mkdirs()) {
+ throw new IOException("Could not create directory " + getConfiguration().getDataPath().getAbsolutePath());
+ }
+ }
+ }
+
+
+ private List<Accessor> accessors = new ArrayList<Accessor>();
+
+ List<Accessor> getAccessors() {
+ return accessors;
+ }
+
+ public Accessor createAccessor(boolean readOnly) throws IOException {
+ Accessor accessor = new Accessor(this, readOnly);
+ accessors.add(accessor);
+ return accessor;
+ }
+
+ public void close() throws IOException {
+ log.info("Closing store..");
+ if (accessors.size() > 0) {
+ log.warn("There are " + accessors.size() + " open accessors. They will be closed.");
+ }
+ for (Accessor accessor : new ArrayList<Accessor>(accessors)) {
+ accessor.close();
+ }
+ log.info("Store has been closed.");
+ }
+
+ private void validateKey(byte[] key) {
+ if (key == null || key.length == 0) {
+ throw new IllegalArgumentException("Null key is not allowed");
+ }
+ }
+
+
+ public byte[] get(Accessor accessor, byte[] key, long hashCode) throws IOException {
+
+ validateKey(key);
+
+ Hashtable hashtable = accessor.getHashtable();
+ Hashtable.Posting hashtablePosting = new Hashtable.Posting();
+ hashtable.readPosting(hashtablePosting, hashtable.calculateHashCodePostingOffset(hashCode));
+
+ //
+ // seek to the correct hash code posting
+ //
+ HashCodesPartition hashCodesPartition = accessor.getHashCodesPartition(hashtablePosting.getHashCodePostingPartition());
+ HashCodesPartition.Posting hashCodePosting = new HashCodesPartition.Posting();
+ hashCodesPartition.readPosting(hashCodePosting, hashtablePosting.getHashCodePostingPartitionOffset());
+ if (hashCodePosting.getFlag() != (byte) 1) {
+ return null;
+ }
+ while (hashCode != hashCodePosting.getKeyHashCode()) {
+ if (hashCodePosting.getNextPostingPartition() < 0) {
+ return null;
+ }
+ if (hashCodePosting.getNextPostingPartition() != hashCodesPartition.getPartitionId()) {
+ hashCodesPartition = accessor.getHashCodesPartition(hashCodePosting.getNextPostingPartition());
+ }
+ hashCodesPartition.readPosting(hashCodePosting, hashCodePosting.getNextPostingPartitionOffset());
+ }
+
+ //
+ // seek to the correct key posting
+ //
+
+ KeysPartition.Posting keyPosting = new KeysPartition.Posting();
+
+ KeysPartition keysPartition = accessor.getKeysPartition(hashCodePosting.getFirstKeyPostingPartition());
+ keysPartition.readPosting(keyPosting, hashCodePosting.getFirstKeyPostingPartitionOffset());
+ while (!Arrays.equals(key, keyPosting.getBytes())) {
+ if (keyPosting.getNextKeyPostingPartition() < 0) {
+ return null;
+ }
+ if (keyPosting.getNextKeyPostingPartition() != keysPartition.getPartitionId()) {
+ keysPartition = accessor.getKeysPartition(keyPosting.getNextKeyPostingPartition());
+ }
+ keysPartition.readPosting(keyPosting, keyPosting.getNextKeyPostingPartitionOffset());
+ }
+
+ //
+ // seek to the correct value posting
+ //
+
+ ValuesPartition.Posting valuePosting = new ValuesPartition.Posting();
+
+ ValuesPartition valuesPartition = accessor.getValuesPartition(keyPosting.getValuePostingPartition());
+ valuesPartition.readPosting(valuePosting, keyPosting.getValuePostingPartitionOffset());
+
+ if (valuePosting.getBytesLength() == 0) {
+ return null;
+ }
+
+ return valuePosting.getBytes();
+ }
+
+ /**
+ * Write locking.
+ *
+ * @param accessor
+ * @param key
+ * @param hashCode
+ * @param value
+ * @return
+ * @throws IOException
+ */
+ public byte[] put(final Accessor accessor, final byte[] key, final long hashCode, final byte[] value) throws IOException {
+
+ validateKey(key);
+
+ Lock.With<byte[]> with = new Lock.With<byte[]>(accessor.getWriteLock(), getConfiguration().getLockWaitTimeoutMilliseconds()) {
+ protected byte[] doBody() throws IOException {
+ byte[] ret = doPut(accessor, key, hashCode, value);
+ Metadata metadata = accessor.getMetadata();
+ Metadata.Header mdh = new Metadata.Header();
+ metadata.readHeader(mdh);
+ mdh.setCommitVersion(mdh.getCommitVersion() + 1);
+ metadata.writeHeader(mdh);
+ return ret;
+ }
+ };
+ return with.run();
+ }
+
+ /**
+ * Write locking.
+ *
+ * @param accessor
+ * @param key
+ * @param hashCode
+ * @param value
+ * @return
+ * @throws IOException
+ */
+ private byte[] doPut(final Accessor accessor, final byte[] key, final long hashCode, final byte[] value) throws IOException {
+
+
+ //
+ // create new value posting
+ //
+
+ int newValuePostingPartition;
+ int newValuePostingPartitionOffset;
+
+ ValuesPartition.Posting valuePosting = new ValuesPartition.Posting();
+
+ if (value == null || value.length == 0) {
+ valuePosting.setBytesLength(0);
+ valuePosting.setBytes(null);
+
+ newValuePostingPartition = -1;
+ newValuePostingPartitionOffset = -1;
+
+ } else {
+ valuePosting.setBytesLength(value.length);
+ valuePosting.setBytes(value);
+
+ Accessor.RequestPartitionWriterResponse<ValuesPartition> valueReservation = accessor.requestValueWrite(valuePosting);
+ newValuePostingPartition = valueReservation.getFileHandler().getPartitionId();
+ ValuesPartition valuesPartition = valueReservation.getFileHandler();
+ newValuePostingPartitionOffset = valueReservation.getStartOffset();
+
+ // write new value posting, keep track of partition and offset
+ valuesPartition.writePosting(valuePosting, newValuePostingPartitionOffset);
+
+ }
+
+
+ //
+ // create new key posting
+ //
+
+ KeysPartition.Posting newKeyPosting = new KeysPartition.Posting();
+ newKeyPosting.setFlag((byte) 1);
+ newKeyPosting.setBytes(key);
+ newKeyPosting.setBytesLength(key.length);
+ newKeyPosting.setKeyHashCode(hashCode);
+ newKeyPosting.setNextKeyPostingPartition(-1);
+ newKeyPosting.setNextKeyPostingPartitionOffset(-1);
+ newKeyPosting.setValuePostingPartition(newValuePostingPartition);
+ newKeyPosting.setValuePostingPartitionOffset(newValuePostingPartitionOffset);
+
+ Accessor.RequestPartitionWriterResponse<KeysPartition> keyReservation = accessor.requestValueWrite(newKeyPosting);
+ int newKeyPostingPartition = keyReservation.getFileHandler().getPartitionId();
+ KeysPartition keysPartition = keyReservation.getFileHandler();
+ int newKeyPostingPartitionOffset = keyReservation.getStartOffset();
+
+ keysPartition.writePosting(newKeyPosting, newKeyPostingPartitionOffset);
+
+
+ //
+ // find hashcode posting and hashtable posting for the new key
+ //
+
+ Hashtable hashtable = accessor.getHashtable();
+ Hashtable.Posting hashtablePosting = new Hashtable.Posting();
+ HashCodesPartition.Posting hashCodePosting = new HashCodesPartition.Posting();
+
+ int hashtablePostingOffset = hashtable.calculateHashCodePostingOffset(hashCode);
+ hashtable.readPosting(hashtablePosting, hashtablePostingOffset);
+ if (hashtablePosting.getFlag() != (byte) 1) {
+
+ // this is the first time we create a posting at this hashtable position
+ // that means there is no hash code posting either
+
+ hashCodePosting.setFlag((byte) 1);
+ hashCodePosting.setFirstKeyPostingPartition(newKeyPostingPartition);
+ hashCodePosting.setFirstKeyPostingPartitionOffset(newKeyPostingPartitionOffset);
+ hashCodePosting.setKeyHashCode(hashCode);
+ hashCodePosting.setNextPostingPartition(-1);
+ hashCodePosting.setNextPostingPartitionOffset(-1);
+
+ Accessor.RequestPartitionWriterResponse<HashCodesPartition> hashCodeReservation = accessor.requestValueWrite(hashCodePosting);
+ int newHashCodePostingPatition = hashCodeReservation.getFileHandler().getPartitionId();
+ HashCodesPartition hashCodesPartition = hashCodeReservation.getFileHandler();
+ int newHashCodePostingPatitionOffset = hashCodeReservation.getStartOffset();
+
+ hashCodesPartition.writePosting(hashCodePosting, newHashCodePostingPatitionOffset);
+
+ // update hashtable posting
+
+ hashtablePosting.setFlag((byte) 1);
+ hashtablePosting.setHashCodePostingPartition(newHashCodePostingPatition);
+ hashtablePosting.setHashCodePostingPartitionOffset(newHashCodePostingPatitionOffset);
+ hashtable.writePosting(hashtablePosting, hashtablePostingOffset);
+
+ return null;
+
+ } else {
+
+ // there is a hashtable posting at the position for this hash code
+
+ //
+ // seek to the correct hash code posting
+ //
+
+ HashCodesPartition hashCodesPartition = accessor.getHashCodesPartition(hashtablePosting.getHashCodePostingPartition());
+ int currentHashCodesPotingPartitionOffset = hashtablePosting.getHashCodePostingPartitionOffset();
+ hashCodesPartition.readPosting(hashCodePosting, hashtablePosting.getHashCodePostingPartitionOffset());
+ while (hashCode != hashCodePosting.getKeyHashCode()) {
+ if (hashCodePosting.getNextPostingPartition() < 0) {
+
+ // there is no hash code posting matching this hash code.
+
+ //
+ // create new hash code posting
+ //
+
+ HashCodesPartition.Posting newHashCodePosting = new HashCodesPartition.Posting();
+ newHashCodePosting.setFlag((byte) 1);
+ newHashCodePosting.setKeyHashCode(hashCode);
+ newHashCodePosting.setNextPostingPartition(-1);
+ newHashCodePosting.setNextPostingPartitionOffset(-1);
+ newHashCodePosting.setFirstKeyPostingPartition(newKeyPostingPartition);
+ newHashCodePosting.setFirstKeyPostingPartitionOffset(newKeyPostingPartitionOffset);
+
+ Accessor.RequestPartitionWriterResponse<HashCodesPartition> hashCodeReservation = accessor.requestValueWrite(newHashCodePosting);
+
+ int newHashCodePostingPartition = hashCodeReservation.getFileHandler().getPartitionId();
+ int newHashCodePostingPartitionOffset = hashCodeReservation.getStartOffset();
+
+ hashCodeReservation.getFileHandler().writePosting(newHashCodePosting, newHashCodePostingPartitionOffset);
+
+
+ //
+ // and update the current posting to point at the new one as next in chain.
+ //
+
+ hashCodePosting.setNextPostingPartition(newHashCodePostingPartition);
+ hashCodePosting.setNextPostingPartitionOffset(newHashCodePostingPartitionOffset);
+ hashCodesPartition.writePosting(hashCodePosting, currentHashCodesPotingPartitionOffset);
+
+ return null;
+
+ }
+ if (hashCodePosting.getNextPostingPartition() != hashCodesPartition.getPartitionId()) {
+ hashCodesPartition = accessor.getHashCodesPartition(hashCodePosting.getNextPostingPartition());
+ }
+ currentHashCodesPotingPartitionOffset = hashCodePosting.getNextPostingPartitionOffset();
+ hashCodesPartition.readPosting(hashCodePosting, hashCodePosting.getNextPostingPartitionOffset());
+ }
+
+ //
+ // seek for the same key
+ //
+
+ keysPartition = accessor.getKeysPartition(hashCodePosting.getFirstKeyPostingPartition());
+
+ KeysPartition.Posting keyPosting = new KeysPartition.Posting();
+
+ int previousKeyPostingPartition = -1;
+ int previousKeyPostingPartitionOffset = -1;
+
+ int currentKeyPostingPartition = keysPartition.getPartitionId();
+ int currentKeyPostingPartitionOffset = hashCodePosting.getFirstKeyPostingPartitionOffset();
+ keysPartition.readPosting(keyPosting, hashCodePosting.getFirstKeyPostingPartitionOffset());
+ while (!Arrays.equals(key, keyPosting.getBytes())) {
+ if (keyPosting.getNextKeyPostingPartition() < 0) {
+
+ // the key did not exist
+ // update the current key posting to point at the new key posting partition and offset as next in chain.
+ keyPosting.setNextKeyPostingPartition(newKeyPostingPartition);
+ keyPosting.setNextKeyPostingPartitionOffset(newKeyPostingPartitionOffset);
+ keysPartition.writePosting(keyPosting, currentKeyPostingPartitionOffset);
+
+ return null;
+ }
+ if (keyPosting.getNextKeyPostingPartition() != keysPartition.getPartitionId()) {
+ keysPartition = accessor.getKeysPartition(keyPosting.getNextKeyPostingPartition());
+ }
+
+ previousKeyPostingPartition = currentKeyPostingPartition;
+ previousKeyPostingPartitionOffset = currentKeyPostingPartitionOffset;
+
+ currentKeyPostingPartitionOffset = keyPosting.getNextKeyPostingPartitionOffset();
+ currentKeyPostingPartition = keysPartition.getPartitionId();
+
+ keysPartition.readPosting(keyPosting, keyPosting.getNextKeyPostingPartitionOffset());
+ }
+
+ //
+ // a posting exists for this key.
+ //
+
+
+ if (hashCodePosting.getFirstKeyPostingPartition() == currentKeyPostingPartition
+ && hashCodePosting.getFirstKeyPostingPartitionOffset() == currentKeyPostingPartitionOffset) {
+ // no previous key
+ // update the hash code posting to point at new key posting as the first in chain
+
+ hashCodePosting.setFirstKeyPostingPartition(newKeyPostingPartition);
+ hashCodePosting.setFirstKeyPostingPartitionOffset(newKeyPostingPartitionOffset);
+ hashCodesPartition.writePosting(hashCodePosting, currentHashCodesPotingPartitionOffset);
+ } else {
+
+ // mark old key as deleted
+ keysPartition.deletePosting(currentKeyPostingPartitionOffset);
+
+ // update previous key posting in chain to point chain at new key posting rather than the deleted
+ if (previousKeyPostingPartition != currentKeyPostingPartition) {
+ keysPartition = accessor.getKeysPartition(previousKeyPostingPartition);
+ }
+ keysPartition.readPosting(keyPosting, previousKeyPostingPartitionOffset);
+ keyPosting.setNextKeyPostingPartition(newKeyPostingPartition);
+ keyPosting.setNextKeyPostingPartitionOffset(newKeyPostingPartitionOffset);
+ keysPartition.writePosting(keyPosting, previousKeyPostingPartitionOffset);
+ }
+
+
+ // read the old value
+ ValuesPartition valuesPartition = accessor.getValuesPartition(keyPosting.getValuePostingPartition());
+ valuesPartition.readPosting(valuePosting, keyPosting.getValuePostingPartitionOffset());
+ byte[] oldValue;
+ if (valuePosting.getBytesLength() > 0) {
+ oldValue = valuePosting.getBytes();
+ } else {
+ oldValue = null;
+ }
+
+ // mark the old value as deleted
+ valuesPartition.deletePosting(keyPosting.getValuePostingPartitionOffset());
+
+ return oldValue;
+
+ }
+
+ }
+
+ /**
+ * Write locking.
+ *
+ * @param accessor
+ * @param key
+ * @param hashCode
+ * @return
+ * @throws IOException
+ */
+ public byte[] remove(final Accessor accessor, final byte[] key, final long hashCode) throws IOException {
+
+ validateKey(key);
+
+ Lock.With<byte[]> with = new Lock.With<byte[]>(accessor.getWriteLock(), getConfiguration().getLockWaitTimeoutMilliseconds()) {
+ protected byte[] doBody() throws IOException {
+
+ byte[] ret = doRemove(accessor, key, hashCode);
+
+ Metadata metadata = accessor.getMetadata();
+ Metadata.Header mdh = new Metadata.Header();
+ metadata.readHeader(mdh);
+ mdh.setCommitVersion(mdh.getCommitVersion() + 1);
+ metadata.writeHeader(mdh);
+
+ return ret;
+
+ }
+ };
+ return with.run();
+ }
+
+ /**
+ * Write locking.
+ *
+ * @param accessor
+ * @param key
+ * @param hashCode
+ * @return
+ * @throws IOException
+ */
+ private byte[] doRemove(final Accessor accessor, final byte[] key, final long hashCode) throws IOException {
+
+ Hashtable.Posting hashtablePosting = new Hashtable.Posting();
+
+ //
+ // find hashtable posting
+ //
+
+ Hashtable hashtable = accessor.getHashtable();
+ int hashtablePostingOffset = hashtable.calculateHashCodePostingOffset(hashCode);
+ accessor.getHashtable().readPosting(hashtablePosting, hashtablePostingOffset);
+ if (hashtablePosting.getHashCodePostingPartition() < 0) {
+ throw new NoSuchElementException(); // todo return null?
+ }
+
+ //
+ // seek to the correct hash code posting
+ //
+
+ HashCodesPartition.Posting hashCodePosting = new HashCodesPartition.Posting();
+
+ HashCodesPartition hashCodesPartition = accessor.getHashCodesPartition(hashtablePosting.getHashCodePostingPartition());
+ int currentHashCodePostingPartitionOffset = hashtablePosting.getHashCodePostingPartitionOffset();
+ int currentHashCodePostingPartition = hashtablePosting.getHashCodePostingPartition();
+ hashCodesPartition.readPosting(hashCodePosting, hashtablePosting.getHashCodePostingPartitionOffset());
+ while (hashCode != hashCodePosting.getKeyHashCode()) {
+ if (hashCodePosting.getNextPostingPartition() < 0) {
+ throw new NoSuchElementException(); // todo return null?
+ }
+
+ if (hashCodePosting.getNextPostingPartition() != hashCodesPartition.getPartitionId()) {
+ hashCodesPartition = accessor.getHashCodesPartition(hashCodePosting.getNextPostingPartition());
+ }
+ currentHashCodePostingPartitionOffset = hashCodePosting.getNextPostingPartitionOffset();
+ currentHashCodePostingPartition = hashCodePosting.getNextPostingPartition();
+ hashCodesPartition.readPosting(hashCodePosting, hashCodePosting.getNextPostingPartitionOffset());
+ }
+
+ //
+ // seek for the same key
+ //
+
+ KeysPartition.Posting keyPosting = new KeysPartition.Posting();
+
+ KeysPartition keysPartition = accessor.getKeysPartition(hashCodePosting.getFirstKeyPostingPartition());
+
+ int previousKeyPostingPartition = -1;
+ int previousKeyPostingPartitionOffset = -1;
+
+ int currentKeyPostingPartition = keysPartition.getPartitionId();
+ int currentKeyPostingPartitionOffset = hashCodePosting.getFirstKeyPostingPartitionOffset();
+ keysPartition.readPosting(keyPosting, hashCodePosting.getFirstKeyPostingPartitionOffset());
+ while (!Arrays.equals(key, keyPosting.getBytes())) {
+ if (keyPosting.getNextKeyPostingPartition() < 0) {
+ // the key did not exist
+ throw new NoSuchElementException(); // todo return null?
+ }
+ if (keyPosting.getNextKeyPostingPartition() != keysPartition.getPartitionId()) {
+ keysPartition = accessor.getKeysPartition(keyPosting.getNextKeyPostingPartition());
+ }
+
+ previousKeyPostingPartition = currentKeyPostingPartition;
+ previousKeyPostingPartitionOffset = currentKeyPostingPartitionOffset;
+
+ currentKeyPostingPartitionOffset = keyPosting.getNextKeyPostingPartitionOffset();
+ currentKeyPostingPartition = keysPartition.getPartitionId();
+
+ keysPartition.readPosting(keyPosting, keyPosting.getNextKeyPostingPartitionOffset());
+ }
+
+ //
+ // a posting exists for this key.
+ //
+
+
+ if (hashCodePosting.getFirstKeyPostingPartition() == currentKeyPostingPartition
+ && hashCodePosting.getFirstKeyPostingPartitionOffset() == currentKeyPostingPartitionOffset) {
+
+ //
+ // no previous key in chain
+ //
+
+ if (hashtablePosting.getHashCodePostingPartition() == currentHashCodePostingPartition
+ && hashtablePosting.getHashCodePostingPartitionOffset() == currentHashCodePostingPartitionOffset) {
+
+ //
+ // no previous hash code posting in chain
+ // i.e. there are now no postings in the hashtable that match the hash code of this key
+ // so delete the hashtable and hash code posting
+ //
+
+ hashCodesPartition.deletePosting(currentHashCodePostingPartitionOffset);
+
+ hashtable.deletePosting(hashtablePostingOffset);
+
+ }
+
+ } else {
+
+ //
+ // there is a previous key in the chain.
+ // update it to point at the next key in chain as defined by the current key
+ //
+
+ if (keysPartition.getPartitionId() != previousKeyPostingPartition) {
+ keysPartition = accessor.getKeysPartition(previousKeyPostingPartition);
+ }
+ KeysPartition.Posting previousKeyPosting = new KeysPartition.Posting();
+ keysPartition.readPosting(previousKeyPosting, previousKeyPostingPartitionOffset);
+ previousKeyPosting.setNextKeyPostingPartition(keyPosting.getNextKeyPostingPartition());
+ previousKeyPosting.setNextKeyPostingPartitionOffset(keyPosting.getNextKeyPostingPartitionOffset());
+ keysPartition.writePosting(previousKeyPosting, previousKeyPostingPartitionOffset);
+
+ }
+
+
+ // mark old key as deleted
+ keysPartition.deletePosting(currentKeyPostingPartitionOffset);
+
+
+ // read the old value
+ ValuesPartition.Posting valuePosting = new ValuesPartition.Posting();
+
+ ValuesPartition oldValuePartition = accessor.getValuesPartition(keyPosting.getValuePostingPartition());
+ oldValuePartition.readPosting(valuePosting, keyPosting.getValuePostingPartitionOffset());
+ byte[] oldValue;
+ if (valuePosting.getBytesLength() > 0) {
+ oldValue = valuePosting.getBytes();
+ } else {
+ oldValue = null;
+ }
+
+ // mark the old value as deleted
+ oldValuePartition.deletePosting(keyPosting.getValuePostingPartitionOffset());
+
+ return oldValue;
+
+ }
+
+ public boolean containsKey(Accessor accessor, byte[] key, long hashCode) throws IOException {
+
+ validateKey(key);
+
+ Hashtable hashtable = accessor.getHashtable();
+ Hashtable.Posting hashtablePosting = new Hashtable.Posting();
+ hashtable.readPosting(hashtablePosting, hashtable.calculateHashCodePostingOffset(hashCode));
+
+ //
+ // seek to the correct hash code posting
+ //
+
+ HashCodesPartition.Posting hashCodePosting = new HashCodesPartition.Posting();
+
+ HashCodesPartition hashCodesPartition = accessor.getHashCodesPartition(hashtablePosting.getHashCodePostingPartition());
+ hashCodesPartition.readPosting(hashCodePosting, hashtablePosting.getHashCodePostingPartitionOffset());
+ if (hashCodePosting.getFlag() != (byte) 1) {
+ return false;
+ }
+ while (hashCode != hashCodePosting.getKeyHashCode()) {
+ if (hashCodePosting.getNextPostingPartition() < 0) {
+ return false;
+ }
+ if (hashCodePosting.getNextPostingPartition() != hashCodesPartition.getPartitionId()) {
+ hashCodesPartition = accessor.getHashCodesPartition(hashCodePosting.getNextPostingPartition());
+ }
+ hashCodesPartition.readPosting(hashCodePosting, hashCodePosting.getNextPostingPartitionOffset());
+ }
+
+ //
+ // seek to the correct key posting
+ //
+
+ KeysPartition.Posting keyPosting = new KeysPartition.Posting();
+
+ KeysPartition keysPartition = accessor.getKeysPartition(hashCodePosting.getFirstKeyPostingPartition());
+ keysPartition.readPosting(keyPosting, hashCodePosting.getFirstKeyPostingPartitionOffset());
+ while (!Arrays.equals(key, keyPosting.getBytes())) {
+ if (keyPosting.getNextKeyPostingPartition() < 0) {
+ return false;
+ }
+ if (keyPosting.getNextKeyPostingPartition() != keysPartition.getPartitionId()) {
+ keysPartition = accessor.getKeysPartition(keyPosting.getNextKeyPostingPartition());
+ }
+ keysPartition.readPosting(keyPosting, keyPosting.getNextKeyPostingPartitionOffset());
+ }
+
+ return true;
+
+ }
+
+ public Cursor values() {
+
+ // todo iterate all value partitions
+ throw new UnsupportedOperationException();
+
+ }
+
+ public Cursor keys() {
+
+ // todo iterate all key partitions
+ throw new UnsupportedOperationException();
+
+ }
+
+ /**
+ * Removes all deleted postings from the store
+ * Write locking.
+ */
+ public void optimize() {
+ throw new UnsupportedOperationException();
+
+ }
+
+ /**
+ * Rehashes the hash table.
+ * Write locking.
+ *
+ * @param resolution number of postings in new hashtable file
+ */
+ public void rehash(int resolution) {
+ throw new UnsupportedOperationException();
+ }
+
+ public Configuration getConfiguration() {
+ return configuration;
+ }
+
+
+}
Added: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/ValuesPartition.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/ValuesPartition.java?rev=755179&view=auto
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/ValuesPartition.java (added)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/ValuesPartition.java Tue Mar 17 10:14:03 2009
@@ -0,0 +1,174 @@
+package org.apache.labs.bananadb.store;
+
+/*
+ * 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.RandomAccessFile;
+import java.io.IOException;
+import java.io.File;
+
+/**
+ * Values postings partition file.
+ * <p/>
+ * This file is NOT affected by rehashing.
+ *
+ * @author kalle
+ * @since 2009-mar-16 14:00:13
+ */
+public class ValuesPartition extends FileHandler<ValuesPartition.Header, ValuesPartition.Posting> {
+
+
+ private int partitionId;
+
+ public ValuesPartition(File directory, int partitionId, String access) throws IOException {
+ super(directory, partitionId, "v", access);
+ this.partitionId = partitionId;
+ }
+
+ public static final int HEADER_BYTE_SIZE = 1024;
+
+ public int getHeaderByteSize() {
+ return HEADER_BYTE_SIZE;
+ }
+
+ public int getPartitionId() {
+ return partitionId;
+ }
+
+
+ public static class Header extends FileHandler.Header {
+
+ /**
+ * Offset in this partition for next new posting.
+ */
+ private int nextPostingOffset;
+ /**
+ * Bytes left for use in this partition.
+ */
+ private int bytesLeft;
+
+ public void update(Posting posting) {
+ int postingByteSize = posting.getPostingByteSize();
+ nextPostingOffset += postingByteSize;
+ bytesLeft -= postingByteSize;
+ }
+
+ public int getNextPostingOffset() {
+ return nextPostingOffset;
+ }
+
+ public void setNextPostingOffset(int nextPostingOffset) {
+ this.nextPostingOffset = nextPostingOffset;
+ }
+
+ public int getBytesLeft() {
+ return bytesLeft;
+ }
+
+ public void setBytesLeft(int bytesLeft) {
+ this.bytesLeft = bytesLeft;
+ }
+ }
+
+ public static class Posting extends FileHandler.Posting {
+
+ /**
+ * 0 = never used
+ * 1 = in use
+ * 2 = deleted
+ */
+ private byte flag;
+
+
+ /**
+ * Length in bytes of serializaed value.
+ * 0 == null
+ */
+ private int bytesLength;
+
+ /**
+ * Serialized value.
+ */
+ private byte[] bytes;
+
+
+ public int getPostingByteSize() {
+ return 1 + 4 + bytesLength;
+ }
+
+ public byte getFlag() {
+ return flag;
+ }
+
+ public void setFlag(byte flag) {
+ this.flag = flag;
+ }
+
+ public int getBytesLength() {
+ return bytesLength;
+ }
+
+ public void setBytesLength(int valueBytesLength) {
+ this.bytesLength = valueBytesLength;
+ }
+
+ public byte[] getBytes() {
+ return bytes;
+ }
+
+ public void setBytes(byte[] valueBytes) {
+ this.bytes = valueBytes;
+ }
+ }
+
+ public void readHeader(Header header, RandomAccessFile RAF) throws IOException {
+ header.nextPostingOffset = RAF.readInt();
+ header.bytesLeft = RAF.readInt();
+ }
+
+ public void writeHeader(Header header, RandomAccessFile RAF) throws IOException {
+ RAF.writeInt(header.nextPostingOffset);
+ RAF.writeInt(header.bytesLeft);
+ }
+
+ public void readPosting(Posting posting, RandomAccessFile RAF) throws IOException {
+ posting.flag = RAF.readByte();
+ posting.bytesLength = RAF.readInt();
+ if (posting.bytesLength > 0) {
+ posting.bytes = new byte[posting.bytesLength];
+ int read = RAF.read(posting.bytes, 0, posting.bytesLength);
+ if (read != posting.bytesLength) {
+ throw new IOException("Unexpected EOF");
+ }
+ }
+ }
+
+ public void writePosting(Posting posting, RandomAccessFile RAF) throws IOException {
+ RAF.writeByte(posting.flag);
+ RAF.writeInt(posting.bytesLength);
+ if (posting.bytesLength > 0) {
+ RAF.write(posting.bytes, 0, posting.bytesLength);
+ }
+ }
+
+ public void deletePosting(int startOffset, RandomAccessFile RAF) throws IOException {
+ RAF.seek(startOffset);
+ RAF.writeByte((byte) 2);
+ }
+
+}
Modified: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/lock/Lock.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/lock/Lock.java?rev=755179&r1=754666&r2=755179&view=diff
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/lock/Lock.java (original)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/lock/Lock.java Tue Mar 17 10:14:03 2009
@@ -1,4 +1,4 @@
-package org.apache.labs.bananadb.lock;
+package org.apache.labs.bananadb.store.lock;
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
Modified: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/lock/LockFactory.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/lock/LockFactory.java?rev=755179&r1=754666&r2=755179&view=diff
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/lock/LockFactory.java (original)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/lock/LockFactory.java Tue Mar 17 10:14:03 2009
@@ -1,4 +1,4 @@
-package org.apache.labs.bananadb.lock;
+package org.apache.labs.bananadb.store.lock;
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
Modified: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/lock/LockObtainFailedException.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/lock/LockObtainFailedException.java?rev=755179&r1=754666&r2=755179&view=diff
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/lock/LockObtainFailedException.java (original)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/lock/LockObtainFailedException.java Tue Mar 17 10:14:03 2009
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package org.apache.labs.bananadb.lock;
+package org.apache.labs.bananadb.store.lock;
import java.io.IOException;
Modified: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/lock/LockReleaseFailedException.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/lock/LockReleaseFailedException.java?rev=755179&r1=754666&r2=755179&view=diff
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/lock/LockReleaseFailedException.java (original)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/lock/LockReleaseFailedException.java Tue Mar 17 10:14:03 2009
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package org.apache.labs.bananadb.lock;
+package org.apache.labs.bananadb.store.lock;
import java.io.IOException;
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@labs.apache.org
For additional commands, e-mail: commits-help@labs.apache.org