예제 #1
0
 /// <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;
 }
예제 #2
0
        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;
        }
예제 #3
0
        /// <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);
        }
예제 #4
0
        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;
        }
예제 #5
0
        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;
        }
예제 #6
0
        /// <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.
        ///                        &#064;param object The object to be updated
        ///                        &#064;param forceUpdate when true, no verification is done to check if update must be done.
        ///                        &#064;return The oid of the object, as a negative number
        ///                        &#064;</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);
                }
            }
        }
예제 #7
0
 /// <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);
 }
예제 #8
0
        /// <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;
        }