LCOV - app.info - rdf/base/src/nsInMemoryDataSource.cpp

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-04-21 | 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            4158 :     NS_DECL_CYCLE_COLLECTING_AGGREGATED
         363          128232 :     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            1396 : 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               4 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_AGGREGATED(InMemoryDataSource)
         988               4 :     NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mObservers)
         989               4 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
         990                 :
         991          440961 : NS_IMPL_CYCLE_COLLECTING_AGGREGATED(InMemoryDataSource)
         992          116353 : NS_INTERFACE_MAP_BEGIN_AGGREGATED(InMemoryDataSource)
         993          114291 :     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            4188 : }
        2259                 :
        2260                 : ////////////////////////////////////////////////////////////////////////
        2261                 :

Generated by: LCOV version 1.7