internal static IOdbComparable BuildIndexKey(string indexName, NonNativeObjectInfo oi, int[] fieldIds) { var keys = new IOdbComparable[fieldIds.Length]; for (var i = 0; i < fieldIds.Length; i++) { try { var aoi = oi.GetAttributeValueFromId(fieldIds[i]); var item = (IComparable)aoi.GetObject(); // If the index is on NonNativeObjectInfo, then the key is the oid of the object if (aoi.IsNonNativeObject()) { var nnoi = (NonNativeObjectInfo)aoi; item = nnoi.GetOid(); } keys[i] = new SimpleCompareKey(item); } catch (Exception) { throw new OdbRuntimeException( NDatabaseError.IndexKeysMustImplementComparable.AddParameter(indexName).AddParameter(fieldIds[i]).AddParameter( oi.GetAttributeValueFromId(fieldIds[i]).GetType().FullName)); } } return(keys.Length == 1 ? keys[0] : new ComposedCompareKey(keys)); }
private void StoreChangedObject(NonNativeObjectInfo aoi1, NonNativeObjectInfo aoi2, int fieldId, int objectRecursionLevel) { _nbChanges++; if (aoi1 == null || aoi2 == null) { return; } _changes.Add(new ChangedObjectInfo(aoi1.GetClassInfo(), aoi2.GetClassInfo(), fieldId, aoi1.GetAttributeValueFromId(fieldId), aoi2.GetAttributeValueFromId(fieldId), objectRecursionLevel)); // also the max recursion level if (objectRecursionLevel > _maxObjectRecursionLevel) { _maxObjectRecursionLevel = objectRecursionLevel; } }
private OID WriteNonNativeObjectInfo(OID existingOid, NonNativeObjectInfo objectInfo, long position, bool writeDataInTransaction, bool isNewObject) { var lsession = _session; var cache = lsession.GetCache(); var hasObject = objectInfo.GetObject() != null; // Checks if object is null,for null objects,there is nothing to do if (objectInfo.IsNull()) { return(StorageEngineConstant.NullObjectId); } var metaModel = lsession.GetMetaModel(); // first checks if the class of this object already exist in the // metamodel if (!metaModel.ExistClass(objectInfo.GetClassInfo().UnderlyingType)) { _objectWriter.AddClass(objectInfo.GetClassInfo(), true); } // if position is -1, gets the position where to write the object if (position == -1) { // Write at the end of the file position = _objectWriter.FileSystemProcessor.FileSystemInterface.GetAvailablePosition(); // Updates the meta object position objectInfo.SetPosition(position); } // Gets the object id var oid = existingOid; if (oid == null) { // If, to get the next id, a new id block must be created, then // there is an extra work // to update the current object position if (_objectWriter.GetIdManager().MustShift()) { oid = _objectWriter.GetIdManager().GetNextObjectId(position); // The id manager wrote in the file so the position for the // object must be re-computed position = _objectWriter.FileSystemProcessor.FileSystemInterface.GetAvailablePosition(); // The oid must be associated to this new position - id // operations are always out of transaction // in this case, the update is done out of the transaction as a // rollback won t need to // undo this. We are just creating the id // => third parameter(write in transaction) = false _objectWriter.GetIdManager().UpdateObjectPositionForOid(oid, position, false); } else { oid = _objectWriter.GetIdManager().GetNextObjectId(position); } } else { // If an oid was passed, it is because object already exist and // is being updated. So we // must update the object position // Here the update of the position of the id must be done in // transaction as the object // position of the id is being updated, and a rollback should undo // this // => third parameter(write in transaction) = true _objectWriter.GetIdManager().UpdateObjectPositionForOid(oid, position, true); // Keep the relation of id and position in the cache until the // commit cache.SavePositionOfObjectWithOid(oid, position); } // Sets the oid of the object in the inserting cache cache.UpdateIdOfInsertingObject(objectInfo.GetObject(), oid); // Only add the oid to unconnected zone if it is a new object if (isNewObject) { cache.AddOIDToUnconnectedZone(oid); } objectInfo.SetOid(oid); if (objectInfo.GetClassInfo() == null || objectInfo.GetClassInfo().ClassInfoId == null) { if (objectInfo.GetClassInfo() != null) { var clinfo = _storageEngine.GetSession().GetMetaModel().GetClassInfo( objectInfo.GetClassInfo().FullClassName, true); objectInfo.SetClassInfo(clinfo); } else { throw new OdbRuntimeException(NDatabaseError.UndefinedClassInfo.AddParameter(objectInfo.ToString())); } } // updates the meta model - If class already exist, it returns the // metamodel class, which contains // a bit more informations var classInfo = _objectWriter.AddClass(objectInfo.GetClassInfo(), true); objectInfo.SetClassInfo(classInfo); // if (isNewObject) { _objectWriter.ManageNewObjectPointers(objectInfo, classInfo); } _objectWriter.FileSystemProcessor.FileSystemInterface.SetWritePosition(position, writeDataInTransaction); objectInfo.SetPosition(position); var nbAttributes = objectInfo.GetClassInfo().Attributes.Count; // compute the size of the array of byte needed till the attibute // positions // BlockSize + Block Type + OID + ClassOid + PrevOid + NextOid + CreatDate + UpdateDate + objectVersion + NbAttributes + RefCoutner + IsRoot // Int + Byte + Long + Long + Long + Long + Long + Long + int + int + long + byte // 6 Longs + 3Ints + Byte var tsize = 7 * OdbType.SizeOfLong + 3 * OdbType.SizeOfInt + 2 * OdbType.SizeOfByte; var bytes = new byte[tsize]; // Block size IntToByteArray(0, bytes, 0); // Block type bytes[4] = BlockTypes.BlockTypeNonNativeObject; // The object id EncodeOid(oid, bytes, 5); // Class info id LongToByteArray(classInfo.ClassInfoId.ObjectId, bytes, 13); // previous instance EncodeOid(objectInfo.GetPreviousObjectOID(), bytes, 21); // next instance EncodeOid(objectInfo.GetNextObjectOID(), bytes, 29); // creation date, for update operation must be the original one LongToByteArray(objectInfo.GetHeader().GetCreationDate(), bytes, 37); LongToByteArray(OdbTime.GetCurrentTimeInTicks(), bytes, 45); IntToByteArray(objectInfo.GetHeader().GetObjectVersion(), bytes, 53); LongToByteArray(objectInfo.GetHeader().RefCounter, bytes, 57); BooleanToByteArray(objectInfo.GetHeader().IsRoot, bytes, 65); // now write the number of attributes and the position of all // attributes, we do not know them yet, so write 00 but at the end of the write operation // These positions will be updated The positions that is going to be written are 'int' representing // the offset position of the attribute first write the number of attributes IntToByteArray(nbAttributes, bytes, 66); // Then write the array of bytes _objectWriter.FileSystemProcessor.FileSystemInterface.WriteBytes(bytes, writeDataInTransaction); // Store the position var attributePositionStart = _objectWriter.FileSystemProcessor.FileSystemInterface.GetPosition(); var attributeSize = OdbType.SizeOfInt + OdbType.SizeOfLong; var abytes = new byte[nbAttributes * (attributeSize)]; // here, just write an empty (0) array, as real values will be set at // the end _objectWriter.FileSystemProcessor.FileSystemInterface.WriteBytes(abytes, writeDataInTransaction); var attributesIdentification = new long[nbAttributes]; var attributeIds = new int[nbAttributes]; // Puts the object info in the cache // storageEngine.getSession().getCache().addObject(position, // aoi.getObject(), objectInfo.getHeader()); var maxWritePosition = _objectWriter.FileSystemProcessor.FileSystemInterface.GetPosition(); // Loop on all attributes for (var i = 0; i < nbAttributes; i++) { // Gets the attribute meta description var classAttributeInfo = classInfo.GetAttributeInfo(i); // Gets the id of the attribute attributeIds[i] = classAttributeInfo.GetId(); // Gets the attribute data var aoi2 = objectInfo.GetAttributeValueFromId(classAttributeInfo.GetId()); if (aoi2 == null) { // This only happens in 1 case : when a class has a field with // the same name of one of is superclass. In this, the deeper // attribute is null if (classAttributeInfo.IsNative()) { aoi2 = new NullNativeObjectInfo(classAttributeInfo.GetAttributeType().Id); } else { aoi2 = new NonNativeNullObjectInfo(classAttributeInfo.GetClassInfo()); } } if (aoi2.IsNative()) { var nativeAttributePosition = _objectWriter.InternalStoreObject((NativeObjectInfo)aoi2); // For native objects , odb stores their position attributesIdentification[i] = nativeAttributePosition; } else { OID nonNativeAttributeOid; if (aoi2.IsObjectReference()) { var or = (ObjectReference)aoi2; nonNativeAttributeOid = or.GetOid(); } else { nonNativeAttributeOid = _objectWriter.StoreObject(null, (NonNativeObjectInfo)aoi2); } // For non native objects , odb stores its oid as a negative // number!!u if (nonNativeAttributeOid != null) { attributesIdentification[i] = -nonNativeAttributeOid.ObjectId; } else { attributesIdentification[i] = StorageEngineConstant.NullObjectIdId; } } var p = _objectWriter.FileSystemProcessor.FileSystemInterface.GetPosition(); if (p > maxWritePosition) { maxWritePosition = p; } } // Updates attributes identification in the object info header objectInfo.GetHeader().SetAttributesIdentification(attributesIdentification); objectInfo.GetHeader().SetAttributesIds(attributeIds); var positionAfterWrite = maxWritePosition; // Now writes back the attribute positions _objectWriter.FileSystemProcessor.FileSystemInterface.SetWritePosition(attributePositionStart, writeDataInTransaction); abytes = new byte[attributesIdentification.Length * (attributeSize)]; for (var i = 0; i < attributesIdentification.Length; i++) { IntToByteArray(attributeIds[i], abytes, i * attributeSize); LongToByteArray(attributesIdentification[i], abytes, i * (attributeSize) + OdbType.SizeOfInt); // fsi.writeInt(attributeIds[i], writeDataInTransaction, "attr id"); // fsi.writeLong(attributesIdentification[i], // writeDataInTransaction, "att real pos", // WriteAction.DATA_WRITE_ACTION); // if (classInfo.getAttributeInfo(i).isNonNative() && // attributesIdentification[i] > 0) { if (objectInfo.GetAttributeValueFromId(attributeIds[i]).IsNonNativeObject() && attributesIdentification[i] > 0) { throw new OdbRuntimeException( NDatabaseError.NonNativeAttributeStoredByPositionInsteadOfOid.AddParameter( classInfo.GetAttributeInfo(i).GetName()).AddParameter(classInfo.FullClassName). AddParameter(attributesIdentification[i])); } } _objectWriter.FileSystemProcessor.FileSystemInterface.WriteBytes(abytes, writeDataInTransaction); _objectWriter.FileSystemProcessor.FileSystemInterface.SetWritePosition(positionAfterWrite, writeDataInTransaction); var blockSize = (int)(positionAfterWrite - position); WriteBlockSizeAt(position, blockSize, writeDataInTransaction, objectInfo); // Only insert in index for new objects if (isNewObject) { // insert object id in indexes, if exist _objectWriter.ManageIndexesForInsert(oid, objectInfo); var value = hasObject ? objectInfo.GetObject() : objectInfo; _triggerManager.ManageInsertTriggerAfter(objectInfo.GetClassInfo().UnderlyingType, value, oid); } return(oid); }
public virtual object BuildOneInstance(NonNativeObjectInfo objectInfo) { ICache cache = GetSession().GetCache(); // verify if the object is check to delete if (objectInfo.IsDeletedObject()) { throw new ODBRuntimeException(NeoDatisError.ObjectIsMarkedAsDeletedForOid.AddParameter(objectInfo.GetOid())); } // Then check if object is in cache object o = cache.GetObjectWithOid(objectInfo.GetOid()); if (o != null) { return(o); } Type instanceClazz = null; instanceClazz = classPool.GetClass(objectInfo.GetClassInfo().GetFullClassName()); try { o = classIntrospector.NewInstanceOf(instanceClazz); } catch (System.Exception e) { throw new ODBRuntimeException(NeoDatisError.InstanciationError.AddParameter(objectInfo.GetClassInfo().GetFullClassName()), e); } // This can happen if ODB can not create the instance // TODO Check if returning null is correct if (o == null) { return(null); } // Keep the initial hash code. In some cases, when the class redefines // the hash code method // Hash code can return wrong values when attributes are not set (when // hash code depends on attribute values) // Hash codes are used as the key of the map, // So at the end of this method, if hash codes are different, object // will be removed from the cache and inserted back bool hashCodeIsOk = true; int initialHashCode = 0; try { initialHashCode = o.GetHashCode(); } catch (System.Exception) { hashCodeIsOk = false; } // Adds this incomplete instance in the cache to manage cyclic reference if (hashCodeIsOk) { cache.AddObject(objectInfo.GetOid(), o, objectInfo.GetHeader()); } ClassInfo ci = objectInfo.GetClassInfo(); IOdbList <FieldInfo> fields = classIntrospector.GetAllFields(ci.GetFullClassName()); FieldInfo field = null; AbstractObjectInfo aoi = null; object value = null; for (int i = 0; i < fields.Count; i++) { field = fields[i]; // Gets the id of this field int attributeId = ci.GetAttributeId(field.Name); if (OdbConfiguration.IsDebugEnabled(LogIdDebug)) { DLogger.Debug("getting field with name " + field.Name + ", attribute id is " + attributeId); } aoi = objectInfo.GetAttributeValueFromId(attributeId); // Check consistency // ensureClassCompatibily(field, // instanceInfo.getClassInfo().getAttributeinfo(i).getFullClassname()); if (aoi != null && (!aoi.IsNull())) { if (aoi.IsNative()) { if (aoi.IsAtomicNativeObject()) { if (aoi.IsNull()) { value = null; } else { value = aoi.GetObject(); } } if (aoi.IsCollectionObject()) { value = BuildCollectionInstance((CollectionObjectInfo)aoi); // Manage a specific case of Set /* * if (typeof(Java.Util.Set).IsAssignableFrom(field.GetType()) && typeof(ICollection).IsAssignableFrom(value.GetType())) * { * Java.Util.Set s = new Java.Util.HashSet(); * s.AddAll((System.Collections.ICollection)value); * value = s; * }*/ } if (aoi.IsArrayObject()) { value = BuildArrayInstance((ArrayObjectInfo)aoi); } if (aoi.IsMapObject()) { value = BuildMapInstance((MapObjectInfo)aoi); } if (aoi.IsEnumObject()) { value = BuildEnumInstance((EnumNativeObjectInfo)aoi, field.FieldType); } } else { if (aoi.IsNonNativeObject()) { if (aoi.IsDeletedObject()) { if (NeoDatis.Odb.OdbConfiguration.DisplayWarnings()) { IError warning = NeoDatisError.AttributeReferencesADeletedObject .AddParameter(objectInfo.GetClassInfo().GetFullClassName()) .AddParameter(objectInfo.GetOid()).AddParameter(field.Name); DLogger.Info(warning.ToString()); } value = null; } else { value = BuildOneInstance((NonNativeObjectInfo)aoi); } } } if (value != null) { if (OdbConfiguration.IsDebugEnabled(LogIdDebug)) { DLogger.Debug("Setting field " + field.Name + "(" + field.GetType().FullName + ") to " + value + " / " + value.GetType().FullName); } try { field.SetValue(o, value); } catch (System.Exception e) { throw new ODBRuntimeException(NeoDatisError.InstanceBuilderWrongObjectContainerType .AddParameter(objectInfo.GetClassInfo().GetFullClassName()) .AddParameter(value.GetType().FullName).AddParameter(field.GetType().FullName), e); } } } } if (o != null && !OdbClassUtil.GetFullName(o.GetType()).Equals(objectInfo.GetClassInfo().GetFullClassName())) { new ODBRuntimeException(NeoDatisError.InstanceBuilderWrongObjectType .AddParameter(objectInfo.GetClassInfo().GetFullClassName()) .AddParameter(o.GetType().FullName)); } if (hashCodeIsOk || initialHashCode != o.GetHashCode()) { // Bug (sf bug id=1875544 )detected by glsender // This can happen when an object has redefined its own hashcode // method and depends on the field values // Then, we have to remove object from the cache and re-insert to // correct map hash code cache.RemoveObjectWithOid(objectInfo.GetOid()); // re-Adds instance in the cache cache.AddObject(objectInfo.GetOid(), o, objectInfo.GetHeader()); } if (triggerManager != null) { triggerManager.ManageSelectTriggerAfter(objectInfo.GetClassInfo().GetFullClassName (), objectInfo, objectInfo.GetOid()); } if (OdbConfiguration.ReconnectObjectsToSession()) { ICrossSessionCache crossSessionCache = CacheFactory.GetCrossSessionCache(engine.GetBaseIdentification().GetIdentification()); crossSessionCache.AddObject(o, objectInfo.GetOid()); } return(o); }
private bool HasChanged(NonNativeObjectInfo nnoi1, NonNativeObjectInfo nnoi2, int objectRecursionLevel) { var hasChanged = false; // If the object is already being checked, return false, this second // check will not affect the check int n; _alreadyCheckingObjects.TryGetValue(nnoi2, out n); if (n != 0) { return(false); } // Put the object in the temporary cache _alreadyCheckingObjects[nnoi1] = 1; _alreadyCheckingObjects[nnoi2] = 1; // Warning ID Start with 1 and not 0 for (var id = 1; id <= nnoi1.GetMaxNbattributes(); id++) { var value1 = nnoi1.GetAttributeValueFromId(id); // Gets the value by the attribute id to be sure // Problem because a new object info may not have the right ids ? // Check if // the new oiD is ok. var value2 = nnoi2.GetAttributeValueFromId(id); if (value2 == null) { // this means the object to have attribute id StoreChangedObject(nnoi1, nnoi2, id, objectRecursionLevel); hasChanged = true; continue; } if (value1 == null) { //throw new ODBRuntimeException("ObjectInfoComparator.hasChanged:attribute with id "+id+" does not exist on "+nnoi2); // This happens when this object was created with an version of ClassInfo (which has been refactored). // In this case,we simply tell that in place update is not supported so that the object will be rewritten with // new metamodel continue; } // If both are null, no effect if (value1.IsNull() && value2.IsNull()) { continue; } if (value2.IsNull()) { hasChanged = true; _nbChanges++; continue; } if (value1.IsNull() && value2.IsNonNativeObject()) { hasChanged = true; _nbChanges++; continue; } if (!ClassAreCompatible(value1, value2)) { var nativeObjectInfo = value2 as NativeObjectInfo; if (nativeObjectInfo != null) { StoreChangedObject(nnoi1, nnoi2, id, objectRecursionLevel); _nbChanges++; } var objectReference = value2 as ObjectReference; if (objectReference != null) { var nnoi = (NonNativeObjectInfo)value1; var oref = objectReference; if (!nnoi.GetOid().Equals(oref.GetOid())) { StoreChangedObject(nnoi1, nnoi2, id, objectRecursionLevel); _nbChanges++; } else { continue; } } hasChanged = true; continue; } if (value1.IsAtomicNativeObject()) { if (!value1.Equals(value2)) { _nbChanges++; hasChanged = true; } continue; } if (value1.IsArrayObject()) { var aoi1 = (ArrayObjectInfo)value1; var aoi2 = (ArrayObjectInfo)value2; var arrayHasChanged = ManageArrayChanges(nnoi1, nnoi2, id, aoi1, aoi2, objectRecursionLevel); hasChanged = hasChanged || arrayHasChanged; continue; } if (value1.IsEnumObject()) { var enoi1 = (EnumNativeObjectInfo)value1; var enoi2 = (EnumNativeObjectInfo)value2; var enumHasChanged = !enoi1.GetEnumClassInfo().ClassInfoId.Equals(enoi2.GetEnumClassInfo().ClassInfoId) || !enoi1.GetEnumValue().Equals(enoi2.GetEnumValue()); hasChanged = hasChanged || enumHasChanged; continue; } if (value1.IsNonNativeObject()) { var oi1 = (NonNativeObjectInfo)value1; var oi2 = (NonNativeObjectInfo)value2; // If oids are equal, they are the same objects if (oi1.GetOid() != null && oi1.GetOid().Equals(oi2.GetOid())) { hasChanged = HasChanged(value1, value2, objectRecursionLevel + 1) || hasChanged; } else { // This means that an object reference has changed. hasChanged = true; _nbChanges++; objectRecursionLevel++; } } } var i1 = _alreadyCheckingObjects[nnoi1]; var i2 = _alreadyCheckingObjects[nnoi2]; i1 = i1 - 1; i2 = i2 - 1; if (i1 == 0) { _alreadyCheckingObjects.Remove(nnoi1); } else { _alreadyCheckingObjects.Add(nnoi1, i1); } if (i2 == 0) { _alreadyCheckingObjects.Remove(nnoi2); } else { _alreadyCheckingObjects.Add(nnoi2, i2); } return(hasChanged); }
private bool HasChanged(NonNativeObjectInfo nnoi1, NonNativeObjectInfo nnoi2, int objectRecursionLevel) { var hasChanged = false; // If the object is already being checked, return false, this second // check will not affect the check int n; _alreadyCheckingObjects.TryGetValue(nnoi2, out n); if (n != 0) return false; // Put the object in the temporary cache _alreadyCheckingObjects[nnoi1] = 1; _alreadyCheckingObjects[nnoi2] = 1; // Warning ID Start with 1 and not 0 for (var id = 1; id <= nnoi1.GetMaxNbattributes(); id++) { var value1 = nnoi1.GetAttributeValueFromId(id); // Gets the value by the attribute id to be sure // Problem because a new object info may not have the right ids ? // Check if // the new oiD is ok. var value2 = nnoi2.GetAttributeValueFromId(id); if (value2 == null) { // this means the object to have attribute id StoreChangedObject(nnoi1, nnoi2, id, objectRecursionLevel); hasChanged = true; continue; } if (value1 == null) { //throw new ODBRuntimeException("ObjectInfoComparator.hasChanged:attribute with id "+id+" does not exist on "+nnoi2); // This happens when this object was created with an version of ClassInfo (which has been refactored). // In this case,we simply tell that in place update is not supported so that the object will be rewritten with // new metamodel continue; } // If both are null, no effect if (value1.IsNull() && value2.IsNull()) continue; if (value2.IsNull()) { hasChanged = true; _nbChanges++; continue; } if (value1.IsNull() && value2.IsNonNativeObject()) { hasChanged = true; _nbChanges++; continue; } if (!ClassAreCompatible(value1, value2)) { var nativeObjectInfo = value2 as NativeObjectInfo; if (nativeObjectInfo != null) { StoreChangedObject(nnoi1, nnoi2, id, objectRecursionLevel); _nbChanges++; } var objectReference = value2 as ObjectReference; if (objectReference != null) { var nnoi = (NonNativeObjectInfo) value1; var oref = objectReference; if (!nnoi.GetOid().Equals(oref.GetOid())) { StoreChangedObject(nnoi1, nnoi2, id, objectRecursionLevel); _nbChanges++; } else continue; } hasChanged = true; continue; } if (value1.IsAtomicNativeObject()) { if (!value1.Equals(value2)) { _nbChanges++; hasChanged = true; } continue; } if (value1.IsArrayObject()) { var aoi1 = (ArrayObjectInfo) value1; var aoi2 = (ArrayObjectInfo) value2; var arrayHasChanged = ManageArrayChanges(nnoi1, nnoi2, id, aoi1, aoi2, objectRecursionLevel); hasChanged = hasChanged || arrayHasChanged; continue; } if (value1.IsEnumObject()) { var enoi1 = (EnumNativeObjectInfo) value1; var enoi2 = (EnumNativeObjectInfo) value2; var enumHasChanged = !enoi1.GetEnumClassInfo().ClassInfoId.Equals(enoi2.GetEnumClassInfo().ClassInfoId) || !enoi1.GetEnumValue().Equals(enoi2.GetEnumValue()); hasChanged = hasChanged || enumHasChanged; continue; } if (value1.IsNonNativeObject()) { var oi1 = (NonNativeObjectInfo) value1; var oi2 = (NonNativeObjectInfo) value2; // If oids are equal, they are the same objects if (oi1.GetOid() != null && oi1.GetOid().Equals(oi2.GetOid())) hasChanged = HasChanged(value1, value2, objectRecursionLevel + 1) || hasChanged; else { // This means that an object reference has changed. hasChanged = true; _nbChanges++; objectRecursionLevel++; } } } var i1 = _alreadyCheckingObjects[nnoi1]; var i2 = _alreadyCheckingObjects[nnoi2]; i1 = i1 - 1; i2 = i2 - 1; if (i1 == 0) _alreadyCheckingObjects.Remove(nnoi1); else _alreadyCheckingObjects.Add(nnoi1, i1); if (i2 == 0) _alreadyCheckingObjects.Remove(nnoi2); else _alreadyCheckingObjects.Add(nnoi2, i2); return hasChanged; }
private void StoreChangedObject(NonNativeObjectInfo aoi1, NonNativeObjectInfo aoi2, int fieldId, int objectRecursionLevel) { _nbChanges++; if (aoi1 == null || aoi2 == null) return; _changes.Add(new ChangedObjectInfo(aoi1.GetClassInfo(), aoi2.GetClassInfo(), fieldId, aoi1.GetAttributeValueFromId(fieldId), aoi2.GetAttributeValueFromId(fieldId), objectRecursionLevel)); // also the max recursion level if (objectRecursionLevel > _maxObjectRecursionLevel) _maxObjectRecursionLevel = objectRecursionLevel; }
public object BuildOneInstance(NonNativeObjectInfo objectInfo, IOdbCache cache) { // verify if the object is check to delete if (objectInfo.IsDeletedObject()) { throw new OdbRuntimeException( NDatabaseError.ObjectIsMarkedAsDeletedForOid.AddParameter(objectInfo.GetOid())); } // Then check if object is in cache var o = cache.GetObject(objectInfo.GetOid()); if (o != null) { return(o); } try { o = FormatterServices.GetUninitializedObject(objectInfo.GetClassInfo().UnderlyingType); } catch (Exception e) { throw new OdbRuntimeException( NDatabaseError.InstanciationError.AddParameter(objectInfo.GetClassInfo().FullClassName), e); } // This can happen if ODB can not create the instance from security reasons if (o == null) { throw new OdbRuntimeException( NDatabaseError.InstanciationError.AddParameter(objectInfo.GetClassInfo().FullClassName)); } // Keep the initial hash code. In some cases, when the class redefines // the hash code method // Hash code can return wrong values when attributes are not set (when // hash code depends on attribute values) // Hash codes are used as the key of the map, // So at the end of this method, if hash codes are different, object // will be removed from the cache and inserted back var hashCodeIsOk = true; var initialHashCode = 0; try { initialHashCode = o.GetHashCode(); } catch { hashCodeIsOk = false; } // Adds this incomplete instance in the cache to manage cyclic reference if (hashCodeIsOk) { cache.AddObject(objectInfo.GetOid(), o, objectInfo.GetHeader()); } var classInfo = objectInfo.GetClassInfo(); var fields = ClassIntrospector.GetAllFieldsFrom(classInfo.UnderlyingType); object value = null; foreach (var fieldInfo in fields) { // Gets the id of this field var attributeId = classInfo.GetAttributeId(fieldInfo.Name); if (OdbConfiguration.IsLoggingEnabled()) { DLogger.Debug(string.Concat("InstanceBuilder: ", "getting field with name ", fieldInfo.Name, ", attribute id is ", attributeId.ToString())); } var abstractObjectInfo = objectInfo.GetAttributeValueFromId(attributeId); // Check consistency // ensureClassCompatibily(field, // instanceInfo.getClassInfo().getAttributeinfo(i).getFullClassname()); if (abstractObjectInfo == null || (abstractObjectInfo.IsNull())) { continue; } if (abstractObjectInfo.IsNative()) { if (abstractObjectInfo.IsAtomicNativeObject()) { value = abstractObjectInfo.IsNull() ? null : abstractObjectInfo.GetObject(); } if (abstractObjectInfo.IsArrayObject()) { value = BuildArrayInstance((ArrayObjectInfo)abstractObjectInfo); } if (abstractObjectInfo.IsEnumObject()) { value = BuildEnumInstance((EnumNativeObjectInfo)abstractObjectInfo, fieldInfo.FieldType); } } else { if (abstractObjectInfo.IsNonNativeObject()) { if (abstractObjectInfo.IsDeletedObject()) { if (OdbConfiguration.IsLoggingEnabled()) { var warning = NDatabaseError.AttributeReferencesADeletedObject.AddParameter( objectInfo.GetClassInfo().FullClassName).AddParameter( objectInfo.GetOid()).AddParameter(fieldInfo.Name); DLogger.Warning("InstanceBuilder: " + warning); } value = null; } else { value = BuildOneInstance((NonNativeObjectInfo)abstractObjectInfo); } } } if (value == null) { continue; } if (OdbConfiguration.IsLoggingEnabled()) { DLogger.Debug(String.Format("InstanceBuilder: Setting field {0}({1}) to {2} / {3}", fieldInfo.Name, fieldInfo.GetType().FullName, value, value.GetType().FullName)); } try { fieldInfo.SetValue(o, value); } catch (Exception e) { throw new OdbRuntimeException( NDatabaseError.InstanceBuilderWrongObjectContainerType.AddParameter( objectInfo.GetClassInfo().FullClassName).AddParameter(value.GetType().FullName) .AddParameter(fieldInfo.GetType().FullName), e); } } if (o.GetType() != objectInfo.GetClassInfo().UnderlyingType) { throw new OdbRuntimeException( NDatabaseError.InstanceBuilderWrongObjectType.AddParameter( objectInfo.GetClassInfo().FullClassName).AddParameter(o.GetType().FullName)); } if (hashCodeIsOk || initialHashCode != o.GetHashCode()) { // Bug (sf bug id=1875544 )detected by glsender // This can happen when an object has redefined its own hashcode // method and depends on the field values // Then, we have to remove object from the cache and re-insert to // correct map hash code cache.RemoveObjectByOid(objectInfo.GetOid()); // re-Adds instance in the cache cache.AddObject(objectInfo.GetOid(), o, objectInfo.GetHeader()); } if (_triggerManager != null) { _triggerManager.ManageSelectTriggerAfter(objectInfo.GetClassInfo().UnderlyingType, o, objectInfo.GetOid()); } return(o); }
private OID WriteNonNativeObjectInfo(OID existingOid, NonNativeObjectInfo objectInfo, long position, bool writeDataInTransaction, bool isNewObject) { var lsession = _session; var cache = lsession.GetCache(); var hasObject = objectInfo.GetObject() != null; // Checks if object is null,for null objects,there is nothing to do if (objectInfo.IsNull()) return StorageEngineConstant.NullObjectId; var metaModel = lsession.GetMetaModel(); // first checks if the class of this object already exist in the // metamodel if (!metaModel.ExistClass(objectInfo.GetClassInfo().UnderlyingType)) _objectWriter.AddClass(objectInfo.GetClassInfo(), true); // if position is -1, gets the position where to write the object if (position == -1) { // Write at the end of the file position = _objectWriter.FileSystemProcessor.FileSystemInterface.GetAvailablePosition(); // Updates the meta object position objectInfo.SetPosition(position); } // Gets the object id var oid = existingOid; if (oid == null) { // If, to get the next id, a new id block must be created, then // there is an extra work // to update the current object position if (_objectWriter.GetIdManager().MustShift()) { oid = _objectWriter.GetIdManager().GetNextObjectId(position); // The id manager wrote in the file so the position for the // object must be re-computed position = _objectWriter.FileSystemProcessor.FileSystemInterface.GetAvailablePosition(); // The oid must be associated to this new position - id // operations are always out of transaction // in this case, the update is done out of the transaction as a // rollback won t need to // undo this. We are just creating the id // => third parameter(write in transaction) = false _objectWriter.GetIdManager().UpdateObjectPositionForOid(oid, position, false); } else oid = _objectWriter.GetIdManager().GetNextObjectId(position); } else { // If an oid was passed, it is because object already exist and // is being updated. So we // must update the object position // Here the update of the position of the id must be done in // transaction as the object // position of the id is being updated, and a rollback should undo // this // => third parameter(write in transaction) = true _objectWriter.GetIdManager().UpdateObjectPositionForOid(oid, position, true); // Keep the relation of id and position in the cache until the // commit cache.SavePositionOfObjectWithOid(oid, position); } // Sets the oid of the object in the inserting cache cache.UpdateIdOfInsertingObject(objectInfo.GetObject(), oid); // Only add the oid to unconnected zone if it is a new object if (isNewObject) cache.AddOIDToUnconnectedZone(oid); objectInfo.SetOid(oid); if (objectInfo.GetClassInfo() == null || objectInfo.GetClassInfo().ClassInfoId == null) { if (objectInfo.GetClassInfo() != null) { var clinfo = _storageEngine.GetSession().GetMetaModel().GetClassInfo( objectInfo.GetClassInfo().FullClassName, true); objectInfo.SetClassInfo(clinfo); } else throw new OdbRuntimeException(NDatabaseError.UndefinedClassInfo.AddParameter(objectInfo.ToString())); } // updates the meta model - If class already exist, it returns the // metamodel class, which contains // a bit more informations var classInfo = _objectWriter.AddClass(objectInfo.GetClassInfo(), true); objectInfo.SetClassInfo(classInfo); // if (isNewObject) _objectWriter.ManageNewObjectPointers(objectInfo, classInfo); _objectWriter.FileSystemProcessor.FileSystemInterface.SetWritePosition(position, writeDataInTransaction); objectInfo.SetPosition(position); var nbAttributes = objectInfo.GetClassInfo().Attributes.Count; // compute the size of the array of byte needed till the attibute // positions // BlockSize + Block Type + OID + ClassOid + PrevOid + NextOid + CreatDate + UpdateDate + objectVersion + NbAttributes + RefCoutner + IsRoot // Int + Byte + Long + Long + Long + Long + Long + Long + int + int + long + byte // 6 Longs + 3Ints + Byte var tsize = 7 * OdbType.SizeOfLong + 3 * OdbType.SizeOfInt + 2 * OdbType.SizeOfByte; var bytes = new byte[tsize]; // Block size IntToByteArray(0, bytes, 0); // Block type bytes[4] = BlockTypes.BlockTypeNonNativeObject; // The object id EncodeOid(oid, bytes, 5); // Class info id LongToByteArray(classInfo.ClassInfoId.ObjectId, bytes, 13); // previous instance EncodeOid(objectInfo.GetPreviousObjectOID(), bytes, 21); // next instance EncodeOid(objectInfo.GetNextObjectOID(), bytes, 29); // creation date, for update operation must be the original one LongToByteArray(objectInfo.GetHeader().GetCreationDate(), bytes, 37); LongToByteArray(OdbTime.GetCurrentTimeInTicks(), bytes, 45); IntToByteArray(objectInfo.GetHeader().GetObjectVersion(), bytes, 53); LongToByteArray(objectInfo.GetHeader().RefCounter, bytes, 57); BooleanToByteArray(objectInfo.GetHeader().IsRoot, bytes, 65); // now write the number of attributes and the position of all // attributes, we do not know them yet, so write 00 but at the end of the write operation // These positions will be updated The positions that is going to be written are 'int' representing // the offset position of the attribute first write the number of attributes IntToByteArray(nbAttributes, bytes, 66); // Then write the array of bytes _objectWriter.FileSystemProcessor.FileSystemInterface.WriteBytes(bytes, writeDataInTransaction); // Store the position var attributePositionStart = _objectWriter.FileSystemProcessor.FileSystemInterface.GetPosition(); var attributeSize = OdbType.SizeOfInt + OdbType.SizeOfLong; var abytes = new byte[nbAttributes * (attributeSize)]; // here, just write an empty (0) array, as real values will be set at // the end _objectWriter.FileSystemProcessor.FileSystemInterface.WriteBytes(abytes, writeDataInTransaction); var attributesIdentification = new long[nbAttributes]; var attributeIds = new int[nbAttributes]; // Puts the object info in the cache // storageEngine.getSession().getCache().addObject(position, // aoi.getObject(), objectInfo.getHeader()); var maxWritePosition = _objectWriter.FileSystemProcessor.FileSystemInterface.GetPosition(); // Loop on all attributes for (var i = 0; i < nbAttributes; i++) { // Gets the attribute meta description var classAttributeInfo = classInfo.GetAttributeInfo(i); // Gets the id of the attribute attributeIds[i] = classAttributeInfo.GetId(); // Gets the attribute data var aoi2 = objectInfo.GetAttributeValueFromId(classAttributeInfo.GetId()); if (aoi2 == null) { // This only happens in 1 case : when a class has a field with // the same name of one of is superclass. In this, the deeper // attribute is null if (classAttributeInfo.IsNative()) aoi2 = new NullNativeObjectInfo(classAttributeInfo.GetAttributeType().Id); else aoi2 = new NonNativeNullObjectInfo(classAttributeInfo.GetClassInfo()); } if (aoi2.IsNative()) { var nativeAttributePosition = _objectWriter.InternalStoreObject((NativeObjectInfo)aoi2); // For native objects , odb stores their position attributesIdentification[i] = nativeAttributePosition; } else { OID nonNativeAttributeOid; if (aoi2.IsObjectReference()) { var or = (ObjectReference)aoi2; nonNativeAttributeOid = or.GetOid(); } else nonNativeAttributeOid = _objectWriter.StoreObject(null, (NonNativeObjectInfo)aoi2); // For non native objects , odb stores its oid as a negative // number!!u if (nonNativeAttributeOid != null) attributesIdentification[i] = -nonNativeAttributeOid.ObjectId; else attributesIdentification[i] = StorageEngineConstant.NullObjectIdId; } var p = _objectWriter.FileSystemProcessor.FileSystemInterface.GetPosition(); if (p > maxWritePosition) maxWritePosition = p; } // Updates attributes identification in the object info header objectInfo.GetHeader().SetAttributesIdentification(attributesIdentification); objectInfo.GetHeader().SetAttributesIds(attributeIds); var positionAfterWrite = maxWritePosition; // Now writes back the attribute positions _objectWriter.FileSystemProcessor.FileSystemInterface.SetWritePosition(attributePositionStart, writeDataInTransaction); abytes = new byte[attributesIdentification.Length * (attributeSize)]; for (var i = 0; i < attributesIdentification.Length; i++) { IntToByteArray(attributeIds[i], abytes, i * attributeSize); LongToByteArray(attributesIdentification[i], abytes, i * (attributeSize) + OdbType.SizeOfInt); // fsi.writeInt(attributeIds[i], writeDataInTransaction, "attr id"); // fsi.writeLong(attributesIdentification[i], // writeDataInTransaction, "att real pos", // WriteAction.DATA_WRITE_ACTION); // if (classInfo.getAttributeInfo(i).isNonNative() && // attributesIdentification[i] > 0) { if (objectInfo.GetAttributeValueFromId(attributeIds[i]).IsNonNativeObject() && attributesIdentification[i] > 0) { throw new OdbRuntimeException( NDatabaseError.NonNativeAttributeStoredByPositionInsteadOfOid.AddParameter( classInfo.GetAttributeInfo(i).GetName()).AddParameter(classInfo.FullClassName). AddParameter(attributesIdentification[i])); } } _objectWriter.FileSystemProcessor.FileSystemInterface.WriteBytes(abytes, writeDataInTransaction); _objectWriter.FileSystemProcessor.FileSystemInterface.SetWritePosition(positionAfterWrite, writeDataInTransaction); var blockSize = (int)(positionAfterWrite - position); WriteBlockSizeAt(position, blockSize, writeDataInTransaction, objectInfo); // Only insert in index for new objects if (isNewObject) { // insert object id in indexes, if exist _objectWriter.ManageIndexesForInsert(oid, objectInfo); var value = hasObject ? objectInfo.GetObject() : objectInfo; _triggerManager.ManageInsertTriggerAfter(objectInfo.GetClassInfo().UnderlyingType, value, oid); } return oid; }
private bool HasChanged(NonNativeObjectInfo nnoi1, NonNativeObjectInfo nnoi2, int objectRecursionLevel) { AbstractObjectInfo value1 = null; AbstractObjectInfo value2 = null; bool hasChanged = false; // If the object is already being checked, return false, this second // check will not affect the check int n = 0; alreadyCheckingObjects.TryGetValue(nnoi2, out n); if (n != 0) { return(false); } // Put the object in the temporary cache alreadyCheckingObjects[nnoi1] = 1; alreadyCheckingObjects[nnoi2] = 1; // Warning ID Start with 1 and not 0 for (int id = 1; id <= nnoi1.GetMaxNbattributes(); id++) { value1 = nnoi1.GetAttributeValueFromId(id); // Gets the value by the attribute id to be sure // Problem because a new object info may not have the right ids ? // Check if // the new oiD is ok. value2 = nnoi2.GetAttributeValueFromId(id); if (value2 == null) { // this means the object to have attribute id StoreChangedObject(nnoi1, nnoi2, id, objectRecursionLevel); hasChanged = true; continue; } if (value1 == null) { //throw new ODBRuntimeException("ObjectInfoComparator.hasChanged:attribute with id "+id+" does not exist on "+nnoi2); // This happens when this object was created with an version of ClassInfo (which has been refactored). // In this case,we simply tell that in place update is not supported so that the object will be rewritten with // new metamodel supportInPlaceUpdate = false; continue; } // If both are null, no effect if (value1.IsNull() && value2.IsNull()) { continue; } if (value1.IsNull() || value2.IsNull()) { supportInPlaceUpdate = false; hasChanged = true; StoreActionSetAttributetoNull(nnoi1, id, objectRecursionLevel); continue; } if (!ClassAreCompatible(value1, value2)) { if (value2 is NativeObjectInfo) { StoreChangedObject(nnoi1, nnoi2, id, objectRecursionLevel); StoreChangedAttributeAction(new ChangedNativeAttributeAction (nnoi1, nnoi2, nnoi1.GetHeader().GetAttributeIdentificationFromId(id), (NativeObjectInfo )value2, objectRecursionLevel, false, nnoi1.GetClassInfo().GetAttributeInfoFromId (id).GetName())); } if (value2 is ObjectReference) { NonNativeObjectInfo nnoi = (NonNativeObjectInfo )value1; ObjectReference oref = (ObjectReference )value2; if (!nnoi.GetOid().Equals(oref.GetOid())) { StoreChangedObject(nnoi1, nnoi2, id, objectRecursionLevel); int attributeIdThatHasChanged = id; // this is the exact position where the object reference // definition is stored long attributeDefinitionPosition = nnoi2.GetAttributeDefinitionPosition(attributeIdThatHasChanged ); StoreChangedAttributeAction(new ChangedObjectReferenceAttributeAction (attributeDefinitionPosition, (ObjectReference )value2, objectRecursionLevel)); } else { continue; } } hasChanged = true; continue; } if (value1.IsAtomicNativeObject()) { if (!value1.Equals(value2)) { // storeChangedObject(nnoi1, nnoi2, id, // objectRecursionLevel); StoreChangedAttributeAction(new ChangedNativeAttributeAction (nnoi1, nnoi2, nnoi1.GetHeader().GetAttributeIdentificationFromId(id), (NativeObjectInfo )value2, objectRecursionLevel, false, nnoi1.GetClassInfo().GetAttributeInfoFromId (id).GetName())); hasChanged = true; continue; } continue; } if (value1.IsCollectionObject()) { CollectionObjectInfo coi1 = (CollectionObjectInfo)value1; CollectionObjectInfo coi2 = (CollectionObjectInfo)value2; bool collectionHasChanged = ManageCollectionChanges(nnoi1, nnoi2, id, coi1, coi2, objectRecursionLevel); hasChanged = hasChanged || collectionHasChanged; continue; } if (value1.IsArrayObject()) { ArrayObjectInfo aoi1 = (ArrayObjectInfo)value1; ArrayObjectInfo aoi2 = (ArrayObjectInfo)value2; bool arrayHasChanged = ManageArrayChanges(nnoi1, nnoi2, id, aoi1, aoi2, objectRecursionLevel ); hasChanged = hasChanged || arrayHasChanged; continue; } if (value1.IsMapObject()) { MapObjectInfo moi1 = (MapObjectInfo)value1; MapObjectInfo moi2 = (MapObjectInfo)value2; bool mapHasChanged = ManageMapChanges(nnoi1, nnoi2, id, moi1, moi2, objectRecursionLevel ); hasChanged = hasChanged || mapHasChanged; continue; } if (value1.IsEnumObject()) { EnumNativeObjectInfo enoi1 = (EnumNativeObjectInfo)value1; EnumNativeObjectInfo enoi2 = (EnumNativeObjectInfo)value2; bool enumHasChanged = !enoi1.GetEnumClassInfo().GetId().Equals(enoi2.GetEnumClassInfo ().GetId()) || !enoi1.GetEnumName().Equals(enoi2.GetEnumName()); hasChanged = hasChanged || enumHasChanged; continue; } if (value1.IsNonNativeObject()) { NonNativeObjectInfo oi1 = (NonNativeObjectInfo)value1; NonNativeObjectInfo oi2 = (NonNativeObjectInfo)value2; // If oids are equal, they are the same objects if (oi1.GetOid() != null && oi1.GetOid().Equals(oi2.GetOid())) { hasChanged = HasChanged(value1, value2, objectRecursionLevel + 1) || hasChanged; } else { // This means that an object reference has changed. hasChanged = true; // keep track of the position where the reference must be // updated long positionToUpdateReference = nnoi1.GetAttributeDefinitionPosition(id); StoreNewObjectReference(positionToUpdateReference, oi2, objectRecursionLevel, nnoi1 .GetClassInfo().GetAttributeInfoFromId(id).GetName()); objectRecursionLevel++; // Value2 may have change too AddPendingVerification(value2); } continue; } } int i1 = (int)alreadyCheckingObjects[nnoi1]; int i2 = (int)alreadyCheckingObjects[nnoi2]; if (i1 != null) { i1 = i1 - 1; } if (i2 != null) { i2 = i2 - 1; } if (i1 == 0) { alreadyCheckingObjects.Remove(nnoi1); } else { alreadyCheckingObjects.Add(nnoi1, i1); } if (i2 == 0) { alreadyCheckingObjects.Remove(nnoi2); } else { alreadyCheckingObjects.Add(nnoi2, i2); } return(hasChanged); }
private void StoreChangedObject(NonNativeObjectInfo aoi1, NonNativeObjectInfo aoi2, int fieldId , int objectRecursionLevel) { nbChanges++; if (aoi1 != null && aoi2 != null) { changes.Add(new ChangedObjectInfo(aoi1 .GetClassInfo(), aoi2.GetClassInfo(), fieldId, aoi1.GetAttributeValueFromId(fieldId ), aoi2.GetAttributeValueFromId(fieldId), objectRecursionLevel)); // also the max recursion level if (objectRecursionLevel > maxObjectRecursionLevel) { maxObjectRecursionLevel = objectRecursionLevel; } } else { NeoDatis.Tool.DLogger.Info("Non native object with null object"); } }