From 39fce59a840b723eb013bc79285687986592b2da Mon Sep 17 00:00:00 2001 From: "Brian S. O'Neill" Date: Sun, 3 Sep 2006 06:14:41 +0000 Subject: More work on query engine. --- .../amazon/carbonado/repo/toy/ToyRepository.java | 106 +++++++++ .../carbonado/repo/toy/ToyStorableGenerator.java | 143 ++++++++++++ .../com/amazon/carbonado/repo/toy/ToyStorage.java | 242 +++++++++++++++++++++ .../amazon/carbonado/repo/toy/ToyTransaction.java | 51 +++++ .../amazon/carbonado/repo/toy/package-info.java | 25 +++ 5 files changed, 567 insertions(+) create mode 100644 src/test/java/com/amazon/carbonado/repo/toy/ToyRepository.java create mode 100644 src/test/java/com/amazon/carbonado/repo/toy/ToyStorableGenerator.java create mode 100644 src/test/java/com/amazon/carbonado/repo/toy/ToyStorage.java create mode 100644 src/test/java/com/amazon/carbonado/repo/toy/ToyTransaction.java create mode 100644 src/test/java/com/amazon/carbonado/repo/toy/package-info.java (limited to 'src/test/java/com/amazon/carbonado/repo/toy') diff --git a/src/test/java/com/amazon/carbonado/repo/toy/ToyRepository.java b/src/test/java/com/amazon/carbonado/repo/toy/ToyRepository.java new file mode 100644 index 0000000..159f451 --- /dev/null +++ b/src/test/java/com/amazon/carbonado/repo/toy/ToyRepository.java @@ -0,0 +1,106 @@ +/* + * Copyright 2006 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.repo.toy; + +import java.util.HashMap; +import java.util.Map; + +import com.amazon.carbonado.IsolationLevel; +import com.amazon.carbonado.Repository; +import com.amazon.carbonado.RepositoryException; +import com.amazon.carbonado.Storable; +import com.amazon.carbonado.Storage; +import com.amazon.carbonado.SupportException; +import com.amazon.carbonado.Transaction; + +import com.amazon.carbonado.capability.Capability; + +import com.amazon.carbonado.spi.SequenceValueGenerator; +import com.amazon.carbonado.spi.SequenceValueProducer; + +/** + * + * @author Brian S O'Neill + */ +public class ToyRepository implements Repository { + private final String mName; + private final Map mStorages; + private final Map mSequences; + + public ToyRepository() { + this("toy"); + } + + public ToyRepository(String name) { + mName = name; + mStorages = new HashMap(); + mSequences = new HashMap(); + } + + public String getName() { + return mName; + } + + public Storage storageFor(Class type) + throws SupportException, RepositoryException + { + synchronized (mStorages) { + Storage storage = (Storage) mStorages.get(type); + if (storage == null) { + storage = new ToyStorage(this, type); + mStorages.put(type, storage); + } + return storage; + } + } + + public Transaction enterTransaction() { + return new ToyTransaction(); + } + + public Transaction enterTransaction(IsolationLevel level) { + return enterTransaction(); + } + + public Transaction enterTopTransaction(IsolationLevel level) { + return enterTransaction(level); + } + + public IsolationLevel getTransactionIsolationLevel() { + return null; + } + + public C getCapability(Class capabilityType) { + return null; + } + + public void close() { + } + + SequenceValueProducer getSequenceValueProducer(String name) throws RepositoryException { + synchronized (mSequences) { + SequenceValueProducer producer = mSequences.get(name); + if (producer == null) { + producer = new SequenceValueGenerator(this, name); + mSequences.put(name, producer); + } + return producer; + } + } +} diff --git a/src/test/java/com/amazon/carbonado/repo/toy/ToyStorableGenerator.java b/src/test/java/com/amazon/carbonado/repo/toy/ToyStorableGenerator.java new file mode 100644 index 0000000..a72c7d5 --- /dev/null +++ b/src/test/java/com/amazon/carbonado/repo/toy/ToyStorableGenerator.java @@ -0,0 +1,143 @@ +/* + * Copyright 2006 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.repo.toy; + +import java.util.EnumSet; +import java.util.Map; + +import org.cojen.classfile.ClassFile; +import org.cojen.classfile.CodeBuilder; +import org.cojen.classfile.MethodInfo; +import org.cojen.classfile.Modifiers; +import org.cojen.classfile.TypeDesc; + +import org.cojen.util.ClassInjector; +import org.cojen.util.SoftValuedHashMap; + +import com.amazon.carbonado.Storable; +import com.amazon.carbonado.SupportException; +import com.amazon.carbonado.Trigger; + +import com.amazon.carbonado.spi.MasterFeature; +import com.amazon.carbonado.spi.MasterStorableGenerator; +import com.amazon.carbonado.spi.MasterSupport; +import com.amazon.carbonado.spi.StorableGenerator; +import com.amazon.carbonado.spi.TriggerSupport; + +/** + * + * + * @author Brian S O'Neill + */ +public class ToyStorableGenerator { + private static final Map cCache; + + static { + cCache = new SoftValuedHashMap(); + } + + /** + * Generated class has a constructor that accepts a ToyStorage instance. + */ + public static Class getGeneratedClass(Class type) + throws SupportException + { + synchronized (cCache) { + Class generatedClass = (Class) cCache.get(type); + if (generatedClass != null) { + return generatedClass; + } + generatedClass = new ToyStorableGenerator(type).generateAndInjectClass(); + cCache.put(type, generatedClass); + return generatedClass; + } + } + + private final Class mStorableType; + + private final ClassInjector mClassInjector; + private final ClassFile mClassFile; + + private ToyStorableGenerator(Class type) throws SupportException { + mStorableType = type; + + EnumSet features = EnumSet + .of(MasterFeature.VERSIONING, MasterFeature.INSERT_SEQUENCES); + + final Class abstractClass = + MasterStorableGenerator.getAbstractClass(mStorableType, features); + + mClassInjector = ClassInjector.create(mStorableType.getName(), + abstractClass.getClassLoader()); + + mClassFile = new ClassFile(mClassInjector.getClassName(), abstractClass); + mClassFile.markSynthetic(); + mClassFile.setSourceFile(ToyStorableGenerator.class.getName()); + mClassFile.setTarget("1.5"); + } + + private Class generateAndInjectClass() { + TypeDesc masterSupportType = TypeDesc.forClass(MasterSupport.class); + TypeDesc toyStorageType = TypeDesc.forClass(ToyStorage.class); + + // Add constructor that accepts a ToyStorage. + { + TypeDesc[] params = {toyStorageType}; + MethodInfo mi = mClassFile.addConstructor(Modifiers.PUBLIC, params); + CodeBuilder b = new CodeBuilder(mi); + b.loadThis(); + b.loadLocal(b.getParameter(0)); + b.invokeSuperConstructor(new TypeDesc[] {masterSupportType}); + b.returnVoid(); + } + + // Implement abstract methods which all delegate to ToyStorage instance. + + generateDelegatedMethod + (MasterStorableGenerator.DO_TRY_LOAD_MASTER_METHOD_NAME, "doTryLoad"); + generateDelegatedMethod + (MasterStorableGenerator.DO_TRY_INSERT_MASTER_METHOD_NAME, "doTryInsert"); + generateDelegatedMethod + (MasterStorableGenerator.DO_TRY_UPDATE_MASTER_METHOD_NAME, "doTryUpdate"); + generateDelegatedMethod + (MasterStorableGenerator.DO_TRY_DELETE_MASTER_METHOD_NAME, "doTryDelete"); + + Class generatedClass = mClassInjector.defineClass(mClassFile); + + return generatedClass; + } + + private void generateDelegatedMethod(String masterMethodName, String supportMethodName) { + TypeDesc triggerSupportType = TypeDesc.forClass(TriggerSupport.class); + TypeDesc toyStorageType = TypeDesc.forClass(ToyStorage.class); + + TypeDesc[] storableParam = {TypeDesc.forClass(Storable.class)}; + + MethodInfo mi = mClassFile.addMethod + (Modifiers.PROTECTED, masterMethodName, TypeDesc.BOOLEAN, null); + CodeBuilder b = new CodeBuilder(mi); + + b.loadThis(); + b.loadField(StorableGenerator.SUPPORT_FIELD_NAME, triggerSupportType); + b.checkCast(toyStorageType); + b.loadThis(); + b.invokeVirtual(toyStorageType, supportMethodName, TypeDesc.BOOLEAN, storableParam); + b.returnValue(TypeDesc.BOOLEAN); + } +} diff --git a/src/test/java/com/amazon/carbonado/repo/toy/ToyStorage.java b/src/test/java/com/amazon/carbonado/repo/toy/ToyStorage.java new file mode 100644 index 0000000..dd29e4b --- /dev/null +++ b/src/test/java/com/amazon/carbonado/repo/toy/ToyStorage.java @@ -0,0 +1,242 @@ +/* + * Copyright 2006 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.repo.toy; + +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; + +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import com.amazon.carbonado.FetchException; +import com.amazon.carbonado.IsolationLevel; +import com.amazon.carbonado.PersistException; +import com.amazon.carbonado.Query; +import com.amazon.carbonado.Repository; +import com.amazon.carbonado.RepositoryException; +import com.amazon.carbonado.Storable; +import com.amazon.carbonado.Storage; +import com.amazon.carbonado.SupportException; +import com.amazon.carbonado.Transaction; +import com.amazon.carbonado.Trigger; + +import com.amazon.carbonado.spi.MasterSupport; +import com.amazon.carbonado.spi.SequenceValueProducer; + +import com.amazon.carbonado.util.QuickConstructorGenerator; + +import com.amazon.carbonado.filter.Filter; +import com.amazon.carbonado.filter.FilterValues; + +import com.amazon.carbonado.info.OrderedProperty; +import com.amazon.carbonado.info.StorableIntrospector; + +import com.amazon.carbonado.qe.FilteredQueryExecutor; +import com.amazon.carbonado.qe.IterableQueryExecutor; +import com.amazon.carbonado.qe.QueryExecutor; +import com.amazon.carbonado.qe.SortedQueryExecutor; +import com.amazon.carbonado.qe.StandardQuery; + +/** + * + * @author Brian S O'Neill + */ +public class ToyStorage implements Storage, MasterSupport { + final ToyRepository mRepo; + final Class mType; + + final InstanceFactory mInstanceFactory; + + final Collection mData; + final Lock mDataLock; + + public ToyStorage(ToyRepository repo, Class type) throws SupportException { + StorableIntrospector.examine(type); + mRepo = repo; + mType = type; + + Class generatedStorableClass = ToyStorableGenerator.getGeneratedClass(type); + mInstanceFactory = QuickConstructorGenerator + .getInstance(generatedStorableClass, InstanceFactory.class); + + mData = new LinkedList(); + mDataLock = new ReentrantLock(); + } + + public Class getStorableType() { + return mType; + } + + public S prepare() { + return (S) mInstanceFactory.instantiate(this); + } + + public Query query() throws FetchException { + return new ToyQuery(null); + } + + public Query query(String filter) throws FetchException { + return query(Filter.filterFor(mType, filter)); + } + + public Query query(Filter filter) throws FetchException { + return new ToyQuery(filter.initialFilterValues()); + } + + public boolean addTrigger(Trigger trigger) { + return false; + } + + public boolean removeTrigger(Trigger trigger) { + return false; + } + + public boolean doTryLoad(S storable) { + mDataLock.lock(); + try { + for (S existing : mData) { + if (existing.equalPrimaryKeys(storable)) { + storable.markAllPropertiesDirty(); + existing.copyAllProperties(storable); + storable.markAllPropertiesClean(); + return true; + } + } + return false; + } finally { + mDataLock.unlock(); + } + } + + public boolean doTryInsert(S storable) { + mDataLock.lock(); + try { + for (S existing : mData) { + if (existing.equalPrimaryKeys(storable)) { + return false; + } + } + storable.markAllPropertiesClean(); + mData.add((S) storable.copy()); + return true; + } finally { + mDataLock.unlock(); + } + } + + public boolean doTryUpdate(S storable) { + mDataLock.lock(); + try { + for (S existing : mData) { + if (existing.equalPrimaryKeys(storable)) { + existing.markAllPropertiesDirty(); + storable.copyAllProperties(existing); + existing.markAllPropertiesClean(); + existing.copyAllProperties(storable); + storable.markAllPropertiesClean(); + return true; + } + } + return false; + } finally { + mDataLock.unlock(); + } + } + + public boolean doTryDelete(S storable) { + mDataLock.lock(); + try { + Iterator it = mData.iterator(); + while (it.hasNext()) { + S existing = it.next(); + if (existing.equalPrimaryKeys(storable)) { + it.remove(); + return true; + } + } + return false; + } finally { + mDataLock.unlock(); + } + } + + public Repository getRootRepository() { + return mRepo; + } + + public boolean isPropertySupported(String propertyName) { + return StorableIntrospector.examine(mType) + .getAllProperties().containsKey(propertyName); + } + + public Trigger getInsertTrigger() { + return null; + } + + public Trigger getUpdateTrigger() { + return null; + } + + public Trigger getDeleteTrigger() { + return null; + } + + public SequenceValueProducer getSequenceValueProducer(String name) throws PersistException { + try { + return mRepo.getSequenceValueProducer(name); + } catch (RepositoryException e) { + throw e.toPersistException(); + } + } + + public static interface InstanceFactory { + Storable instantiate(ToyStorage storage); + } + + private class ToyQuery extends StandardQuery { + ToyQuery(FilterValues values, String... orderings) { + super(values, orderings); + } + + protected Storage getStorage() { + return ToyStorage.this; + } + + protected Transaction enterTransactionForDelete(IsolationLevel level) { + return mRepo.enterTransaction(level); + } + + protected QueryExecutor getExecutor(FilterValues values, String... orderings) { + QueryExecutor executor = new IterableQueryExecutor(mType, mData, mDataLock); + + if (values != null) { + executor = new FilteredQueryExecutor(executor, values.getFilter()); + } + + // FIXME: sorting + + return executor; + } + + protected StandardQuery newInstance(FilterValues values, String... orderings) { + return new ToyQuery(values, orderings); + } + } +} diff --git a/src/test/java/com/amazon/carbonado/repo/toy/ToyTransaction.java b/src/test/java/com/amazon/carbonado/repo/toy/ToyTransaction.java new file mode 100644 index 0000000..c16d1f1 --- /dev/null +++ b/src/test/java/com/amazon/carbonado/repo/toy/ToyTransaction.java @@ -0,0 +1,51 @@ +/* + * Copyright 2006 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.repo.toy; + +import java.util.concurrent.TimeUnit; + +import com.amazon.carbonado.IsolationLevel; +import com.amazon.carbonado.PersistException; +import com.amazon.carbonado.Transaction; + +/** + * + * @author Brian S O'Neill + */ +public class ToyTransaction implements Transaction { + public void commit() throws PersistException { + } + + public void exit() throws PersistException { + } + + public void setForUpdate(boolean forUpdate) { + } + + public boolean isForUpdate() { + return false; + } + + public void setDesiredLockTimeout(int timeout, TimeUnit unit) { + } + + public IsolationLevel getIsolationLevel() { + throw new UnsupportedOperationException(); + } +} diff --git a/src/test/java/com/amazon/carbonado/repo/toy/package-info.java b/src/test/java/com/amazon/carbonado/repo/toy/package-info.java new file mode 100644 index 0000000..769ea8b --- /dev/null +++ b/src/test/java/com/amazon/carbonado/repo/toy/package-info.java @@ -0,0 +1,25 @@ +/* + * Copyright 2006 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. + */ + +/** + * Standalone toy repository implementation. This repository is only suitable + * for running tests that don't require anything sophisticated. It doesn't + * support transactions, nothing is actually persisted, and all queries do full + * scans. The repository is thread-safe, however. + */ +package com.amazon.carbonado.repo.toy; -- cgit v1.2.3