public IBTree LoadBTree(object id) { var oid = (OID)id; try { if (OdbConfiguration.IsLoggingEnabled()) { DLogger.Debug(string.Format("LazyOdbBtreePersister: Loading btree with id {0}", oid)); } if (oid == StorageEngineConstant.NullObjectId) { throw new OdbRuntimeException( BTreeError.InvalidIdForBtree.AddParameter(StorageEngineConstant.NullObjectId)); } _tree = (IBTree)_engine.GetObjectFromOid(oid); _tree.SetId(oid); _tree.SetPersister(this); var root = _tree.GetRoot(); root.SetBTree(_tree); return(_tree); } catch (Exception e) { throw new OdbRuntimeException(BTreeError.InternalError, e); } }
public long ReadOidPosition(OID oid) { if (OdbConfiguration.IsLoggingEnabled()) { DLogger.Debug("ObjectReader: Start of readOidPosition for oid " + oid); } var blockNumber = StorageEngineConstant.GetIdBlockNumberOfOid(oid); var blockPosition = GetIdBlockPositionFromNumber(blockNumber); if (OdbConfiguration.IsLoggingEnabled()) { var blockNumberAsString = blockNumber.ToString(); var blockPositionAsString = blockPosition.ToString(); DLogger.Debug(string.Format("ObjectReader: Block number of oid {0} is ", oid) + blockNumberAsString + " / block position = " + blockPositionAsString); } var position = blockPosition + StorageEngineConstant.BlockIdOffsetForStartOfRepetition + ((oid.ObjectId - 1) % StorageEngineConstant.NbIdsPerBlock) * StorageEngineConstant.IdBlockRepetitionSize; if (OdbConfiguration.IsLoggingEnabled()) { var positionAsString = position.ToString(); DLogger.Debug(string.Format("ObjectReader: End of readOidPosition for oid {0} returning position ", oid) + positionAsString); } return(position); }
/// <summary> /// Gets the real object position from its OID /// </summary> /// <param name="oid"> The oid of the object to get the position </param> /// <param name="useCache"> </param> /// <param name="throwException"> To indicate if an exception must be thrown if object is not found </param> /// <returns> The object position, if object has been marked as deleted then return StorageEngineConstant.DELETED_OBJECT_POSITION @ </returns> public long GetObjectPositionFromItsOid(OID oid, bool useCache, bool throwException) { if (OdbConfiguration.IsLoggingEnabled()) { DLogger.Debug("ObjectReader: getObjectPositionFromItsId for oid " + oid); } // Check if oid is in cache var position = StorageEngineConstant.ObjectIsNotInCache; if (useCache) { // This return -1 if not in the cache position = _storageEngine.GetSession().GetCache().GetObjectPositionByOid(oid); } // FIXME Check if we need this. Removing it causes the TestDelete.test6 to fail if (position == StorageEngineConstant.DeletedObjectPosition) { if (throwException) { throw new CorruptedDatabaseException(NDatabaseError.ObjectIsMarkedAsDeletedForOid.AddParameter(oid)); } return(StorageEngineConstant.DeletedObjectPosition); } if (position != StorageEngineConstant.ObjectIsNotInCache && position != StorageEngineConstant.DeletedObjectPosition) { return(position); } // The position was not found is the cache position = ReadOidPosition(oid); position += StorageEngineConstant.BlockIdRepetitionIdStatus; _fsi.SetReadPosition(position); var idStatus = _fsi.ReadByte(); var objectPosition = _fsi.ReadLong(); if (!IDStatus.IsActive(idStatus)) { // if object position == 0, The object dos not exist if (throwException) { if (objectPosition == 0) { throw new CorruptedDatabaseException(NDatabaseError.ObjectWithOidDoesNotExist.AddParameter(oid)); } throw new CorruptedDatabaseException(NDatabaseError.ObjectIsMarkedAsDeletedForOid.AddParameter(oid)); } return(objectPosition == 0 ? StorageEngineConstant.ObjectDoesNotExist : StorageEngineConstant.DeletedObjectPosition); } if (OdbConfiguration.IsLoggingEnabled()) { var positionAsString = objectPosition.ToString(); DLogger.Debug("ObjectReader: object position of object with oid " + oid + " is " + positionAsString); } return(objectPosition); }
/// <summary> /// Read the class info header with the specific oid /// </summary> /// <returns> The read class info object @ </returns> public ClassInfo ReadClassInfoHeader(OID classInfoOid) { if (OdbConfiguration.IsLoggingEnabled()) { DLogger.Debug("FileSystemReader: Reading new Class info Header with oid " + classInfoOid); } var classInfoPosition = GetObjectPositionFromItsOid(classInfoOid, true, true); _fsi.SetReadPosition(classInfoPosition); var blockSize = _fsi.ReadInt(); var blockType = _fsi.ReadByte(); if (!BlockTypes.IsClassHeader(blockType)) { throw new OdbRuntimeException( NDatabaseError.WrongTypeForBlockType.AddParameter("Class Header").AddParameter(blockType). AddParameter(classInfoPosition)); } //class info category, to remove _fsi.ReadByte(); var classInfoId = OIDFactory.BuildClassOID(_fsi.ReadLong()); var previousClassOID = ReadOid(); var nextClassOID = ReadOid(); var nbObjects = _fsi.ReadLong(); var originalZoneInfoFirst = ReadOid(); var originalZoneInfoLast = ReadOid(); var fullClassName = _fsi.ReadString(); var maxAttributeId = _fsi.ReadInt(); var attributesDefinitionPosition = _fsi.ReadLong(); var classInfo = new ClassInfo(fullClassName) { Position = classInfoPosition, ClassInfoId = classInfoId, PreviousClassOID = previousClassOID, NextClassOID = nextClassOID, MaxAttributeId = maxAttributeId, AttributesDefinitionPosition = attributesDefinitionPosition }; classInfo.OriginalZoneInfo.SetNbObjects(nbObjects); classInfo.OriginalZoneInfo.First = originalZoneInfoFirst; classInfo.OriginalZoneInfo.Last = originalZoneInfoLast; classInfo.CommitedZoneInfo.SetBasedOn(classInfo.OriginalZoneInfo); // FIXME Convert block size to long ?? var realBlockSize = (int)(_fsi.GetPosition() - classInfoPosition); if (blockSize != realBlockSize) { throw new OdbRuntimeException( NDatabaseError.WrongBlockSize.AddParameter(blockSize).AddParameter(realBlockSize).AddParameter( classInfoPosition)); } return(classInfo); }
private void Persist() { _nbPersist++; if (OdbConfiguration.IsLoggingEnabled()) { var count = _modifiedObjectOids.Count.ToString(); DLogger.Debug(string.Concat("LazyOdbBtreePersister: ", "persist ", _nbPersist.ToString(), " : Saving " + count + " objects - ", GetHashCode().ToString())); } var nbCommited = 0; var i = 0; var size = _modifiedObjectOids.Count; IEnumerator iterator = _modifiedObjectOidList.GetEnumerator(); while (iterator.MoveNext()) { var oid = (OID)iterator.Current; if (oid == null) { continue; } nbCommited++; long t0; long t1; try { t0 = OdbTime.GetCurrentTimeInMs(); var @object = _oids[oid]; _engine.Store(@object); t1 = OdbTime.GetCurrentTimeInMs(); } catch (Exception e) { throw new OdbRuntimeException( BTreeError.InternalError.AddParameter("Error while storing object with oid " + oid), e); } if (OdbConfiguration.IsLoggingEnabled()) { DLogger.Debug(string.Concat("LazyOdbBtreePersister: ", "Committing oid " + oid, " | ", i.ToString(), "/", size.ToString(), " | ", (t1 - t0).ToString(), " ms")); } i++; } if (OdbConfiguration.IsLoggingEnabled()) { DLogger.Debug(string.Concat("LazyOdbBtreePersister: ", nbCommited.ToString(), " commits / ", size.ToString())); } }
/// <summary> /// Adds a write action to the transaction /// </summary> /// <param name="writeAction"> The write action to be added </param> /// <param name="persistWriteAction"> To indicate if write action must be persisted </param> private void AddWriteAction(WriteAction writeAction, bool persistWriteAction) { if (OdbConfiguration.IsLoggingEnabled()) { DLogger.Info(string.Format("OdbTransaction: Adding WriteAction in Transaction of session {0}", _session.GetId())); } if (writeAction.IsEmpty()) { return; } CheckRollback(); if (!_hasBeenPersisted && persistWriteAction) { Persist(); } if (persistWriteAction) { writeAction.PersistMeTo(_fsi); } // Only adds the write action to the list if the transaction keeps all in // memory if (_hasAllWriteActionsInMemory) { _writeActions.Add(writeAction); } _numberOfWriteActions++; if (_hasAllWriteActionsInMemory && _numberOfWriteActions > StorageEngineConstant.MaxNumberOfWriteObjectPerTransaction) { _hasAllWriteActionsInMemory = false; foreach (var defaultWriteAction in _writeActions) { defaultWriteAction.Clear(); } _writeActions.Clear(); if (OdbConfiguration.IsLoggingEnabled()) { var numberOfWriteActions = _numberOfWriteActions.ToString(); var maxNumberOfWriteObjectPerTransactionAsString = StorageEngineConstant.MaxNumberOfWriteObjectPerTransaction.ToString(); DLogger.Info("OdbTransaction: Number of objects has exceeded the max number " + numberOfWriteActions + "/" + maxNumberOfWriteObjectPerTransactionAsString + ": switching to persistent transaction managment"); } } }
public void Check_turning_on_the_logging() { Assert.That(OdbConfiguration.IsLoggingEnabled(), Is.False); OdbConfiguration.EnableLogging(); Assert.That(OdbConfiguration.IsLoggingEnabled(), Is.True); OdbConfiguration.DisableLogging(); Assert.That(OdbConfiguration.IsLoggingEnabled(), Is.False); }
/// <summary> /// Used to rebuild an index /// </summary> public void RebuildIndex(string className, string indexName) { if (OdbConfiguration.IsLoggingEnabled()) { DLogger.Info(string.Format("StorageEngine: Rebuilding index {0} on class {1}", indexName, className)); } var classInfo = GetMetaModel().GetClassInfo(className, true); var classInfoIndex = GetClassInfoIndex(className, indexName, classInfo); DeleteIndex(className, indexName); AddIndexOn(className, indexName, classInfo.GetAttributeNames(classInfoIndex.AttributeIds), !classInfoIndex.IsUnique); }
private void UpdateMetaModel() { if (OdbConfiguration.IsLoggingEnabled()) { DLogger.Info("StorageEngine: Automatic refactoring : updating meta model"); } var metaModel = GetMetaModel(); var storedClasses = metaModel.GetAllClasses().ToList(); foreach (var userClass in storedClasses) { _objectWriter.UpdateClassInfo(userClass, true); } }
private void Persist() { CheckFileAccess(null); if (OdbConfiguration.IsLoggingEnabled()) { DLogger.Debug(string.Format("OdbTransaction: # Persisting transaction {0}", GetName())); } _fsi.SetWritePosition(0, false); _fsi.WriteBoolean(_isCommited, false); _fsi.WriteLong(_creationDateTime, false); // Size _fsi.WriteLong(0, false); _hasBeenPersisted = true; }
public void DeleteIndex(string className, string indexName) { var classInfo = GetMetaModel().GetClassInfo(className, true); var classInfoIndex = GetClassInfoIndex(className, indexName, classInfo); if (OdbConfiguration.IsLoggingEnabled()) { DLogger.Info(string.Format("StorageEngine: Deleting index {0} on class {1}", indexName, className)); } Delete(classInfoIndex); classInfo.RemoveIndex(classInfoIndex); if (OdbConfiguration.IsLoggingEnabled()) { DLogger.Info(string.Format("StorageEngine: Index {0} deleted", indexName)); } }
public override void DefragmentTo(string newFileName) { var start = OdbTime.GetCurrentTimeInMs(); var totalNbObjects = 0L; var newStorageEngine = new StorageEngine(new FileIdentification(newFileName)); var j = 0; var criteriaQuery = new SodaQuery(typeof(object)); var defragObjects = GetObjects <object>(criteriaQuery, true, -1, -1); foreach (var defragObject in defragObjects) { newStorageEngine.Store(defragObject); totalNbObjects++; if (OdbConfiguration.IsLoggingEnabled()) { if (j % 10000 == 0) { DLogger.Info(string.Concat("\nStorageEngine: ", totalNbObjects.ToString(), " objects saved.")); } } j++; } newStorageEngine.Close(); var time = OdbTime.GetCurrentTimeInMs() - start; if (!OdbConfiguration.IsLoggingEnabled()) { return; } var nbObjectsAsString = totalNbObjects.ToString(); var timeAsString = time.ToString(); DLogger.Info(string.Format("StorageEngine: New storage {0} created with {1} objects in {2} ms.", newFileName, nbObjectsAsString, timeAsString)); }
/// <summary> /// saves the bree node Only puts the current node in an 'modified Node' map to be saved on commit /// </summary> public void SaveNode(IBTreeNode node) { OID oid; // Here we only save the node if it does not have id, // else we just save into the hashmap if (node.GetId() == StorageEngineConstant.NullObjectId) { try { // first get the oid. : -2:it could be any value oid = _engine.GetObjectWriter().GetIdManager().GetNextObjectId(-2); node.SetId(oid); oid = _engine.Store(oid, node); if (OdbConfiguration.IsLoggingEnabled()) { DLogger.Debug(string.Format("LazyOdbBtreePersister: Saved node id {0}", oid)); } // + " : " + // node.toString()); if (_tree != null && node.GetBTree() == null) { node.SetBTree(_tree); } _oids.Add(oid, node); return; } catch (Exception e) { throw new OdbRuntimeException(BTreeError.InternalError.AddParameter("While saving node"), e); } } oid = (OID)node.GetId(); _oids.Add(oid, node); AddModifiedOid(oid); }
/// <summary> /// Loads a node from its id. /// </summary> /// <remarks> /// Loads a node from its id. Tries to get if from memory, if not present then loads it from odb storage /// </remarks> /// <param name="id"> The id of the nod </param> /// <returns> The node with the specific id </returns> public IBTreeNode LoadNodeById(object id) { var oid = (OID)id; // Check if node is in memory var node = (IBTreeNode)_oids[oid]; if (node != null) { return(node); } // else load from odb try { if (OdbConfiguration.IsLoggingEnabled()) { DLogger.Debug(string.Format("LazyOdbBtreePersister: Loading node with id {0}", oid)); } if (oid == null) { throw new OdbRuntimeException(BTreeError.InvalidIdForBtree.AddParameter("oid")); } var pn = (IBTreeNode)_engine.GetObjectFromOid(oid); pn.SetId(oid); if (_tree != null) { pn.SetBTree(_tree); } // Keep the node in memory _oids.Add(oid, pn); return(pn); } catch (Exception e) { throw new OdbRuntimeException(BTreeError.InternalError, e); } }
internal static WriteAction Read(IFileSystemInterface fsi) { try { var position = fsi.ReadLong(); var size = fsi.ReadInt(); var bytes = fsi.ReadBytes(size); var writeAction = new WriteAction(position, bytes); if (OdbConfiguration.IsLoggingEnabled()) { DLogger.Debug(string.Format("Transaction WriteAction: Loading Write Action at {0} => {1}", fsi.GetPosition(), writeAction)); } return(writeAction); } catch (OdbRuntimeException) { DLogger.Error(string.Format("Transaction WriteAction: error reading write action at position {0}", fsi.GetPosition())); throw; } }
private void LoadWriteActions(string filename, bool apply) { if (OdbConfiguration.IsLoggingEnabled()) { DLogger.Debug(string.Format("OdbTransaction: Load write actions of {0}", filename)); } CheckFileAccess(filename); _fsi.SetReadPosition(0); _isCommited = _fsi.ReadByte() == 1; _creationDateTime = _fsi.ReadLong(); var totalNumberOfWriteActions = _fsi.ReadLong(); if (OdbConfiguration.IsLoggingEnabled()) { DLogger.Info(string.Concat("OdbTransaction: ", _writeActions.Count.ToString(), " write actions in file")); } for (var i = 0; i < totalNumberOfWriteActions; i++) { var defaultWriteAction = WriteAction.Read(_fsi); if (apply) { defaultWriteAction.ApplyTo(_fsiToApplyWriteActions); defaultWriteAction.Clear(); } else { AddWriteAction(defaultWriteAction, false); } } if (apply) { _fsiToApplyWriteActions.Flush(); } }
public void SaveBTree(IBTree treeToSave) { try { var oid = (OID)treeToSave.GetId(); if (oid == null) { // first get the oid. -2 : it could be any value oid = _engine.GetObjectWriter().GetIdManager().GetNextObjectId(-2); treeToSave.SetId(oid); oid = _engine.Store(oid, treeToSave); if (OdbConfiguration.IsLoggingEnabled()) { DLogger.Debug(string.Format("LazyOdbBtreePersister: Saved btree {0} with id {1} and root {2}", treeToSave.GetId(), oid, treeToSave.GetRoot())); } if (_tree == null) { _tree = treeToSave; } _oids.Add(oid, treeToSave); } else { _oids.Add(oid, treeToSave); AddModifiedOid(oid); } } catch (Exception e) { throw new OdbRuntimeException(BTreeError.InternalError, e); } }
/// <summary> /// Execute query using index /// </summary> /// <param name="inMemory"> </param> /// <param name="returnObjects"> </param> /// <param name="queryResultAction"> </param> private IInternalObjectSet <T> ExecuteForOneOid <T>(bool inMemory, bool returnObjects, IMatchingObjectAction queryResultAction) { if (OdbConfiguration.IsLoggingEnabled()) { DLogger.Debug(string.Format("GenericQueryExecutor: loading Object with oid {0} - class {1}", Query.GetOidOfObjectToQuery(), ClassInfo.FullClassName)); } if (ExecuteStartAndEndOfQueryAction()) { queryResultAction.Start(); } PrepareQuery(); var oid = Query.GetOidOfObjectToQuery(); MatchObjectWithOid(oid, returnObjects, inMemory); queryResultAction.ObjectMatch(oid, GetCurrentObjectMetaRepresentation(), _orderByKey); queryResultAction.End(); return(queryResultAction.GetObjects <T>()); }
public void AddIndexOn(string className, string indexName, string[] indexFields, bool acceptMultipleValuesForSameKey) { var classInfo = GetMetaModel().GetClassInfo(className, true); if (classInfo.HasIndex(indexName)) { throw new OdbRuntimeException( NDatabaseError.IndexAlreadyExist.AddParameter(indexName).AddParameter(className)); } var classInfoIndex = classInfo.AddIndexOn(indexName, indexFields, acceptMultipleValuesForSameKey); IBTree btree; var lazyOdbBtreePersister = new LazyOdbBtreePersister(this); if (acceptMultipleValuesForSameKey) { btree = new OdbBtreeMultiple(OdbConfiguration.GetIndexBTreeDegree(), lazyOdbBtreePersister); } else { btree = new OdbBtreeSingle(OdbConfiguration.GetIndexBTreeDegree(), lazyOdbBtreePersister); } classInfoIndex.BTree = btree; Store(classInfoIndex); // Now The index must be updated with all existing objects. if (classInfo.NumberOfObjects == 0) { // There are no objects. Nothing to do return; } if (OdbConfiguration.IsLoggingEnabled()) { var numberOfObjectsAsString = classInfo.NumberOfObjects.ToString(); DLogger.Info( string.Format( "StorageEngine: Creating index {0} on class {1} - Class has already {2} Objects. Updating index", indexName, className, numberOfObjectsAsString)); DLogger.Info(string.Format("StorageEngine: {0} : loading {1} objects from database", indexName, numberOfObjectsAsString)); } // We must load all objects and insert them in the index! var criteriaQuery = new SodaQuery(classInfo.UnderlyingType); var objects = GetObjectInfos(criteriaQuery); if (OdbConfiguration.IsLoggingEnabled()) { var numberOfObjectsAsString = classInfo.NumberOfObjects.ToString(); DLogger.Info(string.Format("StorageEngine: {0} : {1} objects loaded", indexName, numberOfObjectsAsString)); } while (objects.HasNext()) { var nnoi = (NonNativeObjectInfo)objects.Next(); var odbComparable = IndexTool.BuildIndexKey(classInfoIndex.Name, nnoi, classInfoIndex.AttributeIds); btree.Insert(odbComparable, nnoi.GetOid()); } if (OdbConfiguration.IsLoggingEnabled()) { DLogger.Info(string.Format("StorageEngine: {0} created!", indexName)); } }
/// <summary> /// Query execution full scan <pre>startIndex & endIndex /// A B C D E F G H I J K L /// [1,3] : nb >=1 && nb<3 /// 1) /// analyze A /// nb = 0 /// nb E [1,3] ? no /// r=[] /// 2) /// analyze B /// nb = 1 /// nb E [1,3] ? yes /// r=[B] /// 3) analyze C /// nb = 2 /// nb E [1,3] ? yes /// r=[B,C] /// 4) analyze C /// nb = 3 /// nb E [1,3] ? no and 3> upperBound([1,3]) => exit</pre> /// </summary> /// <param name="inMemory"> </param> /// <param name="startIndex"> </param> /// <param name="endIndex"> </param> /// <param name="returnObjects"> </param> /// <param name="queryResultAction"> </param> private IInternalObjectSet <T> ExecuteFullScan <T>(bool inMemory, int startIndex, int endIndex, bool returnObjects, IMatchingObjectAction queryResultAction) { if (StorageEngine.IsClosed()) { throw new OdbRuntimeException( NDatabaseError.OdbIsClosed.AddParameter(StorageEngine.GetBaseIdentification().Id)); } var nbObjects = ClassInfo.NumberOfObjects; if (OdbConfiguration.IsLoggingEnabled()) { DLogger.Debug(string.Format("GenericQueryExecutor: loading {0} instance(s) of {1}", nbObjects, ClassInfo.FullClassName)); } if (ExecuteStartAndEndOfQueryAction()) { queryResultAction.Start(); } OID currentOID = null; // TODO check if all instances are in the cache! and then load from the cache NextOID = ClassInfo.CommitedZoneInfo.First; if (nbObjects > 0 && NextOID == null) { // This means that some changes have not been commited! // Take next position from uncommited zone NextOID = ClassInfo.UncommittedZoneInfo.First; } PrepareQuery(); if (Query != null) { _queryHasOrderBy = Query.HasOrderBy(); } // used when startIndex and endIndex are not negative var nbObjectsInResult = 0; for (var i = 0; i < nbObjects; i++) { // Reset the order by key _orderByKey = null; var prevOID = currentOID; currentOID = NextOID; // This is an error if (currentOID == null) { throw new OdbRuntimeException( NDatabaseError.NullNextObjectOid.AddParameter(ClassInfo.FullClassName).AddParameter(i). AddParameter(nbObjects).AddParameter(prevOID)); } // If there is an endIndex condition if (endIndex != -1 && nbObjectsInResult >= endIndex) { break; } // If there is a startIndex condition bool objectInRange; if (startIndex != -1 && nbObjectsInResult < startIndex) { objectInRange = false; } else { objectInRange = true; } // There is no query if (!inMemory && Query == null) { nbObjectsInResult++; // keep object position if we must if (objectInRange) { _orderByKey = BuildOrderByKey(CurrentNnoi); // TODO Where is the key for order by queryResultAction.ObjectMatch(NextOID, _orderByKey); } NextOID = ObjectReader.GetNextObjectOID(currentOID); } else { var objectMatches = MatchObjectWithOid(currentOID, returnObjects, inMemory); if (objectMatches) { nbObjectsInResult++; if (objectInRange) { if (_queryHasOrderBy) { _orderByKey = BuildOrderByKey(GetCurrentObjectMetaRepresentation()); } queryResultAction.ObjectMatch(currentOID, GetCurrentObjectMetaRepresentation(), _orderByKey); } } } } if (ExecuteStartAndEndOfQueryAction()) { queryResultAction.End(); } return(queryResultAction.GetObjects <T>()); }
/// <summary> /// Execute query using index /// </summary> /// <param name="index"> </param> /// <param name="inMemory"> </param> /// <param name="returnObjects"> </param> /// <param name="queryResultAction"> </param> private IInternalObjectSet <T> ExecuteUsingIndex <T>(ClassInfoIndex index, bool inMemory, bool returnObjects, IMatchingObjectAction queryResultAction) { // Index that have not been used yet do not have persister! if (index.BTree.GetPersister() == null) { index.BTree.SetPersister(new LazyOdbBtreePersister(StorageEngine)); } var nbObjects = ClassInfo.NumberOfObjects; var btreeSize = index.BTree.GetSize(); // the two values should be equal if (nbObjects != btreeSize) { var classInfo = StorageEngine.GetSession().GetMetaModel().GetClassInfoFromId(index.ClassInfoId); throw new OdbRuntimeException( NDatabaseError.IndexIsCorrupted.AddParameter(index.Name).AddParameter(classInfo.FullClassName). AddParameter(nbObjects).AddParameter(btreeSize)); } if (OdbConfiguration.IsLoggingEnabled()) { DLogger.Debug(string.Format("GenericQueryExecutor: loading {0} instance(s) of {1}", nbObjects, ClassInfo.FullClassName)); } if (ExecuteStartAndEndOfQueryAction()) { queryResultAction.Start(); } PrepareQuery(); if (Query != null) { _queryHasOrderBy = Query.HasOrderBy(); } var tree = index.BTree; var isUnique = index.IsUnique; // Iterator iterator = new BTreeIterator(tree, // OrderByConstants.ORDER_BY_ASC); var key = ComputeIndexKey(index); IList list = null; // If index is unique, get the object if (isUnique) { var treeSingle = (IBTreeSingleValuePerKey)tree; var value = treeSingle.Search(key); if (value != null) { list = new List <object> { value } } ; } else { var treeMultiple = (IBTreeMultipleValuesPerKey)tree; list = treeMultiple.Search(key); } if (list != null) { foreach (OID oid in list) { // FIXME Why calling this method ObjectReader.GetObjectPositionFromItsOid(oid, true, true); _orderByKey = null; var objectMatches = MatchObjectWithOid(oid, returnObjects, inMemory); if (objectMatches) { queryResultAction.ObjectMatch(oid, GetCurrentObjectMetaRepresentation(), _orderByKey); } } queryResultAction.End(); return(queryResultAction.GetObjects <T>()); } if (ExecuteStartAndEndOfQueryAction()) { queryResultAction.End(); } return(queryResultAction.GetObjects <T>()); }
public void Commit() { if (OdbConfiguration.IsLoggingEnabled()) { var numberOfWriteActionsAsString = _numberOfWriteActions.ToString(); var hasAllWriteActionsInMemoryAsString = _hasAllWriteActionsInMemory.ToString(); DLogger.Info("OdbTransaction: Commiting " + numberOfWriteActionsAsString + " write actions - In Memory : " + hasAllWriteActionsInMemoryAsString + string.Format(" - sid={0}", _session.GetId())); } // Check if database has been rollbacked CheckRollback(); // call the commit listeners ManageCommitListenersBefore(); if (_currentWriteAction != null && !_currentWriteAction.IsEmpty()) { AddWriteAction(_currentWriteAction, true); _currentWriteAction = null; } if (_fsi == null && _numberOfWriteActions != 0) { throw new OdbRuntimeException(NDatabaseError.TransactionAlreadyCommitedOrRollbacked); } if (_numberOfWriteActions == 0) { // FIXME call commitMetaModel in realOnlyMode? CommitMetaModel(); // Nothing to do if (_fsi != null) { _fsi.Close(); _fsi = null; } if (_session != null) { _session.GetCache().ClearOnCommit(); } return; } // Marks the transaction as committed SetCommited(); // Apply the write actions the main database file ApplyTo(); // Commit Meta Model changes CommitMetaModel(); if (_fsi != null) { _fsi.Close(); _fsi = null; } if (_session != null) { _session.GetCache().ClearOnCommit(); } ManageCommitListenersAfter(); }
/// <summary> /// Used to commit meta model : classes This is useful when running in client server mode TODO Check this /// </summary> private void CommitMetaModel() { var sessionMetaModel = _session.GetMetaModel(); // If meta model has not been modified, there is nothing to do if (!sessionMetaModel.HasChanged()) { return; } if (OdbConfiguration.IsLoggingEnabled()) { DLogger.Debug("OdbTransaction: Start commitMetaModel"); } // In local mode, we must not reload the meta model as there is no // concurrent access var lastCommitedMetaModel = sessionMetaModel; var writer = _session.GetStorageEngine().GetObjectWriter(); // Gets the classes that have changed (that have modified ,deleted or inserted objects) var enumerator = sessionMetaModel.GetChangedClassInfo().GetEnumerator(); // for all changes between old and new meta model while (enumerator.MoveNext()) { var newClassInfo = enumerator.Current; if (newClassInfo == null) { continue; } ClassInfo lastCommittedClassInfo; if (lastCommitedMetaModel.ExistClass(newClassInfo.UnderlyingType)) { // The last CI represents the last committed meta model of the // database lastCommittedClassInfo = lastCommitedMetaModel.GetClassInfoFromId(newClassInfo.ClassInfoId); // Just be careful to keep track of current CI committed zone // deleted objects lastCommittedClassInfo.CommitedZoneInfo.SetNbDeletedObjects( newClassInfo.CommitedZoneInfo.GetNbDeletedObjects()); } else { lastCommittedClassInfo = newClassInfo; } var lastCommittedObjectOidOfThisTransaction = newClassInfo.CommitedZoneInfo.Last; var lastCommittedObjectOidOfPrevTransaction = lastCommittedClassInfo.CommitedZoneInfo.Last; var lastCommittedObjectOid = lastCommittedObjectOidOfPrevTransaction; // If some object have been created then if (lastCommittedObjectOidOfPrevTransaction != null) { // Checks if last object of committed meta model has not been // deleted if (_session.GetCache().IsDeleted(lastCommittedObjectOidOfPrevTransaction)) { // TODO This is wrong: if a committed transaction deleted a // committed object and creates x new // objects, then all these new objects will be lost: // if it has been deleted then use the last object of the // session class info lastCommittedObjectOid = lastCommittedObjectOidOfThisTransaction; newClassInfo.CommitedZoneInfo.Last = lastCommittedObjectOid; } } // Connect Unconnected zone to connected zone // make next oid of last committed object point to first // uncommitted object // make previous oid of first uncommitted object point to // last committed object if (lastCommittedObjectOid != null && newClassInfo.UncommittedZoneInfo.HasObjects()) { if (newClassInfo.CommitedZoneInfo.HasObjects()) { // these 2 updates are executed directly without // transaction, because // We are in the commit process. writer.UpdateNextObjectFieldOfObjectInfo(lastCommittedObjectOid, newClassInfo.UncommittedZoneInfo.First, false); writer.UpdatePreviousObjectFieldOfObjectInfo(newClassInfo.UncommittedZoneInfo.First, lastCommittedObjectOid, false); } else { // Committed zone has 0 object writer.UpdatePreviousObjectFieldOfObjectInfo(newClassInfo.UncommittedZoneInfo.First, null, false); } } // The number of committed objects must be updated with the number // of the last committed CI because a transaction may have been // committed changing this number. // Notice that the setNbObjects receive the full CommittedCIZoneInfo // object // because it will set the number of objects and the number of // deleted objects newClassInfo.CommitedZoneInfo.SetNbObjects(lastCommittedClassInfo.CommitedZoneInfo); // and don't forget to set the deleted objects // This sets the number of objects, the first object OID and the // last object OID newClassInfo = BuildClassInfoForCommit(newClassInfo); writer.FileSystemProcessor.UpdateInstanceFieldsOfClassInfo(newClassInfo, false); if (OdbConfiguration.IsLoggingEnabled()) { DLogger.Debug(string.Format("OdbTransaction: Analysing class {0}", newClassInfo.FullClassName)); DLogger.Debug(string.Format("\t-Commited CI = {0}", newClassInfo)); DLogger.Debug( string.Format("\t-connect last commited object with oid {0} to first uncommited object {1}", lastCommittedObjectOid, newClassInfo.UncommittedZoneInfo.First)); DLogger.Debug(string.Concat("\t-Commiting new Number of objects = ", newClassInfo.NumberOfObjects.ToString())); } } sessionMetaModel.ResetChangedClasses(); }
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); }