From: Steven M. <sr...@us...> - 2005-11-24 23:09:49
|
Update of /cvsroot/instantobjects/Source/Core In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv17597 Modified Files: InstantPersistence.pas Log Message: 1. function TInstantObjectReference.Create - Refactored to use new private method DoAssignInstance. 2. procedure TInstantObjectReference.AssignInstance - a) Remove [AOwner: TInstantComplex] parameter. Change of owner should not be allowed unless further processing is introduced to handle update of ReferenceBy info. b) Refactored to use new private method DoAssignInstance. 3. function TInstantObjectReference.Dereference - Refactored to use new private method DoAssignInstance. 4. procedure TInstantObjectReference.DestroyInstance - Rearranged code based on understanding that ReferencedBy processing is only applied to references when OwnsInstance is True. 5. procedure TInstantObjectReference.DoAssignInstance - New private method DoAssignInstance. 6. procedure TInstantObjectReference.SetInstance - Refactored to use new private method DoAssignInstance. 7. procedure TInstantObjectReference.SetOwnsInstance - Added code to adjust ReferencedBy if OwnsInstance is changed. 8. function TInstantReference.GetValue - Updated code to ensure that ReferencedBy is only adjusted once as this now done in both RetrieveObject and AssignInstance. 9. procedure TInstantReferences.LoadReferencesFromStream - Updated code to set FOwner for TInstantObjectReference. 10. procedure TInstantReferences.ReadObject - Updated code to set FOwner for TInstantObjectReference by using CreateObjectReference method. 11. procedure TInstantSQLResolver.ReadAttribute [local] procedure ReadReferencesAttribute - Updated code to set FOwner for TInstantObjectReference.Create. 12. procedure TInstantNavigationalQuery.InternalRefreshObjects procedure TInstantSQLQuery.InternalRefreshObjects - Optimise the InternalRefreshObjects so that no unnecessary object refreshes occur as these can be expensive reloading of objects from the database. See comments in code. 13. constructor TInstantObjectReference.Clone - Changed sequence of FOwner assignment to ensure that processing occurs correctly for remaining assignments. 14. function TInstantNavigationalQuery.InternalAddObject procedure TInstantNavigationalQuery.InternalInsertObject - Remove code that adds a reference count to InstantObjects to prevent memory leakage. 15. function TInstantSQLQuery.InternalAddObject procedure TInstantSQLQuery.InternalInsertObject - Add code that releases a reference count to InstantObjects to prevent memory leakage. Index: InstantPersistence.pas =================================================================== RCS file: /cvsroot/instantobjects/Source/Core/InstantPersistence.pas,v retrieving revision 1.72 retrieving revision 1.73 diff -C2 -d -r1.72 -r1.73 *** InstantPersistence.pas 6 Nov 2005 20:37:11 -0000 1.72 --- InstantPersistence.pas 24 Nov 2005 23:09:40 -0000 1.73 *************** *** 524,527 **** --- 524,528 ---- FOwnsInstance: Boolean; procedure ClearReference; + procedure DoAssignInstance(AInstance: TInstantObject; AOwnsInstance: Boolean); function GetInstance: TInstantObject; function GetObjectClass: TInstantObjectClass; *************** *** 542,546 **** destructor Destroy; override; procedure Assign(Source: TPersistent); override; ! procedure AssignInstance(AInstance: TInstantObject; AOwner: TInstantComplex = nil); function Dereference(Connector: TInstantConnector = nil; AOwnsInstance: Boolean = True; Retry: Boolean = False): TInstantObject; --- 543,547 ---- destructor Destroy; override; procedure Assign(Source: TPersistent); override; ! procedure AssignInstance(AInstance: TInstantObject); function Dereference(Connector: TInstantConnector = nil; AOwnsInstance: Boolean = True; Retry: Boolean = False): TInstantObject; *************** *** 4310,4325 **** end; ! procedure TInstantObjectReference.AssignInstance(AInstance: TInstantObject; ! AOwner: TInstantComplex); begin ! if not Equals(AInstance) then ! DestroyInstance; ! if Assigned(AInstance) then ! begin ! FInstance := AInstance; ! if OwnsInstance then ! Instance.AddRef; ! end; ! FOwner := AOwner; end; --- 4311,4317 ---- end; ! procedure TInstantObjectReference.AssignInstance(AInstance: TInstantObject); begin ! DoAssignInstance(AInstance, OwnsInstance); end; *************** *** 4334,4340 **** begin Create; Assign(Source); OwnsInstance := AOwnsInstance; - FOwner := AOwner; end; --- 4326,4332 ---- begin Create; + FOwner := AOwner; Assign(Source); OwnsInstance := AOwnsInstance; end; *************** *** 4343,4349 **** begin inherited Create; - Instance := AInstance; - OwnsInstance := AOwnsInstance; FOwner := AOwner; end; --- 4335,4340 ---- begin inherited Create; FOwner := AOwner; + DoAssignInstance(AInstance, AOwnsInstance); end; *************** *** 4356,4359 **** --- 4347,4352 ---- function TInstantObjectReference.Dereference(Connector: TInstantConnector; AOwnsInstance: Boolean; Retry: Boolean): TInstantObject; + var + Obj: TInstantObject; begin if not Assigned(Instance) or (IsBroken and Retry) then *************** *** 4361,4367 **** InstantCheckConnector(Connector); if HasReference then ! FInstance := ObjectClass.Retrieve(ObjectId, False, False, Connector); if Assigned(FInstance) then ! FOwnsInstance := AOwnsInstance else Integer(FInstance) := -1; --- 4354,4363 ---- InstantCheckConnector(Connector); if HasReference then ! begin ! Obj := ObjectClass.Retrieve(ObjectId, False, False, Connector); ! DoAssignInstance(Obj, AOwnsInstance); ! end; if Assigned(FInstance) then ! FInstance.Release else Integer(FInstance) := -1; *************** *** 4385,4395 **** procedure TInstantObjectReference.DestroyInstance; begin ! if HasInstance and Assigned(FOwner) then ! Instance.ReferencedBy.Remove(FOwner); ! if FOwnsInstance then ! Instance.Free; FInstance := nil; end; function TInstantObjectReference.Equals(AObject: TInstantObject): Boolean; begin --- 4381,4405 ---- procedure TInstantObjectReference.DestroyInstance; begin ! if HasInstance and FOwnsInstance then ! begin ! if Assigned(FOwner) then ! FInstance.ReferencedBy.Remove(FOwner); ! FInstance.Free; ! end; FInstance := nil; end; + procedure TInstantObjectReference.DoAssignInstance(AInstance: TInstantObject; + AOwnsInstance: Boolean); + begin + if FInstance <> AInstance then + begin + DestroyInstance; + FInstance := AInstance; + FOwnsInstance := False; + end; + OwnsInstance := AOwnsInstance; + end; + function TInstantObjectReference.Equals(AObject: TInstantObject): Boolean; begin *************** *** 4506,4518 **** begin if not Equals(Value) then ! Reset; ! if Assigned(Value) then ! begin ! FInstance := Value; ! if Assigned(FOwner) then ! FInstance.ReferencedBy.Add(FOwner); ! if OwnsInstance then ! FInstance.AddRef; ! end; end; --- 4516,4521 ---- begin if not Equals(Value) then ! ClearReference; ! DoAssignInstance(Value, OwnsInstance); end; *************** *** 4521,4527 **** if Assigned(Instance) then if Value and not OwnsInstance then ! Instance.AddRef else if not Value and OwnsInstance then ! Instance.Release; FOwnsInstance := Value; end; --- 4524,4538 ---- if Assigned(Instance) then if Value and not OwnsInstance then ! begin ! FInstance.AddRef; ! if Assigned(FOwner) then ! FInstance.ReferencedBy.Add(FOwner); ! end else if not Value and OwnsInstance then ! begin ! FInstance.Release; ! if Assigned(FOwner) then ! FInstance.ReferencedBy.Remove(FOwner); ! end; FOwnsInstance := Value; end; *************** *** 6278,6290 **** begin if not IsBroken then ! Obj := RetrieveObject ! else ! Obj := nil; end else - Obj := CreateObject; - if Assigned(Obj) then begin ! ObjectReference.AssignInstance(Obj); ! Obj.Release; end; end; --- 6289,6301 ---- begin if not IsBroken then ! RetrieveObject; end else begin ! Obj := CreateObject; ! if Assigned(Obj) then ! begin ! ObjectReference.AssignInstance(Obj); ! Obj.Release; ! end; end; end; *************** *** 7261,7269 **** Obj := InstantReadObjectFromStream(AStream); try ! ObjectReferenceList.Add(Obj as TInstantObjectReference); ! TInstantObjectReference(Obj).OwnsInstance := True; ! except Obj.Free; - raise; end; end; --- 7272,7287 ---- Obj := InstantReadObjectFromStream(AStream); try ! ObjReference := TInstantObjectReference.Create(nil, True, Self); ! try ! ObjReference.ReferenceObject( ! TInstantObjectReference(Obj).ObjectClassName, ! TInstantObjectReference(Obj).ObjectId); ! ObjectReferenceList.Add(ObjReference); ! except ! ObjReference.Free; ! raise; ! end; ! finally Obj.Free; end; end; *************** *** 7283,7294 **** ObjId := Processor.ReadData; //Data = ObjectId Processor.ReadTag; //closing tag ! ObjReference := TInstantObjectReference.Create; ! Try ObjReference.ReferenceObject(ObjClassName, ObjId); ObjectReferenceList.Add(ObjReference); ! Except ObjReference.Free; ! End; ! ObjReference.OwnsInstance := True; end; finally --- 7301,7311 ---- ObjId := Processor.ReadData; //Data = ObjectId Processor.ReadTag; //closing tag ! ObjReference := TInstantObjectReference.Create(nil, True, Self); ! try ObjReference.ReferenceObject(ObjClassName, ObjId); ObjectReferenceList.Add(ObjReference); ! except ObjReference.Free; ! end; end; finally *************** *** 7308,7312 **** while not Reader.EndOfList do begin ! Ref := TInstantObjectReference.Create; try Ref.ReadAsObject(Reader); --- 7325,7329 ---- while not Reader.EndOfList do begin ! Ref := CreateObjectReference(nil); try Ref.ReadAsObject(Reader); *************** *** 12484,12489 **** ObjectRow.Row := -1; ObjectRow.Instance := AObject; - if AObject is TInstantObject then - TInstantObject(AObject).AddRef; Result := ObjectRowList.Add(ObjectRow); except --- 12501,12504 ---- *************** *** 12540,12545 **** ObjectRow.Row := -1; ObjectRow.Instance := AObject; - if AObject is TInstantObject then - TInstantObject(AObject).AddRef; ObjectRowList.Insert(Index, ObjectRow); except --- 12555,12558 ---- *************** *** 12558,12563 **** procedure TInstantNavigationalQuery.InternalRefreshObjects; var ! I: Integer; BusyObjects: TObjectList; begin if not DataSet.Active then --- 12571,12578 ---- procedure TInstantNavigationalQuery.InternalRefreshObjects; var ! I, Idx: Integer; BusyObjects: TObjectList; + Obj: TInstantObject; + ObjStore: TInstantObjectStore; begin if not DataSet.Active then *************** *** 12565,12580 **** BusyObjects := TObjectList.Create; try for I := 0 to Pred(ObjectRowCount) do with ObjectRows[I]^ do ! if (Instance is TInstantObject) ! and (TInstantObject(Instance).RefCount > 0) then begin ! BusyObjects.Add(Instance); ! TInstantObject(Instance).AddRef; end; Close; Open; for I := 0 to Pred(BusyObjects.Count) do ! TInstantObject(BusyObjects[I]).Refresh; finally BusyObjects.Free; --- 12580,12618 ---- BusyObjects := TObjectList.Create; try + // Collect a reference to all objects in query. + // Note: In this list of TInstantObjectReferences + // OwnsInstance is false. for I := 0 to Pred(ObjectRowCount) do with ObjectRows[I]^ do ! if (Instance is TInstantObject) then begin ! Idx := BusyObjects.Add(TInstantObjectReference.Create(nil)); ! TInstantObjectReference(BusyObjects[Idx]).ReferenceObject( ! TInstantObject(Instance).ClassName, ! TInstantObject(Instance).Id); end; + Close; + + // Remove references from the BusyList for objects deleted + // when the query was closed. + for I := Pred(BusyObjects.Count) downto 0 do + with TInstantObjectReference(BusyObjects[I]) do + begin + ObjStore := Connector.ObjectStores.FindObjectStore(ObjectClass); + if not (Assigned(ObjStore) and Assigned(ObjStore.Find(ObjectId))) then + BusyObjects.Delete(I); + end; + Open; + + // Refresh objects in the BusyList that were not deleted + // when the query was closed. for I := 0 to Pred(BusyObjects.Count) do ! begin ! Obj := TInstantObjectReference(BusyObjects[I]).Dereference(Connector, False); ! if Assigned(Obj) then ! Obj.Refresh; ! end; finally BusyObjects.Free; *************** *** 14354,14360 **** while not DataSet.Eof do begin ! RefObject := TInstantObjectReference.Create(nil, True); RefObject.ReferenceObject(Metadata.ObjectClass, DataSet.Fields[1].AsString); ! (Attribute as TInstantReferences).ObjectReferenceList.Add(RefObject); DataSet.Next; end; --- 14392,14399 ---- while not DataSet.Eof do begin ! RefObject := TInstantObjectReference.Create(nil, True, ! Attribute as TInstantReferences); RefObject.ReferenceObject(Metadata.ObjectClass, DataSet.Fields[1].AsString); ! (Attribute as TInstantReferences).ObjectReferenceList.Add(RefObject); DataSet.Next; end; *************** *** 14613,14616 **** --- 14652,14656 ---- try Result := ObjectReferenceList.Add(ObjectRef); + TInstantObject(AObject).Release; except ObjectRef.Free; *************** *** 14652,14655 **** --- 14692,14696 ---- try ObjectReferenceList.Insert(Index, ObjectRef); + TInstantObject(AObject).Release; except ObjectRef.Free; *************** *** 14676,14695 **** procedure TInstantSQLQuery.InternalRefreshObjects; var ! I: Integer; BusyObjects: TObjectList; begin BusyObjects := TObjectList.Create; try for I := 0 to Pred(ObjectReferenceCount) do with ObjectReferences[I] do ! if HasInstance and (Instance.RefCount > 0) then begin ! BusyObjects.Add(Instance); ! TInstantObject(Instance).AddRef; end; Close; Open; ! for I := 0 to Pred(BusyObjects.Count) do ! TInstantObject(BusyObjects[I]).Refresh; finally BusyObjects.Free; --- 14717,14761 ---- procedure TInstantSQLQuery.InternalRefreshObjects; var ! I, Idx: Integer; BusyObjects: TObjectList; + Obj: TInstantObject; + ObjStore: TInstantObjectStore; begin BusyObjects := TObjectList.Create; try + // Collect a reference to all objects in query. + // Note: In this list of TInstantObjectReferences + // OwnsInstance is false. for I := 0 to Pred(ObjectReferenceCount) do with ObjectReferences[I] do ! if HasInstance then begin ! Idx := BusyObjects.Add(TInstantObjectReference.Create(nil)); ! TInstantObjectReference(BusyObjects[Idx]).ReferenceObject( ! Instance.ClassName, Instance.Id); end; + Close; + + // Remove references from the BusyList for objects deleted + // when the query was closed. + for I := Pred(BusyObjects.Count) downto 0 do + with TInstantObjectReference(BusyObjects[I]) do + begin + ObjStore := Connector.ObjectStores.FindObjectStore(ObjectClass); + if not (Assigned(ObjStore) and Assigned(ObjStore.Find(ObjectId))) then + BusyObjects.Delete(I); + end; + Open; ! ! // Refresh objects in the BusyList that were not deleted ! // when the query was closed. ! for I := Pred(BusyObjects.Count) downto 0 do ! begin ! Obj := TInstantObjectReference(BusyObjects[I]).Dereference(Connector, False); ! if Assigned(Obj) then ! Obj.Refresh; ! end; finally BusyObjects.Free; |