/// <param name="oid"> The Oid of the object to be inserted </param> /// <param name="nnoi"> The object meta representation The object to be inserted in the database </param> /// <param name="isNewObject"> To indicate if object is new </param> /// <returns> The position of the inserted object </returns> public OID InsertNonNativeObject(OID oid, NonNativeObjectInfo nnoi, bool isNewObject) { var ci = nnoi.GetClassInfo(); var @object = nnoi.GetObject(); // First check if object is already being inserted // This method returns -1 if object is not being inserted var cachedOid = _session.GetCache().IdOfInsertingObject(@object); if (cachedOid != null) return cachedOid; // Then checks if the class of this object already exist in the // meta model ci = _objectWriter.AddClass(ci, true); // Resets the ClassInfo in the objectInfo to be sure it contains all // updated class info data nnoi.SetClassInfo(ci); // Mark this object as being inserted. To manage cyclic relations // The oid may be equal to -1 // Later in the process the cache will be updated with the right oid _session.GetCache().StartInsertingObjectWithOid(@object, oid); // false : do not write data in transaction. Data are always written // directly to disk. Pointers are written in transaction var newOid = WriteNonNativeObjectInfo(oid, nnoi, -1, false, isNewObject); if (!Equals(newOid, StorageEngineConstant.NullObjectId)) _session.GetCache().AddObject(newOid, @object, nnoi.GetHeader()); return newOid; }
public NonNativeObjectInfo EnrichWithOid(NonNativeObjectInfo nnoi, object o) { var cache = _session.GetCache(); var oid = cache.GetOid(o); if (oid != null) { nnoi.SetOid(oid); // Sets some values to the new header to keep track of the infos when // executing NDatabase without closing it, just committing. var objectInfoHeader = cache.GetObjectInfoHeaderByOid(oid, true); nnoi.GetHeader().SetObjectVersion(objectInfoHeader.GetObjectVersion()); nnoi.GetHeader().SetUpdateDate(objectInfoHeader.GetUpdateDate()); nnoi.GetHeader().SetCreationDate(objectInfoHeader.GetCreationDate()); } return nnoi; }
/// <summary> /// Create a copy oh this meta object /// </summary> /// <param name="cache"> </param> /// <param name="onlyData"> if true, only copy attributes values </param> /// <returns> </returns> public override AbstractObjectInfo CreateCopy(IDictionary <OID, AbstractObjectInfo> cache, bool onlyData) { NonNativeObjectInfo nnoi; if (_objectHeader.GetOid() != null && cache.ContainsKey(_objectHeader.GetOid())) { nnoi = (NonNativeObjectInfo)cache[_objectHeader.GetOid()]; if (nnoi != null) { return(nnoi); } } if (_theObject == null) { return(new NonNativeNullObjectInfo(_classInfo)); } if (onlyData) { var oih = new ObjectInfoHeader(); nnoi = new NonNativeObjectInfo(_theObject, _classInfo, null, oih.GetAttributesIdentification(), oih.GetAttributeIds()); } else { nnoi = new NonNativeObjectInfo(_theObject, _classInfo, null, _objectHeader.GetAttributesIdentification(), _objectHeader.GetAttributeIds()); nnoi.GetHeader().SetOid(GetHeader().GetOid()); } var newAttributeValues = new AbstractObjectInfo[_attributeValues.Length]; for (var i = 0; i < _attributeValues.Length; i++) { newAttributeValues[i] = _attributeValues[i].CreateCopy(cache, onlyData); } nnoi._attributeValues = newAttributeValues; if (_objectHeader.GetOid() != null) { cache.Add(_objectHeader.GetOid(), nnoi); } return(nnoi); }
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; }
/// <summary> /// Updates an object. /// </summary> /// <remarks> /// Updates an object. <pre>Try to update in place. Only change what has changed. This is restricted to particular types (fixed size types). If in place update is /// not possible, then deletes the current object and creates a new at the end of the database file and updates /// OID object position. /// @param object The object to be updated /// @param forceUpdate when true, no verification is done to check if update must be done. /// @return The oid of the object, as a negative number /// @</pre> /// </remarks> public OID UpdateNonNativeObjectInfo(NonNativeObjectInfo nnoi, bool forceUpdate) { var hasObject = true; var @object = nnoi.GetObject(); var oid = nnoi.GetOid(); if (@object == null) hasObject = false; // When there is index,we must *always* load the old meta representation // to compute index keys var withIndex = !nnoi.GetClassInfo().GetIndexes().IsEmpty(); NonNativeObjectInfo oldMetaRepresentation = null; // Used to check consistency, at the end, the number of // nbConnectedObjects must and nbUnconnected must remain unchanged //TODO: why we are not using / checking that? (below is continuity) nnoi.GetClassInfo().CommitedZoneInfo.GetNumberbOfObjects(); nnoi.GetClassInfo().UncommittedZoneInfo.GetNumberbOfObjects(); var objectHasChanged = false; try { var lsession = _session; var positionBeforeWrite = _objectWriter.FileSystemProcessor.FileSystemInterface.GetPosition(); var tmpCache = lsession.GetTmpCache(); var cache = lsession.GetCache(); // Get header of the object (position, previous object position, // next // object position and class info position) // The header must be in the cache. var lastHeader = cache.GetObjectInfoHeaderByOid(oid, true); if (lastHeader == null) throw new OdbRuntimeException( NDatabaseError.UnexpectedSituation.AddParameter("Header is null in update")); if (lastHeader.GetOid() == null) throw new OdbRuntimeException( NDatabaseError.InternalError.AddParameter("Header oid is null for oid " + oid)); var objectIsInConnectedZone = cache.IsInCommitedZone(oid); var currentPosition = lastHeader.GetPosition(); if (currentPosition == -1) { throw new OdbRuntimeException( NDatabaseError.InstancePositionIsNegative.AddParameter(currentPosition).AddParameter(oid). AddParameter("In Object Info Header")); } // triggers,FIXME passing null to old object representation _storageEngine.GetTriggerManager().ManageUpdateTriggerBefore(nnoi.GetClassInfo().UnderlyingType, null, hasObject ? @object : nnoi, oid); // Use to control if the in place update is ok. The // ObjectInstrospector stores the number of changes // that were detected and here we try to apply them using in place // update.If at the end // of the in place update the number of applied changes is smaller // then the number // of detected changes, then in place update was not successfully, // we // must do a real update, // creating an object elsewhere :-( if (!forceUpdate) { var cachedOid = cache.IdOfInsertingObject(@object); if (cachedOid != null) { // The object is being inserted (must be a cyclic // reference), simply returns id id return cachedOid; } // the nnoi (NonNativeObjectInfo is the meta representation of // the object to update // To know what must be upated we must get the meta // representation of this object before // The modification. Taking this 'old' meta representation from // the // cache does not resolve // : because cache is a reference to the real object and object // has been changed, // so the cache is pointing to the reference, that has changed! // This old meta representation must be re-read from the last // committed database // false, = returnInstance (java object) = false try { var useCache = !objectIsInConnectedZone; oldMetaRepresentation = _objectReader.ReadNonNativeObjectInfoFromPosition(null, oid, currentPosition, useCache, false); tmpCache.ClearObjectInfos(); } catch (OdbRuntimeException e) { var position = currentPosition.ToString(); throw new OdbRuntimeException( NDatabaseError.InternalError.AddParameter("Error while reading old Object Info of oid " + oid + " at pos " + position), e); } // Make sure we work with the last version of the object var onDiskVersion = oldMetaRepresentation.GetHeader().GetObjectVersion(); var onDiskUpdateDate = oldMetaRepresentation.GetHeader().GetUpdateDate(); var inCacheVersion = lastHeader.GetObjectVersion(); var inCacheUpdateDate = lastHeader.GetUpdateDate(); if (onDiskUpdateDate > inCacheUpdateDate || onDiskVersion > inCacheVersion) lastHeader = oldMetaRepresentation.GetHeader(); nnoi.SetHeader(lastHeader); // increase the object version number from the old meta // representation nnoi.GetHeader().IncrementVersionAndUpdateDate(); // Keep the creation date nnoi.GetHeader().SetCreationDate(oldMetaRepresentation.GetHeader().GetCreationDate()); // Set the object of the old meta to make the object comparator // understand, they are 2 // meta representation of the same object // TODO , check if if is the best way to do oldMetaRepresentation.SetObject(nnoi.GetObject()); // Reset the comparator _comparator.Clear(); objectHasChanged = _comparator.HasChanged(oldMetaRepresentation, nnoi); if (!objectHasChanged) { _objectWriter.FileSystemProcessor.FileSystemInterface.SetWritePosition(positionBeforeWrite, true); return oid; } } // If we reach this update, In Place Update was not possible. Do a // normal update. Deletes the // current object and creates a new one if (oldMetaRepresentation == null && withIndex) { // We must load old meta representation to be able to compute // old index key to update index oldMetaRepresentation = _objectReader.ReadNonNativeObjectInfoFromPosition(null, oid, currentPosition, false, false); } var previousObjectOID = lastHeader.GetPreviousObjectOID(); var nextObjectOid = lastHeader.GetNextObjectOID(); nnoi.SetPreviousInstanceOID(previousObjectOID); nnoi.SetNextObjectOID(nextObjectOid); // Mark the block of current object as deleted _objectWriter.MarkAsDeleted(currentPosition, objectIsInConnectedZone); // Creates the new object oid = InsertNonNativeObject(oid, nnoi, false); // This position after write must be call just after the insert!! var positionAfterWrite = _objectWriter.FileSystemProcessor.FileSystemInterface.GetPosition(); if (hasObject) { // update cache cache.AddObject(oid, @object, nnoi.GetHeader()); } _objectWriter.FileSystemProcessor.FileSystemInterface.SetWritePosition(positionAfterWrite, true); //TODO: why we are not using / checking that? (below is continuity) nnoi.GetClassInfo().CommitedZoneInfo.GetNumberbOfObjects(); nnoi.GetClassInfo().UncommittedZoneInfo.GetNumberbOfObjects(); return oid; } catch (Exception e) { var message = string.Format("Error updating object {0} : {1}", nnoi, e); throw new OdbRuntimeException(e, message); } finally { if (objectHasChanged) { if (withIndex) ManageIndexesForUpdate(oid, nnoi, oldMetaRepresentation); // triggers,FIXME passing null to old object representation // (oldMetaRepresentation may be null) _storageEngine.GetTriggerManager().ManageUpdateTriggerAfter( nnoi.GetClassInfo().UnderlyingType, oldMetaRepresentation, hasObject ? @object : nnoi, oid); } } }
/// <summary> /// Updates pointers of objects, Only changes uncommitted info pointers /// </summary> /// <param name="objectInfo"> The meta representation of the object being inserted </param> /// <param name="classInfo"> The class of the object being inserted </param> public void ManageNewObjectPointers(NonNativeObjectInfo objectInfo, ClassInfo classInfo) { var cache = _storageEngine.GetSession().GetCache(); var isFirstUncommitedObject = !classInfo.UncommittedZoneInfo.HasObjects(); // if it is the first uncommitted object if (isFirstUncommitedObject) { classInfo.UncommittedZoneInfo.First = objectInfo.GetOid(); var lastCommittedObjectOid = classInfo.CommitedZoneInfo.Last; if (lastCommittedObjectOid != null) { // Also updates the last committed object next object oid in // memory to connect the committed // zone with unconnected for THIS transaction (only in memory) var oih = cache.GetObjectInfoHeaderByOid(lastCommittedObjectOid, true); oih.SetNextObjectOID(objectInfo.GetOid()); // And sets the previous oid of the current object with the last // committed oid objectInfo.SetPreviousInstanceOID(lastCommittedObjectOid); } } else { // Gets the last object, updates its (next object) // pointer to the new object and updates the class info 'last // uncommitted object // oid' field var oip = classInfo.LastObjectInfoHeader; if (oip == null) { throw new OdbRuntimeException( NDatabaseError.InternalError.AddParameter("last OIP is null in manageNewObjectPointers oid=" + objectInfo.GetOid())); } if (oip.GetNextObjectOID() != objectInfo.GetOid()) { oip.SetNextObjectOID(objectInfo.GetOid()); // Here we are working in unconnected zone, so this // can be done without transaction: actually // write in database file UpdateNextObjectFieldOfObjectInfo(oip.GetOid(), oip.GetNextObjectOID(), false); objectInfo.SetPreviousInstanceOID(oip.GetOid()); // Resets the class info oid: In some case, // (client // server) it may be -1. oip.SetClassInfoId(classInfo.ClassInfoId); // object info oip has been changed, we must put it // in the cache to turn this change available for current // transaction until the commit _storageEngine.GetSession().GetCache().AddObjectInfoOfNonCommitedObject(oip); } } // always set the new last object oid and the number of objects classInfo.UncommittedZoneInfo.Last = objectInfo.GetOid(); classInfo.UncommittedZoneInfo.IncreaseNbObjects(); // Then updates the last info pointers of the class info // with this new created object // At this moment, the objectInfo.getHeader() do not have the // attribute ids. // but later in this code, the attributes will be set, so the class // info also will have them classInfo.LastObjectInfoHeader = objectInfo.GetHeader(); // // Saves the fact that something has changed in the class (number of // objects and/or last object oid) _storageEngine.GetSession().GetMetaModel().AddChangedClass(classInfo); }
/// <summary> /// Create a copy oh this meta object /// </summary> /// <param name="cache"> </param> /// <param name="onlyData"> if true, only copy attributes values </param> /// <returns> </returns> public override AbstractObjectInfo CreateCopy(IDictionary<OID, AbstractObjectInfo> cache, bool onlyData) { NonNativeObjectInfo nnoi; if (_objectHeader.GetOid() != null && cache.ContainsKey(_objectHeader.GetOid())) { nnoi = (NonNativeObjectInfo) cache[_objectHeader.GetOid()]; if (nnoi != null) return nnoi; } if (_theObject == null) return new NonNativeNullObjectInfo(_classInfo); if (onlyData) { var oih = new ObjectInfoHeader(); nnoi = new NonNativeObjectInfo(_theObject, _classInfo, null, oih.GetAttributesIdentification(), oih.GetAttributeIds()); } else { nnoi = new NonNativeObjectInfo(_theObject, _classInfo, null, _objectHeader.GetAttributesIdentification(), _objectHeader.GetAttributeIds()); nnoi.GetHeader().SetOid(GetHeader().GetOid()); } var newAttributeValues = new AbstractObjectInfo[_attributeValues.Length]; for (var i = 0; i < _attributeValues.Length; i++) newAttributeValues[i] = _attributeValues[i].CreateCopy(cache, onlyData); nnoi._attributeValues = newAttributeValues; if (_objectHeader.GetOid() != null) cache.Add(_objectHeader.GetOid(), nnoi); return nnoi; }