LCOV - code coverage report
Current view: directory - rdf/base/src - nsInMemoryDataSource.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 925 524 56.6 %
Date: 2012-06-02 Functions: 104 78 75.0 %

       1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  *
       3                 :  * ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is mozilla.org code.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * Netscape Communications Corporation.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   Chris Waterson         <waterson@netscape.com>
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      28                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK *****
      39                 :  *
      40                 :  *
      41                 :  * This Original Code has been modified by IBM Corporation.
      42                 :  * Modifications made by IBM described herein are
      43                 :  * Copyright (c) International Business Machines
      44                 :  * Corporation, 2000
      45                 :  *
      46                 :  * Modifications to Mozilla code or documentation
      47                 :  * identified per MPL Section 3.3
      48                 :  *
      49                 :  * Date         Modified by     Description of modification
      50                 :  * 03/27/2000   IBM Corp.       Added PR_CALLBACK for Optlink
      51                 :  *                               use in OS2
      52                 :  */
      53                 : 
      54                 : /*
      55                 : 
      56                 :   Implementation for an in-memory RDF data store.
      57                 : 
      58                 :   TO DO
      59                 : 
      60                 :   1) Instrument this code to gather space and time performance
      61                 :      characteristics.
      62                 : 
      63                 :   2) Optimize lookups for datasources which have a small number
      64                 :      of properties + fanning out to a large number of targets.
      65                 : 
      66                 :   3) Complete implementation of thread-safety; specifically, make
      67                 :      assertions be reference counted objects (so that a cursor can
      68                 :      still refer to an assertion that gets removed from the graph).
      69                 : 
      70                 :  */
      71                 : 
      72                 : #include "nsAgg.h"
      73                 : #include "nsCOMPtr.h"
      74                 : #include "nscore.h"
      75                 : #include "nsIOutputStream.h"
      76                 : #include "nsIRDFDataSource.h"
      77                 : #include "nsIRDFLiteral.h"
      78                 : #include "nsIRDFNode.h"
      79                 : #include "nsIRDFObserver.h"
      80                 : #include "nsIRDFInMemoryDataSource.h"
      81                 : #include "nsIRDFPropagatableDataSource.h"
      82                 : #include "nsIRDFPurgeableDataSource.h"
      83                 : #include "nsIRDFService.h"
      84                 : #include "nsIServiceManager.h"
      85                 : #include "nsISupportsArray.h"
      86                 : #include "nsCOMArray.h"
      87                 : #include "nsEnumeratorUtils.h"
      88                 : #include "nsTArray.h"
      89                 : #include "nsCRT.h"
      90                 : #include "nsRDFCID.h"
      91                 : #include "nsRDFBaseDataSources.h"
      92                 : #include "nsString.h"
      93                 : #include "nsReadableUtils.h"
      94                 : #include "nsXPIDLString.h"
      95                 : #include "nsFixedSizeAllocator.h"
      96                 : #include "rdfutil.h"
      97                 : #include "pldhash.h"
      98                 : #include "plstr.h"
      99                 : #include "prlog.h"
     100                 : #include "rdf.h"
     101                 : 
     102                 : #include "rdfIDataSource.h"
     103                 : #include "rdfITripleVisitor.h"
     104                 : 
     105                 : #ifdef PR_LOGGING
     106                 : static PRLogModuleInfo* gLog = nsnull;
     107                 : #endif
     108                 : 
     109                 : 
     110                 : // This struct is used as the slot value in the forward and reverse
     111                 : // arcs hash tables.
     112                 : //
     113                 : // Assertion objects are reference counted, because each Assertion's
     114                 : // ownership is shared between the datasource and any enumerators that
     115                 : // are currently iterating over the datasource.
     116                 : //
     117                 : class Assertion 
     118                 : {
     119                 : public:
     120                 :     static Assertion*
     121           36438 :     Create(nsFixedSizeAllocator& aAllocator,
     122                 :            nsIRDFResource* aSource,
     123                 :            nsIRDFResource* aProperty,
     124                 :            nsIRDFNode* aTarget,
     125                 :            bool aTruthValue) {
     126           36438 :         void* place = aAllocator.Alloc(sizeof(Assertion));
     127                 :         return place
     128           36438 :             ? ::new (place) Assertion(aSource, aProperty, aTarget, aTruthValue)
     129           72876 :             : nsnull; }
     130                 :     static Assertion*
     131               0 :     Create(nsFixedSizeAllocator& aAllocator, nsIRDFResource* aSource) {
     132               0 :         void* place = aAllocator.Alloc(sizeof(Assertion));
     133                 :         return place
     134               0 :             ? ::new (place) Assertion(aSource)
     135               0 :             : nsnull; }
     136                 : 
     137                 :     static void
     138           36438 :     Destroy(nsFixedSizeAllocator& aAllocator, Assertion* aAssertion) {
     139           36438 :         if (aAssertion->mHashEntry && aAssertion->u.hash.mPropertyHash) {
     140                 :             PL_DHashTableEnumerate(aAssertion->u.hash.mPropertyHash,
     141               0 :                 DeletePropertyHashEntry, &aAllocator);
     142               0 :             PL_DHashTableDestroy(aAssertion->u.hash.mPropertyHash);
     143               0 :             aAssertion->u.hash.mPropertyHash = nsnull;
     144                 :         }
     145           36438 :         aAssertion->~Assertion();
     146           36438 :         aAllocator.Free(aAssertion, sizeof(*aAssertion)); }
     147                 : 
     148                 :     static PLDHashOperator
     149                 :     DeletePropertyHashEntry(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
     150                 :                            PRUint32 aNumber, void* aArg);
     151                 : 
     152                 :     Assertion(nsIRDFResource* aSource,      // normal assertion
     153                 :               nsIRDFResource* aProperty,
     154                 :               nsIRDFNode* aTarget,
     155                 :               bool aTruthValue);
     156                 :     Assertion(nsIRDFResource* aSource);     // PLDHashTable assertion variant
     157                 : 
     158                 :     ~Assertion();
     159                 : 
     160          102310 :     void AddRef() {
     161          102310 :         if (mRefCnt == PR_UINT16_MAX) {
     162               0 :             NS_WARNING("refcount overflow, leaking Assertion");
     163               0 :             return;
     164                 :         }
     165          102310 :         ++mRefCnt;
     166                 :     }
     167                 : 
     168          102310 :     void Release(nsFixedSizeAllocator& aAllocator) {
     169          102310 :         if (mRefCnt == PR_UINT16_MAX) {
     170               0 :             NS_WARNING("refcount overflow, leaking Assertion");
     171               0 :             return;
     172                 :         }
     173          102310 :         if (--mRefCnt == 0)
     174           36438 :             Destroy(aAllocator, this);
     175                 :     }
     176                 : 
     177                 :     // For nsIRDFPurgeableDataSource
     178             371 :     inline  void    Mark()      { u.as.mMarked = true; }
     179             339 :     inline  bool    IsMarked()  { return u.as.mMarked; }
     180             339 :     inline  void    Unmark()    { u.as.mMarked = false; }
     181                 : 
     182                 :     // public for now, because I'm too lazy to go thru and clean this up.
     183                 : 
     184                 :     // These are shared between hash/as (see the union below)
     185                 :     nsIRDFResource*         mSource;
     186                 :     Assertion*              mNext;
     187                 : 
     188                 :     union
     189                 :     {
     190                 :         struct hash
     191                 :         {
     192                 :             PLDHashTable*   mPropertyHash; 
     193                 :         } hash;
     194                 :         struct as
     195                 :         {
     196                 :             nsIRDFResource* mProperty;
     197                 :             nsIRDFNode*     mTarget;
     198                 :             Assertion*      mInvNext;
     199                 :             // make sure bool are final elements
     200                 :             bool            mTruthValue;
     201                 :             bool            mMarked;
     202                 :         } as;
     203                 :     } u;
     204                 : 
     205                 :     // also shared between hash/as (see the union above)
     206                 :     // but placed after union definition to ensure that
     207                 :     // all 32-bit entries are long aligned
     208                 :     PRUint16                    mRefCnt;
     209                 :     bool                        mHashEntry;
     210                 : 
     211                 : private:
     212                 :     // Hide so that only Create() and Destroy() can be used to
     213                 :     // allocate and deallocate from the heap
     214                 :     static void* operator new(size_t) CPP_THROW_NEW { return 0; }
     215                 :     static void operator delete(void*, size_t) {}
     216                 : };
     217                 : 
     218                 : 
     219                 : struct Entry {
     220                 :     PLDHashEntryHdr mHdr;
     221                 :     nsIRDFNode*     mNode;
     222                 :     Assertion*      mAssertions;
     223                 : };
     224                 : 
     225                 : 
     226               0 : Assertion::Assertion(nsIRDFResource* aSource)
     227                 :     : mSource(aSource),
     228                 :       mNext(nsnull),
     229                 :       mRefCnt(0),
     230               0 :       mHashEntry(true)
     231                 : {
     232               0 :     MOZ_COUNT_CTOR(RDF_Assertion);
     233                 : 
     234               0 :     NS_ADDREF(mSource);
     235                 : 
     236                 :     u.hash.mPropertyHash = PL_NewDHashTable(PL_DHashGetStubOps(),
     237               0 :                       nsnull, sizeof(Entry), PL_DHASH_MIN_SIZE);
     238               0 : }
     239                 : 
     240           36438 : Assertion::Assertion(nsIRDFResource* aSource,
     241                 :                      nsIRDFResource* aProperty,
     242                 :                      nsIRDFNode* aTarget,
     243                 :                      bool aTruthValue)
     244                 :     : mSource(aSource),
     245                 :       mNext(nsnull),
     246                 :       mRefCnt(0),
     247           36438 :       mHashEntry(false)
     248                 : {
     249           36438 :     MOZ_COUNT_CTOR(RDF_Assertion);
     250                 : 
     251           36438 :     u.as.mProperty = aProperty;
     252           36438 :     u.as.mTarget = aTarget;
     253                 : 
     254           36438 :     NS_ADDREF(mSource);
     255           36438 :     NS_ADDREF(u.as.mProperty);
     256           36438 :     NS_ADDREF(u.as.mTarget);
     257                 : 
     258           36438 :     u.as.mInvNext = nsnull;
     259           36438 :     u.as.mTruthValue = aTruthValue;
     260           36438 :     u.as.mMarked = false;
     261           36438 : }
     262                 : 
     263           36438 : Assertion::~Assertion()
     264                 : {
     265           36438 :     MOZ_COUNT_DTOR(RDF_Assertion);
     266                 : #ifdef DEBUG_REFS
     267                 :     --gInstanceCount;
     268                 :     fprintf(stdout, "%d - RDF: Assertion\n", gInstanceCount);
     269                 : #endif
     270                 : 
     271           36438 :     NS_RELEASE(mSource);
     272           36438 :     if (!mHashEntry)
     273                 :     {
     274           36438 :         NS_RELEASE(u.as.mProperty);
     275           36438 :         NS_RELEASE(u.as.mTarget);
     276                 :     }
     277           36438 : }
     278                 : 
     279                 : PLDHashOperator
     280               0 : Assertion::DeletePropertyHashEntry(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
     281                 :                                            PRUint32 aNumber, void* aArg)
     282                 : {
     283               0 :     Entry* entry = reinterpret_cast<Entry*>(aHdr);
     284               0 :     nsFixedSizeAllocator* allocator = static_cast<nsFixedSizeAllocator*>(aArg);
     285                 : 
     286               0 :     Assertion* as = entry->mAssertions;
     287               0 :     while (as) {
     288               0 :         Assertion* doomed = as;
     289               0 :         as = as->mNext;
     290                 : 
     291                 :         // Unlink, and release the datasource's reference.
     292               0 :         doomed->mNext = doomed->u.as.mInvNext = nsnull;
     293               0 :         doomed->Release(*allocator);
     294                 :     }
     295               0 :     return PL_DHASH_NEXT;
     296                 : }
     297                 : 
     298                 : 
     299                 : 
     300                 : ////////////////////////////////////////////////////////////////////////
     301                 : // InMemoryDataSource
     302                 : class InMemoryArcsEnumeratorImpl;
     303                 : class InMemoryAssertionEnumeratorImpl;
     304                 : class InMemoryResourceEnumeratorImpl;
     305                 : 
     306                 : class InMemoryDataSource : public nsIRDFDataSource,
     307                 :                            public nsIRDFInMemoryDataSource,
     308                 :                            public nsIRDFPropagatableDataSource,
     309                 :                            public nsIRDFPurgeableDataSource,
     310                 :                            public rdfIDataSource
     311                 : {
     312                 : protected:
     313                 :     nsFixedSizeAllocator mAllocator;
     314                 : 
     315                 :     // These hash tables are keyed on pointers to nsIRDFResource
     316                 :     // objects (the nsIRDFService ensures that there is only ever one
     317                 :     // nsIRDFResource object per unique URI). The value of an entry is
     318                 :     // an Assertion struct, which is a linked list of (subject
     319                 :     // predicate object) triples.
     320                 :     PLDHashTable mForwardArcs; 
     321                 :     PLDHashTable mReverseArcs; 
     322                 : 
     323                 :     nsCOMArray<nsIRDFObserver> mObservers;  
     324                 :     PRUint32                   mNumObservers;
     325                 : 
     326                 :     // VisitFoo needs to block writes, [Un]Assert only allowed
     327                 :     // during mReadCount == 0
     328                 :     PRUint32 mReadCount;
     329                 : 
     330                 :     static PLDHashOperator
     331                 :     DeleteForwardArcsEntry(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
     332                 :                            PRUint32 aNumber, void* aArg);
     333                 : 
     334                 :     static PLDHashOperator
     335                 :     ResourceEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
     336                 :                        PRUint32 aNumber, void* aArg);
     337                 : 
     338                 :     friend class InMemoryArcsEnumeratorImpl;
     339                 :     friend class InMemoryAssertionEnumeratorImpl;
     340                 :     friend class InMemoryResourceEnumeratorImpl; // b/c it needs to enumerate mForwardArcs
     341                 : 
     342                 :     // Thread-safe writer implementation methods.
     343                 :     nsresult
     344                 :     LockedAssert(nsIRDFResource* source, 
     345                 :                  nsIRDFResource* property, 
     346                 :                  nsIRDFNode* target,
     347                 :                  bool tv);
     348                 : 
     349                 :     nsresult
     350                 :     LockedUnassert(nsIRDFResource* source,
     351                 :                    nsIRDFResource* property,
     352                 :                    nsIRDFNode* target);
     353                 : 
     354                 :     InMemoryDataSource(nsISupports* aOuter);
     355                 :     virtual ~InMemoryDataSource();
     356                 :     nsresult Init();
     357                 : 
     358                 :     friend nsresult
     359                 :     NS_NewRDFInMemoryDataSource(nsISupports* aOuter, const nsIID& aIID, void** aResult);
     360                 : 
     361                 : public:
     362            4168 :     NS_DECL_CYCLE_COLLECTING_AGGREGATED
     363          128310 :     NS_DECL_AGGREGATED_CYCLE_COLLECTION_CLASS(InMemoryDataSource)
     364                 : 
     365                 :     // nsIRDFDataSource methods
     366                 :     NS_DECL_NSIRDFDATASOURCE
     367                 : 
     368                 :     // nsIRDFInMemoryDataSource methods
     369                 :     NS_DECL_NSIRDFINMEMORYDATASOURCE
     370                 : 
     371                 :     // nsIRDFPropagatableDataSource methods
     372                 :     NS_DECL_NSIRDFPROPAGATABLEDATASOURCE
     373                 : 
     374                 :     // nsIRDFPurgeableDataSource methods
     375                 :     NS_DECL_NSIRDFPURGEABLEDATASOURCE
     376                 : 
     377                 :     // rdfIDataSource methods
     378                 :     NS_DECL_RDFIDATASOURCE
     379                 : 
     380                 : protected:
     381                 :     static PLDHashOperator
     382                 :     SweepForwardArcsEntries(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
     383                 :                             PRUint32 aNumber, void* aArg);
     384                 : 
     385                 : public:
     386                 :     // Implementation methods
     387                 :     Assertion*
     388          107422 :     GetForwardArcs(nsIRDFResource* u) {
     389          107422 :         PLDHashEntryHdr* hdr = PL_DHashTableOperate(&mForwardArcs, u, PL_DHASH_LOOKUP);
     390          107422 :         return PL_DHASH_ENTRY_IS_BUSY(hdr)
     391                 :             ? reinterpret_cast<Entry*>(hdr)->mAssertions
     392          107422 :             : nsnull; }
     393                 : 
     394                 :     Assertion*
     395           38553 :     GetReverseArcs(nsIRDFNode* v) {
     396           38553 :         PLDHashEntryHdr* hdr = PL_DHashTableOperate(&mReverseArcs, v, PL_DHASH_LOOKUP);
     397           38553 :         return PL_DHASH_ENTRY_IS_BUSY(hdr)
     398                 :             ? reinterpret_cast<Entry*>(hdr)->mAssertions
     399           38553 :             : nsnull; }
     400                 : 
     401                 :     void
     402           10915 :     SetForwardArcs(nsIRDFResource* u, Assertion* as) {
     403                 :         PLDHashEntryHdr* hdr = PL_DHashTableOperate(&mForwardArcs, u,
     404           10915 :                                                     as ? PL_DHASH_ADD : PL_DHASH_REMOVE);
     405           10915 :         if (as && hdr) {
     406           10901 :             Entry* entry = reinterpret_cast<Entry*>(hdr);
     407           10901 :             entry->mNode = u;
     408           10901 :             entry->mAssertions = as;
     409           10915 :         } }
     410                 : 
     411                 :     void
     412           37622 :     SetReverseArcs(nsIRDFNode* v, Assertion* as) {
     413                 :         PLDHashEntryHdr* hdr = PL_DHashTableOperate(&mReverseArcs, v,
     414           37622 :                                                     as ? PL_DHASH_ADD : PL_DHASH_REMOVE);
     415           37622 :         if (as && hdr) {
     416           37078 :             Entry* entry = reinterpret_cast<Entry*>(hdr);
     417           37078 :             entry->mNode = v;
     418           37078 :             entry->mAssertions = as;
     419           37622 :         } }
     420                 : 
     421                 : #ifdef PR_LOGGING
     422                 :     void
     423                 :     LogOperation(const char* aOperation,
     424                 :                  nsIRDFResource* asource,
     425                 :                  nsIRDFResource* aProperty,
     426                 :                  nsIRDFNode* aTarget,
     427                 :                  bool aTruthValue = true);
     428                 : #endif
     429                 : 
     430                 :     bool    mPropagateChanges;
     431                 : };
     432                 : 
     433                 : //----------------------------------------------------------------------
     434                 : //
     435                 : // InMemoryAssertionEnumeratorImpl
     436                 : //
     437                 : 
     438                 : /**
     439                 :  * InMemoryAssertionEnumeratorImpl
     440                 :  */
     441                 : class InMemoryAssertionEnumeratorImpl : public nsISimpleEnumerator
     442                 : {
     443                 : private:
     444                 :     InMemoryDataSource* mDataSource;
     445                 :     nsIRDFResource* mSource;
     446                 :     nsIRDFResource* mProperty;
     447                 :     nsIRDFNode*     mTarget;
     448                 :     nsIRDFNode*     mValue;
     449                 :     PRInt32         mCount;
     450                 :     bool            mTruthValue;
     451                 :     Assertion*      mNextAssertion;
     452                 :     nsCOMPtr<nsISupportsArray> mHashArcs;
     453                 : 
     454                 :     // Hide so that only Create() and Destroy() can be used to
     455                 :     // allocate and deallocate from the heap
     456                 :     static void* operator new(size_t) CPP_THROW_NEW { return 0; }
     457               0 :     static void operator delete(void*, size_t) {}
     458                 : 
     459                 :     InMemoryAssertionEnumeratorImpl(InMemoryDataSource* aDataSource,
     460                 :                                     nsIRDFResource* aSource,
     461                 :                                     nsIRDFResource* aProperty,
     462                 :                                     nsIRDFNode* aTarget,
     463                 :                                     bool aTruthValue);
     464                 : 
     465                 :     virtual ~InMemoryAssertionEnumeratorImpl();
     466                 : 
     467                 : public:
     468                 :     static InMemoryAssertionEnumeratorImpl*
     469           13720 :     Create(InMemoryDataSource* aDataSource,
     470                 :            nsIRDFResource* aSource,
     471                 :            nsIRDFResource* aProperty,
     472                 :            nsIRDFNode* aTarget,
     473                 :            bool aTruthValue) {
     474           13720 :         void* place = aDataSource->mAllocator.Alloc(sizeof(InMemoryAssertionEnumeratorImpl));
     475                 :         return place
     476                 :             ? ::new (place) InMemoryAssertionEnumeratorImpl(aDataSource,
     477                 :                                                             aSource, aProperty, aTarget,
     478           13720 :                                                             aTruthValue)
     479           27440 :             : nsnull; }
     480                 : 
     481                 :     static void
     482           13720 :     Destroy(InMemoryAssertionEnumeratorImpl* aEnumerator) {
     483                 :         // Keep the datasource alive for the duration of the stack
     484                 :         // frame so its allocator stays valid.
     485           27440 :         nsCOMPtr<nsIRDFDataSource> kungFuDeathGrip = aEnumerator->mDataSource;
     486                 : 
     487                 :         // Grab the pool from the datasource; since we keep the
     488                 :         // datasource alive, this has to be safe.
     489           13720 :         nsFixedSizeAllocator& pool = aEnumerator->mDataSource->mAllocator;
     490           13720 :         aEnumerator->~InMemoryAssertionEnumeratorImpl();
     491           27440 :         pool.Free(aEnumerator, sizeof(*aEnumerator)); }
     492                 : 
     493                 :     // nsISupports interface
     494                 :     NS_DECL_ISUPPORTS
     495                 :    
     496                 :     // nsISimpleEnumerator interface
     497                 :     NS_DECL_NSISIMPLEENUMERATOR
     498                 : };
     499                 : 
     500                 : ////////////////////////////////////////////////////////////////////////
     501                 : 
     502                 : 
     503           13720 : InMemoryAssertionEnumeratorImpl::InMemoryAssertionEnumeratorImpl(
     504                 :                  InMemoryDataSource* aDataSource,
     505                 :                  nsIRDFResource* aSource,
     506                 :                  nsIRDFResource* aProperty,
     507                 :                  nsIRDFNode* aTarget,
     508                 :                  bool aTruthValue)
     509                 :     : mDataSource(aDataSource),
     510                 :       mSource(aSource),
     511                 :       mProperty(aProperty),
     512                 :       mTarget(aTarget),
     513                 :       mValue(nsnull),
     514                 :       mCount(0),
     515                 :       mTruthValue(aTruthValue),
     516           13720 :       mNextAssertion(nsnull)
     517                 : {
     518           13720 :     NS_ADDREF(mDataSource);
     519           13720 :     NS_IF_ADDREF(mSource);
     520           13720 :     NS_ADDREF(mProperty);
     521           13720 :     NS_IF_ADDREF(mTarget);
     522                 : 
     523           13720 :     if (mSource) {
     524           13715 :         mNextAssertion = mDataSource->GetForwardArcs(mSource);
     525                 : 
     526           13715 :         if (mNextAssertion && mNextAssertion->mHashEntry) {
     527                 :             // its our magical HASH_ENTRY forward hash for assertions
     528                 :             PLDHashEntryHdr* hdr = PL_DHashTableOperate(mNextAssertion->u.hash.mPropertyHash,
     529               0 :                 aProperty, PL_DHASH_LOOKUP);
     530               0 :             mNextAssertion = PL_DHASH_ENTRY_IS_BUSY(hdr)
     531                 :                 ? reinterpret_cast<Entry*>(hdr)->mAssertions
     532               0 :                 : nsnull;
     533                 :         }
     534                 :     }
     535                 :     else {
     536               5 :         mNextAssertion = mDataSource->GetReverseArcs(mTarget);
     537                 :     }
     538                 : 
     539                 :     // Add an owning reference from the enumerator
     540           13720 :     if (mNextAssertion)
     541           13720 :         mNextAssertion->AddRef();
     542           13720 : }
     543                 : 
     544           27440 : InMemoryAssertionEnumeratorImpl::~InMemoryAssertionEnumeratorImpl()
     545                 : {
     546                 : #ifdef DEBUG_REFS
     547                 :     --gInstanceCount;
     548                 :     fprintf(stdout, "%d - RDF: InMemoryAssertionEnumeratorImpl\n", gInstanceCount);
     549                 : #endif
     550                 : 
     551           13720 :     if (mNextAssertion)
     552               0 :         mNextAssertion->Release(mDataSource->mAllocator);
     553                 : 
     554           13720 :     NS_IF_RELEASE(mDataSource);
     555           13720 :     NS_IF_RELEASE(mSource);
     556           13720 :     NS_IF_RELEASE(mProperty);
     557           13720 :     NS_IF_RELEASE(mTarget);
     558           13720 :     NS_IF_RELEASE(mValue);
     559           13720 : }
     560                 : 
     561           38925 : NS_IMPL_ADDREF(InMemoryAssertionEnumeratorImpl)
     562           38925 : NS_IMPL_RELEASE_WITH_DESTROY(InMemoryAssertionEnumeratorImpl, Destroy(this))
     563          100631 : NS_IMPL_QUERY_INTERFACE1(InMemoryAssertionEnumeratorImpl, nsISimpleEnumerator)
     564                 : 
     565                 : NS_IMETHODIMP
     566           24036 : InMemoryAssertionEnumeratorImpl::HasMoreElements(bool* aResult)
     567                 : {
     568           24036 :     if (mValue) {
     569            4855 :         *aResult = true;
     570            4855 :         return NS_OK;
     571                 :     }
     572                 : 
     573           99379 :     while (mNextAssertion) {
     574           65872 :         bool foundIt = false;
     575           65872 :         if ((mProperty == mNextAssertion->u.as.mProperty) &&
     576                 :             (mTruthValue == mNextAssertion->u.as.mTruthValue)) {
     577            4855 :             if (mSource) {
     578            4850 :                 mValue = mNextAssertion->u.as.mTarget;
     579            4850 :                 NS_ADDREF(mValue);
     580                 :             }
     581                 :             else {
     582               5 :                 mValue = mNextAssertion->mSource;
     583               5 :                 NS_ADDREF(mValue);
     584                 :             }
     585            4855 :             foundIt = true;
     586                 :         }
     587                 : 
     588                 :         // Remember the last assertion we were holding on to
     589           65872 :         Assertion* as = mNextAssertion;
     590                 : 
     591                 :         // iterate
     592           65872 :         mNextAssertion = (mSource) ? mNextAssertion->mNext : mNextAssertion->u.as.mInvNext;
     593                 : 
     594                 :         // grab an owning reference from the enumerator to the next assertion
     595           65872 :         if (mNextAssertion)
     596           52152 :             mNextAssertion->AddRef();
     597                 : 
     598                 :         // ...and release the reference from the enumerator to the old one.
     599           65872 :         as->Release(mDataSource->mAllocator);
     600                 : 
     601           65872 :         if (foundIt) {
     602            4855 :             *aResult = true;
     603            4855 :             return NS_OK;
     604                 :         }
     605                 :     }
     606                 : 
     607           14326 :     *aResult = false;
     608           14326 :     return NS_OK;
     609                 : }
     610                 : 
     611                 : 
     612                 : NS_IMETHODIMP
     613            4855 : InMemoryAssertionEnumeratorImpl::GetNext(nsISupports** aResult)
     614                 : {
     615                 :     nsresult rv;
     616                 : 
     617                 :     bool hasMore;
     618            4855 :     rv = HasMoreElements(&hasMore);
     619            4855 :     if (NS_FAILED(rv)) return rv;
     620                 : 
     621            4855 :     if (! hasMore)
     622               0 :         return NS_ERROR_UNEXPECTED;
     623                 : 
     624                 :     // Don't AddRef: we "transfer" ownership to the caller
     625            4855 :     *aResult = mValue;
     626            4855 :     mValue = nsnull;
     627                 : 
     628            4855 :     return NS_OK;
     629                 : }
     630                 : 
     631                 : ////////////////////////////////////////////////////////////////////////
     632                 : //
     633                 : 
     634                 : /**
     635                 :  * This class is a little bit bizarre in that it implements both the
     636                 :  * <tt>nsIRDFArcsOutCursor</tt> and <tt>nsIRDFArcsInCursor</tt> interfaces.
     637                 :  * Because the structure of the in-memory graph is pretty flexible, it's
     638                 :  * fairly easy to parameterize this class. The only funky thing to watch
     639                 :  * out for is the multiple inheritance clashes.
     640                 :  */
     641                 : 
     642                 : class InMemoryArcsEnumeratorImpl : public nsISimpleEnumerator
     643                 : {
     644                 : private:
     645                 :     // Hide so that only Create() and Destroy() can be used to
     646                 :     // allocate and deallocate from the heap
     647                 :     static void* operator new(size_t) CPP_THROW_NEW { return 0; }
     648               0 :     static void operator delete(void*, size_t) {}
     649                 : 
     650                 :     InMemoryDataSource* mDataSource;
     651                 :     nsIRDFResource*     mSource;
     652                 :     nsIRDFNode*         mTarget;
     653                 :     nsAutoTArray<nsCOMPtr<nsIRDFResource>, 8> mAlreadyReturned;
     654                 :     nsIRDFResource*     mCurrent;
     655                 :     Assertion*          mAssertion;
     656                 :     nsCOMPtr<nsISupportsArray> mHashArcs;
     657                 : 
     658                 :     InMemoryArcsEnumeratorImpl(InMemoryDataSource* aDataSource,
     659                 :                                nsIRDFResource* aSource,
     660                 :                                nsIRDFNode* aTarget);
     661                 : 
     662                 :     virtual ~InMemoryArcsEnumeratorImpl();
     663                 : 
     664                 :     static PLDHashOperator
     665                 :     ArcEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
     666                 :                        PRUint32 aNumber, void* aArg);
     667                 : 
     668                 : public:
     669                 :     // nsISupports interface
     670                 :     NS_DECL_ISUPPORTS
     671                 : 
     672                 :     // nsISimpleEnumerator interface
     673                 :     NS_DECL_NSISIMPLEENUMERATOR
     674                 : 
     675                 :     static InMemoryArcsEnumeratorImpl*
     676             648 :     Create(InMemoryDataSource* aDataSource,
     677                 :            nsIRDFResource* aSource,
     678                 :            nsIRDFNode* aTarget) {
     679             648 :         void* place = aDataSource->mAllocator.Alloc(sizeof(InMemoryArcsEnumeratorImpl));
     680                 :         return place
     681             648 :             ? ::new (place) InMemoryArcsEnumeratorImpl(aDataSource, aSource, aTarget)
     682            1296 :             : nsnull; }
     683                 : 
     684                 :     static void
     685             648 :     Destroy(InMemoryArcsEnumeratorImpl* aEnumerator) {
     686                 :         // Keep the datasource alive for the duration of the stack
     687                 :         // frame so its allocator stays valid.
     688            1296 :         nsCOMPtr<nsIRDFDataSource> kungFuDeathGrip = aEnumerator->mDataSource;
     689                 : 
     690                 :         // Grab the pool from the datasource; since we keep the
     691                 :         // datasource alive, this has to be safe.
     692             648 :         nsFixedSizeAllocator& pool = aEnumerator->mDataSource->mAllocator;
     693             648 :         aEnumerator->~InMemoryArcsEnumeratorImpl();
     694            1296 :         pool.Free(aEnumerator, sizeof(*aEnumerator)); }
     695                 : };
     696                 : 
     697                 : 
     698                 : PLDHashOperator
     699               0 : InMemoryArcsEnumeratorImpl::ArcEnumerator(PLDHashTable* aTable,
     700                 :                                        PLDHashEntryHdr* aHdr,
     701                 :                                        PRUint32 aNumber, void* aArg)
     702                 : {
     703               0 :     Entry* entry = reinterpret_cast<Entry*>(aHdr);
     704               0 :     nsISupportsArray* resources = static_cast<nsISupportsArray*>(aArg);
     705                 : 
     706               0 :     resources->AppendElement(entry->mNode);
     707               0 :     return PL_DHASH_NEXT;
     708                 : }
     709                 : 
     710                 : 
     711             648 : InMemoryArcsEnumeratorImpl::InMemoryArcsEnumeratorImpl(InMemoryDataSource* aDataSource,
     712                 :                                                        nsIRDFResource* aSource,
     713                 :                                                        nsIRDFNode* aTarget)
     714                 :     : mDataSource(aDataSource),
     715                 :       mSource(aSource),
     716                 :       mTarget(aTarget),
     717             648 :       mCurrent(nsnull)
     718                 : {
     719             648 :     NS_ADDREF(mDataSource);
     720             648 :     NS_IF_ADDREF(mSource);
     721             648 :     NS_IF_ADDREF(mTarget);
     722                 : 
     723             648 :     if (mSource) {
     724                 :         // cast okay because it's a closed system
     725             629 :         mAssertion = mDataSource->GetForwardArcs(mSource);
     726                 : 
     727             629 :         if (mAssertion && mAssertion->mHashEntry) {
     728                 :             // its our magical HASH_ENTRY forward hash for assertions
     729               0 :             nsresult rv = NS_NewISupportsArray(getter_AddRefs(mHashArcs));
     730               0 :             if (NS_SUCCEEDED(rv)) {
     731                 :                 PL_DHashTableEnumerate(mAssertion->u.hash.mPropertyHash,
     732               0 :                     ArcEnumerator, mHashArcs.get());
     733                 :             }
     734               0 :             mAssertion = nsnull;
     735                 :         }
     736                 :     }
     737                 :     else {
     738              19 :         mAssertion = mDataSource->GetReverseArcs(mTarget);
     739                 :     }
     740             648 : }
     741                 : 
     742            1296 : InMemoryArcsEnumeratorImpl::~InMemoryArcsEnumeratorImpl()
     743                 : {
     744                 : #ifdef DEBUG_REFS
     745                 :     --gInstanceCount;
     746                 :     fprintf(stdout, "%d - RDF: InMemoryArcsEnumeratorImpl\n", gInstanceCount);
     747                 : #endif
     748                 : 
     749             648 :     NS_RELEASE(mDataSource);
     750             648 :     NS_IF_RELEASE(mSource);
     751             648 :     NS_IF_RELEASE(mTarget);
     752             648 :     NS_IF_RELEASE(mCurrent);
     753             648 : }
     754                 : 
     755            1370 : NS_IMPL_ADDREF(InMemoryArcsEnumeratorImpl)
     756            1370 : NS_IMPL_RELEASE_WITH_DESTROY(InMemoryArcsEnumeratorImpl, Destroy(this))
     757            1222 : NS_IMPL_QUERY_INTERFACE1(InMemoryArcsEnumeratorImpl, nsISimpleEnumerator)
     758                 : 
     759                 : NS_IMETHODIMP
     760            3359 : InMemoryArcsEnumeratorImpl::HasMoreElements(bool* aResult)
     761                 : {
     762            3359 :     NS_PRECONDITION(aResult != nsnull, "null ptr");
     763            3359 :     if (! aResult)
     764               0 :         return NS_ERROR_NULL_POINTER;
     765                 : 
     766            3359 :     if (mCurrent) {
     767            1358 :         *aResult = true;
     768            1358 :         return NS_OK;
     769                 :     }
     770                 : 
     771            2001 :     if (mHashArcs) {
     772                 :         PRUint32    itemCount;
     773                 :         nsresult    rv;
     774               0 :         if (NS_FAILED(rv = mHashArcs->Count(&itemCount)))   return(rv);
     775               0 :         if (itemCount > 0) {
     776               0 :             --itemCount;
     777                 :             mCurrent = static_cast<nsIRDFResource *>
     778               0 :                                   (mHashArcs->ElementAt(itemCount));
     779               0 :             mHashArcs->RemoveElementAt(itemCount);
     780               0 :             *aResult = true;
     781               0 :             return NS_OK;
     782                 :         }
     783                 :     }
     784                 :     else
     785            4002 :         while (mAssertion) {
     786            1358 :             nsIRDFResource* next = mAssertion->u.as.mProperty;
     787                 : 
     788                 :             // "next" is the property arc we are tentatively going to return
     789                 :             // in a subsequent GetNext() call.  It is important to do two
     790                 :             // things, however, before that can happen:
     791                 :             //   1) Make sure it's not an arc we've already returned.
     792                 :             //   2) Make sure that |mAssertion| is not left pointing to
     793                 :             //      another assertion that has the same property as this one.
     794                 :             // The first is a practical concern; the second a defense against
     795                 :             // an obscure crash and other erratic behavior.  To ensure the
     796                 :             // second condition, skip down the chain until we find the next 
     797                 :             // assertion with a property that doesn't match the current one.
     798                 :             // (All these assertions would be skipped via mAlreadyReturned
     799                 :             // checks anyways; this is even a bit faster.)
     800                 : 
     801            1390 :             do {
     802                 :                 mAssertion = (mSource ? mAssertion->mNext :
     803            1390 :                         mAssertion->u.as.mInvNext);
     804                 :             }
     805                 :             while (mAssertion && (next == mAssertion->u.as.mProperty));
     806                 : 
     807            1358 :             bool alreadyReturned = false;
     808            2429 :             for (PRInt32 i = mAlreadyReturned.Length() - 1; i >= 0; --i) {
     809            1071 :                 if (mAlreadyReturned[i] == next) {
     810               0 :                     alreadyReturned = true;
     811               0 :                     break;
     812                 :                 }
     813                 :             }
     814                 : 
     815            1358 :             if (! alreadyReturned) {
     816            1358 :                 mCurrent = next;
     817            1358 :                 NS_ADDREF(mCurrent);
     818            1358 :                 *aResult = true;
     819            1358 :                 return NS_OK;
     820                 :             }
     821                 :         }
     822                 : 
     823             643 :     *aResult = false;
     824             643 :     return NS_OK;
     825                 : }
     826                 : 
     827                 : 
     828                 : NS_IMETHODIMP
     829            1358 : InMemoryArcsEnumeratorImpl::GetNext(nsISupports** aResult)
     830                 : {
     831                 :     nsresult rv;
     832                 : 
     833                 :     bool hasMore;
     834            1358 :     rv = HasMoreElements(&hasMore);
     835            1358 :     if (NS_FAILED(rv)) return rv;
     836                 : 
     837            1358 :     if (! hasMore)
     838               0 :         return NS_ERROR_UNEXPECTED;
     839                 : 
     840                 :     // Add this to the set of things we've already returned so that we
     841                 :     // can ensure uniqueness
     842            1358 :     mAlreadyReturned.AppendElement(mCurrent);
     843                 : 
     844                 :     // Don't AddRef: we "transfer" ownership to the caller
     845            1358 :     *aResult = mCurrent;
     846            1358 :     mCurrent = nsnull;
     847                 : 
     848            1358 :     return NS_OK;
     849                 : }
     850                 : 
     851                 : 
     852                 : ////////////////////////////////////////////////////////////////////////
     853                 : // InMemoryDataSource
     854                 : 
     855                 : nsresult
     856            2072 : NS_NewRDFInMemoryDataSource(nsISupports* aOuter, const nsIID& aIID, void** aResult)
     857                 : {
     858            2072 :     NS_PRECONDITION(aResult != nsnull, "null ptr");
     859            2072 :     if (! aResult)
     860               0 :         return NS_ERROR_NULL_POINTER;
     861            2072 :     *aResult = nsnull;
     862                 : 
     863            2072 :     if (aOuter && !aIID.Equals(NS_GET_IID(nsISupports))) {
     864               0 :         NS_ERROR("aggregation requires nsISupports");
     865               0 :         return NS_ERROR_ILLEGAL_VALUE;
     866                 :     }
     867                 : 
     868            2072 :     InMemoryDataSource* datasource = new InMemoryDataSource(aOuter);
     869            2072 :     if (! datasource)
     870               0 :         return NS_ERROR_OUT_OF_MEMORY;
     871            2072 :     NS_ADDREF(datasource);
     872                 : 
     873            2072 :     nsresult rv = datasource->Init();
     874            2072 :     if (NS_SUCCEEDED(rv)) {
     875            2072 :         datasource->fAggregated.AddRef();
     876            2072 :         rv = datasource->AggregatedQueryInterface(aIID, aResult); // This'll AddRef()
     877            2072 :         datasource->fAggregated.Release();
     878                 :     }
     879                 : 
     880            2072 :     NS_RELEASE(datasource);
     881            2072 :     return rv;
     882                 : }
     883                 : 
     884                 : 
     885            2072 : InMemoryDataSource::InMemoryDataSource(nsISupports* aOuter)
     886            2072 :     : mNumObservers(0), mReadCount(0)
     887                 : {
     888            2072 :     NS_INIT_AGGREGATED(aOuter);
     889                 : 
     890                 :     static const size_t kBucketSizes[] = {
     891                 :         sizeof(Assertion),
     892                 :         sizeof(Entry),
     893                 :         sizeof(InMemoryArcsEnumeratorImpl),
     894                 :         sizeof(InMemoryAssertionEnumeratorImpl) };
     895                 : 
     896                 :     static const PRInt32 kNumBuckets = sizeof(kBucketSizes) / sizeof(size_t);
     897                 : 
     898                 :     // Per news://news.mozilla.org/39BEC105.5090206%40netscape.com
     899                 :     static const PRInt32 kInitialSize = 1024;
     900                 : 
     901            2072 :     mAllocator.Init("nsInMemoryDataSource", kBucketSizes, kNumBuckets, kInitialSize);
     902                 : 
     903            2072 :     mForwardArcs.ops = nsnull;
     904            2072 :     mReverseArcs.ops = nsnull;
     905            2072 :     mPropagateChanges = true;
     906            2072 : }
     907                 : 
     908                 : 
     909                 : nsresult
     910            2072 : InMemoryDataSource::Init()
     911                 : {
     912            2072 :     if (!PL_DHashTableInit(&mForwardArcs,
     913                 :                            PL_DHashGetStubOps(),
     914                 :                            nsnull,
     915                 :                            sizeof(Entry),
     916            2072 :                            PL_DHASH_MIN_SIZE)) {
     917               0 :         mForwardArcs.ops = nsnull;
     918               0 :         return NS_ERROR_OUT_OF_MEMORY;
     919                 :     }
     920            2072 :     if (!PL_DHashTableInit(&mReverseArcs,
     921                 :                            PL_DHashGetStubOps(),
     922                 :                            nsnull,
     923                 :                            sizeof(Entry),
     924            2072 :                            PL_DHASH_MIN_SIZE)) {
     925               0 :         mReverseArcs.ops = nsnull;
     926               0 :         return NS_ERROR_OUT_OF_MEMORY;
     927                 :     }
     928                 : 
     929                 : #ifdef PR_LOGGING
     930            2072 :     if (! gLog)
     931             172 :         gLog = PR_NewLogModule("InMemoryDataSource");
     932                 : #endif
     933                 : 
     934            2072 :     return NS_OK;
     935                 : }
     936                 : 
     937                 : 
     938            6216 : InMemoryDataSource::~InMemoryDataSource()
     939                 : {
     940                 : #ifdef DEBUG_REFS
     941                 :     --gInstanceCount;
     942                 :     fprintf(stdout, "%d - RDF: InMemoryDataSource\n", gInstanceCount);
     943                 : #endif
     944                 : 
     945            2072 :     if (mForwardArcs.ops) {
     946                 :         // This'll release all of the Assertion objects that are
     947                 :         // associated with this data source. We only need to do this
     948                 :         // for the forward arcs, because the reverse arcs table
     949                 :         // indexes the exact same set of resources.
     950            2072 :         PL_DHashTableEnumerate(&mForwardArcs, DeleteForwardArcsEntry, &mAllocator);
     951            2072 :         PL_DHashTableFinish(&mForwardArcs);
     952                 :     }
     953            2072 :     if (mReverseArcs.ops)
     954            2072 :         PL_DHashTableFinish(&mReverseArcs);
     955                 : 
     956            2072 :     PR_LOG(gLog, PR_LOG_NOTICE,
     957                 :            ("InMemoryDataSource(%p): destroyed.", this));
     958                 : 
     959            8288 : }
     960                 : 
     961                 : PLDHashOperator
     962           10853 : InMemoryDataSource::DeleteForwardArcsEntry(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
     963                 :                                            PRUint32 aNumber, void* aArg)
     964                 : {
     965           10853 :     Entry* entry = reinterpret_cast<Entry*>(aHdr);
     966           10853 :     nsFixedSizeAllocator* allocator = static_cast<nsFixedSizeAllocator*>(aArg);
     967                 : 
     968           10853 :     Assertion* as = entry->mAssertions;
     969           56060 :     while (as) {
     970           34354 :         Assertion* doomed = as;
     971           34354 :         as = as->mNext;
     972                 : 
     973                 :         // Unlink, and release the datasource's reference.
     974           34354 :         doomed->mNext = doomed->u.as.mInvNext = nsnull;
     975           34354 :         doomed->Release(*allocator);
     976                 :     }
     977           10853 :     return PL_DHASH_NEXT;
     978                 : }
     979                 : 
     980                 : 
     981                 : ////////////////////////////////////////////////////////////////////////
     982                 : 
     983            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(InMemoryDataSource)
     984               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(InMemoryDataSource)
     985               0 :     NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mObservers)
     986               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     987               6 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_AGGREGATED(InMemoryDataSource)
     988               6 :     NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mObservers)
     989               6 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     990                 : 
     991          440989 : NS_IMPL_CYCLE_COLLECTING_AGGREGATED(InMemoryDataSource)
     992          116381 : NS_INTERFACE_MAP_BEGIN_AGGREGATED(InMemoryDataSource)
     993          114319 :     NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION_AGGREGATED(InMemoryDataSource)
     994           90214 :     NS_INTERFACE_MAP_ENTRY(nsIRDFDataSource)
     995           66690 :     NS_INTERFACE_MAP_ENTRY(nsIRDFInMemoryDataSource)
     996           66690 :     NS_INTERFACE_MAP_ENTRY(nsIRDFPropagatableDataSource)
     997           66690 :     NS_INTERFACE_MAP_ENTRY(nsIRDFPurgeableDataSource)
     998           66311 :     NS_INTERFACE_MAP_ENTRY(rdfIDataSource)
     999           66292 : NS_INTERFACE_MAP_END
    1000                 : 
    1001                 : ////////////////////////////////////////////////////////////////////////
    1002                 : 
    1003                 : 
    1004                 : #ifdef PR_LOGGING
    1005                 : void
    1006           38897 : InMemoryDataSource::LogOperation(const char* aOperation,
    1007                 :                                  nsIRDFResource* aSource,
    1008                 :                                  nsIRDFResource* aProperty,
    1009                 :                                  nsIRDFNode* aTarget,
    1010                 :                                  bool aTruthValue)
    1011                 : {
    1012           38897 :     if (! PR_LOG_TEST(gLog, PR_LOG_NOTICE))
    1013           38897 :         return;
    1014                 : 
    1015               0 :     nsXPIDLCString uri;
    1016               0 :     aSource->GetValue(getter_Copies(uri));
    1017                 :     PR_LogPrint
    1018               0 :            ("InMemoryDataSource(%p): %s", this, aOperation);
    1019                 : 
    1020                 :     PR_LogPrint
    1021               0 :            ("  [(%p)%s]--", aSource, (const char*) uri);
    1022                 : 
    1023               0 :     aProperty->GetValue(getter_Copies(uri));
    1024                 : 
    1025               0 :     char tv = (aTruthValue ? '-' : '!');
    1026                 :     PR_LogPrint
    1027               0 :            ("  --%c[(%p)%s]--", tv, aProperty, (const char*) uri);
    1028                 : 
    1029               0 :     nsCOMPtr<nsIRDFResource> resource;
    1030               0 :     nsCOMPtr<nsIRDFLiteral> literal;
    1031                 : 
    1032               0 :     if ((resource = do_QueryInterface(aTarget)) != nsnull) {
    1033               0 :         resource->GetValue(getter_Copies(uri));
    1034                 :         PR_LogPrint
    1035               0 :            ("  -->[(%p)%s]", aTarget, (const char*) uri);
    1036                 :     }
    1037               0 :     else if ((literal = do_QueryInterface(aTarget)) != nsnull) {
    1038               0 :         nsXPIDLString value;
    1039               0 :         literal->GetValue(getter_Copies(value));
    1040               0 :         nsAutoString valueStr(value);
    1041               0 :         char* valueCStr = ToNewCString(valueStr);
    1042                 : 
    1043                 :         PR_LogPrint
    1044               0 :            ("  -->(\"%s\")\n", valueCStr);
    1045                 : 
    1046               0 :         NS_Free(valueCStr);
    1047                 :     }
    1048                 :     else {
    1049                 :         PR_LogPrint
    1050               0 :            ("  -->(unknown-type)\n");
    1051                 :     }
    1052                 : }
    1053                 : #endif
    1054                 : 
    1055                 : 
    1056                 : NS_IMETHODIMP
    1057               0 : InMemoryDataSource::GetURI(char* *uri)
    1058                 : {
    1059               0 :     NS_PRECONDITION(uri != nsnull, "null ptr");
    1060               0 :     if (! uri)
    1061               0 :         return NS_ERROR_NULL_POINTER;
    1062                 : 
    1063               0 :     *uri = nsnull;
    1064               0 :     return NS_OK;
    1065                 : }
    1066                 : 
    1067                 : NS_IMETHODIMP
    1068               1 : InMemoryDataSource::GetSource(nsIRDFResource* property,
    1069                 :                               nsIRDFNode* target,
    1070                 :                               bool tv,
    1071                 :                               nsIRDFResource** source)
    1072                 : {
    1073               1 :     NS_PRECONDITION(source != nsnull, "null ptr");
    1074               1 :     if (! source)
    1075               0 :         return NS_ERROR_NULL_POINTER;
    1076                 : 
    1077               1 :     NS_PRECONDITION(property != nsnull, "null ptr");
    1078               1 :     if (! property)
    1079               0 :         return NS_ERROR_NULL_POINTER;
    1080                 : 
    1081               1 :     NS_PRECONDITION(target != nsnull, "null ptr");
    1082               1 :     if (! target)
    1083               0 :         return NS_ERROR_NULL_POINTER;
    1084                 : 
    1085               1 :     for (Assertion* as = GetReverseArcs(target); as; as = as->u.as.mInvNext) {
    1086               1 :         if ((property == as->u.as.mProperty) && (tv == as->u.as.mTruthValue)) {
    1087               1 :             *source = as->mSource;
    1088               1 :             NS_ADDREF(*source);
    1089               1 :             return NS_OK;
    1090                 :         }
    1091                 :     }
    1092               0 :     *source = nsnull;
    1093               0 :     return NS_RDF_NO_VALUE;
    1094                 : }
    1095                 : 
    1096                 : NS_IMETHODIMP
    1097           43680 : InMemoryDataSource::GetTarget(nsIRDFResource* source,
    1098                 :                               nsIRDFResource* property,
    1099                 :                               bool tv,
    1100                 :                               nsIRDFNode** target)
    1101                 : {
    1102           43680 :     NS_PRECONDITION(source != nsnull, "null ptr");
    1103           43680 :     if (! source)
    1104               0 :         return NS_ERROR_NULL_POINTER;
    1105                 : 
    1106           43680 :     NS_PRECONDITION(property != nsnull, "null ptr");
    1107           43680 :     if (! property)
    1108               0 :         return NS_ERROR_NULL_POINTER;
    1109                 : 
    1110           43680 :     NS_PRECONDITION(target != nsnull, "null ptr");
    1111           43680 :     if (! target)
    1112               0 :         return NS_ERROR_NULL_POINTER;
    1113                 : 
    1114           43680 :     Assertion *as = GetForwardArcs(source);
    1115           43680 :     if (as && as->mHashEntry) {
    1116               0 :         PLDHashEntryHdr* hdr = PL_DHashTableOperate(as->u.hash.mPropertyHash, property, PL_DHASH_LOOKUP);
    1117               0 :         Assertion* val = PL_DHASH_ENTRY_IS_BUSY(hdr)
    1118                 :             ? reinterpret_cast<Entry*>(hdr)->mAssertions
    1119               0 :             : nsnull;
    1120               0 :         while (val) {
    1121               0 :             if (tv == val->u.as.mTruthValue) {
    1122               0 :                 *target = val->u.as.mTarget;
    1123               0 :                 NS_IF_ADDREF(*target);
    1124               0 :                 return NS_OK;
    1125                 :             }
    1126               0 :             val = val->mNext;
    1127               0 :         }
    1128                 :     }
    1129                 :     else
    1130          200128 :     for (; as != nsnull; as = as->mNext) {
    1131          173649 :         if ((property == as->u.as.mProperty) && (tv == (as->u.as.mTruthValue))) {
    1132           17201 :             *target = as->u.as.mTarget;
    1133           17201 :             NS_ADDREF(*target);
    1134           17201 :             return NS_OK;
    1135                 :         }
    1136                 :     }
    1137                 : 
    1138                 :     // If we get here, then there was no target with for the specified
    1139                 :     // property & truth value.
    1140           26479 :     *target = nsnull;
    1141           26479 :     return NS_RDF_NO_VALUE;
    1142                 : }
    1143                 : 
    1144                 : NS_IMETHODIMP
    1145            9699 : InMemoryDataSource::HasAssertion(nsIRDFResource* source,
    1146                 :                                  nsIRDFResource* property,
    1147                 :                                  nsIRDFNode* target,
    1148                 :                                  bool tv,
    1149                 :                                  bool* hasAssertion)
    1150                 : {
    1151            9699 :     if (! source)
    1152               0 :         return NS_ERROR_NULL_POINTER;
    1153                 : 
    1154            9699 :     if (! property)
    1155               0 :         return NS_ERROR_NULL_POINTER;
    1156                 : 
    1157            9699 :     if (! target)
    1158               0 :         return NS_ERROR_NULL_POINTER;
    1159                 : 
    1160            9699 :     Assertion *as = GetForwardArcs(source);
    1161            9699 :     if (as && as->mHashEntry) {
    1162               0 :         PLDHashEntryHdr* hdr = PL_DHashTableOperate(as->u.hash.mPropertyHash, property, PL_DHASH_LOOKUP);
    1163               0 :         Assertion* val = PL_DHASH_ENTRY_IS_BUSY(hdr)
    1164                 :             ? reinterpret_cast<Entry*>(hdr)->mAssertions
    1165               0 :             : nsnull;
    1166               0 :         while (val) {
    1167               0 :             if ((val->u.as.mTarget == target) && (tv == (val->u.as.mTruthValue))) {
    1168               0 :                 *hasAssertion = true;
    1169               0 :                 return NS_OK;
    1170                 :             }
    1171               0 :             val = val->mNext;
    1172               0 :         }
    1173                 :     }
    1174                 :     else
    1175           12282 :     for (; as != nsnull; as = as->mNext) {
    1176                 :         // check target first as its most unique
    1177            5262 :         if (target != as->u.as.mTarget)
    1178            2583 :             continue;
    1179                 : 
    1180            2679 :         if (property != as->u.as.mProperty)
    1181               0 :             continue;
    1182                 : 
    1183            2679 :         if (tv != (as->u.as.mTruthValue))
    1184               0 :             continue;
    1185                 : 
    1186                 :         // found it!
    1187            2679 :         *hasAssertion = true;
    1188            2679 :         return NS_OK;
    1189                 :     }
    1190                 : 
    1191                 :     // If we get here, we couldn't find the assertion
    1192            7020 :     *hasAssertion = false;
    1193            7020 :     return NS_OK;
    1194                 : }
    1195                 : 
    1196                 : NS_IMETHODIMP
    1197               5 : InMemoryDataSource::GetSources(nsIRDFResource* aProperty,
    1198                 :                                nsIRDFNode* aTarget,
    1199                 :                                bool aTruthValue,
    1200                 :                                nsISimpleEnumerator** aResult)
    1201                 : {
    1202               5 :     NS_PRECONDITION(aProperty != nsnull, "null ptr");
    1203               5 :     if (! aProperty)
    1204               0 :         return NS_ERROR_NULL_POINTER;
    1205                 : 
    1206               5 :     NS_PRECONDITION(aTarget != nsnull, "null ptr");
    1207               5 :     if (! aTarget)
    1208               0 :         return NS_ERROR_NULL_POINTER;
    1209                 : 
    1210               5 :     NS_PRECONDITION(aResult != nsnull, "null ptr");
    1211               5 :     if (! aResult)
    1212               0 :         return NS_ERROR_NULL_POINTER;
    1213                 : 
    1214                 :     InMemoryAssertionEnumeratorImpl* result =
    1215                 :         InMemoryAssertionEnumeratorImpl::Create(this, nsnull, aProperty,
    1216               5 :                                                   aTarget, aTruthValue);
    1217                 : 
    1218               5 :     if (! result)
    1219               0 :         return NS_ERROR_OUT_OF_MEMORY;
    1220                 : 
    1221               5 :     NS_ADDREF(result);
    1222               5 :     *aResult = result;
    1223                 : 
    1224               5 :     return NS_OK;
    1225                 : }
    1226                 : 
    1227                 : NS_IMETHODIMP
    1228           13715 : InMemoryDataSource::GetTargets(nsIRDFResource* aSource,
    1229                 :                                nsIRDFResource* aProperty,
    1230                 :                                bool aTruthValue,
    1231                 :                                nsISimpleEnumerator** aResult)
    1232                 : {
    1233           13715 :     NS_PRECONDITION(aSource != nsnull, "null ptr");
    1234           13715 :     if (! aSource)
    1235               0 :         return NS_ERROR_NULL_POINTER;
    1236                 :     
    1237           13715 :     NS_PRECONDITION(aProperty != nsnull, "null ptr");
    1238           13715 :     if (! aProperty)
    1239               0 :         return NS_ERROR_NULL_POINTER;
    1240                 : 
    1241           13715 :     NS_PRECONDITION(aResult != nsnull, "null ptr");
    1242           13715 :     if (! aResult)
    1243               0 :         return NS_ERROR_NULL_POINTER;
    1244                 : 
    1245                 :     InMemoryAssertionEnumeratorImpl* result =
    1246                 :         InMemoryAssertionEnumeratorImpl::Create(this, aSource, aProperty,
    1247           13715 :                                                 nsnull, aTruthValue);
    1248                 : 
    1249           13715 :     if (! result)
    1250               0 :         return NS_ERROR_OUT_OF_MEMORY;
    1251                 : 
    1252           13715 :     NS_ADDREF(result);
    1253           13715 :     *aResult = result;
    1254                 : 
    1255           13715 :     return NS_OK;
    1256                 : }
    1257                 : 
    1258                 : 
    1259                 : nsresult
    1260           36442 : InMemoryDataSource::LockedAssert(nsIRDFResource* aSource,
    1261                 :                                  nsIRDFResource* aProperty,
    1262                 :                                  nsIRDFNode* aTarget,
    1263                 :                                  bool aTruthValue)
    1264                 : {
    1265                 : #ifdef PR_LOGGING
    1266           36442 :     LogOperation("ASSERT", aSource, aProperty, aTarget, aTruthValue);
    1267                 : #endif
    1268                 : 
    1269           36442 :     Assertion* next = GetForwardArcs(aSource);
    1270           36442 :     Assertion* prev = next;
    1271           36442 :     Assertion* as = nsnull;
    1272                 : 
    1273           36442 :     bool    haveHash = (next) ? next->mHashEntry : false;
    1274           36442 :     if (haveHash) {
    1275               0 :         PLDHashEntryHdr* hdr = PL_DHashTableOperate(next->u.hash.mPropertyHash, aProperty, PL_DHASH_LOOKUP);
    1276               0 :         Assertion* val = PL_DHASH_ENTRY_IS_BUSY(hdr)
    1277                 :             ? reinterpret_cast<Entry*>(hdr)->mAssertions
    1278               0 :             : nsnull;
    1279               0 :         while (val) {
    1280               0 :             if (val->u.as.mTarget == aTarget) {
    1281                 :                 // Wow, we already had the assertion. Make sure that the
    1282                 :                 // truth values are correct and bail.
    1283               0 :                 val->u.as.mTruthValue = aTruthValue;
    1284               0 :                 return NS_OK;
    1285                 :             }
    1286               0 :             val = val->mNext;
    1287                 :         }
    1288                 :     }
    1289                 :     else
    1290                 :     {
    1291          125404 :         while (next) {
    1292                 :             // check target first as its most unique
    1293           52524 :             if (aTarget == next->u.as.mTarget) {
    1294            2405 :                 if (aProperty == next->u.as.mProperty) {
    1295                 :                     // Wow, we already had the assertion. Make sure that the
    1296                 :                     // truth values are correct and bail.
    1297               4 :                     next->u.as.mTruthValue = aTruthValue;
    1298               4 :                     return NS_OK;
    1299                 :                 }
    1300                 :             }
    1301                 : 
    1302           52520 :             prev = next;
    1303           52520 :             next = next->mNext;
    1304                 :         }
    1305                 :     }
    1306                 : 
    1307           36438 :     as = Assertion::Create(mAllocator, aSource, aProperty, aTarget, aTruthValue);
    1308           36438 :     if (! as)
    1309               0 :         return NS_ERROR_OUT_OF_MEMORY;
    1310                 : 
    1311                 :     // Add the datasource's owning reference.
    1312           36438 :     as->AddRef();
    1313                 : 
    1314           36438 :     if (haveHash)
    1315                 :     {
    1316                 :         PLDHashEntryHdr* hdr = PL_DHashTableOperate(next->u.hash.mPropertyHash,
    1317               0 :             aProperty, PL_DHASH_LOOKUP);
    1318               0 :         Assertion *asRef = PL_DHASH_ENTRY_IS_BUSY(hdr)
    1319                 :             ? reinterpret_cast<Entry*>(hdr)->mAssertions
    1320               0 :             : nsnull;
    1321               0 :         if (asRef)
    1322                 :         {
    1323               0 :             as->mNext = asRef->mNext;
    1324               0 :             asRef->mNext = as;
    1325                 :         }
    1326                 :         else
    1327                 :         {
    1328                 :             hdr = PL_DHashTableOperate(next->u.hash.mPropertyHash,
    1329               0 :                                             aProperty, PL_DHASH_ADD);
    1330               0 :             if (hdr)
    1331                 :             {
    1332               0 :                 Entry* entry = reinterpret_cast<Entry*>(hdr);
    1333               0 :                 entry->mNode = aProperty;
    1334               0 :                 entry->mAssertions = as;
    1335                 :             }
    1336                 :         }
    1337                 :     }
    1338                 :     else
    1339                 :     {
    1340                 :         // Link it in to the "forward arcs" table
    1341           36438 :         if (!prev) {
    1342           10867 :             SetForwardArcs(aSource, as);
    1343                 :         } else {
    1344           25571 :             prev->mNext = as;
    1345                 :         }
    1346                 :     }
    1347                 : 
    1348                 :     // Link it in to the "reverse arcs" table
    1349                 : 
    1350           36438 :     next = GetReverseArcs(aTarget);
    1351           36438 :     as->u.as.mInvNext = next;
    1352           36438 :     next = as;
    1353           36438 :     SetReverseArcs(aTarget, next);
    1354                 : 
    1355           36438 :     return NS_OK;
    1356                 : }
    1357                 : 
    1358                 : NS_IMETHODIMP
    1359           36408 : InMemoryDataSource::Assert(nsIRDFResource* aSource,
    1360                 :                            nsIRDFResource* aProperty, 
    1361                 :                            nsIRDFNode* aTarget,
    1362                 :                            bool aTruthValue) 
    1363                 : {
    1364           36408 :     NS_PRECONDITION(aSource != nsnull, "null ptr");
    1365           36408 :     if (! aSource)
    1366               0 :         return NS_ERROR_NULL_POINTER;
    1367                 : 
    1368           36408 :     NS_PRECONDITION(aProperty != nsnull, "null ptr");
    1369           36408 :     if (! aProperty)
    1370               0 :         return NS_ERROR_NULL_POINTER;
    1371                 : 
    1372           36408 :     NS_PRECONDITION(aTarget != nsnull, "null ptr");
    1373           36408 :     if (! aTarget)
    1374               0 :         return NS_ERROR_NULL_POINTER;
    1375                 : 
    1376           36408 :     if (mReadCount) {
    1377               0 :         NS_WARNING("Writing to InMemoryDataSource during read\n");
    1378               0 :         return NS_RDF_ASSERTION_REJECTED;
    1379                 :     }
    1380                 : 
    1381                 :     nsresult rv;
    1382           36408 :     rv = LockedAssert(aSource, aProperty, aTarget, aTruthValue);
    1383           36408 :     if (NS_FAILED(rv)) return rv;
    1384                 : 
    1385                 :     // notify observers
    1386           36408 :     for (PRInt32 i = (PRInt32)mNumObservers - 1; mPropagateChanges && i >= 0; --i) {
    1387               0 :         nsIRDFObserver* obs = mObservers[i];
    1388                 : 
    1389                 :         // XXX this should never happen, but it does, and we can't figure out why.
    1390               0 :         NS_ASSERTION(obs, "observer array corrupted!");
    1391               0 :         if (! obs)
    1392               0 :           continue;
    1393                 : 
    1394               0 :         obs->OnAssert(this, aSource, aProperty, aTarget);
    1395                 :         // XXX ignore return value?
    1396                 :     }
    1397                 : 
    1398           36408 :     return NS_RDF_ASSERTION_ACCEPTED;
    1399                 : }
    1400                 : 
    1401                 : 
    1402                 : nsresult
    1403            2084 : InMemoryDataSource::LockedUnassert(nsIRDFResource* aSource,
    1404                 :                                    nsIRDFResource* aProperty,
    1405                 :                                    nsIRDFNode* aTarget)
    1406                 : {
    1407                 : #ifdef PR_LOGGING
    1408            2084 :     LogOperation("UNASSERT", aSource, aProperty, aTarget);
    1409                 : #endif
    1410                 : 
    1411            2084 :     Assertion* next = GetForwardArcs(aSource);
    1412            2084 :     Assertion* prev = next;
    1413            2084 :     Assertion* root = next;
    1414            2084 :     Assertion* as = nsnull;
    1415                 :     
    1416            2084 :     bool    haveHash = (next) ? next->mHashEntry : false;
    1417            2084 :     if (haveHash) {
    1418                 :         PLDHashEntryHdr* hdr = PL_DHashTableOperate(next->u.hash.mPropertyHash,
    1419               0 :             aProperty, PL_DHASH_LOOKUP);
    1420               0 :         prev = next = PL_DHASH_ENTRY_IS_BUSY(hdr)
    1421                 :             ? reinterpret_cast<Entry*>(hdr)->mAssertions
    1422               0 :             : nsnull;
    1423               0 :         bool first = true;
    1424               0 :         while (next) {
    1425               0 :             if (aTarget == next->u.as.mTarget) {
    1426               0 :                 break;
    1427                 :             }
    1428               0 :             first = false;
    1429               0 :             prev = next;
    1430               0 :             next = next->mNext;
    1431                 :         }
    1432                 :         // We don't even have the assertion, so just bail.
    1433               0 :         if (!next)
    1434               0 :             return NS_OK;
    1435                 : 
    1436               0 :         as = next;
    1437                 : 
    1438               0 :         if (first) {
    1439               0 :             PL_DHashTableRawRemove(root->u.hash.mPropertyHash, hdr);
    1440                 : 
    1441               0 :             if (next && next->mNext) {
    1442                 :                 PLDHashEntryHdr* hdr = PL_DHashTableOperate(root->u.hash.mPropertyHash,
    1443               0 :                                      aProperty, PL_DHASH_ADD);
    1444               0 :                 if (hdr) {
    1445               0 :                     Entry* entry = reinterpret_cast<Entry*>(hdr);
    1446               0 :                     entry->mNode = aProperty;
    1447               0 :                     entry->mAssertions = next->mNext;
    1448               0 :                 }
    1449                 :             }
    1450                 :             else {
    1451                 :                 // If this second-level hash empties out, clean it up.
    1452               0 :                 if (!root->u.hash.mPropertyHash->entryCount) {
    1453               0 :                     Assertion::Destroy(mAllocator, root);
    1454               0 :                     SetForwardArcs(aSource, nsnull);
    1455                 :                 }
    1456                 :             }
    1457                 :         }
    1458                 :         else {
    1459               0 :             prev->mNext = next->mNext;
    1460                 :         }
    1461                 :     }
    1462                 :     else
    1463                 :     {
    1464            6775 :         while (next) {
    1465                 :             // check target first as its most unique
    1466            4691 :             if (aTarget == next->u.as.mTarget) {
    1467            2084 :                 if (aProperty == next->u.as.mProperty) {
    1468            2084 :                     if (prev == next) {
    1469              48 :                         SetForwardArcs(aSource, next->mNext);
    1470                 :                     } else {
    1471            2036 :                         prev->mNext = next->mNext;
    1472                 :                     }
    1473            2084 :                     as = next;
    1474            2084 :                     break;
    1475                 :                 }
    1476                 :             }
    1477                 : 
    1478            2607 :             prev = next;
    1479            2607 :             next = next->mNext;
    1480                 :         }
    1481                 :     }
    1482                 :     // We don't even have the assertion, so just bail.
    1483            2084 :     if (!as)
    1484               0 :         return NS_OK;
    1485                 : 
    1486                 : #ifdef DEBUG
    1487            2084 :     bool foundReverseArc = false;
    1488                 : #endif
    1489                 : 
    1490            2084 :     next = prev = GetReverseArcs(aTarget);
    1491            5598 :     while (next) {
    1492            3514 :         if (next == as) {
    1493            2084 :             if (prev == next) {
    1494            1184 :                 SetReverseArcs(aTarget, next->u.as.mInvNext);
    1495                 :             } else {
    1496             900 :                 prev->u.as.mInvNext = next->u.as.mInvNext;
    1497                 :             }
    1498                 : #ifdef DEBUG
    1499            2084 :             foundReverseArc = true;
    1500                 : #endif
    1501            2084 :             break;
    1502                 :         }
    1503            1430 :         prev = next;
    1504            1430 :         next = next->u.as.mInvNext;
    1505                 :     }
    1506                 : 
    1507                 : #ifdef DEBUG
    1508            2084 :     NS_ASSERTION(foundReverseArc, "in-memory db corrupted: unable to find reverse arc");
    1509                 : #endif
    1510                 : 
    1511                 :     // Unlink, and release the datasource's reference
    1512            2084 :     as->mNext = as->u.as.mInvNext = nsnull;
    1513            2084 :     as->Release(mAllocator);
    1514                 : 
    1515            2084 :     return NS_OK;
    1516                 : }
    1517                 : 
    1518                 : NS_IMETHODIMP
    1519            2050 : InMemoryDataSource::Unassert(nsIRDFResource* aSource,
    1520                 :                              nsIRDFResource* aProperty,
    1521                 :                              nsIRDFNode* aTarget)
    1522                 : {
    1523            2050 :     NS_PRECONDITION(aSource != nsnull, "null ptr");
    1524            2050 :     if (! aSource)
    1525               0 :         return NS_ERROR_NULL_POINTER;
    1526                 : 
    1527            2050 :     NS_PRECONDITION(aProperty != nsnull, "null ptr");
    1528            2050 :     if (! aProperty)
    1529               0 :         return NS_ERROR_NULL_POINTER;
    1530                 : 
    1531            2050 :     NS_PRECONDITION(aTarget != nsnull, "null ptr");
    1532            2050 :     if (! aTarget)
    1533               0 :         return NS_ERROR_NULL_POINTER;
    1534                 : 
    1535            2050 :     if (mReadCount) {
    1536               0 :         NS_WARNING("Writing to InMemoryDataSource during read\n");
    1537               0 :         return NS_RDF_ASSERTION_REJECTED;
    1538                 :     }
    1539                 : 
    1540                 :     nsresult rv;
    1541                 : 
    1542            2050 :     rv = LockedUnassert(aSource, aProperty, aTarget);
    1543            2050 :     if (NS_FAILED(rv)) return rv;
    1544                 : 
    1545                 :     // Notify the world
    1546            2050 :     for (PRInt32 i = PRInt32(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
    1547               0 :         nsIRDFObserver* obs = mObservers[i];
    1548                 : 
    1549                 :         // XXX this should never happen, but it does, and we can't figure out why.
    1550               0 :         NS_ASSERTION(obs, "observer array corrupted!");
    1551               0 :         if (! obs)
    1552               0 :           continue;
    1553                 : 
    1554               0 :         obs->OnUnassert(this, aSource, aProperty, aTarget);
    1555                 :         // XXX ignore return value?
    1556                 :     }
    1557                 : 
    1558            2050 :     return NS_RDF_ASSERTION_ACCEPTED;
    1559                 : }
    1560                 : 
    1561                 : 
    1562                 : NS_IMETHODIMP
    1563              34 : InMemoryDataSource::Change(nsIRDFResource* aSource,
    1564                 :                            nsIRDFResource* aProperty,
    1565                 :                            nsIRDFNode* aOldTarget,
    1566                 :                            nsIRDFNode* aNewTarget)
    1567                 : {
    1568              34 :     NS_PRECONDITION(aSource != nsnull, "null ptr");
    1569              34 :     if (! aSource)
    1570               0 :         return NS_ERROR_NULL_POINTER;
    1571                 : 
    1572              34 :     NS_PRECONDITION(aProperty != nsnull, "null ptr");
    1573              34 :     if (! aProperty)
    1574               0 :         return NS_ERROR_NULL_POINTER;
    1575                 : 
    1576              34 :     NS_PRECONDITION(aOldTarget != nsnull, "null ptr");
    1577              34 :     if (! aOldTarget)
    1578               0 :         return NS_ERROR_NULL_POINTER;
    1579                 : 
    1580              34 :     NS_PRECONDITION(aNewTarget != nsnull, "null ptr");
    1581              34 :     if (! aNewTarget)
    1582               0 :         return NS_ERROR_NULL_POINTER;
    1583                 : 
    1584              34 :     if (mReadCount) {
    1585               0 :         NS_WARNING("Writing to InMemoryDataSource during read\n");
    1586               0 :         return NS_RDF_ASSERTION_REJECTED;
    1587                 :     }
    1588                 : 
    1589                 :     nsresult rv;
    1590                 : 
    1591                 :     // XXX We can implement LockedChange() if we decide that this
    1592                 :     // is a performance bottleneck.
    1593                 : 
    1594              34 :     rv = LockedUnassert(aSource, aProperty, aOldTarget);
    1595              34 :     if (NS_FAILED(rv)) return rv;
    1596                 : 
    1597              34 :     rv = LockedAssert(aSource, aProperty, aNewTarget, true);
    1598              34 :     if (NS_FAILED(rv)) return rv;
    1599                 : 
    1600                 :     // Notify the world
    1601              34 :     for (PRInt32 i = PRInt32(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
    1602               0 :         nsIRDFObserver* obs = mObservers[i];
    1603                 : 
    1604                 :         // XXX this should never happen, but it does, and we can't figure out why.
    1605               0 :         NS_ASSERTION(obs, "observer array corrupted!");
    1606               0 :         if (! obs)
    1607               0 :           continue;
    1608                 : 
    1609               0 :         obs->OnChange(this, aSource, aProperty, aOldTarget, aNewTarget);
    1610                 :         // XXX ignore return value?
    1611                 :     }
    1612                 : 
    1613              34 :     return NS_RDF_ASSERTION_ACCEPTED;
    1614                 : }
    1615                 : 
    1616                 : 
    1617                 : NS_IMETHODIMP
    1618               0 : InMemoryDataSource::Move(nsIRDFResource* aOldSource,
    1619                 :                          nsIRDFResource* aNewSource,
    1620                 :                          nsIRDFResource* aProperty,
    1621                 :                          nsIRDFNode* aTarget)
    1622                 : {
    1623               0 :     NS_PRECONDITION(aOldSource != nsnull, "null ptr");
    1624               0 :     if (! aOldSource)
    1625               0 :         return NS_ERROR_NULL_POINTER;
    1626                 : 
    1627               0 :     NS_PRECONDITION(aNewSource != nsnull, "null ptr");
    1628               0 :     if (! aNewSource)
    1629               0 :         return NS_ERROR_NULL_POINTER;
    1630                 : 
    1631               0 :     NS_PRECONDITION(aProperty != nsnull, "null ptr");
    1632               0 :     if (! aProperty)
    1633               0 :         return NS_ERROR_NULL_POINTER;
    1634                 : 
    1635               0 :     NS_PRECONDITION(aTarget != nsnull, "null ptr");
    1636               0 :     if (! aTarget)
    1637               0 :         return NS_ERROR_NULL_POINTER;
    1638                 : 
    1639               0 :     if (mReadCount) {
    1640               0 :         NS_WARNING("Writing to InMemoryDataSource during read\n");
    1641               0 :         return NS_RDF_ASSERTION_REJECTED;
    1642                 :     }
    1643                 : 
    1644                 :     nsresult rv;
    1645                 : 
    1646                 :     // XXX We can implement LockedMove() if we decide that this
    1647                 :     // is a performance bottleneck.
    1648                 : 
    1649               0 :     rv = LockedUnassert(aOldSource, aProperty, aTarget);
    1650               0 :     if (NS_FAILED(rv)) return rv;
    1651                 : 
    1652               0 :     rv = LockedAssert(aNewSource, aProperty, aTarget, true);
    1653               0 :     if (NS_FAILED(rv)) return rv;
    1654                 : 
    1655                 :     // Notify the world
    1656               0 :     for (PRInt32 i = PRInt32(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
    1657               0 :         nsIRDFObserver* obs = mObservers[i];
    1658                 : 
    1659                 :         // XXX this should never happen, but it does, and we can't figure out why.
    1660               0 :         NS_ASSERTION(obs, "observer array corrupted!");
    1661               0 :         if (! obs)
    1662               0 :           continue;
    1663                 : 
    1664               0 :         obs->OnMove(this, aOldSource, aNewSource, aProperty, aTarget);
    1665                 :         // XXX ignore return value?
    1666                 :     }
    1667                 : 
    1668               0 :     return NS_RDF_ASSERTION_ACCEPTED;
    1669                 : }
    1670                 : 
    1671                 : 
    1672                 : NS_IMETHODIMP
    1673               0 : InMemoryDataSource::AddObserver(nsIRDFObserver* aObserver)
    1674                 : {
    1675               0 :     NS_PRECONDITION(aObserver != nsnull, "null ptr");
    1676               0 :     if (! aObserver)
    1677               0 :         return NS_ERROR_NULL_POINTER;
    1678                 : 
    1679               0 :     mObservers.AppendObject(aObserver);
    1680               0 :     mNumObservers = mObservers.Count();
    1681                 : 
    1682               0 :     return NS_OK;
    1683                 : }
    1684                 : 
    1685                 : NS_IMETHODIMP
    1686               0 : InMemoryDataSource::RemoveObserver(nsIRDFObserver* aObserver)
    1687                 : {
    1688               0 :     NS_PRECONDITION(aObserver != nsnull, "null ptr");
    1689               0 :     if (! aObserver)
    1690               0 :         return NS_ERROR_NULL_POINTER;
    1691                 : 
    1692               0 :     mObservers.RemoveObject(aObserver);
    1693                 :     // note: use Count() instead of just decrementing
    1694                 :     // in case aObserver wasn't in list, for example
    1695               0 :     mNumObservers = mObservers.Count();
    1696                 : 
    1697               0 :     return NS_OK;
    1698                 : }
    1699                 : 
    1700                 : NS_IMETHODIMP 
    1701               6 : InMemoryDataSource::HasArcIn(nsIRDFNode *aNode, nsIRDFResource *aArc, bool *result)
    1702                 : {
    1703               6 :     Assertion* ass = GetReverseArcs(aNode);
    1704              12 :     while (ass) {
    1705               2 :         nsIRDFResource* elbow = ass->u.as.mProperty;
    1706               2 :         if (elbow == aArc) {
    1707               2 :             *result = true;
    1708               2 :             return NS_OK;
    1709                 :         }
    1710               0 :         ass = ass->u.as.mInvNext;
    1711                 :     }
    1712               4 :     *result = false;
    1713               4 :     return NS_OK;
    1714                 : }
    1715                 : 
    1716                 : NS_IMETHODIMP 
    1717             431 : InMemoryDataSource::HasArcOut(nsIRDFResource *aSource, nsIRDFResource *aArc, bool *result)
    1718                 : {
    1719             431 :     Assertion* ass = GetForwardArcs(aSource);
    1720             431 :     if (ass && ass->mHashEntry) {
    1721                 :         PLDHashEntryHdr* hdr = PL_DHashTableOperate(ass->u.hash.mPropertyHash,
    1722               0 :             aArc, PL_DHASH_LOOKUP);
    1723               0 :         Assertion* val = PL_DHASH_ENTRY_IS_BUSY(hdr)
    1724                 :             ? reinterpret_cast<Entry*>(hdr)->mAssertions
    1725               0 :             : nsnull;
    1726               0 :         if (val) {
    1727               0 :             *result = true;
    1728               0 :             return NS_OK;
    1729                 :         }
    1730               0 :         ass = ass->mNext;
    1731                 :     }
    1732            1350 :     while (ass) {
    1733             601 :         nsIRDFResource* elbow = ass->u.as.mProperty;
    1734             601 :         if (elbow == aArc) {
    1735             113 :             *result = true;
    1736             113 :             return NS_OK;
    1737                 :         }
    1738             488 :         ass = ass->mNext;
    1739                 :     }
    1740             318 :     *result = false;
    1741             318 :     return NS_OK;
    1742                 : }
    1743                 : 
    1744                 : NS_IMETHODIMP
    1745              19 : InMemoryDataSource::ArcLabelsIn(nsIRDFNode* aTarget, nsISimpleEnumerator** aResult)
    1746                 : {
    1747              19 :     NS_PRECONDITION(aTarget != nsnull, "null ptr");
    1748              19 :     if (! aTarget)
    1749               0 :         return NS_ERROR_NULL_POINTER;
    1750                 : 
    1751                 :     InMemoryArcsEnumeratorImpl* result =
    1752              19 :         InMemoryArcsEnumeratorImpl::Create(this, nsnull, aTarget);
    1753                 : 
    1754              19 :     if (! result)
    1755               0 :         return NS_ERROR_OUT_OF_MEMORY;
    1756                 : 
    1757              19 :     NS_ADDREF(result);
    1758              19 :     *aResult = result;
    1759                 : 
    1760              19 :     return NS_OK;
    1761                 : }
    1762                 : 
    1763                 : NS_IMETHODIMP
    1764             629 : InMemoryDataSource::ArcLabelsOut(nsIRDFResource* aSource, nsISimpleEnumerator** aResult)
    1765                 : {
    1766             629 :     NS_PRECONDITION(aSource != nsnull, "null ptr");
    1767             629 :     if (! aSource)
    1768               0 :         return NS_ERROR_NULL_POINTER;
    1769                 : 
    1770                 :     InMemoryArcsEnumeratorImpl* result =
    1771             629 :         InMemoryArcsEnumeratorImpl::Create(this, aSource, nsnull);
    1772                 : 
    1773             629 :     if (! result)
    1774               0 :         return NS_ERROR_OUT_OF_MEMORY;
    1775                 : 
    1776             629 :     NS_ADDREF(result);
    1777             629 :     *aResult = result;
    1778                 : 
    1779             629 :     return NS_OK;
    1780                 : }
    1781                 : 
    1782                 : PLDHashOperator
    1783             349 : InMemoryDataSource::ResourceEnumerator(PLDHashTable* aTable,
    1784                 :                                        PLDHashEntryHdr* aHdr,
    1785                 :                                        PRUint32 aNumber, void* aArg)
    1786                 : {
    1787             349 :     Entry* entry = reinterpret_cast<Entry*>(aHdr);
    1788             349 :     nsISupportsArray* resources = static_cast<nsISupportsArray*>(aArg);
    1789                 : 
    1790             349 :     resources->AppendElement(entry->mNode);
    1791             349 :     return PL_DHASH_NEXT;
    1792                 : }
    1793                 : 
    1794                 : 
    1795                 : NS_IMETHODIMP
    1796              19 : InMemoryDataSource::GetAllResources(nsISimpleEnumerator** aResult)
    1797                 : {
    1798                 :     nsresult rv;
    1799                 : 
    1800              38 :     nsCOMPtr<nsISupportsArray> values;
    1801              19 :     rv = NS_NewISupportsArray(getter_AddRefs(values));
    1802              19 :     if (NS_FAILED(rv)) return rv;
    1803                 : 
    1804                 :     // Enumerate all of our entries into an nsISupportsArray.
    1805              19 :     PL_DHashTableEnumerate(&mForwardArcs, ResourceEnumerator, values.get());
    1806                 : 
    1807              19 :     return NS_NewArrayEnumerator(aResult, values);
    1808                 : }
    1809                 : 
    1810                 : NS_IMETHODIMP
    1811               0 : InMemoryDataSource::GetAllCmds(nsIRDFResource* source,
    1812                 :                                nsISimpleEnumerator/*<nsIRDFResource>*/** commands)
    1813                 : {
    1814               0 :     return(NS_NewEmptyEnumerator(commands));
    1815                 : }
    1816                 : 
    1817                 : NS_IMETHODIMP
    1818               0 : InMemoryDataSource::IsCommandEnabled(nsISupportsArray/*<nsIRDFResource>*/* aSources,
    1819                 :                                      nsIRDFResource*   aCommand,
    1820                 :                                      nsISupportsArray/*<nsIRDFResource>*/* aArguments,
    1821                 :                                      bool* aResult)
    1822                 : {
    1823               0 :     *aResult = false;
    1824               0 :     return NS_OK;
    1825                 : }
    1826                 : 
    1827                 : NS_IMETHODIMP
    1828               0 : InMemoryDataSource::DoCommand(nsISupportsArray/*<nsIRDFResource>*/* aSources,
    1829                 :                               nsIRDFResource*   aCommand,
    1830                 :                               nsISupportsArray/*<nsIRDFResource>*/* aArguments)
    1831                 : {
    1832               0 :     return NS_OK;
    1833                 : }
    1834                 : 
    1835                 : NS_IMETHODIMP
    1836               0 : InMemoryDataSource::BeginUpdateBatch()
    1837                 : {
    1838               0 :     for (PRInt32 i = PRInt32(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
    1839               0 :         nsIRDFObserver* obs = mObservers[i];
    1840               0 :         obs->OnBeginUpdateBatch(this);
    1841                 :     }
    1842               0 :     return NS_OK;
    1843                 : }
    1844                 : 
    1845                 : NS_IMETHODIMP
    1846               0 : InMemoryDataSource::EndUpdateBatch()
    1847                 : {
    1848               0 :     for (PRInt32 i = PRInt32(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
    1849               0 :         nsIRDFObserver* obs = mObservers[i];
    1850               0 :         obs->OnEndUpdateBatch(this);
    1851                 :     }
    1852               0 :     return NS_OK;
    1853                 : }
    1854                 : 
    1855                 : 
    1856                 : 
    1857                 : ////////////////////////////////////////////////////////////////////////
    1858                 : // nsIRDFInMemoryDataSource methods
    1859                 : 
    1860                 : NS_IMETHODIMP
    1861               0 : InMemoryDataSource::EnsureFastContainment(nsIRDFResource* aSource)
    1862                 : {
    1863               0 :     Assertion *as = GetForwardArcs(aSource);
    1864               0 :     bool    haveHash = (as) ? as->mHashEntry : false;
    1865                 :     
    1866                 :     // if its already a hash, then nothing to do
    1867               0 :     if (haveHash)   return(NS_OK);
    1868                 : 
    1869                 :     // convert aSource in forward hash into a hash
    1870               0 :     Assertion *hashAssertion = Assertion::Create(mAllocator, aSource);
    1871               0 :     NS_ASSERTION(hashAssertion, "unable to Assertion::Create");
    1872               0 :     if (!hashAssertion) return(NS_ERROR_OUT_OF_MEMORY);
    1873                 : 
    1874                 :     // Add the datasource's owning reference.
    1875               0 :     hashAssertion->AddRef();
    1876                 : 
    1877               0 :     register Assertion *first = GetForwardArcs(aSource);
    1878               0 :     SetForwardArcs(aSource, hashAssertion);
    1879                 : 
    1880                 :     // mutate references of existing forward assertions into this hash
    1881               0 :     PLDHashTable *table = hashAssertion->u.hash.mPropertyHash;
    1882                 :     Assertion *nextRef;
    1883               0 :     while(first) {
    1884               0 :         nextRef = first->mNext;
    1885               0 :         nsIRDFResource *prop = first->u.as.mProperty;
    1886                 : 
    1887                 :         PLDHashEntryHdr* hdr = PL_DHashTableOperate(table,
    1888               0 :             prop, PL_DHASH_LOOKUP);
    1889               0 :         Assertion* val = PL_DHASH_ENTRY_IS_BUSY(hdr)
    1890                 :             ? reinterpret_cast<Entry*>(hdr)->mAssertions
    1891               0 :             : nsnull;
    1892               0 :         if (val) {
    1893               0 :             first->mNext = val->mNext;
    1894               0 :             val->mNext = first;
    1895                 :         }
    1896                 :         else {
    1897                 :             PLDHashEntryHdr* hdr = PL_DHashTableOperate(table,
    1898               0 :                                             prop, PL_DHASH_ADD);
    1899               0 :             if (hdr) {
    1900               0 :                 Entry* entry = reinterpret_cast<Entry*>(hdr);
    1901               0 :                 entry->mNode = prop;
    1902               0 :                 entry->mAssertions = first;
    1903               0 :                 first->mNext = nsnull;
    1904                 :             }
    1905                 :         }
    1906               0 :         first = nextRef;
    1907                 :     }
    1908               0 :     return(NS_OK);
    1909                 : }
    1910                 : 
    1911                 : 
    1912                 : ////////////////////////////////////////////////////////////////////////
    1913                 : // nsIRDFPropagatableDataSource methods
    1914                 : NS_IMETHODIMP
    1915               0 : InMemoryDataSource::GetPropagateChanges(bool* aPropagateChanges)
    1916                 : {
    1917               0 :     *aPropagateChanges = mPropagateChanges;
    1918               0 :     return NS_OK;
    1919                 : }
    1920                 : 
    1921                 : NS_IMETHODIMP
    1922               0 : InMemoryDataSource::SetPropagateChanges(bool aPropagateChanges)
    1923                 : {
    1924               0 :     mPropagateChanges = aPropagateChanges;
    1925               0 :     return NS_OK;
    1926                 : }
    1927                 : 
    1928                 : 
    1929                 : ////////////////////////////////////////////////////////////////////////
    1930                 : // nsIRDFPurgeableDataSource methods
    1931                 : 
    1932                 : NS_IMETHODIMP
    1933             742 : InMemoryDataSource::Mark(nsIRDFResource* aSource,
    1934                 :                          nsIRDFResource* aProperty,
    1935                 :                          nsIRDFNode* aTarget,
    1936                 :                          bool aTruthValue,
    1937                 :                          bool* aDidMark)
    1938                 : {
    1939             742 :     NS_PRECONDITION(aSource != nsnull, "null ptr");
    1940             742 :     if (! aSource)
    1941               0 :         return NS_ERROR_NULL_POINTER;
    1942                 : 
    1943             742 :     NS_PRECONDITION(aProperty != nsnull, "null ptr");
    1944             742 :     if (! aProperty)
    1945               0 :         return NS_ERROR_NULL_POINTER;
    1946                 : 
    1947             742 :     NS_PRECONDITION(aTarget != nsnull, "null ptr");
    1948             742 :     if (! aTarget)
    1949               0 :         return NS_ERROR_NULL_POINTER;
    1950                 : 
    1951             742 :     Assertion *as = GetForwardArcs(aSource);
    1952             742 :     if (as && as->mHashEntry) {
    1953                 :         PLDHashEntryHdr* hdr = PL_DHashTableOperate(as->u.hash.mPropertyHash,
    1954               0 :             aProperty, PL_DHASH_LOOKUP);
    1955               0 :         Assertion* val = PL_DHASH_ENTRY_IS_BUSY(hdr)
    1956                 :             ? reinterpret_cast<Entry*>(hdr)->mAssertions
    1957               0 :             : nsnull;
    1958               0 :         while (val) {
    1959               0 :             if ((val->u.as.mTarget == aTarget) &&
    1960                 :                 (aTruthValue == (val->u.as.mTruthValue))) {
    1961                 : 
    1962                 :                 // found it! so mark it.
    1963               0 :                 as->Mark();
    1964               0 :                 *aDidMark = true;
    1965                 : 
    1966                 : #ifdef PR_LOGGING
    1967               0 :                 LogOperation("MARK", aSource, aProperty, aTarget, aTruthValue);
    1968                 : #endif
    1969                 : 
    1970               0 :                 return NS_OK;
    1971                 :             }
    1972               0 :             val = val->mNext;
    1973               0 :         }
    1974                 :     }
    1975            2526 :     else for (; as != nsnull; as = as->mNext) {
    1976                 :         // check target first as its most unique
    1977            2155 :         if (aTarget != as->u.as.mTarget)
    1978            1760 :             continue;
    1979                 : 
    1980             395 :         if (aProperty != as->u.as.mProperty)
    1981              24 :             continue;
    1982                 : 
    1983             371 :         if (aTruthValue != (as->u.as.mTruthValue))
    1984               0 :             continue;
    1985                 : 
    1986                 :         // found it! so mark it.
    1987             371 :         as->Mark();
    1988             371 :         *aDidMark = true;
    1989                 : 
    1990                 : #ifdef PR_LOGGING
    1991             371 :         LogOperation("MARK", aSource, aProperty, aTarget, aTruthValue);
    1992                 : #endif
    1993                 : 
    1994             371 :         return NS_OK;
    1995                 :     }
    1996                 : 
    1997                 :     // If we get here, we couldn't find the assertion
    1998             371 :     *aDidMark = false;
    1999             371 :     return NS_OK;
    2000                 : }
    2001                 : 
    2002                 : 
    2003                 : struct SweepInfo {
    2004                 :     Assertion* mUnassertList;
    2005                 :     PLDHashTable* mReverseArcs;
    2006                 :     nsFixedSizeAllocator* mAllocator;
    2007                 : };
    2008                 : 
    2009                 : NS_IMETHODIMP
    2010               8 : InMemoryDataSource::Sweep()
    2011                 : {
    2012               8 :     SweepInfo info = { nsnull, &mReverseArcs, &mAllocator};
    2013                 : 
    2014                 :     // Remove all the assertions, but don't notify anyone.
    2015               8 :     PL_DHashTableEnumerate(&mForwardArcs, SweepForwardArcsEntries, &info);
    2016                 : 
    2017                 :     // Now do the notification.
    2018               8 :     Assertion* as = info.mUnassertList;
    2019              16 :     while (as) {
    2020                 : #ifdef PR_LOGGING
    2021               0 :         LogOperation("SWEEP", as->mSource, as->u.as.mProperty, as->u.as.mTarget, as->u.as.mTruthValue);
    2022                 : #endif
    2023               0 :         if (!(as->mHashEntry))
    2024                 :         {
    2025               0 :             for (PRInt32 i = PRInt32(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
    2026               0 :                 nsIRDFObserver* obs = mObservers[i];
    2027                 :                 // XXXbz other loops over mObservers null-check |obs| here!
    2028               0 :                 obs->OnUnassert(this, as->mSource, as->u.as.mProperty, as->u.as.mTarget);
    2029                 :                 // XXX ignore return value?
    2030                 :             }
    2031                 :         }
    2032                 : 
    2033               0 :         Assertion* doomed = as;
    2034               0 :         as = as->mNext;
    2035                 : 
    2036                 :         // Unlink, and release the datasource's reference
    2037               0 :         doomed->mNext = doomed->u.as.mInvNext = nsnull;
    2038               0 :         doomed->Release(mAllocator);
    2039                 :     }
    2040                 : 
    2041               8 :     return NS_OK;
    2042                 : }
    2043                 : 
    2044                 : 
    2045                 : PLDHashOperator
    2046              75 : InMemoryDataSource::SweepForwardArcsEntries(PLDHashTable* aTable,
    2047                 :                                             PLDHashEntryHdr* aHdr,
    2048                 :                                             PRUint32 aNumber, void* aArg)
    2049                 : {
    2050              75 :     PLDHashOperator result = PL_DHASH_NEXT;
    2051              75 :     Entry* entry = reinterpret_cast<Entry*>(aHdr);
    2052              75 :     SweepInfo* info = static_cast<SweepInfo*>(aArg);
    2053                 : 
    2054              75 :     Assertion* as = entry->mAssertions;
    2055              75 :     if (as && (as->mHashEntry))
    2056                 :     {
    2057                 :         // Stuff in sub-hashes must be swept recursively (max depth: 1)
    2058                 :         PL_DHashTableEnumerate(as->u.hash.mPropertyHash, 
    2059               0 :                                SweepForwardArcsEntries, info);
    2060                 : 
    2061                 :         // If the sub-hash is now empty, clean it up.
    2062               0 :         if (!as->u.hash.mPropertyHash->entryCount) {
    2063               0 :             Assertion::Destroy(*info->mAllocator, as);
    2064               0 :             result = PL_DHASH_REMOVE;
    2065                 :         }
    2066                 : 
    2067               0 :         return result;
    2068                 :     }
    2069                 : 
    2070              75 :     Assertion* prev = nsnull;
    2071             489 :     while (as) {
    2072             339 :         if (as->IsMarked()) {
    2073             339 :             prev = as;
    2074             339 :             as->Unmark();
    2075             339 :             as = as->mNext;
    2076                 :         }
    2077                 :         else {
    2078                 :             // remove from the list of assertions in the datasource
    2079               0 :             Assertion* next = as->mNext;
    2080               0 :             if (prev) {
    2081               0 :                 prev->mNext = next;
    2082                 :             }
    2083                 :             else {
    2084                 :                 // it's the first one. update the hashtable entry.
    2085               0 :                 entry->mAssertions = next;
    2086                 :             }
    2087                 : 
    2088                 :             // remove from the reverse arcs
    2089                 :             PLDHashEntryHdr* hdr =
    2090               0 :                 PL_DHashTableOperate(info->mReverseArcs, as->u.as.mTarget, PL_DHASH_LOOKUP);
    2091               0 :             NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(hdr), "no assertion in reverse arcs");
    2092                 : 
    2093               0 :             Entry* rentry = reinterpret_cast<Entry*>(hdr);
    2094               0 :             Assertion* ras = rentry->mAssertions;
    2095               0 :             Assertion* rprev = nsnull;
    2096               0 :             while (ras) {
    2097               0 :                 if (ras == as) {
    2098               0 :                     if (rprev) {
    2099               0 :                         rprev->u.as.mInvNext = ras->u.as.mInvNext;
    2100                 :                     }
    2101                 :                     else {
    2102                 :                         // it's the first one. update the hashtable entry.
    2103               0 :                         rentry->mAssertions = ras->u.as.mInvNext;
    2104                 :                     }
    2105               0 :                     as->u.as.mInvNext = nsnull; // for my sanity.
    2106               0 :                     break;
    2107                 :                 }
    2108               0 :                 rprev = ras;
    2109               0 :                 ras = ras->u.as.mInvNext;
    2110                 :             }
    2111                 : 
    2112                 :             // Wow, it was the _only_ one. Unhash it.
    2113               0 :             if (! rentry->mAssertions)
    2114                 :             {
    2115               0 :                 PL_DHashTableRawRemove(info->mReverseArcs, hdr);
    2116                 :             }
    2117                 : 
    2118                 :             // add to the list of assertions to unassert
    2119               0 :             as->mNext = info->mUnassertList;
    2120               0 :             info->mUnassertList = as;
    2121                 : 
    2122                 :             // Advance to the next assertion
    2123               0 :             as = next;
    2124                 :         }
    2125                 :     }
    2126                 : 
    2127                 :     // if no more assertions exist for this resource, then unhash it.
    2128              75 :     if (! entry->mAssertions)
    2129               0 :         result = PL_DHASH_REMOVE;
    2130                 : 
    2131              75 :     return result;
    2132                 : }
    2133                 : 
    2134                 : ////////////////////////////////////////////////////////////////////////
    2135                 : // rdfIDataSource methods
    2136                 : 
    2137                 : class VisitorClosure
    2138                 : {
    2139                 : public:
    2140              19 :     VisitorClosure(rdfITripleVisitor* aVisitor) :
    2141                 :         mVisitor(aVisitor),
    2142              19 :         mRv(NS_OK)
    2143              19 :     {}
    2144                 :     rdfITripleVisitor* mVisitor;
    2145                 :     nsresult mRv;
    2146                 : };
    2147                 : 
    2148                 : PLDHashOperator
    2149               0 : SubjectEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
    2150                 :                   PRUint32 aNumber, void* aArg) {
    2151               0 :     Entry* entry = reinterpret_cast<Entry*>(aHdr);
    2152               0 :     VisitorClosure* closure = static_cast<VisitorClosure*>(aArg);
    2153                 : 
    2154                 :     nsresult rv;
    2155               0 :     nsCOMPtr<nsIRDFNode> subject = do_QueryInterface(entry->mNode, &rv);
    2156               0 :     NS_ENSURE_SUCCESS(rv, PL_DHASH_NEXT);
    2157                 : 
    2158               0 :     closure->mRv = closure->mVisitor->Visit(subject, nsnull, nsnull, true);
    2159               0 :     if (NS_FAILED(closure->mRv) || closure->mRv == NS_RDF_STOP_VISIT)
    2160               0 :         return PL_DHASH_STOP;
    2161                 : 
    2162               0 :     return PL_DHASH_NEXT;
    2163                 : }
    2164                 : 
    2165                 : NS_IMETHODIMP
    2166               0 : InMemoryDataSource::VisitAllSubjects(rdfITripleVisitor *aVisitor)
    2167                 : {
    2168                 :     // Lock datasource against writes
    2169               0 :     ++mReadCount;
    2170                 : 
    2171                 :     // Enumerate all of our entries into an nsISupportsArray.
    2172               0 :     VisitorClosure cls(aVisitor);
    2173               0 :     PL_DHashTableEnumerate(&mForwardArcs, SubjectEnumerator, &cls);
    2174                 : 
    2175                 :     // Unlock datasource
    2176               0 :     --mReadCount;
    2177                 : 
    2178               0 :     return cls.mRv;
    2179                 : } 
    2180                 : 
    2181                 : class TriplesInnerClosure
    2182                 : {
    2183                 : public:
    2184               0 :     TriplesInnerClosure(nsIRDFNode* aSubject, VisitorClosure* aClosure) :
    2185               0 :         mSubject(aSubject), mOuter(aClosure) {}
    2186                 :     nsIRDFNode* mSubject;
    2187                 :     VisitorClosure* mOuter;
    2188                 : };
    2189                 : 
    2190                 : PLDHashOperator
    2191               0 : TriplesInnerEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
    2192                 :                   PRUint32 aNumber, void* aArg) {
    2193               0 :     Entry* entry = reinterpret_cast<Entry*>(aHdr);
    2194               0 :     Assertion* assertion = entry->mAssertions;
    2195                 :     TriplesInnerClosure* closure = 
    2196               0 :         static_cast<TriplesInnerClosure*>(aArg);
    2197               0 :     while (assertion) {
    2198               0 :         NS_ASSERTION(!assertion->mHashEntry, "shouldn't have to hashes");
    2199               0 :         VisitorClosure* cls = closure->mOuter;
    2200                 :         cls->mRv = cls->mVisitor->Visit(closure->mSubject,
    2201                 :                                         assertion->u.as.mProperty,
    2202                 :                                         assertion->u.as.mTarget,
    2203               0 :                                         assertion->u.as.mTruthValue);
    2204               0 :         if (NS_FAILED(cls->mRv) || cls->mRv == NS_RDF_STOP_VISIT) {
    2205               0 :             return PL_DHASH_STOP;
    2206                 :         }
    2207               0 :         assertion = assertion->mNext;
    2208                 :     }
    2209               0 :     return PL_DHASH_NEXT;
    2210                 : }
    2211                 : PLDHashOperator
    2212             349 : TriplesEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
    2213                 :                   PRUint32 aNumber, void* aArg) {
    2214             349 :     Entry* entry = reinterpret_cast<Entry*>(aHdr);
    2215             349 :     VisitorClosure* closure = static_cast<VisitorClosure*>(aArg);
    2216                 : 
    2217                 :     nsresult rv;
    2218             698 :     nsCOMPtr<nsIRDFNode> subject = do_QueryInterface(entry->mNode, &rv);
    2219             349 :     NS_ENSURE_SUCCESS(rv, PL_DHASH_NEXT);
    2220                 : 
    2221             349 :     if (entry->mAssertions->mHashEntry) {
    2222               0 :         TriplesInnerClosure cls(subject, closure);
    2223                 :         PL_DHashTableEnumerate(entry->mAssertions->u.hash.mPropertyHash,
    2224               0 :                                TriplesInnerEnumerator, &cls);
    2225               0 :         if (NS_FAILED(closure->mRv)) {
    2226               0 :             return PL_DHASH_STOP;
    2227                 :         }
    2228               0 :         return PL_DHASH_NEXT;
    2229                 :     }
    2230             349 :     Assertion* assertion = entry->mAssertions;
    2231            1481 :     while (assertion) {
    2232             783 :         NS_ASSERTION(!assertion->mHashEntry, "shouldn't have to hashes");
    2233                 :         closure->mRv = closure->mVisitor->Visit(subject,
    2234                 :                                                 assertion->u.as.mProperty,
    2235                 :                                                 assertion->u.as.mTarget,
    2236             783 :                                                 assertion->u.as.mTruthValue);
    2237             783 :         if (NS_FAILED(closure->mRv) || closure->mRv == NS_RDF_STOP_VISIT) {
    2238               0 :             return PL_DHASH_STOP;
    2239                 :         }
    2240             783 :         assertion = assertion->mNext;
    2241                 :     }
    2242             349 :     return PL_DHASH_NEXT;
    2243                 : }
    2244                 : NS_IMETHODIMP
    2245              19 : InMemoryDataSource::VisitAllTriples(rdfITripleVisitor *aVisitor)
    2246                 : {
    2247                 :     // Lock datasource against writes
    2248              19 :     ++mReadCount;
    2249                 : 
    2250                 :     // Enumerate all of our entries into an nsISupportsArray.
    2251              19 :     VisitorClosure cls(aVisitor);
    2252              19 :     PL_DHashTableEnumerate(&mForwardArcs, TriplesEnumerator, &cls);
    2253                 : 
    2254                 :     // Unlock datasource
    2255              19 :     --mReadCount;
    2256                 : 
    2257              19 :     return cls.mRv;
    2258            4392 : } 
    2259                 : 
    2260                 : ////////////////////////////////////////////////////////////////////////
    2261                 : 

Generated by: LCOV version 1.7