/* This file is part of the db4o object database http://www.db4o.com
Copyright (C) 2004 - 2011 Versant Corporation http://www.versant.com
db4o is free software; you can redistribute it and/or modify it under
the terms of version 3 of the GNU General Public License as published
by the Free Software Foundation.
db4o is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see http://www.gnu.org/licenses/. */
package com.db4o.internal;
import static com.db4o.foundation.Environments.*;
import java.util.*;
import com.db4o.*;
import com.db4o.config.*;
import com.db4o.ext.*;
import com.db4o.foundation.*;
import com.db4o.internal.activation.*;
import com.db4o.internal.callbacks.*;
import com.db4o.internal.encoding.*;
import com.db4o.internal.handlers.array.*;
import com.db4o.internal.marshall.*;
import com.db4o.internal.metadata.*;
import com.db4o.internal.query.*;
import com.db4o.internal.query.processor.*;
import com.db4o.internal.query.result.*;
import com.db4o.internal.references.*;
import com.db4o.internal.replication.*;
import com.db4o.internal.slots.*;
import com.db4o.internal.threading.*;
import com.db4o.internal.weakref.*;
import com.db4o.query.*;
import com.db4o.reflect.*;
import com.db4o.reflect.core.*;
import com.db4o.reflect.generic.*;
import com.db4o.typehandlers.*;
import com.db4o.types.*;
/**
* @exclude
* @sharpen.extends System.IDisposable
* @sharpen.partial
*/
public abstract class ObjectContainerBase implements TransientClass, Internal4, ObjectContainerSpec, InternalObjectContainer {
// Collection of all classes
// if (_classCollection == null) the engine is down.
protected ClassMetadataRepository _classCollection;
// the Configuration context for this ObjectContainer
protected Config4Impl _config;
// Counts the number of toplevel calls into YapStream
private int _stackDepth;
private final int _maxStackDepth;
private final ReferenceSystemRegistry _referenceSystemRegistry = new ReferenceSystemRegistry();
private Tree _justPeeked;
protected Object _lock;
// currently used to resolve self-linking concurrency problems
// in cylic links, stores only ClassMetadata objects
private List4 _pendingClassUpdates;
// a value greater than 0 indicates class implementing the
// "Internal" interface are visible in queries and can
// be used.
int _showInternalClasses = 0;
private List4 _stillToActivate;
private List4 _stillToDeactivate;
private List4 _stillToSet;
private boolean _handlingStackLimitPendings = false;
// used for ClassMetadata and ClassMetadataRepository
// may be parent or equal to i_trans
private Transaction _systemTransaction;
// used for Objects
protected Transaction _transaction;
// all the per-YapStream references that we don't
// want created in YapobjectCarrier
public HandlerRegistry _handlers;
// One of three constants in ReplicationHandler: NONE, OLD, NEW
// Detailed replication variables are stored in i_handlers.
// Call state has to be maintained here, so YapObjectCarrier (who shares i_handlers) does
// not accidentally think it operates in a replication call.
int _replicationCallState;
// weak reference management
WeakReferenceSupport _references;
private NativeQueryHandler _nativeQueryHandler;
private Callbacks _callbacks = new com.db4o.internal.callbacks.NullCallbacks();
protected final TimeStampIdGenerator _timeStampIdGenerator = new TimeStampIdGenerator();
private int _topLevelCallId = 1;
private IntIdGenerator _topLevelCallIdGenerator = new IntIdGenerator();
private final Environment _environment;
private ReferenceSystemFactory _referenceSystemFactory;
private String _name;
protected BlockConverter _blockConverter = new DisabledBlockConverter();
protected ObjectContainerBase(Configuration config) {
_lock = new Object();
_config = (Config4Impl)config;
_environment = createEnvironment(_config);
_maxStackDepth = _config.maxStackDepth();
}
private Environment createEnvironment(Config4Impl config) {
final ArrayList bindings = new ArrayList();
bindings.addAll(config.environmentContributions());
bindings.add(this); // my(ObjectContainer.class)
bindings.add(config); // my(Configuration.class)
return Environments.newConventionBasedEnvironment(bindings.toArray());
}
protected Environment environment() {
return _environment;
}
protected final void open() throws OldFormatException {
withEnvironment(new Runnable() { public void run() {
boolean ok = false;
synchronized (_lock) {
try {
_name = configImpl().nameProvider().name(ObjectContainerBase.this);
initializeReferenceSystemFactory(_config);
initializeTransactions();
initialize1(_config);
openImpl();
initializePostOpen();
callbacks().openOnFinished(ObjectContainerBase.this);
ok = true;
} finally {
if(!ok) {
// TODO: This will swallow the causing exception if
// an exception occurs during shutdown.
shutdownObjectContainer();
}
}
}
}});
}
private void initializeReferenceSystemFactory(Config4Impl config){
_referenceSystemFactory = config.referenceSystemFactory();
}
public void withEnvironment(Runnable runnable) {
runWith(_environment, runnable);
}
protected abstract void openImpl() throws Db4oIOException;
public ActivationDepth defaultActivationDepth(ClassMetadata classMetadata) {
return activationDepthProvider().activationDepthFor(classMetadata, ActivationMode.ACTIVATE);
}
public ActivationDepthProvider activationDepthProvider() {
return configImpl().activationDepthProvider();
}
public final void activate(Transaction trans, Object obj){
synchronized (_lock) {
activate(trans, obj, defaultActivationDepthForObject(obj));
}
}
public final void deactivate(Transaction trans, Object obj){
deactivate(trans, obj, 1);
}
private final ActivationDepth defaultActivationDepthForObject(Object obj) {
ClassMetadata classMetadata = classMetadataForObject(obj);
return defaultActivationDepth(classMetadata);
}
public final void activate(Transaction trans, final Object obj, final ActivationDepth depth) {
synchronized (_lock) {
asTopLevelCall(new Function4<Transaction,Object>() {
public Object apply(Transaction trans) {
stillToActivate(activationContextFor(trans, obj, depth));
activatePending(trans);
return null;
}
}, trans);
}
}
static final class PendingActivation {
public final ObjectReference ref;
public final ActivationDepth depth;
public PendingActivation(ObjectReference ref_, ActivationDepth depth_) {
this.ref = ref_;
this.depth = depth_;
}
}
final void activatePending(Transaction ta){
while (_stillToActivate != null) {
// TODO: Optimize! A lightweight int array would be faster.
final Iterator4 i = new Iterator4Impl(_stillToActivate);
_stillToActivate = null;
while (i.moveNext()) {
final PendingActivation item = (PendingActivation) i.current();
final ObjectReference ref = item.ref;
final Object obj = ref.getObject();
if (obj == null) {
ta.removeReference(ref);
} else {
ref.activateInternal(activationContextFor(ta, obj, item.depth));
}
}
}
}
public void backup(String path) throws DatabaseClosedException, Db4oIOException {
backup(configImpl().storage(), path);
}
public ActivationContext4 activationContextFor(Transaction ta,
final Object obj, final ActivationDepth depth) {
return new ActivationContext4(ta, obj, depth);
}
public final void bind(Transaction trans, Object obj, long id) throws ArgumentNullException, IllegalArgumentException {
synchronized (_lock) {
if(obj == null){
throw new ArgumentNullException();
}
if(DTrace.enabled){
DTrace.BIND.log(id, " ihc " + System.identityHashCode(obj));
}
trans = checkTransaction(trans);
int intID = (int) id;
Object oldObject = getByID(trans, id);
if (oldObject == null) {
throw new IllegalArgumentException("id");
}
ObjectReference ref = trans.referenceForId(intID);
if(ref == null){
throw new IllegalArgumentException("obj");
}
if (reflectorForObject(obj) == ref.classMetadata().classReflector()) {
ObjectReference newRef = bind2(trans, ref, obj);
newRef.virtualAttributes(trans, false);
} else {
throw new Db4oException(Messages.get(57));
}
}
}
public final ObjectReference bind2(Transaction trans, ObjectReference oldRef, Object obj){
int id = oldRef.getID();
trans.removeReference(oldRef);
ObjectReference newRef = new ObjectReference(classMetadataForObject(obj), id);
newRef.setObjectWeak(this, obj);
newRef.setStateDirty();
trans.referenceSystem().addExistingReference(newRef);
return newRef;
}
public ClassMetadata classMetadataForObject(Object obj) {
return produceClassMetadata(reflectorForObject(obj));
}
public abstract byte blockSize();
private final boolean breakDeleteForEnum(ObjectReference reference, boolean userCall){
if(Deploy.csharp){
return false;
}
if(userCall){
return false;
}
if(reference == null){
return false;
}
return Platform4.isEnum(reflector(), reference.classMetadata().classReflector());
}
boolean canUpdate() {
return true;
}
public final void checkClosed() throws DatabaseClosedException {
if (_classCollection == null) {
throw new DatabaseClosedException();
}
}
protected void checkReadOnly() throws DatabaseReadOnlyException {
if(_config.isReadOnly()) {
throw new DatabaseReadOnlyException();
}
}
final void processPendingClassUpdates() {
if (_pendingClassUpdates == null) {
return;
}
Iterator4 i = new Iterator4Impl(_pendingClassUpdates);
while (i.moveNext()) {
ClassMetadata classMetadata = (ClassMetadata) i.current();
classMetadata.setStateDirty();
classMetadata.write(_systemTransaction);
}
_pendingClassUpdates = null;
}
public final Transaction checkTransaction() {
return checkTransaction(null);
}
public final Transaction checkTransaction(Transaction ta) {
checkClosed();
if (ta != null) {
return ta;
}
return transaction();
}
final public boolean close() {
synchronized (_lock) {
callbacks().closeOnStarted(this);
if(DTrace.enabled){
DTrace.CLOSE_CALLED.log(this.toString());
}
close1();
return true;
}
}
protected void handleExceptionOnClose(Exception exc) {
fatalException(exc);
}
private void close1() {
if (isClosed()) {
return;
}
processPendingClassUpdates();
if (stateMessages()) {
logMsg(2, toString());
}
close2();
}
protected abstract void close2();
public final void shutdownObjectContainer() {
if (DTrace.enabled) {
DTrace.CLOSE.log();
}
logMsg(3, toString());
synchronized (_lock) {
closeUserTransaction();
closeSystemTransaction();
closeIdSystem();
stopSession();
shutdownDataStorage();
}
}
protected abstract void closeIdSystem();
protected final void closeUserTransaction(){
closeTransaction(_transaction, false,false);
}
protected final void closeSystemTransaction(){
closeTransaction(_systemTransaction, true,false);
}
public abstract void closeTransaction(Transaction transaction, boolean isSystemTransaction, boolean rollbackOnClose);
protected abstract void shutdownDataStorage();
public final void commit(Transaction trans) throws DatabaseReadOnlyException, DatabaseClosedException {
synchronized (_lock) {
if(DTrace.enabled){
DTrace.COMMIT.log();
}
checkReadOnly();
asTopLevelCall(new Function4<Transaction, Object>() {
public Object apply(Transaction trans) {
commit1(trans);
trans.postCommit();
return null;
}
}, trans);
}
}
private <R> R asTopLevelStore(Function4<Transaction,R> block, Transaction trans) {
trans = checkTransaction(trans);
R result = asTopLevelCall(block, trans);
if(_stackDepth == 0){
trans.processDeletes();
}
return result;
}
/**
* @sharpen.ignore
*/
protected <R> R asTopLevelCall(Function4<Transaction,R> block, Transaction trans) {
trans = checkTransaction(trans);
beginTopLevelCall();
try{
return block.apply(trans);
}
catch(Db4oRecoverableException exc) {
throw exc;
}
catch(RuntimeException exc) {
fatalShutdown(exc);
}
finally {
endTopLevelCall();
}
// should never happen - just to make compiler happy
throw new Db4oException();
}
public void fatalShutdown(Throwable origExc) {
try {
stopSession();
fatalStorageShutdown();
}
catch(Throwable exc) {
throw new CompositeDb4oException(origExc, exc);
}
Platform4.throwUncheckedException(origExc);
}
protected abstract void fatalStorageShutdown();
public abstract void commit1(Transaction trans);
public Configuration configure() {
return configImpl();
}
public Config4Impl config(){
return configImpl();
}
public abstract int converterVersion();
public abstract AbstractQueryResult newQueryResult(Transaction trans, QueryEvaluationMode mode);
protected final void createStringIO(byte encoding) {
stringIO(BuiltInStringEncoding.stringIoForEncoding(encoding, configImpl().stringEncoding()));
}
final protected void initializeTransactions() {
_systemTransaction = newSystemTransaction();
_transaction = newUserTransaction();
}
public abstract Transaction newTransaction(Transaction parentTransaction, ReferenceSystem referenceSystem, boolean isSystemTransaction);
public Transaction newUserTransaction(){
return newTransaction(systemTransaction(), createReferenceSystem(), false);
}
public Transaction newSystemTransaction(){
return newTransaction(null, createReferenceSystem(), true);
}
public abstract long currentVersion();
public boolean createClassMetadata(ClassMetadata classMeta, ReflectClass clazz, ClassMetadata superClassMeta) {
return classMeta.init(superClassMeta);
}
/**
* allows special handling for all Db4oType objects.
* Redirected here from #set() so only instanceof check is necessary
* in the #set() method.
* @return object if handled here and #set() should not continue processing
*/
public Db4oType db4oTypeStored(Transaction trans, Object obj) {
if (!(obj instanceof Db4oDatabase)) {
return null;
}
Db4oDatabase database = (Db4oDatabase) obj;
if (trans.referenceForObject(obj) != null) {
return database;
}
showInternalClasses(true);
try {
return database.query(trans);
} finally {
showInternalClasses(false);
}
}
public final void deactivate(Transaction trans, final Object obj, final int depth) throws DatabaseClosedException {
synchronized (_lock) {
asTopLevelCall(new Function4<Transaction,Object>() {
public Object apply(Transaction trans) {
deactivateInternal(trans, obj, activationDepthProvider().activationDepth(depth, ActivationMode.DEACTIVATE));
return null;
}
}, trans);
}
}
private final void deactivateInternal(Transaction trans, Object obj, ActivationDepth depth) {
stillToDeactivate(trans, obj, depth, true);
deactivatePending(trans);
}
private void deactivatePending(Transaction trans) {
while (_stillToDeactivate != null) {
Iterator4 i = new Iterator4Impl(_stillToDeactivate);
_stillToDeactivate = null;
while (i.moveNext()) {
PendingActivation item = (PendingActivation) i.current();
item.ref.deactivate(trans, item.depth);
}
}
}
public final void delete(Transaction trans, Object obj) throws DatabaseReadOnlyException, DatabaseClosedException {
if (null == obj) {
throw new ArgumentNullException();
}
synchronized (lock()) {
trans = checkTransaction(trans);
checkReadOnly();
delete1(trans, obj, true);
unregisterFromTransparentPersistence(trans, obj);
trans.processDeletes();
}
}
public final void delete1(Transaction trans, final Object obj, final boolean userCall) {
if (obj == null) {
return;
}
final ObjectReference ref = trans.referenceForObject(obj);
if(ref == null){
return;
}
if(userCall){
generateCallIDOnTopLevel();
}
asTopLevelCall(new Function4<Transaction, Object>() {
public Object apply(Transaction trans) {
delete2(trans, ref, obj, 0, userCall);
return null;
}
}, trans);
}
public final void delete2(Transaction trans, ObjectReference ref, Object obj, int cascade, boolean userCall) {
// This check is performed twice, here and in delete3, intentionally.
if(breakDeleteForEnum(ref, userCall)){
return;
}
if(obj instanceof Entry){
if(! flagForDelete(ref)){
return;
}
delete3(trans, ref, obj, cascade, userCall);
return;
}
trans.delete(ref, ref.getID(), cascade);
}
final void delete3(Transaction trans, ObjectReference ref, Object obj, int cascade, boolean userCall) {
// The passed reference can be null, when calling from Transaction.
if(ref == null || ! ref.beginProcessing()){
return;
}
// This check is performed twice, here and in delete2, intentionally.
if(breakDeleteForEnum(ref, userCall)){
ref.endProcessing();
return;
}
if(! ref.isFlaggedForDelete()){
ref.endProcessing();
return;
}
ClassMetadata yc = ref.classMetadata();
// We have to end processing temporarily here, otherwise the can delete callback
// can't do anything at all with this object.
ref.endProcessing();
activateForDeletionCallback(trans, yc, ref, obj);
if (!objectCanDelete(trans, yc, ref)) {
return;
}
ref.beginProcessing();
if(DTrace.enabled){
DTrace.DELETE.log(ref.getID());
}
if(delete4(trans, ref, obj, cascade, userCall)){
objectOnDelete(trans, yc, ref);
if (configImpl().messageLevel() > Const4.STATE) {
message("" + ref.getID() + " delete " + ref.classMetadata().getName());
}
}
ref.endProcessing();
}
private void unregisterFromTransparentPersistence(Transaction trans, Object obj) {
if (!(activationDepthProvider() instanceof TransparentActivationDepthProvider)) {
return;
}
final TransparentActivationDepthProvider provider = (TransparentActivationDepthProvider) activationDepthProvider();
provider.removeModified(obj, trans);
}
private void activateForDeletionCallback(Transaction trans, ClassMetadata classMetadata, ObjectReference ref, Object obj) {
if (!ref.isActive() && (caresAboutDeleting(classMetadata) || caresAboutDeleted(classMetadata))) {
// Activate Objects for Callbacks, because in C/S mode Objects are not activated on the Server
// FIXME: [TA] review activation depth
ActivationDepth depth = classMetadata.adjustCollectionDepthToBorders(new FixedActivationDepth(1));
activate(trans, obj, depth);
}
}
private boolean caresAboutDeleting(ClassMetadata yc) {
return this._callbacks.caresAboutDeleting()
|| yc.hasEventRegistered(systemTransaction(), EventDispatchers.CAN_DELETE);
}
private boolean caresAboutDeleted(ClassMetadata yc) {
return this._callbacks.caresAboutDeleted()
|| yc.hasEventRegistered(systemTransaction(), EventDispatchers.DELETE);
}
private boolean objectCanDelete(Transaction transaction, ClassMetadata yc, ObjectInfo objectInfo) {
return callbacks().objectCanDelete(transaction, objectInfo)
&& yc.dispatchEvent(transaction, objectInfo.getObject(), EventDispatchers.CAN_DELETE);
}
private void objectOnDelete(Transaction transaction, ClassMetadata yc, ObjectInfo reference) {
callbacks().objectOnDelete(transaction, reference);
yc.dispatchEvent(transaction, reference.getObject(), EventDispatchers.DELETE);
}
public abstract boolean delete4(Transaction ta, ObjectReference ref, Object obj, int a_cascade, boolean userCall);
Object descend(Transaction trans, Object obj, String[] path){
synchronized (_lock) {
trans = checkTransaction(trans);
ObjectReference ref = trans.referenceForObject(obj);
if(ref == null){
return null;
}
final String fieldName = path[0];
if(fieldName == null){
return null;
}
ClassMetadata classMetadata = ref.classMetadata();
final ByRef foundField = new ByRef();
classMetadata.traverseAllAspects(new TraverseFieldCommand() {
@Override
protected void process(FieldMetadata field) {
if(field.canAddToQuery(fieldName)){
foundField.value = field;
}
}
});
FieldMetadata field = (FieldMetadata) foundField.value;
if(field == null){
return null;
}
Object child = ref.isActive()
? field.get(trans, obj)
: descendMarshallingContext(trans, ref).readFieldValue(field);
if(path.length == 1){
return child;
}
if(child == null){
return null;
}
String[] subPath = new String[path.length - 1];
System.arraycopy(path, 1, subPath, 0, path.length - 1);
return descend(trans, child, subPath);
}
}
private UnmarshallingContext descendMarshallingContext(Transaction trans,
ObjectReference ref) {
final UnmarshallingContext context = new UnmarshallingContext(trans, ref, Const4.ADD_TO_ID_TREE, false);
context.activationDepth(activationDepthProvider().activationDepth(1, ActivationMode.ACTIVATE));
return context;
}
public boolean detectSchemaChanges() {
// overriden in YapClient
return configImpl().detectSchemaChanges();
}
public boolean dispatchsEvents() {
return true;
}
protected boolean doFinalize() {
return true;
}
/*
* This method will be exuected on finalization, and vm exit if it's enabled
* by configuration.
*/
final void shutdownHook() {
if(isClosed()) {
return;
}
if (allOperationsCompleted()) {
Messages.logErr(configImpl(), 50, toString(), null);
close();
} else {
shutdownObjectContainer();
if (operationIsProcessing()) {
Messages.logErr(configImpl(), 24, null, null);
}
}
}
private boolean operationIsProcessing() {
return _stackDepth > 0;
}
private boolean allOperationsCompleted() {
return _stackDepth == 0;
}
void fatalException(int msgID) {
fatalException(null,msgID);
}
final void fatalException(Throwable t) {
fatalException(t,Messages.FATAL_MSG_ID);
}
final void fatalException(Throwable t, int msgID) {
if(DTrace.enabled){
DTrace.FATAL_EXCEPTION.log(t.toString());
}
Messages.logErr(configImpl(), (msgID == Messages.FATAL_MSG_ID ? 18
: msgID), null, t);
if (!isClosed()) {
shutdownObjectContainer();
}
throw new Db4oException(Messages.get(msgID));
}
/**
* @sharpen.ignore
*/
protected void finalize() {
if (doFinalize() && configuredForAutomaticShutDown()) {
shutdownHook();
}
}
private boolean configuredForAutomaticShutDown() {
return (configImpl() == null || configImpl().automaticShutDown());
}
void gc() {
_references.purge();
}
public final ObjectSet queryByExample(Transaction trans, final Object template) {
synchronized (_lock) {
trans = checkTransaction(trans);
QueryResult res = asTopLevelCall(new Function4<Transaction,QueryResult>() {
public QueryResult apply(Transaction trans) {
return queryByExampleInternal(trans, template);
}
}, trans);
return new ObjectSetFacade(res);
}
}
private final QueryResult queryByExampleInternal(Transaction trans, Object template) {
if (template == null || template.getClass() == Const4.CLASS_OBJECT || template == Const4.CLASS_OBJECT) {
return queryAllObjects(trans);
}
Query q = query(trans);
q.constrain(template).byExample();
return executeQuery((QQuery)q);
}
public abstract AbstractQueryResult queryAllObjects(Transaction ta);
public final Object tryGetByID(Transaction ta, long id) throws DatabaseClosedException{
try {
return getByID(ta, id);
} catch (InvalidSlotException ise){
// can happen return null
} catch (InvalidIDException iie){
// can happen return null
}
return null;
}
public final Object getByID(Transaction ta, long id) throws DatabaseClosedException, InvalidIDException {
synchronized (_lock) {
if (id <= 0 || id >= Integer.MAX_VALUE) {
throw new IllegalArgumentException();
}
checkClosed();
ta = checkTransaction(ta);
beginTopLevelCall();
try {
return getByID2(ta, (int) id);
}
catch(Db4oRecoverableException exc) {
throw exc;
}
catch(OutOfMemoryError e){
throw new Db4oRecoverableException(e);
}
catch(RuntimeException e){
throw new Db4oRecoverableException(e);
}
finally {
// Never shut down for getById()
// There may be OutOfMemoryErrors or similar
// The user may want to catch and continue working.
endTopLevelCall();
}
}
}
public Object getByID2(Transaction ta, int id) {
Object obj = ta.objectForIdFromCache(id);
if (obj != null) {
// Take care about handling the returned candidate reference.
// If you loose the reference, weak reference management might
// also.
return obj;
}
return new ObjectReference(id).read(ta, new LegacyActivationDepth(0), Const4.ADD_TO_ID_TREE, true);
}
public final Object getActivatedObjectFromCache(Transaction ta, int id){
Object obj = ta.objectForIdFromCache(id);
if(obj == null){
return null;
}
activate(ta, obj);
return obj;
}
public final Object readActivatedObjectNotInCache(Transaction trans, final int id){
Object obj = asTopLevelCall(new Function4<Transaction,Object>() {
public Object apply(Transaction trans) {
return new ObjectReference(id).read(trans, UnknownActivationDepth.INSTANCE, Const4.ADD_TO_ID_TREE, true);
}
}, trans);
activatePending(trans);
return obj;
}
public final Object getByUUID(Transaction trans, Db4oUUID uuid){
synchronized (_lock) {
if(uuid == null){
return null;
}
HardObjectReference hardRef = getHardReferenceBySignature(checkTransaction(trans),
uuid.getLongPart(),
uuid.getSignaturePart());
return hardRef._object;
}
}
public HardObjectReference getHardReferenceBySignature(Transaction trans, long uuid, byte[] signature) {
return uUIDIndex().getHardObjectReferenceBySignature(trans, uuid, signature);
}
public final int getID(Transaction trans, Object obj) {
synchronized (_lock) {
trans = checkTransaction(trans);
checkClosed();
if(obj == null){
return 0;
}
ObjectReference yo = trans.referenceForObject(obj);
if (yo != null) {
return yo.getID();
}
return 0;
}
}
public final ObjectInfo getObjectInfo (Transaction trans, Object obj){
synchronized(_lock){
trans = checkTransaction(trans);
return trans.referenceForObject(obj);
}
}
public final HardObjectReference getHardObjectReferenceById(Transaction trans, int id) {
if (id <= 0) {
return HardObjectReference.INVALID;
}
ObjectReference ref = trans.referenceForId(id);
if (ref != null) {
// Take care about handling the returned candidate reference.
// If you loose the reference, weak reference management might also.
Object candidate = ref.getObject();
if (candidate != null) {
return new HardObjectReference(ref, candidate);
}
trans.removeReference(ref);
}
ref = new ObjectReference(id);
Object readObject = ref.read(trans, new LegacyActivationDepth(0), Const4.ADD_TO_ID_TREE, true);
if(readObject == null){
return HardObjectReference.INVALID;
}
// check class creation side effect and simply retry recursively
// if it hits:
if(readObject != ref.getObject()){
return getHardObjectReferenceById(trans, id);
}
return new HardObjectReference(ref, readObject);
}
public final StatefulBuffer createStatefulBuffer(Transaction trans, int address, int length) {
if (Debug4.exceedsMaximumBlockSize(length)) {
return null;
}
return new StatefulBuffer(trans, address, length);
}
public final Transaction systemTransaction() {
return _systemTransaction;
}
public final Transaction transaction() {
return _transaction;
}
public ClassMetadata classMetadataForReflectClass(ReflectClass claxx){
if (null == claxx) {
throw new ArgumentNullException();
}
if(hideClassForExternalUse(claxx)){
return null;
}
ClassMetadata classMetadata = _handlers.classMetadataForClass(claxx);
if (classMetadata != null) {
return classMetadata;
}
return _classCollection.classMetadataForReflectClass(claxx);
}
// TODO: Some ReflectClass implementations could hold a
// reference to ClassMetadata to improve lookup performance here.
public ClassMetadata produceClassMetadata(ReflectClass claxx) {
if (null == claxx) {
throw new ArgumentNullException();
}
if(hideClassForExternalUse(claxx)){
return null;
}
ClassMetadata classMetadata = _handlers.classMetadataForClass(claxx);
if (classMetadata != null) {
return classMetadata;
}
return _classCollection.produceClassMetadata(claxx);
}
/**
* Differentiating getActiveClassMetadata from getYapClass is a tuning
* optimization: If we initialize a YapClass, #set3() has to check for
* the possibility that class initialization associates the currently
* stored object with a previously stored static object, causing the
* object to be known afterwards.
*
* In this call we only return active YapClasses, initialization
* is not done on purpose
*/
final ClassMetadata getActiveClassMetadata(ReflectClass claxx) {
if(hideClassForExternalUse(claxx)){
return null;
}
return _classCollection.getActiveClassMetadata(claxx);
}
private final boolean hideClassForExternalUse(ReflectClass claxx){
if ((!showInternalClasses()) && _handlers.ICLASS_INTERNAL.isAssignableFrom(claxx)) {
return true;
}
return false;
}
public int classMetadataIdForName(String name) {
return _classCollection.classMetadataIdForName(name);
}
public ClassMetadata classMetadataForName(String name) {
return classMetadataForID(classMetadataIdForName(name));
}
public ClassMetadata classMetadataForID(int id) {
if(DTrace.enabled){
DTrace.CLASSMETADATA_BY_ID.log(id);
}
if (id == 0) {
return null;
}
ClassMetadata classMetadata = _handlers.classMetadataForId(id);
if (classMetadata != null) {
return classMetadata;
}
return _classCollection.classMetadataForId(id);
}
public HandlerRegistry handlers(){
return _handlers;
}
public boolean needsLockFileThread() {
if(! Debug4.lockFile){
return false;
}
if (!Platform4.needsLockFileThread()) {
return false;
}
if (configImpl().isReadOnly()) {
return false;
}
return configImpl().lockFile();
}
protected boolean hasShutDownHook() {
return configImpl().automaticShutDown();
}
protected void initialize1(Configuration config) {
_config = initializeConfig(config);
_handlers = new HandlerRegistry(this, configImpl().encoding(), configImpl().reflector());
if (_references != null) {
gc();
_references.stop();
}
_references = WeakReferenceSupportFactory.forObjectContainer(this);
if (hasShutDownHook()) {
Platform4.addShutDownHook(this);
}
_handlers.initEncryption(configImpl());
_stillToSet = null;
}
private Config4Impl initializeConfig(Configuration config) {
Config4Impl impl=((Config4Impl)config);
impl.container(this);
impl.reflector().setTransaction(systemTransaction());
impl.reflector().configuration(new ReflectorConfigurationImpl(impl));
impl.taint();
return impl;
}
public ReferenceSystem createReferenceSystem() {
ReferenceSystem referenceSystem = _referenceSystemFactory.newReferenceSystem(this);
_referenceSystemRegistry.addReferenceSystem(referenceSystem);
return referenceSystem;
}
protected void initalizeWeakReferenceSupport() {
_references.start();
}
protected void initializeClassMetadataRepository() {
_classCollection = new ClassMetadataRepository(_systemTransaction);
}
private void initializePostOpen() {
_showInternalClasses = 100000;
initializePostOpenExcludingTransportObjectContainer();
_showInternalClasses = 0;
}
protected void initializePostOpenExcludingTransportObjectContainer() {
initializeEssentialClasses();
rename(configImpl());
_classCollection.initOnUp(_systemTransaction);
_transaction.postOpen();
if (configImpl().detectSchemaChanges()) {
if(! configImpl().isReadOnly()){
_systemTransaction.commit();
}
}
configImpl().applyConfigurationItems(this);
}
void initializeEssentialClasses(){
if(Debug4.staticIdentity){
return;
}
for (int i = 0; i < Const4.ESSENTIAL_CLASSES.length; i++) {
produceClassMetadata(reflector().forClass(Const4.ESSENTIAL_CLASSES[i]));
}
}
final boolean isActive(Transaction trans, Object obj) {
synchronized (_lock) {
trans = checkTransaction(trans);
if (obj != null) {
ObjectReference ref = trans.referenceForObject(obj);
if (ref != null) {
return ref.isActive();
}
}
return false;
}
}
public boolean isCached(Transaction trans, long id) {
synchronized (_lock) {
trans = checkTransaction(trans);
return trans.objectForIdFromCache((int)id) != null;
}
}
/**
* overridden in ClientObjectContainer
* The method allows checking whether will make it easier to refactor than
* an "instanceof YapClient" check.
*/
public boolean isClient() {
return false;
}
public final boolean isClosed() {
synchronized (_lock) {
// this is set to null in close2 and is therefore our check for down.
return _classCollection == null;
}
}
boolean isServer() {
return false;
}
public final boolean isStored(Transaction trans, Object obj) {
synchronized (_lock) {
trans = checkTransaction(trans);
if (obj == null) {
return false;
}
ObjectReference ref = trans.referenceForObject(obj);
if (ref == null) {
return false;
}
return ! isDeleted(trans, ref.getID());
}
}
public ReflectClass[] knownClasses(){
synchronized(_lock){
checkClosed();
return reflector().knownClasses();
}
}
public TypeHandler4 typeHandlerForClass(ReflectClass claxx) {
if(hideClassForExternalUse(claxx)){
return null;
}
TypeHandler4 typeHandler = _handlers.typeHandlerForClass(claxx);
if(typeHandler != null){
return typeHandler;
}
return _classCollection.produceClassMetadata(claxx).typeHandler();
}
public TypeHandler4 typeHandlerForClassMetadataID(int id) {
if (id < 1) {
return null;
}
ClassMetadata classMetadata = classMetadataForID(id);
if(classMetadata == null){
return null;
}
return classMetadata.typeHandler();
}
public Object lock() {
return _lock;
}
public final void logMsg(int code, String msg) {
Messages.logMsg(configImpl(), code, msg);
}
public boolean maintainsIndices() {
return true;
}
void message(String msg) {
new MessageOutput(this, msg);
}
public final void needsUpdate(ClassMetadata classMetadata) {
_pendingClassUpdates = new List4(_pendingClassUpdates, classMetadata);
}
public long generateTimeStampId() {
return _timeStampIdGenerator.generate();
}
public abstract int idForNewUserObject(Transaction trans);
public Object peekPersisted(Transaction trans, final Object obj, final ActivationDepth depth, final boolean committed) throws DatabaseClosedException {
// TODO: peekPersisted is not stack overflow safe, if depth is too high.
synchronized (_lock) {
checkClosed();
return asTopLevelCall(new Function4<Transaction, Object>() {
public Object apply(Transaction trans) {
trans = checkTransaction(trans);
ObjectReference ref = trans.referenceForObject(obj);
trans = committed ? _systemTransaction : trans;
Object cloned = null;
if (ref != null) {
cloned = peekPersisted(trans, ref.getID(), depth, true);
}
return cloned;
}
}, trans);
}
}
public final Object peekPersisted(Transaction trans, int id, ActivationDepth depth, boolean resetJustPeeked) {
if(resetJustPeeked){
_justPeeked = null;
}else{
TreeInt ti = new TreeInt(id);
TreeIntObject tio = (TreeIntObject) Tree.find(_justPeeked, ti);
if(tio != null){
return tio._object;
}
}
ObjectReference ref = peekReference(trans, id, depth, resetJustPeeked);
return ref.getObject();
}
public ObjectReference peekReference(Transaction trans, int id, ActivationDepth depth, boolean resetJustPeeked) {
ObjectReference ref = new ObjectReference(id);
ref.peekPersisted(trans, depth);
if(resetJustPeeked){
_justPeeked = null;
}
return ref;
}
void peeked(int id, Object obj) {
_justPeeked = Tree
.add(_justPeeked, new TreeIntObject(id, obj));
}
public void purge() {
synchronized (_lock) {
checkClosed();
System.gc();
System.runFinalization();
System.gc();
gc();
_classCollection.purge();
}
}
public final void purge(Transaction trans, Object obj) {
synchronized (_lock) {
trans = checkTransaction(trans);
trans.removeObjectFromReferenceSystem(obj);
}
}
final void removeFromAllReferenceSystems(Object obj) {
if (obj == null) {
return;
}
if (obj instanceof ObjectReference) {
_referenceSystemRegistry.removeReference((ObjectReference) obj);
return;
}
_referenceSystemRegistry.removeObject(obj);
}
public final NativeQueryHandler getNativeQueryHandler() {
synchronized(_lock){
if (null == _nativeQueryHandler) {
_nativeQueryHandler = new NativeQueryHandler(this);
}
return _nativeQueryHandler;
}
}
public final ObjectSet query(Transaction trans, Predicate predicate){
return query(trans, predicate,(QueryComparator)null);
}
public final <T> ObjectSet<T> query(Transaction trans, Predicate<T> predicate,QueryComparator<T> comparator){
synchronized (_lock) {
return getNativeQueryHandler().execute(query(trans), predicate, comparator);
}
}
public final <T> ObjectSet<T> query(Transaction trans, Class<T> clazz) {
return queryByExample(trans, clazz);
}
public final Query query(Transaction ta) {
return new QQuery(checkTransaction(ta), null, null);
}
public abstract void raiseCommitTimestamp(long minimumTimestamp);
public abstract void readBytes(byte[] a_bytes, int a_address, int a_length) throws Db4oIOException;
public abstract void readBytes(byte[] bytes, int address, int addressOffset, int length) throws Db4oIOException;
public final ByteArrayBuffer decryptedBufferByAddress(int address, int length)
throws Db4oIOException {
ByteArrayBuffer reader = rawBufferByAddress(address, length);
_handlers.decrypt(reader);
return reader;
}
public ByteArrayBuffer rawBufferByAddress(int address, int length) {
checkAddress(address);
ByteArrayBuffer reader = new ByteArrayBuffer(length);
readBytes(reader._buffer, address, length);
return reader;
}
private void checkAddress(int address) throws IllegalArgumentException {
if (address <= 0) {
throw new IllegalArgumentException("Invalid address offset: "
+ address);
}
}
public final StatefulBuffer readWriterByAddress(Transaction a_trans,
int address, int length) throws Db4oIOException {
checkAddress(address);
StatefulBuffer reader = createStatefulBuffer(a_trans, address, length);
reader.readEncrypt(this, address);
return reader;
}
public abstract StatefulBuffer readStatefulBufferById(Transaction trans, int id);
public abstract StatefulBuffer readStatefulBufferById(Transaction trans, int id, boolean lastCommitted);
public abstract ByteArrayBuffer readBufferById(Transaction trans, int id);
public abstract ByteArrayBuffer readBufferById(Transaction trans, int id, boolean lastCommitted);
public abstract ByteArrayBuffer[] readSlotBuffers(Transaction trans, int[] ids);
private void reboot() {
commit(null);
close();
open();
}
public GenericReflector reflector(){
return _handlers._reflector;
}
public final void refresh(Transaction trans, Object obj, int depth) {
synchronized (_lock) {
refreshInternal(trans, obj, depth);
}
}
protected void refreshInternal(Transaction trans, Object obj, int depth) {
activate(trans, obj, refreshActivationDepth(depth));
}
private ActivationDepth refreshActivationDepth(int depth) {
return activationDepthProvider().activationDepth(depth, ActivationMode.REFRESH);
}
public abstract void releaseSemaphore(String name);
public void flagAsHandled(ObjectReference ref){
ref.flagAsHandled(_topLevelCallId);
}
boolean flagForDelete(ObjectReference ref){
if(ref == null){
return false;
}
if(handledInCurrentTopLevelCall(ref)){
return false;
}
ref.flagForDelete(_topLevelCallId);
return true;
}
public abstract void releaseSemaphores(Transaction ta);
void rename(Config4Impl config) {
boolean renamedOne = false;
if (config.rename() != null) {
renamedOne = applyRenames(config);
}
_classCollection.checkChanges();
if (renamedOne) {
reboot();
}
}
protected boolean applyRenames(Config4Impl config) {
boolean renamed = false;
final Iterator4 i = config.rename().iterator();
while (i.moveNext()) {
final Rename ren = (Rename) i.current();
if (alreadyApplied(ren)) {
continue;
}
if (applyRename(ren)) {
renamed = true;
}
}
return renamed;
}
private boolean applyRename(Rename ren) {
if (ren.isField()) {
return applyFieldRename(ren);
}
return applyClassRename(ren);
}
private boolean applyClassRename(Rename ren) {
final ClassMetadata classToRename = _classCollection.getClassMetadata(ren.rFrom);
if (classToRename == null) {
return false;
}
ClassMetadata existing = _classCollection.getClassMetadata(ren.rTo);
if (existing != null) {
logMsg(9, "class " + ren.rTo);
return false;
}
classToRename.setName(ren.rTo);
commitRenameFor(ren, classToRename);
return true;
}
private boolean applyFieldRename(Rename ren) {
final ClassMetadata parentClass = _classCollection.getClassMetadata(ren.rClass);
if (parentClass == null) {
return false;
}
if (!parentClass.renameField(ren.rFrom, ren.rTo)) {
return false;
}
commitRenameFor(ren, parentClass);
return true;
}
private void commitRenameFor(Rename rename, ClassMetadata classMetadata) {
setDirtyInSystemTransaction(classMetadata);
logMsg(8, rename.rFrom + " to " + rename.rTo);
deleteInverseRenames(rename);
// store the rename, so we only do it once
store(systemTransaction(), rename);
}
private void deleteInverseRenames(Rename rename) {
// delete all that rename from the new name
// to allow future backswitching
ObjectSet inverseRenames = queryInverseRenames(rename);
while (inverseRenames.hasNext()) {
delete(systemTransaction(), inverseRenames.next());
}
}
private ObjectSet queryInverseRenames(Rename ren) {
return queryByExample(systemTransaction(), Renames.forInverseQBE(ren));
}
private boolean alreadyApplied(Rename ren) {
return queryByExample(systemTransaction(), ren).size() != 0;
}
public final boolean handledInCurrentTopLevelCall(ObjectReference ref){
return ref.isFlaggedAsHandled(_topLevelCallId);
}
public abstract void reserve(int byteCount);
public final void rollback(Transaction trans) {
synchronized (_lock) {
trans = checkTransaction(trans);
checkReadOnly();
rollback1(trans);
trans.rollbackReferenceSystem();
}
}
public abstract void rollback1(Transaction trans);
/** @param obj */
public void send(Object obj) {
// TODO: implement
throw new NotSupportedException();
}
public final void store(Transaction trans, Object obj)
throws DatabaseClosedException, DatabaseReadOnlyException {
store(trans, obj, updateDepthProvider().unspecified(NullModifiedObjectQuery.INSTANCE));
}
public final int store(Transaction trans, Object obj, UpdateDepth depth)
throws DatabaseClosedException, DatabaseReadOnlyException {
synchronized (_lock) {
try {
showInternalClasses(true);
return storeInternal(trans, obj, depth, true);
} finally {
showInternalClasses(false);
}
}
}
public final int storeInternal(Transaction trans, Object obj,
boolean checkJustSet) throws DatabaseClosedException,
DatabaseReadOnlyException {
return storeInternal(trans, obj, updateDepthProvider().unspecified(NullModifiedObjectQuery.INSTANCE), checkJustSet);
}
public int storeInternal(final Transaction trans, final Object obj, final UpdateDepth depth,
final boolean checkJustSet) throws DatabaseClosedException,
DatabaseReadOnlyException {
checkReadOnly();
return asTopLevelStore(new Function4<Transaction, Integer>() {
public Integer apply(Transaction trans) {
return storeAfterReplication(trans, obj, depth, checkJustSet);
}
}, trans);
}
public final int storeAfterReplication(Transaction trans, Object obj, UpdateDepth depth, boolean checkJust) {
if (obj instanceof Db4oType) {
Db4oType db4oType = db4oTypeStored(trans, obj);
if (db4oType != null) {
return getID(trans, db4oType);
}
}
return store2(trans, obj, depth, checkJust);
}
public final void storeByNewReplication(Db4oReplicationReferenceProvider referenceProvider, Object obj){
synchronized(_lock){
_replicationCallState = Const4.NEW;
_handlers._replicationReferenceProvider = referenceProvider;
try {
store2(checkTransaction(), obj, updateDepthProvider().forDepth(1), false);
} finally {
_replicationCallState = Const4.NONE;
_handlers._replicationReferenceProvider = null;
}
}
}
public void checkStillToSet() {
List4 postponedStillToSet = null;
while (_stillToSet != null) {
Iterator4 i = new Iterator4Impl(_stillToSet);
_stillToSet = null;
while (i.moveNext()) {
PendingSet item = (PendingSet)i.current();
ObjectReference ref = item.ref;
Transaction trans = item.transaction;
if(! ref.continueSet(trans, item.depth)) {
postponedStillToSet = new List4(postponedStillToSet, item);
}
}
}
_stillToSet = postponedStillToSet;
}
void notStorable(ReflectClass claxx, Object obj, String message){
if(! configImpl().exceptionsOnNotStorable()){
return;
}
if(claxx == null){
throw new ObjectNotStorableException(obj.toString());
}
if(_handlers.isTransient(claxx)){
return;
}
if(message != null){
throw new ObjectNotStorableException(claxx, message);
}
throw new ObjectNotStorableException(claxx);
}
public final int store2(Transaction trans, Object obj, UpdateDepth updateDepth, boolean checkJustSet) {
if (obj == null || (obj instanceof TransientClass)) {
return 0;
}
ObjectAnalyzer analyzer = new ObjectAnalyzer(this, obj);
analyzer.analyze(trans);
if(analyzer.notStorable()){
return 0;
}
ObjectReference ref = analyzer.objectReference();
if (ref == null) {
ClassMetadata classMetadata = analyzer.classMetadata();
if (!objectCanNew(trans, classMetadata, obj)) {
return 0;
}
ref = new ObjectReference();
ref.store(trans, classMetadata, obj);
trans.addNewReference(ref);
if(obj instanceof Db4oTypeImpl){
((Db4oTypeImpl)obj).setTrans(trans);
}
if (configImpl().messageLevel() > Const4.STATE) {
message("" + ref.getID() + " new " + ref.classMetadata().getName());
}
flagAsHandled(ref);
stillToSet(trans, ref, updateDepth);
} else {
if (ref.isFlaggedAsHandled(_topLevelCallId)) {
assertNotInCallback();
}
if (canUpdate()) {
if(checkJustSet){
if( (! ref.isNew()) && handledInCurrentTopLevelCall(ref)){
return ref.getID();
}
}
if (updateDepth.sufficientDepth()) {
flagAsHandled(ref);
ref.writeUpdate(trans, updateDepth);
}
}
}
processPendingClassUpdates();
return ref.getID();
}
private void assertNotInCallback() {
if(inCallback()) {
throw new Db4oIllegalStateException("Objects must not be updated in callback");
}
}
private boolean objectCanNew(Transaction transaction, ClassMetadata yc, Object obj) {
return callbacks().objectCanNew(transaction, obj)
&& yc.dispatchEvent(transaction, obj, EventDispatchers.CAN_NEW);
}
public abstract void setDirtyInSystemTransaction(PersistentBase a_object);
public abstract boolean setSemaphore(String name, int timeout);
public abstract boolean setSemaphore(final Transaction trans, final String name, final int timeout);
public abstract void releaseSemaphore(final Transaction trans, final String name);
void stringIO(LatinStringIO io) {
_handlers.stringIO(io);
}
final boolean showInternalClasses() {
return isServer() || _showInternalClasses > 0;
}
/**
* Objects implementing the "Internal4" marker interface are
* not visible to queries, unless this flag is set to true.
* The caller should reset the flag after the call.
*/
public synchronized void showInternalClasses(boolean show) {
if (show) {
_showInternalClasses++;
} else {
_showInternalClasses--;
}
if (_showInternalClasses < 0) {
_showInternalClasses = 0;
}
}
private final boolean stackIsSmall(){
return _stackDepth < _maxStackDepth;
}
boolean stateMessages() {
return true; // overridden to do nothing in YapObjectCarrier
}
final List4 stillTo1(Transaction trans, List4 still, Object obj, ActivationDepth depth) {
if (obj == null || !depth.requiresActivation()) {
return still;
}
ObjectReference ref = trans.referenceForObject(obj);
if (ref != null) {
if(handledInCurrentTopLevelCall(ref)){
return still;
}
flagAsHandled(ref);
return new List4(still, new PendingActivation(ref, depth));
}
final ReflectClass clazz = reflectorForObject(obj);
if (clazz.isArray()) {
if (!clazz.getComponentType().isPrimitive()) {
Iterator4 arr = ArrayHandler.iterator(clazz, obj);
while (arr.moveNext()) {
final Object current = arr.current();
if(current == null){
continue;
}
ClassMetadata classMetadata = classMetadataForObject(current);
still = stillTo1(trans, still, current, depth.descend(classMetadata));
}
}
return still;
} else {
if (obj instanceof Entry) {
still = stillTo1(trans, still, ((Entry) obj).key, depth);
still = stillTo1(trans, still, ((Entry) obj).value, depth);
} else {
if (depth.mode().isDeactivate()) {
// Special handling to deactivate .net structs
ClassMetadata metadata = classMetadataForObject(obj);
if (metadata != null && metadata.isStruct()) {
metadata.forceDeactivation(trans, depth, obj);
}
}
}
}
return still;
}
public final void stillToActivate(ActivationContext context) {
// TODO: We don't want the simple classes to search the hc_tree
// Kick them out here.
// if (a_object != null) {
// Class clazz = a_object.getClass();
// if(! clazz.isPrimitive()){
if(processedByImmediateActivation(context)){
return;
}
_stillToActivate = stillTo1(context.transaction(), _stillToActivate, context.targetObject(), context.depth());
}
private boolean processedByImmediateActivation(ActivationContext context) {
if(! stackIsSmall()){
return false;
}
if (!context.depth().requiresActivation()) {
return true;
}
ObjectReference ref = context.transaction().referenceForObject(context.targetObject());
if(ref == null){
return false;
}
if(handledInCurrentTopLevelCall(ref)){
return true;
}
flagAsHandled(ref);
incStackDepth();
try{
ref.activateInternal(context);
} finally {
decStackDepth();
}
return true;
}
private int decStackDepth() {
int i = _stackDepth--;
if (stackIsSmall() && !_handlingStackLimitPendings) {
_handlingStackLimitPendings = true;
try {
handleStackLimitPendings();
} finally {
_handlingStackLimitPendings = false;
}
}
return i;
}
private void handleStackLimitPendings() {
checkStillToSet();
// activatePending();
// deactivatePending();
}
private int incStackDepth() {
return _stackDepth++;
}
public final void stillToDeactivate(Transaction trans, Object a_object, ActivationDepth a_depth,
boolean a_forceUnknownDeactivate) {
_stillToDeactivate = stillTo1(trans, _stillToDeactivate, a_object, a_depth);
}
static class PendingSet {
public final Transaction transaction;
public final ObjectReference ref;
public final UpdateDepth depth;
public PendingSet(Transaction transaction_, ObjectReference ref_, UpdateDepth depth_) {
this.transaction = transaction_;
this.ref = ref_;
this.depth = depth_;
}
}
void stillToSet(Transaction transaction, ObjectReference ref, UpdateDepth updateDepth) {
if(stackIsSmall()){
if(ref.continueSet(transaction, updateDepth)){
return;
}
}
_stillToSet = new List4(_stillToSet, new PendingSet(transaction, ref, updateDepth));
}
protected final void stopSession() {
if (hasShutDownHook()) {
Platform4.removeShutDownHook(this);
}
_classCollection = null;
if(_references != null){
_references.stop();
}
_systemTransaction = null;
_transaction = null;
}
public final StoredClass storedClass(Transaction trans, Object clazz) {
synchronized (_lock) {
trans = checkTransaction(trans);
ReflectClass claxx = ReflectorUtils.reflectClassFor(reflector(), clazz);
if (claxx == null) {
return null;
}
ClassMetadata classMetadata = classMetadataForReflectClass(claxx);
if(classMetadata == null){
return null;
}
return new StoredClassImpl(trans, classMetadata);
}
}
public StoredClass[] storedClasses(Transaction trans) {
synchronized (_lock) {
trans = checkTransaction(trans);
StoredClass[] classMetadata = _classCollection.storedClasses();
StoredClass[] storedClasses = new StoredClass[classMetadata.length];
for (int i = 0; i < classMetadata.length; i++) {
storedClasses[i] = new StoredClassImpl(trans, (ClassMetadata)classMetadata[i]);
}
return storedClasses;
}
}
public LatinStringIO stringIO(){
return _handlers.stringIO();
}
public abstract SystemInfo systemInfo();
private final void beginTopLevelCall(){
if(DTrace.enabled){
DTrace.BEGIN_TOP_LEVEL_CALL.log();
}
generateCallIDOnTopLevel();
incStackDepth();
}
private final void endTopLevelCall(){
if(DTrace.enabled){
DTrace.END_TOP_LEVEL_CALL.log();
}
decStackDepth();
generateCallIDOnTopLevel();
}
private final void generateCallIDOnTopLevel(){
if(_stackDepth == 0){
_topLevelCallId = _topLevelCallIdGenerator.next();
}
}
public int stackDepth(){
return _stackDepth;
}
public void stackDepth(int depth){
_stackDepth = depth;
}
public int topLevelCallId(){
return _topLevelCallId;
}
public void topLevelCallId(int id){
_topLevelCallId = id;
}
public long version(){
synchronized(_lock){
return currentVersion();
}
}
public abstract void shutdown();
public abstract void writeDirtyClassMetadata();
public abstract void writeNew(Transaction trans, Pointer4 pointer, ClassMetadata classMetadata, ByteArrayBuffer buffer);
public abstract void writeUpdate(Transaction trans, Pointer4 pointer, ClassMetadata classMetadata, ArrayType arrayType, ByteArrayBuffer buffer);
public Callbacks callbacks() {
return _callbacks;
}
public void callbacks(Callbacks cb) {
if (cb == null) {
throw new IllegalArgumentException();
}
_callbacks = cb;
}
public Config4Impl configImpl() {
return _config;
}
public UUIDFieldMetadata uUIDIndex() {
return _handlers.indexes()._uUID;
}
public VersionFieldMetadata versionIndex() {
return _handlers.indexes()._version;
}
public CommitTimestampFieldMetadata commitTimestampIndex() {
return _handlers.indexes()._commitTimestamp;
}
public ClassMetadataRepository classCollection() {
return _classCollection;
}
public abstract long[] getIDsForClass(Transaction trans, ClassMetadata clazz);
public abstract QueryResult classOnlyQuery(QQueryBase queryBase, ClassMetadata clazz);
public abstract QueryResult executeQuery(QQuery query);
public void replicationCallState(int state) {
_replicationCallState = state;
}
public ReferenceSystemRegistry referenceSystemRegistry(){
return _referenceSystemRegistry;
}
public ObjectContainerBase container(){
return this;
}
public void deleteByID(Transaction transaction, int id, int cascadeDeleteDepth) {
if(id <= 0){
throw new IllegalArgumentException("ID: " + id);
// return;
}
if (cascadeDeleteDepth <= 0) {
return;
}
Object obj = getByID2(transaction, id);
if(obj == null){
return;
}
cascadeDeleteDepth--;
ReflectClass claxx = reflectorForObject(obj);
if (claxx.isCollection()) {
cascadeDeleteDepth += 1;
}
ObjectReference ref = transaction.referenceForId(id);
if (ref == null) {
return;
}
delete2(transaction, ref, obj,cascadeDeleteDepth, false);
}
ReflectClass reflectorForObject(Object obj){
return reflector().forObject(obj);
}
public <R> R syncExec(Closure4<R> block) {
synchronized(_lock) {
checkClosed();
return block.run();
}
}
/**
* @sharpen.ignore
*/
@decaf.Ignore(decaf.Platform.JDK11)
public ObjectSet query(Predicate predicate,Comparator comparator) {
return query(null, predicate,new JdkComparatorWrapper(comparator));
}
public void storeAll(Transaction transaction, Iterator4 objects) {
while(objects.moveNext()){
store(transaction, objects.current());
}
}
public void storeAll(Transaction transaction, Iterator4 objects, UpdateDepth depth) {
while(objects.moveNext()){
store(transaction, objects.current(), depth);
}
}
public void withTransaction(Transaction transaction, Runnable runnable) {
synchronized (_lock) {
final Transaction old = _transaction;
_transaction = transaction;
try {
runnable.run();
} finally {
_transaction = old;
}
}
}
public ThreadPool4 threadPool() {
return environment().provide(ThreadPool4.class);
}
public Object newWeakReference(ObjectReference referent, Object obj) {
return _references.newWeakReference(referent, obj);
}
@Override
public final String toString() {
if(_name != null) {
return _name;
}
return defaultToString();
}
protected abstract String defaultToString();
public abstract boolean isDeleted(Transaction trans, int id);
public abstract void blockSize(int size);
public BlockConverter blockConverter(){
return _blockConverter;
}
protected void createBlockConverter(int blockSize) {
if(blockSize == 1){
_blockConverter = new DisabledBlockConverter();
} else {
_blockConverter = new BlockSizeBlockConverter(blockSize);
}
}
public UpdateDepthProvider updateDepthProvider() {
return configImpl().updateDepthProvider();
}
public void replaceClassMetadataRepository(ClassMetadataRepository repository){
_classCollection = repository;
}
public final long generateTransactionTimestamp(long forcedTimestamp){
synchronized (lock()) {
return checkTransaction().generateTransactionTimestamp(forcedTimestamp);
}
}
public final void useDefaultTransactionTimestamp(){
synchronized (lock()) {
checkTransaction().useDefaultTransactionTimestamp();
}
}
}