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); }
public void StartReadingObjectInfoWithOid(OID oid, NonNativeObjectInfo objectInfo) { if (oid == null) throw new OdbRuntimeException(NDatabaseError.CacheNullOid); NonNativeObjectInfo nnoi; var success = _readingObjectInfo.TryGetValue(oid, out nnoi); if (!success) _readingObjectInfo[oid] = objectInfo; }
/// <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 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; }
public ObjectRepresentation(NonNativeObjectInfo nnoi, IObjectIntrospectionDataProvider classInfoProvider) { _nnoi = nnoi; _classInfoProvider = classInfoProvider; }
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; }
public object BuildOneInstance(NonNativeObjectInfo objectInfo) { return BuildOneInstance(objectInfo, _engine.GetSession().GetCache()); }
public ObjectReference(NonNativeObjectInfo nnoi) : base(OdbType.NonNativeId) { _id = null; _nnoi = nnoi; }
/// <summary> /// Store a meta representation of an object(already as meta representation)in ODBFactory database. /// </summary> /// <remarks> /// Store a meta representation of an object(already as meta representation)in ODBFactory database. To detect if object must be updated or insert, we use the cache. To update an object, it must be first selected from the database. When an object is to be stored, if it exist in the cache, then it will be updated, else it will be inserted as a new object. If the object is null, the cache will be used to check if the meta representation is in the cache /// </remarks> /// <param name="oid"> The oid of the object to be inserted/updates </param> /// <param name="nnoi"> The meta representation of an object </param> /// <returns> The object position </returns> public OID StoreObject(OID oid, NonNativeObjectInfo nnoi) { // first detects if we must perform an insert or an update // If object is in the cache, we must perform an update, else an insert var @object = nnoi.GetObject(); var mustUpdate = false; var cache = _session.GetCache(); if (@object != null) { var cacheOid = cache.IdOfInsertingObject(@object); if (cacheOid != null) return cacheOid; // throw new ODBRuntimeException("Inserting meta representation of // an object without the object itself is not yet supported"); mustUpdate = cache.Contains(@object); } if (!mustUpdate) mustUpdate = !Equals(nnoi.GetOid(), StorageEngineConstant.NullObjectId); return mustUpdate ? UpdateNonNativeObjectInfo(nnoi, false) : InsertNonNativeObject(oid, nnoi, true); }
/// <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> /// 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) { return _nonNativeObjectWriter.UpdateNonNativeObjectInfo(nnoi, forceUpdate); }
/// <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) { return _nonNativeObjectWriter.InsertNonNativeObject(oid, nnoi, isNewObject); }
/// <summary> /// Insert the object in the index /// </summary> /// <param name="oid"> The object id </param> /// <param name="nnoi"> The object meta represenation </param> /// <returns> The number of indexes </returns> private static void ManageIndexesForDelete(OID oid, NonNativeObjectInfo nnoi) { var indexes = nnoi.GetClassInfo().GetIndexes(); foreach (var index in indexes) { // TODO manage collision! var odbComparable = IndexTool.BuildIndexKey(index.Name, nnoi, index.AttributeIds); index.BTree.Delete(odbComparable, oid); // Check consistency : index should have size equal to the class // info element number if (index.BTree.GetSize() != nnoi.GetClassInfo().NumberOfObjects) { throw new OdbRuntimeException( NDatabaseError.BtreeSizeDiffersFromClassElementNumber.AddParameter(index.BTree.GetSize()). AddParameter(nnoi.GetClassInfo().NumberOfObjects)); } } }
/// <summary> /// Insert the object in the index /// </summary> /// <param name="oid"> The object id </param> /// <param name="nnoi"> The object meta represenation </param> /// <returns> The number of indexes </returns> public void ManageIndexesForInsert(OID oid, NonNativeObjectInfo nnoi) { var indexes = nnoi.GetClassInfo().GetIndexes(); foreach (var index in indexes) { try { var odbComparable = IndexTool.BuildIndexKey(index.Name, nnoi, index.AttributeIds); index.BTree.Insert(odbComparable, oid); } catch (DuplicatedKeyException) { // rollback what has been done // bug #2510966 _session.Rollback(); throw; } // Check consistency : index should have size equal to the class // info element number if (index.BTree.GetSize() != nnoi.GetClassInfo().NumberOfObjects) { throw new OdbRuntimeException( NDatabaseError.BtreeSizeDiffersFromClassElementNumber.AddParameter(index.BTree.GetSize()). AddParameter(nnoi.GetClassInfo().NumberOfObjects)); } } }