/// <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 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); } } }