1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/rdf/base/src/nsInMemoryDataSource.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,2122 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. 1.9 + * 1.10 + * 1.11 + * This Original Code has been modified by IBM Corporation. 1.12 + * Modifications made by IBM described herein are 1.13 + * Copyright (c) International Business Machines 1.14 + * Corporation, 2000 1.15 + * 1.16 + * Modifications to Mozilla code or documentation 1.17 + * identified per MPL Section 3.3 1.18 + * 1.19 + * Date Modified by Description of modification 1.20 + * 03/27/2000 IBM Corp. Added PR_CALLBACK for Optlink 1.21 + * use in OS2 1.22 + */ 1.23 + 1.24 +/* 1.25 + 1.26 + Implementation for an in-memory RDF data store. 1.27 + 1.28 + TO DO 1.29 + 1.30 + 1) Instrument this code to gather space and time performance 1.31 + characteristics. 1.32 + 1.33 + 2) Optimize lookups for datasources which have a small number 1.34 + of properties + fanning out to a large number of targets. 1.35 + 1.36 + 3) Complete implementation of thread-safety; specifically, make 1.37 + assertions be reference counted objects (so that a cursor can 1.38 + still refer to an assertion that gets removed from the graph). 1.39 + 1.40 + */ 1.41 + 1.42 +#include "nsAgg.h" 1.43 +#include "nsCOMPtr.h" 1.44 +#include "nscore.h" 1.45 +#include "nsArrayEnumerator.h" 1.46 +#include "nsIOutputStream.h" 1.47 +#include "nsIRDFDataSource.h" 1.48 +#include "nsIRDFLiteral.h" 1.49 +#include "nsIRDFNode.h" 1.50 +#include "nsIRDFObserver.h" 1.51 +#include "nsIRDFInMemoryDataSource.h" 1.52 +#include "nsIRDFPropagatableDataSource.h" 1.53 +#include "nsIRDFPurgeableDataSource.h" 1.54 +#include "nsIRDFService.h" 1.55 +#include "nsIServiceManager.h" 1.56 +#include "nsISupportsArray.h" 1.57 +#include "nsCOMArray.h" 1.58 +#include "nsEnumeratorUtils.h" 1.59 +#include "nsTArray.h" 1.60 +#include "nsCRT.h" 1.61 +#include "nsRDFCID.h" 1.62 +#include "nsRDFBaseDataSources.h" 1.63 +#include "nsString.h" 1.64 +#include "nsReadableUtils.h" 1.65 +#include "nsXPIDLString.h" 1.66 +#include "rdfutil.h" 1.67 +#include "pldhash.h" 1.68 +#include "plstr.h" 1.69 +#include "prlog.h" 1.70 +#include "rdf.h" 1.71 + 1.72 +#include "rdfIDataSource.h" 1.73 +#include "rdfITripleVisitor.h" 1.74 + 1.75 +// This struct is used as the slot value in the forward and reverse 1.76 +// arcs hash tables. 1.77 +// 1.78 +// Assertion objects are reference counted, because each Assertion's 1.79 +// ownership is shared between the datasource and any enumerators that 1.80 +// are currently iterating over the datasource. 1.81 +// 1.82 +class Assertion 1.83 +{ 1.84 +public: 1.85 + static PLDHashOperator 1.86 + DeletePropertyHashEntry(PLDHashTable* aTable, PLDHashEntryHdr* aHdr, 1.87 + uint32_t aNumber, void* aArg); 1.88 + 1.89 + Assertion(nsIRDFResource* aSource, // normal assertion 1.90 + nsIRDFResource* aProperty, 1.91 + nsIRDFNode* aTarget, 1.92 + bool aTruthValue); 1.93 + Assertion(nsIRDFResource* aSource); // PLDHashTable assertion variant 1.94 + 1.95 + ~Assertion(); 1.96 + 1.97 + void AddRef() { 1.98 + if (mRefCnt == UINT16_MAX) { 1.99 + NS_WARNING("refcount overflow, leaking Assertion"); 1.100 + return; 1.101 + } 1.102 + ++mRefCnt; 1.103 + } 1.104 + 1.105 + void Release() { 1.106 + if (mRefCnt == UINT16_MAX) { 1.107 + NS_WARNING("refcount overflow, leaking Assertion"); 1.108 + return; 1.109 + } 1.110 + if (--mRefCnt == 0) 1.111 + delete this; 1.112 + } 1.113 + 1.114 + // For nsIRDFPurgeableDataSource 1.115 + inline void Mark() { u.as.mMarked = true; } 1.116 + inline bool IsMarked() { return u.as.mMarked; } 1.117 + inline void Unmark() { u.as.mMarked = false; } 1.118 + 1.119 + // public for now, because I'm too lazy to go thru and clean this up. 1.120 + 1.121 + // These are shared between hash/as (see the union below) 1.122 + nsIRDFResource* mSource; 1.123 + Assertion* mNext; 1.124 + 1.125 + union 1.126 + { 1.127 + struct hash 1.128 + { 1.129 + PLDHashTable* mPropertyHash; 1.130 + } hash; 1.131 + struct as 1.132 + { 1.133 + nsIRDFResource* mProperty; 1.134 + nsIRDFNode* mTarget; 1.135 + Assertion* mInvNext; 1.136 + // make sure bool are final elements 1.137 + bool mTruthValue; 1.138 + bool mMarked; 1.139 + } as; 1.140 + } u; 1.141 + 1.142 + // also shared between hash/as (see the union above) 1.143 + // but placed after union definition to ensure that 1.144 + // all 32-bit entries are long aligned 1.145 + uint16_t mRefCnt; 1.146 + bool mHashEntry; 1.147 +}; 1.148 + 1.149 + 1.150 +struct Entry { 1.151 + PLDHashEntryHdr mHdr; 1.152 + nsIRDFNode* mNode; 1.153 + Assertion* mAssertions; 1.154 +}; 1.155 + 1.156 + 1.157 +Assertion::Assertion(nsIRDFResource* aSource) 1.158 + : mSource(aSource), 1.159 + mNext(nullptr), 1.160 + mRefCnt(0), 1.161 + mHashEntry(true) 1.162 +{ 1.163 + MOZ_COUNT_CTOR(RDF_Assertion); 1.164 + 1.165 + NS_ADDREF(mSource); 1.166 + 1.167 + u.hash.mPropertyHash = PL_NewDHashTable(PL_DHashGetStubOps(), 1.168 + nullptr, sizeof(Entry), PL_DHASH_MIN_SIZE); 1.169 +} 1.170 + 1.171 +Assertion::Assertion(nsIRDFResource* aSource, 1.172 + nsIRDFResource* aProperty, 1.173 + nsIRDFNode* aTarget, 1.174 + bool aTruthValue) 1.175 + : mSource(aSource), 1.176 + mNext(nullptr), 1.177 + mRefCnt(0), 1.178 + mHashEntry(false) 1.179 +{ 1.180 + MOZ_COUNT_CTOR(RDF_Assertion); 1.181 + 1.182 + u.as.mProperty = aProperty; 1.183 + u.as.mTarget = aTarget; 1.184 + 1.185 + NS_ADDREF(mSource); 1.186 + NS_ADDREF(u.as.mProperty); 1.187 + NS_ADDREF(u.as.mTarget); 1.188 + 1.189 + u.as.mInvNext = nullptr; 1.190 + u.as.mTruthValue = aTruthValue; 1.191 + u.as.mMarked = false; 1.192 +} 1.193 + 1.194 +Assertion::~Assertion() 1.195 +{ 1.196 + if (mHashEntry && u.hash.mPropertyHash) { 1.197 + PL_DHashTableEnumerate(u.hash.mPropertyHash, DeletePropertyHashEntry, 1.198 + nullptr); 1.199 + PL_DHashTableDestroy(u.hash.mPropertyHash); 1.200 + u.hash.mPropertyHash = nullptr; 1.201 + } 1.202 + 1.203 + MOZ_COUNT_DTOR(RDF_Assertion); 1.204 +#ifdef DEBUG_REFS 1.205 + --gInstanceCount; 1.206 + fprintf(stdout, "%d - RDF: Assertion\n", gInstanceCount); 1.207 +#endif 1.208 + 1.209 + NS_RELEASE(mSource); 1.210 + if (!mHashEntry) 1.211 + { 1.212 + NS_RELEASE(u.as.mProperty); 1.213 + NS_RELEASE(u.as.mTarget); 1.214 + } 1.215 +} 1.216 + 1.217 +PLDHashOperator 1.218 +Assertion::DeletePropertyHashEntry(PLDHashTable* aTable, PLDHashEntryHdr* aHdr, 1.219 + uint32_t aNumber, void* aArg) 1.220 +{ 1.221 + Entry* entry = reinterpret_cast<Entry*>(aHdr); 1.222 + 1.223 + Assertion* as = entry->mAssertions; 1.224 + while (as) { 1.225 + Assertion* doomed = as; 1.226 + as = as->mNext; 1.227 + 1.228 + // Unlink, and release the datasource's reference. 1.229 + doomed->mNext = doomed->u.as.mInvNext = nullptr; 1.230 + doomed->Release(); 1.231 + } 1.232 + return PL_DHASH_NEXT; 1.233 +} 1.234 + 1.235 + 1.236 + 1.237 +//////////////////////////////////////////////////////////////////////// 1.238 +// InMemoryDataSource 1.239 +class InMemoryArcsEnumeratorImpl; 1.240 +class InMemoryAssertionEnumeratorImpl; 1.241 +class InMemoryResourceEnumeratorImpl; 1.242 + 1.243 +class InMemoryDataSource : public nsIRDFDataSource, 1.244 + public nsIRDFInMemoryDataSource, 1.245 + public nsIRDFPropagatableDataSource, 1.246 + public nsIRDFPurgeableDataSource, 1.247 + public rdfIDataSource 1.248 +{ 1.249 +protected: 1.250 + // These hash tables are keyed on pointers to nsIRDFResource 1.251 + // objects (the nsIRDFService ensures that there is only ever one 1.252 + // nsIRDFResource object per unique URI). The value of an entry is 1.253 + // an Assertion struct, which is a linked list of (subject 1.254 + // predicate object) triples. 1.255 + PLDHashTable mForwardArcs; 1.256 + PLDHashTable mReverseArcs; 1.257 + 1.258 + nsCOMArray<nsIRDFObserver> mObservers; 1.259 + uint32_t mNumObservers; 1.260 + 1.261 + // VisitFoo needs to block writes, [Un]Assert only allowed 1.262 + // during mReadCount == 0 1.263 + uint32_t mReadCount; 1.264 + 1.265 + static PLDHashOperator 1.266 + DeleteForwardArcsEntry(PLDHashTable* aTable, PLDHashEntryHdr* aHdr, 1.267 + uint32_t aNumber, void* aArg); 1.268 + 1.269 + static PLDHashOperator 1.270 + ResourceEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aHdr, 1.271 + uint32_t aNumber, void* aArg); 1.272 + 1.273 + friend class InMemoryArcsEnumeratorImpl; 1.274 + friend class InMemoryAssertionEnumeratorImpl; 1.275 + friend class InMemoryResourceEnumeratorImpl; // b/c it needs to enumerate mForwardArcs 1.276 + 1.277 + // Thread-safe writer implementation methods. 1.278 + nsresult 1.279 + LockedAssert(nsIRDFResource* source, 1.280 + nsIRDFResource* property, 1.281 + nsIRDFNode* target, 1.282 + bool tv); 1.283 + 1.284 + nsresult 1.285 + LockedUnassert(nsIRDFResource* source, 1.286 + nsIRDFResource* property, 1.287 + nsIRDFNode* target); 1.288 + 1.289 + InMemoryDataSource(nsISupports* aOuter); 1.290 + virtual ~InMemoryDataSource(); 1.291 + nsresult Init(); 1.292 + 1.293 + friend nsresult 1.294 + NS_NewRDFInMemoryDataSource(nsISupports* aOuter, const nsIID& aIID, void** aResult); 1.295 + 1.296 +public: 1.297 + NS_DECL_CYCLE_COLLECTING_AGGREGATED 1.298 + NS_DECL_AGGREGATED_CYCLE_COLLECTION_CLASS(InMemoryDataSource) 1.299 + 1.300 + // nsIRDFDataSource methods 1.301 + NS_DECL_NSIRDFDATASOURCE 1.302 + 1.303 + // nsIRDFInMemoryDataSource methods 1.304 + NS_DECL_NSIRDFINMEMORYDATASOURCE 1.305 + 1.306 + // nsIRDFPropagatableDataSource methods 1.307 + NS_DECL_NSIRDFPROPAGATABLEDATASOURCE 1.308 + 1.309 + // nsIRDFPurgeableDataSource methods 1.310 + NS_DECL_NSIRDFPURGEABLEDATASOURCE 1.311 + 1.312 + // rdfIDataSource methods 1.313 + NS_DECL_RDFIDATASOURCE 1.314 + 1.315 +protected: 1.316 + static PLDHashOperator 1.317 + SweepForwardArcsEntries(PLDHashTable* aTable, PLDHashEntryHdr* aHdr, 1.318 + uint32_t aNumber, void* aArg); 1.319 + 1.320 +public: 1.321 + // Implementation methods 1.322 + Assertion* 1.323 + GetForwardArcs(nsIRDFResource* u) { 1.324 + PLDHashEntryHdr* hdr = PL_DHashTableOperate(&mForwardArcs, u, PL_DHASH_LOOKUP); 1.325 + return PL_DHASH_ENTRY_IS_BUSY(hdr) 1.326 + ? reinterpret_cast<Entry*>(hdr)->mAssertions 1.327 + : nullptr; } 1.328 + 1.329 + Assertion* 1.330 + GetReverseArcs(nsIRDFNode* v) { 1.331 + PLDHashEntryHdr* hdr = PL_DHashTableOperate(&mReverseArcs, v, PL_DHASH_LOOKUP); 1.332 + return PL_DHASH_ENTRY_IS_BUSY(hdr) 1.333 + ? reinterpret_cast<Entry*>(hdr)->mAssertions 1.334 + : nullptr; } 1.335 + 1.336 + void 1.337 + SetForwardArcs(nsIRDFResource* u, Assertion* as) { 1.338 + PLDHashEntryHdr* hdr = PL_DHashTableOperate(&mForwardArcs, u, 1.339 + as ? PL_DHASH_ADD : PL_DHASH_REMOVE); 1.340 + if (as && hdr) { 1.341 + Entry* entry = reinterpret_cast<Entry*>(hdr); 1.342 + entry->mNode = u; 1.343 + entry->mAssertions = as; 1.344 + } } 1.345 + 1.346 + void 1.347 + SetReverseArcs(nsIRDFNode* v, Assertion* as) { 1.348 + PLDHashEntryHdr* hdr = PL_DHashTableOperate(&mReverseArcs, v, 1.349 + as ? PL_DHASH_ADD : PL_DHASH_REMOVE); 1.350 + if (as && hdr) { 1.351 + Entry* entry = reinterpret_cast<Entry*>(hdr); 1.352 + entry->mNode = v; 1.353 + entry->mAssertions = as; 1.354 + } } 1.355 + 1.356 +#ifdef PR_LOGGING 1.357 + void 1.358 + LogOperation(const char* aOperation, 1.359 + nsIRDFResource* asource, 1.360 + nsIRDFResource* aProperty, 1.361 + nsIRDFNode* aTarget, 1.362 + bool aTruthValue = true); 1.363 +#endif 1.364 + 1.365 + bool mPropagateChanges; 1.366 + 1.367 +private: 1.368 +#ifdef PR_LOGGING 1.369 + static PRLogModuleInfo* gLog; 1.370 +#endif 1.371 +}; 1.372 + 1.373 +#ifdef PR_LOGGING 1.374 +PRLogModuleInfo* InMemoryDataSource::gLog; 1.375 +#endif 1.376 + 1.377 +//---------------------------------------------------------------------- 1.378 +// 1.379 +// InMemoryAssertionEnumeratorImpl 1.380 +// 1.381 + 1.382 +/** 1.383 + * InMemoryAssertionEnumeratorImpl 1.384 + */ 1.385 +class InMemoryAssertionEnumeratorImpl : public nsISimpleEnumerator 1.386 +{ 1.387 +private: 1.388 + InMemoryDataSource* mDataSource; 1.389 + nsIRDFResource* mSource; 1.390 + nsIRDFResource* mProperty; 1.391 + nsIRDFNode* mTarget; 1.392 + nsIRDFNode* mValue; 1.393 + bool mTruthValue; 1.394 + Assertion* mNextAssertion; 1.395 + nsCOMPtr<nsISupportsArray> mHashArcs; 1.396 + 1.397 +public: 1.398 + InMemoryAssertionEnumeratorImpl(InMemoryDataSource* aDataSource, 1.399 + nsIRDFResource* aSource, 1.400 + nsIRDFResource* aProperty, 1.401 + nsIRDFNode* aTarget, 1.402 + bool aTruthValue); 1.403 + 1.404 + virtual ~InMemoryAssertionEnumeratorImpl(); 1.405 + 1.406 + // nsISupports interface 1.407 + NS_DECL_ISUPPORTS 1.408 + 1.409 + // nsISimpleEnumerator interface 1.410 + NS_DECL_NSISIMPLEENUMERATOR 1.411 +}; 1.412 + 1.413 +//////////////////////////////////////////////////////////////////////// 1.414 + 1.415 + 1.416 +InMemoryAssertionEnumeratorImpl::InMemoryAssertionEnumeratorImpl( 1.417 + InMemoryDataSource* aDataSource, 1.418 + nsIRDFResource* aSource, 1.419 + nsIRDFResource* aProperty, 1.420 + nsIRDFNode* aTarget, 1.421 + bool aTruthValue) 1.422 + : mDataSource(aDataSource), 1.423 + mSource(aSource), 1.424 + mProperty(aProperty), 1.425 + mTarget(aTarget), 1.426 + mValue(nullptr), 1.427 + mTruthValue(aTruthValue), 1.428 + mNextAssertion(nullptr) 1.429 +{ 1.430 + NS_ADDREF(mDataSource); 1.431 + NS_IF_ADDREF(mSource); 1.432 + NS_ADDREF(mProperty); 1.433 + NS_IF_ADDREF(mTarget); 1.434 + 1.435 + if (mSource) { 1.436 + mNextAssertion = mDataSource->GetForwardArcs(mSource); 1.437 + 1.438 + if (mNextAssertion && mNextAssertion->mHashEntry) { 1.439 + // its our magical HASH_ENTRY forward hash for assertions 1.440 + PLDHashEntryHdr* hdr = PL_DHashTableOperate(mNextAssertion->u.hash.mPropertyHash, 1.441 + aProperty, PL_DHASH_LOOKUP); 1.442 + mNextAssertion = PL_DHASH_ENTRY_IS_BUSY(hdr) 1.443 + ? reinterpret_cast<Entry*>(hdr)->mAssertions 1.444 + : nullptr; 1.445 + } 1.446 + } 1.447 + else { 1.448 + mNextAssertion = mDataSource->GetReverseArcs(mTarget); 1.449 + } 1.450 + 1.451 + // Add an owning reference from the enumerator 1.452 + if (mNextAssertion) 1.453 + mNextAssertion->AddRef(); 1.454 +} 1.455 + 1.456 +InMemoryAssertionEnumeratorImpl::~InMemoryAssertionEnumeratorImpl() 1.457 +{ 1.458 +#ifdef DEBUG_REFS 1.459 + --gInstanceCount; 1.460 + fprintf(stdout, "%d - RDF: InMemoryAssertionEnumeratorImpl\n", gInstanceCount); 1.461 +#endif 1.462 + 1.463 + if (mNextAssertion) 1.464 + mNextAssertion->Release(); 1.465 + 1.466 + NS_IF_RELEASE(mDataSource); 1.467 + NS_IF_RELEASE(mSource); 1.468 + NS_IF_RELEASE(mProperty); 1.469 + NS_IF_RELEASE(mTarget); 1.470 + NS_IF_RELEASE(mValue); 1.471 +} 1.472 + 1.473 +NS_IMPL_ADDREF(InMemoryAssertionEnumeratorImpl) 1.474 +NS_IMPL_RELEASE(InMemoryAssertionEnumeratorImpl) 1.475 +NS_IMPL_QUERY_INTERFACE(InMemoryAssertionEnumeratorImpl, nsISimpleEnumerator) 1.476 + 1.477 +NS_IMETHODIMP 1.478 +InMemoryAssertionEnumeratorImpl::HasMoreElements(bool* aResult) 1.479 +{ 1.480 + if (mValue) { 1.481 + *aResult = true; 1.482 + return NS_OK; 1.483 + } 1.484 + 1.485 + while (mNextAssertion) { 1.486 + bool foundIt = false; 1.487 + if ((mProperty == mNextAssertion->u.as.mProperty) && 1.488 + (mTruthValue == mNextAssertion->u.as.mTruthValue)) { 1.489 + if (mSource) { 1.490 + mValue = mNextAssertion->u.as.mTarget; 1.491 + NS_ADDREF(mValue); 1.492 + } 1.493 + else { 1.494 + mValue = mNextAssertion->mSource; 1.495 + NS_ADDREF(mValue); 1.496 + } 1.497 + foundIt = true; 1.498 + } 1.499 + 1.500 + // Remember the last assertion we were holding on to 1.501 + Assertion* as = mNextAssertion; 1.502 + 1.503 + // iterate 1.504 + mNextAssertion = (mSource) ? mNextAssertion->mNext : mNextAssertion->u.as.mInvNext; 1.505 + 1.506 + // grab an owning reference from the enumerator to the next assertion 1.507 + if (mNextAssertion) 1.508 + mNextAssertion->AddRef(); 1.509 + 1.510 + // ...and release the reference from the enumerator to the old one. 1.511 + as->Release(); 1.512 + 1.513 + if (foundIt) { 1.514 + *aResult = true; 1.515 + return NS_OK; 1.516 + } 1.517 + } 1.518 + 1.519 + *aResult = false; 1.520 + return NS_OK; 1.521 +} 1.522 + 1.523 + 1.524 +NS_IMETHODIMP 1.525 +InMemoryAssertionEnumeratorImpl::GetNext(nsISupports** aResult) 1.526 +{ 1.527 + nsresult rv; 1.528 + 1.529 + bool hasMore; 1.530 + rv = HasMoreElements(&hasMore); 1.531 + if (NS_FAILED(rv)) return rv; 1.532 + 1.533 + if (! hasMore) 1.534 + return NS_ERROR_UNEXPECTED; 1.535 + 1.536 + // Don't AddRef: we "transfer" ownership to the caller 1.537 + *aResult = mValue; 1.538 + mValue = nullptr; 1.539 + 1.540 + return NS_OK; 1.541 +} 1.542 + 1.543 +//////////////////////////////////////////////////////////////////////// 1.544 +// 1.545 + 1.546 +/** 1.547 + * This class is a little bit bizarre in that it implements both the 1.548 + * <tt>nsIRDFArcsOutCursor</tt> and <tt>nsIRDFArcsInCursor</tt> interfaces. 1.549 + * Because the structure of the in-memory graph is pretty flexible, it's 1.550 + * fairly easy to parameterize this class. The only funky thing to watch 1.551 + * out for is the multiple inheritance clashes. 1.552 + */ 1.553 + 1.554 +class InMemoryArcsEnumeratorImpl : public nsISimpleEnumerator 1.555 +{ 1.556 +private: 1.557 + InMemoryDataSource* mDataSource; 1.558 + nsIRDFResource* mSource; 1.559 + nsIRDFNode* mTarget; 1.560 + nsAutoTArray<nsCOMPtr<nsIRDFResource>, 8> mAlreadyReturned; 1.561 + nsIRDFResource* mCurrent; 1.562 + Assertion* mAssertion; 1.563 + nsCOMPtr<nsISupportsArray> mHashArcs; 1.564 + 1.565 + static PLDHashOperator 1.566 + ArcEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aHdr, 1.567 + uint32_t aNumber, void* aArg); 1.568 + 1.569 +public: 1.570 + InMemoryArcsEnumeratorImpl(InMemoryDataSource* aDataSource, 1.571 + nsIRDFResource* aSource, 1.572 + nsIRDFNode* aTarget); 1.573 + 1.574 + virtual ~InMemoryArcsEnumeratorImpl(); 1.575 + 1.576 + // nsISupports interface 1.577 + NS_DECL_ISUPPORTS 1.578 + 1.579 + // nsISimpleEnumerator interface 1.580 + NS_DECL_NSISIMPLEENUMERATOR 1.581 +}; 1.582 + 1.583 + 1.584 +PLDHashOperator 1.585 +InMemoryArcsEnumeratorImpl::ArcEnumerator(PLDHashTable* aTable, 1.586 + PLDHashEntryHdr* aHdr, 1.587 + uint32_t aNumber, void* aArg) 1.588 +{ 1.589 + Entry* entry = reinterpret_cast<Entry*>(aHdr); 1.590 + nsISupportsArray* resources = static_cast<nsISupportsArray*>(aArg); 1.591 + 1.592 + resources->AppendElement(entry->mNode); 1.593 + return PL_DHASH_NEXT; 1.594 +} 1.595 + 1.596 + 1.597 +InMemoryArcsEnumeratorImpl::InMemoryArcsEnumeratorImpl(InMemoryDataSource* aDataSource, 1.598 + nsIRDFResource* aSource, 1.599 + nsIRDFNode* aTarget) 1.600 + : mDataSource(aDataSource), 1.601 + mSource(aSource), 1.602 + mTarget(aTarget), 1.603 + mCurrent(nullptr) 1.604 +{ 1.605 + NS_ADDREF(mDataSource); 1.606 + NS_IF_ADDREF(mSource); 1.607 + NS_IF_ADDREF(mTarget); 1.608 + 1.609 + if (mSource) { 1.610 + // cast okay because it's a closed system 1.611 + mAssertion = mDataSource->GetForwardArcs(mSource); 1.612 + 1.613 + if (mAssertion && mAssertion->mHashEntry) { 1.614 + // its our magical HASH_ENTRY forward hash for assertions 1.615 + nsresult rv = NS_NewISupportsArray(getter_AddRefs(mHashArcs)); 1.616 + if (NS_SUCCEEDED(rv)) { 1.617 + PL_DHashTableEnumerate(mAssertion->u.hash.mPropertyHash, 1.618 + ArcEnumerator, mHashArcs.get()); 1.619 + } 1.620 + mAssertion = nullptr; 1.621 + } 1.622 + } 1.623 + else { 1.624 + mAssertion = mDataSource->GetReverseArcs(mTarget); 1.625 + } 1.626 +} 1.627 + 1.628 +InMemoryArcsEnumeratorImpl::~InMemoryArcsEnumeratorImpl() 1.629 +{ 1.630 +#ifdef DEBUG_REFS 1.631 + --gInstanceCount; 1.632 + fprintf(stdout, "%d - RDF: InMemoryArcsEnumeratorImpl\n", gInstanceCount); 1.633 +#endif 1.634 + 1.635 + NS_RELEASE(mDataSource); 1.636 + NS_IF_RELEASE(mSource); 1.637 + NS_IF_RELEASE(mTarget); 1.638 + NS_IF_RELEASE(mCurrent); 1.639 +} 1.640 + 1.641 +NS_IMPL_ADDREF(InMemoryArcsEnumeratorImpl) 1.642 +NS_IMPL_RELEASE(InMemoryArcsEnumeratorImpl) 1.643 +NS_IMPL_QUERY_INTERFACE(InMemoryArcsEnumeratorImpl, nsISimpleEnumerator) 1.644 + 1.645 +NS_IMETHODIMP 1.646 +InMemoryArcsEnumeratorImpl::HasMoreElements(bool* aResult) 1.647 +{ 1.648 + NS_PRECONDITION(aResult != nullptr, "null ptr"); 1.649 + if (! aResult) 1.650 + return NS_ERROR_NULL_POINTER; 1.651 + 1.652 + if (mCurrent) { 1.653 + *aResult = true; 1.654 + return NS_OK; 1.655 + } 1.656 + 1.657 + if (mHashArcs) { 1.658 + uint32_t itemCount; 1.659 + nsresult rv; 1.660 + if (NS_FAILED(rv = mHashArcs->Count(&itemCount))) return(rv); 1.661 + if (itemCount > 0) { 1.662 + --itemCount; 1.663 + nsCOMPtr<nsIRDFResource> tmp = do_QueryElementAt(mHashArcs, itemCount); 1.664 + tmp.forget(&mCurrent); 1.665 + mHashArcs->RemoveElementAt(itemCount); 1.666 + *aResult = true; 1.667 + return NS_OK; 1.668 + } 1.669 + } 1.670 + else 1.671 + while (mAssertion) { 1.672 + nsIRDFResource* next = mAssertion->u.as.mProperty; 1.673 + 1.674 + // "next" is the property arc we are tentatively going to return 1.675 + // in a subsequent GetNext() call. It is important to do two 1.676 + // things, however, before that can happen: 1.677 + // 1) Make sure it's not an arc we've already returned. 1.678 + // 2) Make sure that |mAssertion| is not left pointing to 1.679 + // another assertion that has the same property as this one. 1.680 + // The first is a practical concern; the second a defense against 1.681 + // an obscure crash and other erratic behavior. To ensure the 1.682 + // second condition, skip down the chain until we find the next 1.683 + // assertion with a property that doesn't match the current one. 1.684 + // (All these assertions would be skipped via mAlreadyReturned 1.685 + // checks anyways; this is even a bit faster.) 1.686 + 1.687 + do { 1.688 + mAssertion = (mSource ? mAssertion->mNext : 1.689 + mAssertion->u.as.mInvNext); 1.690 + } 1.691 + while (mAssertion && (next == mAssertion->u.as.mProperty)); 1.692 + 1.693 + bool alreadyReturned = false; 1.694 + for (int32_t i = mAlreadyReturned.Length() - 1; i >= 0; --i) { 1.695 + if (mAlreadyReturned[i] == next) { 1.696 + alreadyReturned = true; 1.697 + break; 1.698 + } 1.699 + } 1.700 + 1.701 + if (! alreadyReturned) { 1.702 + mCurrent = next; 1.703 + NS_ADDREF(mCurrent); 1.704 + *aResult = true; 1.705 + return NS_OK; 1.706 + } 1.707 + } 1.708 + 1.709 + *aResult = false; 1.710 + return NS_OK; 1.711 +} 1.712 + 1.713 + 1.714 +NS_IMETHODIMP 1.715 +InMemoryArcsEnumeratorImpl::GetNext(nsISupports** aResult) 1.716 +{ 1.717 + nsresult rv; 1.718 + 1.719 + bool hasMore; 1.720 + rv = HasMoreElements(&hasMore); 1.721 + if (NS_FAILED(rv)) return rv; 1.722 + 1.723 + if (! hasMore) 1.724 + return NS_ERROR_UNEXPECTED; 1.725 + 1.726 + // Add this to the set of things we've already returned so that we 1.727 + // can ensure uniqueness 1.728 + mAlreadyReturned.AppendElement(mCurrent); 1.729 + 1.730 + // Don't AddRef: we "transfer" ownership to the caller 1.731 + *aResult = mCurrent; 1.732 + mCurrent = nullptr; 1.733 + 1.734 + return NS_OK; 1.735 +} 1.736 + 1.737 + 1.738 +//////////////////////////////////////////////////////////////////////// 1.739 +// InMemoryDataSource 1.740 + 1.741 +nsresult 1.742 +NS_NewRDFInMemoryDataSource(nsISupports* aOuter, const nsIID& aIID, void** aResult) 1.743 +{ 1.744 + NS_PRECONDITION(aResult != nullptr, "null ptr"); 1.745 + if (! aResult) 1.746 + return NS_ERROR_NULL_POINTER; 1.747 + *aResult = nullptr; 1.748 + 1.749 + if (aOuter && !aIID.Equals(NS_GET_IID(nsISupports))) { 1.750 + NS_ERROR("aggregation requires nsISupports"); 1.751 + return NS_ERROR_ILLEGAL_VALUE; 1.752 + } 1.753 + 1.754 + InMemoryDataSource* datasource = new InMemoryDataSource(aOuter); 1.755 + if (! datasource) 1.756 + return NS_ERROR_OUT_OF_MEMORY; 1.757 + NS_ADDREF(datasource); 1.758 + 1.759 + nsresult rv = datasource->Init(); 1.760 + if (NS_SUCCEEDED(rv)) { 1.761 + datasource->fAggregated.AddRef(); 1.762 + rv = datasource->AggregatedQueryInterface(aIID, aResult); // This'll AddRef() 1.763 + datasource->fAggregated.Release(); 1.764 + } 1.765 + 1.766 + NS_RELEASE(datasource); 1.767 + return rv; 1.768 +} 1.769 + 1.770 + 1.771 +InMemoryDataSource::InMemoryDataSource(nsISupports* aOuter) 1.772 + : mNumObservers(0), mReadCount(0) 1.773 +{ 1.774 + NS_INIT_AGGREGATED(aOuter); 1.775 + 1.776 + mForwardArcs.ops = nullptr; 1.777 + mReverseArcs.ops = nullptr; 1.778 + mPropagateChanges = true; 1.779 + MOZ_COUNT_CTOR(InMemoryDataSource); 1.780 +} 1.781 + 1.782 + 1.783 +nsresult 1.784 +InMemoryDataSource::Init() 1.785 +{ 1.786 + PL_DHashTableInit(&mForwardArcs, 1.787 + PL_DHashGetStubOps(), 1.788 + nullptr, 1.789 + sizeof(Entry), 1.790 + PL_DHASH_MIN_SIZE); 1.791 + 1.792 + PL_DHashTableInit(&mReverseArcs, 1.793 + PL_DHashGetStubOps(), 1.794 + nullptr, 1.795 + sizeof(Entry), 1.796 + PL_DHASH_MIN_SIZE); 1.797 + 1.798 +#ifdef PR_LOGGING 1.799 + if (! gLog) 1.800 + gLog = PR_NewLogModule("InMemoryDataSource"); 1.801 +#endif 1.802 + 1.803 + return NS_OK; 1.804 +} 1.805 + 1.806 + 1.807 +InMemoryDataSource::~InMemoryDataSource() 1.808 +{ 1.809 +#ifdef DEBUG_REFS 1.810 + --gInstanceCount; 1.811 + fprintf(stdout, "%d - RDF: InMemoryDataSource\n", gInstanceCount); 1.812 +#endif 1.813 + 1.814 + if (mForwardArcs.ops) { 1.815 + // This'll release all of the Assertion objects that are 1.816 + // associated with this data source. We only need to do this 1.817 + // for the forward arcs, because the reverse arcs table 1.818 + // indexes the exact same set of resources. 1.819 + PL_DHashTableEnumerate(&mForwardArcs, DeleteForwardArcsEntry, nullptr); 1.820 + PL_DHashTableFinish(&mForwardArcs); 1.821 + } 1.822 + if (mReverseArcs.ops) 1.823 + PL_DHashTableFinish(&mReverseArcs); 1.824 + 1.825 + PR_LOG(gLog, PR_LOG_NOTICE, 1.826 + ("InMemoryDataSource(%p): destroyed.", this)); 1.827 + 1.828 + MOZ_COUNT_DTOR(InMemoryDataSource); 1.829 +} 1.830 + 1.831 +PLDHashOperator 1.832 +InMemoryDataSource::DeleteForwardArcsEntry(PLDHashTable* aTable, PLDHashEntryHdr* aHdr, 1.833 + uint32_t aNumber, void* aArg) 1.834 +{ 1.835 + Entry* entry = reinterpret_cast<Entry*>(aHdr); 1.836 + 1.837 + Assertion* as = entry->mAssertions; 1.838 + while (as) { 1.839 + Assertion* doomed = as; 1.840 + as = as->mNext; 1.841 + 1.842 + // Unlink, and release the datasource's reference. 1.843 + doomed->mNext = doomed->u.as.mInvNext = nullptr; 1.844 + doomed->Release(); 1.845 + } 1.846 + return PL_DHASH_NEXT; 1.847 +} 1.848 + 1.849 + 1.850 +//////////////////////////////////////////////////////////////////////// 1.851 + 1.852 +NS_IMPL_CYCLE_COLLECTION_CLASS(InMemoryDataSource) 1.853 + 1.854 +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(InMemoryDataSource) 1.855 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mObservers) 1.856 +NS_IMPL_CYCLE_COLLECTION_UNLINK_END 1.857 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_AGGREGATED(InMemoryDataSource) 1.858 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mObservers) 1.859 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 1.860 + 1.861 +NS_IMPL_CYCLE_COLLECTING_AGGREGATED(InMemoryDataSource) 1.862 +NS_INTERFACE_MAP_BEGIN_AGGREGATED(InMemoryDataSource) 1.863 + NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION_AGGREGATED(InMemoryDataSource) 1.864 + NS_INTERFACE_MAP_ENTRY(nsIRDFDataSource) 1.865 + NS_INTERFACE_MAP_ENTRY(nsIRDFInMemoryDataSource) 1.866 + NS_INTERFACE_MAP_ENTRY(nsIRDFPropagatableDataSource) 1.867 + NS_INTERFACE_MAP_ENTRY(nsIRDFPurgeableDataSource) 1.868 + NS_INTERFACE_MAP_ENTRY(rdfIDataSource) 1.869 +NS_INTERFACE_MAP_END 1.870 + 1.871 +//////////////////////////////////////////////////////////////////////// 1.872 + 1.873 + 1.874 +#ifdef PR_LOGGING 1.875 +void 1.876 +InMemoryDataSource::LogOperation(const char* aOperation, 1.877 + nsIRDFResource* aSource, 1.878 + nsIRDFResource* aProperty, 1.879 + nsIRDFNode* aTarget, 1.880 + bool aTruthValue) 1.881 +{ 1.882 + if (! PR_LOG_TEST(gLog, PR_LOG_NOTICE)) 1.883 + return; 1.884 + 1.885 + nsXPIDLCString uri; 1.886 + aSource->GetValue(getter_Copies(uri)); 1.887 + PR_LogPrint 1.888 + ("InMemoryDataSource(%p): %s", this, aOperation); 1.889 + 1.890 + PR_LogPrint 1.891 + (" [(%p)%s]--", aSource, (const char*) uri); 1.892 + 1.893 + aProperty->GetValue(getter_Copies(uri)); 1.894 + 1.895 + char tv = (aTruthValue ? '-' : '!'); 1.896 + PR_LogPrint 1.897 + (" --%c[(%p)%s]--", tv, aProperty, (const char*) uri); 1.898 + 1.899 + nsCOMPtr<nsIRDFResource> resource; 1.900 + nsCOMPtr<nsIRDFLiteral> literal; 1.901 + 1.902 + if ((resource = do_QueryInterface(aTarget)) != nullptr) { 1.903 + resource->GetValue(getter_Copies(uri)); 1.904 + PR_LogPrint 1.905 + (" -->[(%p)%s]", aTarget, (const char*) uri); 1.906 + } 1.907 + else if ((literal = do_QueryInterface(aTarget)) != nullptr) { 1.908 + nsXPIDLString value; 1.909 + literal->GetValue(getter_Copies(value)); 1.910 + nsAutoString valueStr(value); 1.911 + char* valueCStr = ToNewCString(valueStr); 1.912 + 1.913 + PR_LogPrint 1.914 + (" -->(\"%s\")\n", valueCStr); 1.915 + 1.916 + NS_Free(valueCStr); 1.917 + } 1.918 + else { 1.919 + PR_LogPrint 1.920 + (" -->(unknown-type)\n"); 1.921 + } 1.922 +} 1.923 +#endif 1.924 + 1.925 + 1.926 +NS_IMETHODIMP 1.927 +InMemoryDataSource::GetURI(char* *uri) 1.928 +{ 1.929 + NS_PRECONDITION(uri != nullptr, "null ptr"); 1.930 + if (! uri) 1.931 + return NS_ERROR_NULL_POINTER; 1.932 + 1.933 + *uri = nullptr; 1.934 + return NS_OK; 1.935 +} 1.936 + 1.937 +NS_IMETHODIMP 1.938 +InMemoryDataSource::GetSource(nsIRDFResource* property, 1.939 + nsIRDFNode* target, 1.940 + bool tv, 1.941 + nsIRDFResource** source) 1.942 +{ 1.943 + NS_PRECONDITION(source != nullptr, "null ptr"); 1.944 + if (! source) 1.945 + return NS_ERROR_NULL_POINTER; 1.946 + 1.947 + NS_PRECONDITION(property != nullptr, "null ptr"); 1.948 + if (! property) 1.949 + return NS_ERROR_NULL_POINTER; 1.950 + 1.951 + NS_PRECONDITION(target != nullptr, "null ptr"); 1.952 + if (! target) 1.953 + return NS_ERROR_NULL_POINTER; 1.954 + 1.955 + for (Assertion* as = GetReverseArcs(target); as; as = as->u.as.mInvNext) { 1.956 + if ((property == as->u.as.mProperty) && (tv == as->u.as.mTruthValue)) { 1.957 + *source = as->mSource; 1.958 + NS_ADDREF(*source); 1.959 + return NS_OK; 1.960 + } 1.961 + } 1.962 + *source = nullptr; 1.963 + return NS_RDF_NO_VALUE; 1.964 +} 1.965 + 1.966 +NS_IMETHODIMP 1.967 +InMemoryDataSource::GetTarget(nsIRDFResource* source, 1.968 + nsIRDFResource* property, 1.969 + bool tv, 1.970 + nsIRDFNode** target) 1.971 +{ 1.972 + NS_PRECONDITION(source != nullptr, "null ptr"); 1.973 + if (! source) 1.974 + return NS_ERROR_NULL_POINTER; 1.975 + 1.976 + NS_PRECONDITION(property != nullptr, "null ptr"); 1.977 + if (! property) 1.978 + return NS_ERROR_NULL_POINTER; 1.979 + 1.980 + NS_PRECONDITION(target != nullptr, "null ptr"); 1.981 + if (! target) 1.982 + return NS_ERROR_NULL_POINTER; 1.983 + 1.984 + Assertion *as = GetForwardArcs(source); 1.985 + if (as && as->mHashEntry) { 1.986 + PLDHashEntryHdr* hdr = PL_DHashTableOperate(as->u.hash.mPropertyHash, property, PL_DHASH_LOOKUP); 1.987 + Assertion* val = PL_DHASH_ENTRY_IS_BUSY(hdr) 1.988 + ? reinterpret_cast<Entry*>(hdr)->mAssertions 1.989 + : nullptr; 1.990 + while (val) { 1.991 + if (tv == val->u.as.mTruthValue) { 1.992 + *target = val->u.as.mTarget; 1.993 + NS_IF_ADDREF(*target); 1.994 + return NS_OK; 1.995 + } 1.996 + val = val->mNext; 1.997 + } 1.998 + } 1.999 + else 1.1000 + for (; as != nullptr; as = as->mNext) { 1.1001 + if ((property == as->u.as.mProperty) && (tv == (as->u.as.mTruthValue))) { 1.1002 + *target = as->u.as.mTarget; 1.1003 + NS_ADDREF(*target); 1.1004 + return NS_OK; 1.1005 + } 1.1006 + } 1.1007 + 1.1008 + // If we get here, then there was no target with for the specified 1.1009 + // property & truth value. 1.1010 + *target = nullptr; 1.1011 + return NS_RDF_NO_VALUE; 1.1012 +} 1.1013 + 1.1014 +NS_IMETHODIMP 1.1015 +InMemoryDataSource::HasAssertion(nsIRDFResource* source, 1.1016 + nsIRDFResource* property, 1.1017 + nsIRDFNode* target, 1.1018 + bool tv, 1.1019 + bool* hasAssertion) 1.1020 +{ 1.1021 + if (! source) 1.1022 + return NS_ERROR_NULL_POINTER; 1.1023 + 1.1024 + if (! property) 1.1025 + return NS_ERROR_NULL_POINTER; 1.1026 + 1.1027 + if (! target) 1.1028 + return NS_ERROR_NULL_POINTER; 1.1029 + 1.1030 + Assertion *as = GetForwardArcs(source); 1.1031 + if (as && as->mHashEntry) { 1.1032 + PLDHashEntryHdr* hdr = PL_DHashTableOperate(as->u.hash.mPropertyHash, property, PL_DHASH_LOOKUP); 1.1033 + Assertion* val = PL_DHASH_ENTRY_IS_BUSY(hdr) 1.1034 + ? reinterpret_cast<Entry*>(hdr)->mAssertions 1.1035 + : nullptr; 1.1036 + while (val) { 1.1037 + if ((val->u.as.mTarget == target) && (tv == (val->u.as.mTruthValue))) { 1.1038 + *hasAssertion = true; 1.1039 + return NS_OK; 1.1040 + } 1.1041 + val = val->mNext; 1.1042 + } 1.1043 + } 1.1044 + else 1.1045 + for (; as != nullptr; as = as->mNext) { 1.1046 + // check target first as its most unique 1.1047 + if (target != as->u.as.mTarget) 1.1048 + continue; 1.1049 + 1.1050 + if (property != as->u.as.mProperty) 1.1051 + continue; 1.1052 + 1.1053 + if (tv != (as->u.as.mTruthValue)) 1.1054 + continue; 1.1055 + 1.1056 + // found it! 1.1057 + *hasAssertion = true; 1.1058 + return NS_OK; 1.1059 + } 1.1060 + 1.1061 + // If we get here, we couldn't find the assertion 1.1062 + *hasAssertion = false; 1.1063 + return NS_OK; 1.1064 +} 1.1065 + 1.1066 +NS_IMETHODIMP 1.1067 +InMemoryDataSource::GetSources(nsIRDFResource* aProperty, 1.1068 + nsIRDFNode* aTarget, 1.1069 + bool aTruthValue, 1.1070 + nsISimpleEnumerator** aResult) 1.1071 +{ 1.1072 + NS_PRECONDITION(aProperty != nullptr, "null ptr"); 1.1073 + if (! aProperty) 1.1074 + return NS_ERROR_NULL_POINTER; 1.1075 + 1.1076 + NS_PRECONDITION(aTarget != nullptr, "null ptr"); 1.1077 + if (! aTarget) 1.1078 + return NS_ERROR_NULL_POINTER; 1.1079 + 1.1080 + NS_PRECONDITION(aResult != nullptr, "null ptr"); 1.1081 + if (! aResult) 1.1082 + return NS_ERROR_NULL_POINTER; 1.1083 + 1.1084 + InMemoryAssertionEnumeratorImpl* result = 1.1085 + new InMemoryAssertionEnumeratorImpl(this, nullptr, aProperty, 1.1086 + aTarget, aTruthValue); 1.1087 + 1.1088 + if (! result) 1.1089 + return NS_ERROR_OUT_OF_MEMORY; 1.1090 + 1.1091 + NS_ADDREF(result); 1.1092 + *aResult = result; 1.1093 + 1.1094 + return NS_OK; 1.1095 +} 1.1096 + 1.1097 +NS_IMETHODIMP 1.1098 +InMemoryDataSource::GetTargets(nsIRDFResource* aSource, 1.1099 + nsIRDFResource* aProperty, 1.1100 + bool aTruthValue, 1.1101 + nsISimpleEnumerator** aResult) 1.1102 +{ 1.1103 + NS_PRECONDITION(aSource != nullptr, "null ptr"); 1.1104 + if (! aSource) 1.1105 + return NS_ERROR_NULL_POINTER; 1.1106 + 1.1107 + NS_PRECONDITION(aProperty != nullptr, "null ptr"); 1.1108 + if (! aProperty) 1.1109 + return NS_ERROR_NULL_POINTER; 1.1110 + 1.1111 + NS_PRECONDITION(aResult != nullptr, "null ptr"); 1.1112 + if (! aResult) 1.1113 + return NS_ERROR_NULL_POINTER; 1.1114 + 1.1115 + InMemoryAssertionEnumeratorImpl* result = 1.1116 + new InMemoryAssertionEnumeratorImpl(this, aSource, aProperty, 1.1117 + nullptr, aTruthValue); 1.1118 + 1.1119 + if (! result) 1.1120 + return NS_ERROR_OUT_OF_MEMORY; 1.1121 + 1.1122 + NS_ADDREF(result); 1.1123 + *aResult = result; 1.1124 + 1.1125 + return NS_OK; 1.1126 +} 1.1127 + 1.1128 + 1.1129 +nsresult 1.1130 +InMemoryDataSource::LockedAssert(nsIRDFResource* aSource, 1.1131 + nsIRDFResource* aProperty, 1.1132 + nsIRDFNode* aTarget, 1.1133 + bool aTruthValue) 1.1134 +{ 1.1135 +#ifdef PR_LOGGING 1.1136 + LogOperation("ASSERT", aSource, aProperty, aTarget, aTruthValue); 1.1137 +#endif 1.1138 + 1.1139 + Assertion* next = GetForwardArcs(aSource); 1.1140 + Assertion* prev = next; 1.1141 + Assertion* as = nullptr; 1.1142 + 1.1143 + bool haveHash = (next) ? next->mHashEntry : false; 1.1144 + if (haveHash) { 1.1145 + PLDHashEntryHdr* hdr = PL_DHashTableOperate(next->u.hash.mPropertyHash, aProperty, PL_DHASH_LOOKUP); 1.1146 + Assertion* val = PL_DHASH_ENTRY_IS_BUSY(hdr) 1.1147 + ? reinterpret_cast<Entry*>(hdr)->mAssertions 1.1148 + : nullptr; 1.1149 + while (val) { 1.1150 + if (val->u.as.mTarget == aTarget) { 1.1151 + // Wow, we already had the assertion. Make sure that the 1.1152 + // truth values are correct and bail. 1.1153 + val->u.as.mTruthValue = aTruthValue; 1.1154 + return NS_OK; 1.1155 + } 1.1156 + val = val->mNext; 1.1157 + } 1.1158 + } 1.1159 + else 1.1160 + { 1.1161 + while (next) { 1.1162 + // check target first as its most unique 1.1163 + if (aTarget == next->u.as.mTarget) { 1.1164 + if (aProperty == next->u.as.mProperty) { 1.1165 + // Wow, we already had the assertion. Make sure that the 1.1166 + // truth values are correct and bail. 1.1167 + next->u.as.mTruthValue = aTruthValue; 1.1168 + return NS_OK; 1.1169 + } 1.1170 + } 1.1171 + 1.1172 + prev = next; 1.1173 + next = next->mNext; 1.1174 + } 1.1175 + } 1.1176 + 1.1177 + as = new Assertion(aSource, aProperty, aTarget, aTruthValue); 1.1178 + if (! as) 1.1179 + return NS_ERROR_OUT_OF_MEMORY; 1.1180 + 1.1181 + // Add the datasource's owning reference. 1.1182 + as->AddRef(); 1.1183 + 1.1184 + if (haveHash) 1.1185 + { 1.1186 + PLDHashEntryHdr* hdr = PL_DHashTableOperate(next->u.hash.mPropertyHash, 1.1187 + aProperty, PL_DHASH_LOOKUP); 1.1188 + Assertion *asRef = PL_DHASH_ENTRY_IS_BUSY(hdr) 1.1189 + ? reinterpret_cast<Entry*>(hdr)->mAssertions 1.1190 + : nullptr; 1.1191 + if (asRef) 1.1192 + { 1.1193 + as->mNext = asRef->mNext; 1.1194 + asRef->mNext = as; 1.1195 + } 1.1196 + else 1.1197 + { 1.1198 + hdr = PL_DHashTableOperate(next->u.hash.mPropertyHash, 1.1199 + aProperty, PL_DHASH_ADD); 1.1200 + if (hdr) 1.1201 + { 1.1202 + Entry* entry = reinterpret_cast<Entry*>(hdr); 1.1203 + entry->mNode = aProperty; 1.1204 + entry->mAssertions = as; 1.1205 + } 1.1206 + } 1.1207 + } 1.1208 + else 1.1209 + { 1.1210 + // Link it in to the "forward arcs" table 1.1211 + if (!prev) { 1.1212 + SetForwardArcs(aSource, as); 1.1213 + } else { 1.1214 + prev->mNext = as; 1.1215 + } 1.1216 + } 1.1217 + 1.1218 + // Link it in to the "reverse arcs" table 1.1219 + 1.1220 + next = GetReverseArcs(aTarget); 1.1221 + as->u.as.mInvNext = next; 1.1222 + next = as; 1.1223 + SetReverseArcs(aTarget, next); 1.1224 + 1.1225 + return NS_OK; 1.1226 +} 1.1227 + 1.1228 +NS_IMETHODIMP 1.1229 +InMemoryDataSource::Assert(nsIRDFResource* aSource, 1.1230 + nsIRDFResource* aProperty, 1.1231 + nsIRDFNode* aTarget, 1.1232 + bool aTruthValue) 1.1233 +{ 1.1234 + NS_PRECONDITION(aSource != nullptr, "null ptr"); 1.1235 + if (! aSource) 1.1236 + return NS_ERROR_NULL_POINTER; 1.1237 + 1.1238 + NS_PRECONDITION(aProperty != nullptr, "null ptr"); 1.1239 + if (! aProperty) 1.1240 + return NS_ERROR_NULL_POINTER; 1.1241 + 1.1242 + NS_PRECONDITION(aTarget != nullptr, "null ptr"); 1.1243 + if (! aTarget) 1.1244 + return NS_ERROR_NULL_POINTER; 1.1245 + 1.1246 + if (mReadCount) { 1.1247 + NS_WARNING("Writing to InMemoryDataSource during read\n"); 1.1248 + return NS_RDF_ASSERTION_REJECTED; 1.1249 + } 1.1250 + 1.1251 + nsresult rv; 1.1252 + rv = LockedAssert(aSource, aProperty, aTarget, aTruthValue); 1.1253 + if (NS_FAILED(rv)) return rv; 1.1254 + 1.1255 + // notify observers 1.1256 + for (int32_t i = (int32_t)mNumObservers - 1; mPropagateChanges && i >= 0; --i) { 1.1257 + nsIRDFObserver* obs = mObservers[i]; 1.1258 + 1.1259 + // XXX this should never happen, but it does, and we can't figure out why. 1.1260 + NS_ASSERTION(obs, "observer array corrupted!"); 1.1261 + if (! obs) 1.1262 + continue; 1.1263 + 1.1264 + obs->OnAssert(this, aSource, aProperty, aTarget); 1.1265 + // XXX ignore return value? 1.1266 + } 1.1267 + 1.1268 + return NS_RDF_ASSERTION_ACCEPTED; 1.1269 +} 1.1270 + 1.1271 + 1.1272 +nsresult 1.1273 +InMemoryDataSource::LockedUnassert(nsIRDFResource* aSource, 1.1274 + nsIRDFResource* aProperty, 1.1275 + nsIRDFNode* aTarget) 1.1276 +{ 1.1277 +#ifdef PR_LOGGING 1.1278 + LogOperation("UNASSERT", aSource, aProperty, aTarget); 1.1279 +#endif 1.1280 + 1.1281 + Assertion* next = GetForwardArcs(aSource); 1.1282 + Assertion* prev = next; 1.1283 + Assertion* root = next; 1.1284 + Assertion* as = nullptr; 1.1285 + 1.1286 + bool haveHash = (next) ? next->mHashEntry : false; 1.1287 + if (haveHash) { 1.1288 + PLDHashEntryHdr* hdr = PL_DHashTableOperate(next->u.hash.mPropertyHash, 1.1289 + aProperty, PL_DHASH_LOOKUP); 1.1290 + prev = next = PL_DHASH_ENTRY_IS_BUSY(hdr) 1.1291 + ? reinterpret_cast<Entry*>(hdr)->mAssertions 1.1292 + : nullptr; 1.1293 + bool first = true; 1.1294 + while (next) { 1.1295 + if (aTarget == next->u.as.mTarget) { 1.1296 + break; 1.1297 + } 1.1298 + first = false; 1.1299 + prev = next; 1.1300 + next = next->mNext; 1.1301 + } 1.1302 + // We don't even have the assertion, so just bail. 1.1303 + if (!next) 1.1304 + return NS_OK; 1.1305 + 1.1306 + as = next; 1.1307 + 1.1308 + if (first) { 1.1309 + PL_DHashTableRawRemove(root->u.hash.mPropertyHash, hdr); 1.1310 + 1.1311 + if (next && next->mNext) { 1.1312 + PLDHashEntryHdr* hdr = PL_DHashTableOperate(root->u.hash.mPropertyHash, 1.1313 + aProperty, PL_DHASH_ADD); 1.1314 + if (hdr) { 1.1315 + Entry* entry = reinterpret_cast<Entry*>(hdr); 1.1316 + entry->mNode = aProperty; 1.1317 + entry->mAssertions = next->mNext; 1.1318 + } 1.1319 + } 1.1320 + else { 1.1321 + // If this second-level hash empties out, clean it up. 1.1322 + if (!root->u.hash.mPropertyHash->entryCount) { 1.1323 + delete root; 1.1324 + SetForwardArcs(aSource, nullptr); 1.1325 + } 1.1326 + } 1.1327 + } 1.1328 + else { 1.1329 + prev->mNext = next->mNext; 1.1330 + } 1.1331 + } 1.1332 + else 1.1333 + { 1.1334 + while (next) { 1.1335 + // check target first as its most unique 1.1336 + if (aTarget == next->u.as.mTarget) { 1.1337 + if (aProperty == next->u.as.mProperty) { 1.1338 + if (prev == next) { 1.1339 + SetForwardArcs(aSource, next->mNext); 1.1340 + } else { 1.1341 + prev->mNext = next->mNext; 1.1342 + } 1.1343 + as = next; 1.1344 + break; 1.1345 + } 1.1346 + } 1.1347 + 1.1348 + prev = next; 1.1349 + next = next->mNext; 1.1350 + } 1.1351 + } 1.1352 + // We don't even have the assertion, so just bail. 1.1353 + if (!as) 1.1354 + return NS_OK; 1.1355 + 1.1356 +#ifdef DEBUG 1.1357 + bool foundReverseArc = false; 1.1358 +#endif 1.1359 + 1.1360 + next = prev = GetReverseArcs(aTarget); 1.1361 + while (next) { 1.1362 + if (next == as) { 1.1363 + if (prev == next) { 1.1364 + SetReverseArcs(aTarget, next->u.as.mInvNext); 1.1365 + } else { 1.1366 + prev->u.as.mInvNext = next->u.as.mInvNext; 1.1367 + } 1.1368 +#ifdef DEBUG 1.1369 + foundReverseArc = true; 1.1370 +#endif 1.1371 + break; 1.1372 + } 1.1373 + prev = next; 1.1374 + next = next->u.as.mInvNext; 1.1375 + } 1.1376 + 1.1377 +#ifdef DEBUG 1.1378 + NS_ASSERTION(foundReverseArc, "in-memory db corrupted: unable to find reverse arc"); 1.1379 +#endif 1.1380 + 1.1381 + // Unlink, and release the datasource's reference 1.1382 + as->mNext = as->u.as.mInvNext = nullptr; 1.1383 + as->Release(); 1.1384 + 1.1385 + return NS_OK; 1.1386 +} 1.1387 + 1.1388 +NS_IMETHODIMP 1.1389 +InMemoryDataSource::Unassert(nsIRDFResource* aSource, 1.1390 + nsIRDFResource* aProperty, 1.1391 + nsIRDFNode* aTarget) 1.1392 +{ 1.1393 + NS_PRECONDITION(aSource != nullptr, "null ptr"); 1.1394 + if (! aSource) 1.1395 + return NS_ERROR_NULL_POINTER; 1.1396 + 1.1397 + NS_PRECONDITION(aProperty != nullptr, "null ptr"); 1.1398 + if (! aProperty) 1.1399 + return NS_ERROR_NULL_POINTER; 1.1400 + 1.1401 + NS_PRECONDITION(aTarget != nullptr, "null ptr"); 1.1402 + if (! aTarget) 1.1403 + return NS_ERROR_NULL_POINTER; 1.1404 + 1.1405 + if (mReadCount) { 1.1406 + NS_WARNING("Writing to InMemoryDataSource during read\n"); 1.1407 + return NS_RDF_ASSERTION_REJECTED; 1.1408 + } 1.1409 + 1.1410 + nsresult rv; 1.1411 + 1.1412 + rv = LockedUnassert(aSource, aProperty, aTarget); 1.1413 + if (NS_FAILED(rv)) return rv; 1.1414 + 1.1415 + // Notify the world 1.1416 + for (int32_t i = int32_t(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) { 1.1417 + nsIRDFObserver* obs = mObservers[i]; 1.1418 + 1.1419 + // XXX this should never happen, but it does, and we can't figure out why. 1.1420 + NS_ASSERTION(obs, "observer array corrupted!"); 1.1421 + if (! obs) 1.1422 + continue; 1.1423 + 1.1424 + obs->OnUnassert(this, aSource, aProperty, aTarget); 1.1425 + // XXX ignore return value? 1.1426 + } 1.1427 + 1.1428 + return NS_RDF_ASSERTION_ACCEPTED; 1.1429 +} 1.1430 + 1.1431 + 1.1432 +NS_IMETHODIMP 1.1433 +InMemoryDataSource::Change(nsIRDFResource* aSource, 1.1434 + nsIRDFResource* aProperty, 1.1435 + nsIRDFNode* aOldTarget, 1.1436 + nsIRDFNode* aNewTarget) 1.1437 +{ 1.1438 + NS_PRECONDITION(aSource != nullptr, "null ptr"); 1.1439 + if (! aSource) 1.1440 + return NS_ERROR_NULL_POINTER; 1.1441 + 1.1442 + NS_PRECONDITION(aProperty != nullptr, "null ptr"); 1.1443 + if (! aProperty) 1.1444 + return NS_ERROR_NULL_POINTER; 1.1445 + 1.1446 + NS_PRECONDITION(aOldTarget != nullptr, "null ptr"); 1.1447 + if (! aOldTarget) 1.1448 + return NS_ERROR_NULL_POINTER; 1.1449 + 1.1450 + NS_PRECONDITION(aNewTarget != nullptr, "null ptr"); 1.1451 + if (! aNewTarget) 1.1452 + return NS_ERROR_NULL_POINTER; 1.1453 + 1.1454 + if (mReadCount) { 1.1455 + NS_WARNING("Writing to InMemoryDataSource during read\n"); 1.1456 + return NS_RDF_ASSERTION_REJECTED; 1.1457 + } 1.1458 + 1.1459 + nsresult rv; 1.1460 + 1.1461 + // XXX We can implement LockedChange() if we decide that this 1.1462 + // is a performance bottleneck. 1.1463 + 1.1464 + rv = LockedUnassert(aSource, aProperty, aOldTarget); 1.1465 + if (NS_FAILED(rv)) return rv; 1.1466 + 1.1467 + rv = LockedAssert(aSource, aProperty, aNewTarget, true); 1.1468 + if (NS_FAILED(rv)) return rv; 1.1469 + 1.1470 + // Notify the world 1.1471 + for (int32_t i = int32_t(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) { 1.1472 + nsIRDFObserver* obs = mObservers[i]; 1.1473 + 1.1474 + // XXX this should never happen, but it does, and we can't figure out why. 1.1475 + NS_ASSERTION(obs, "observer array corrupted!"); 1.1476 + if (! obs) 1.1477 + continue; 1.1478 + 1.1479 + obs->OnChange(this, aSource, aProperty, aOldTarget, aNewTarget); 1.1480 + // XXX ignore return value? 1.1481 + } 1.1482 + 1.1483 + return NS_RDF_ASSERTION_ACCEPTED; 1.1484 +} 1.1485 + 1.1486 + 1.1487 +NS_IMETHODIMP 1.1488 +InMemoryDataSource::Move(nsIRDFResource* aOldSource, 1.1489 + nsIRDFResource* aNewSource, 1.1490 + nsIRDFResource* aProperty, 1.1491 + nsIRDFNode* aTarget) 1.1492 +{ 1.1493 + NS_PRECONDITION(aOldSource != nullptr, "null ptr"); 1.1494 + if (! aOldSource) 1.1495 + return NS_ERROR_NULL_POINTER; 1.1496 + 1.1497 + NS_PRECONDITION(aNewSource != nullptr, "null ptr"); 1.1498 + if (! aNewSource) 1.1499 + return NS_ERROR_NULL_POINTER; 1.1500 + 1.1501 + NS_PRECONDITION(aProperty != nullptr, "null ptr"); 1.1502 + if (! aProperty) 1.1503 + return NS_ERROR_NULL_POINTER; 1.1504 + 1.1505 + NS_PRECONDITION(aTarget != nullptr, "null ptr"); 1.1506 + if (! aTarget) 1.1507 + return NS_ERROR_NULL_POINTER; 1.1508 + 1.1509 + if (mReadCount) { 1.1510 + NS_WARNING("Writing to InMemoryDataSource during read\n"); 1.1511 + return NS_RDF_ASSERTION_REJECTED; 1.1512 + } 1.1513 + 1.1514 + nsresult rv; 1.1515 + 1.1516 + // XXX We can implement LockedMove() if we decide that this 1.1517 + // is a performance bottleneck. 1.1518 + 1.1519 + rv = LockedUnassert(aOldSource, aProperty, aTarget); 1.1520 + if (NS_FAILED(rv)) return rv; 1.1521 + 1.1522 + rv = LockedAssert(aNewSource, aProperty, aTarget, true); 1.1523 + if (NS_FAILED(rv)) return rv; 1.1524 + 1.1525 + // Notify the world 1.1526 + for (int32_t i = int32_t(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) { 1.1527 + nsIRDFObserver* obs = mObservers[i]; 1.1528 + 1.1529 + // XXX this should never happen, but it does, and we can't figure out why. 1.1530 + NS_ASSERTION(obs, "observer array corrupted!"); 1.1531 + if (! obs) 1.1532 + continue; 1.1533 + 1.1534 + obs->OnMove(this, aOldSource, aNewSource, aProperty, aTarget); 1.1535 + // XXX ignore return value? 1.1536 + } 1.1537 + 1.1538 + return NS_RDF_ASSERTION_ACCEPTED; 1.1539 +} 1.1540 + 1.1541 + 1.1542 +NS_IMETHODIMP 1.1543 +InMemoryDataSource::AddObserver(nsIRDFObserver* aObserver) 1.1544 +{ 1.1545 + NS_PRECONDITION(aObserver != nullptr, "null ptr"); 1.1546 + if (! aObserver) 1.1547 + return NS_ERROR_NULL_POINTER; 1.1548 + 1.1549 + mObservers.AppendObject(aObserver); 1.1550 + mNumObservers = mObservers.Count(); 1.1551 + 1.1552 + return NS_OK; 1.1553 +} 1.1554 + 1.1555 +NS_IMETHODIMP 1.1556 +InMemoryDataSource::RemoveObserver(nsIRDFObserver* aObserver) 1.1557 +{ 1.1558 + NS_PRECONDITION(aObserver != nullptr, "null ptr"); 1.1559 + if (! aObserver) 1.1560 + return NS_ERROR_NULL_POINTER; 1.1561 + 1.1562 + mObservers.RemoveObject(aObserver); 1.1563 + // note: use Count() instead of just decrementing 1.1564 + // in case aObserver wasn't in list, for example 1.1565 + mNumObservers = mObservers.Count(); 1.1566 + 1.1567 + return NS_OK; 1.1568 +} 1.1569 + 1.1570 +NS_IMETHODIMP 1.1571 +InMemoryDataSource::HasArcIn(nsIRDFNode *aNode, nsIRDFResource *aArc, bool *result) 1.1572 +{ 1.1573 + Assertion* ass = GetReverseArcs(aNode); 1.1574 + while (ass) { 1.1575 + nsIRDFResource* elbow = ass->u.as.mProperty; 1.1576 + if (elbow == aArc) { 1.1577 + *result = true; 1.1578 + return NS_OK; 1.1579 + } 1.1580 + ass = ass->u.as.mInvNext; 1.1581 + } 1.1582 + *result = false; 1.1583 + return NS_OK; 1.1584 +} 1.1585 + 1.1586 +NS_IMETHODIMP 1.1587 +InMemoryDataSource::HasArcOut(nsIRDFResource *aSource, nsIRDFResource *aArc, bool *result) 1.1588 +{ 1.1589 + Assertion* ass = GetForwardArcs(aSource); 1.1590 + if (ass && ass->mHashEntry) { 1.1591 + PLDHashEntryHdr* hdr = PL_DHashTableOperate(ass->u.hash.mPropertyHash, 1.1592 + aArc, PL_DHASH_LOOKUP); 1.1593 + Assertion* val = PL_DHASH_ENTRY_IS_BUSY(hdr) 1.1594 + ? reinterpret_cast<Entry*>(hdr)->mAssertions 1.1595 + : nullptr; 1.1596 + if (val) { 1.1597 + *result = true; 1.1598 + return NS_OK; 1.1599 + } 1.1600 + ass = ass->mNext; 1.1601 + } 1.1602 + while (ass) { 1.1603 + nsIRDFResource* elbow = ass->u.as.mProperty; 1.1604 + if (elbow == aArc) { 1.1605 + *result = true; 1.1606 + return NS_OK; 1.1607 + } 1.1608 + ass = ass->mNext; 1.1609 + } 1.1610 + *result = false; 1.1611 + return NS_OK; 1.1612 +} 1.1613 + 1.1614 +NS_IMETHODIMP 1.1615 +InMemoryDataSource::ArcLabelsIn(nsIRDFNode* aTarget, nsISimpleEnumerator** aResult) 1.1616 +{ 1.1617 + NS_PRECONDITION(aTarget != nullptr, "null ptr"); 1.1618 + if (! aTarget) 1.1619 + return NS_ERROR_NULL_POINTER; 1.1620 + 1.1621 + InMemoryArcsEnumeratorImpl* result = 1.1622 + new InMemoryArcsEnumeratorImpl(this, nullptr, aTarget); 1.1623 + 1.1624 + if (! result) 1.1625 + return NS_ERROR_OUT_OF_MEMORY; 1.1626 + 1.1627 + NS_ADDREF(result); 1.1628 + *aResult = result; 1.1629 + 1.1630 + return NS_OK; 1.1631 +} 1.1632 + 1.1633 +NS_IMETHODIMP 1.1634 +InMemoryDataSource::ArcLabelsOut(nsIRDFResource* aSource, nsISimpleEnumerator** aResult) 1.1635 +{ 1.1636 + NS_PRECONDITION(aSource != nullptr, "null ptr"); 1.1637 + if (! aSource) 1.1638 + return NS_ERROR_NULL_POINTER; 1.1639 + 1.1640 + InMemoryArcsEnumeratorImpl* result = 1.1641 + new InMemoryArcsEnumeratorImpl(this, aSource, nullptr); 1.1642 + 1.1643 + if (! result) 1.1644 + return NS_ERROR_OUT_OF_MEMORY; 1.1645 + 1.1646 + NS_ADDREF(result); 1.1647 + *aResult = result; 1.1648 + 1.1649 + return NS_OK; 1.1650 +} 1.1651 + 1.1652 +PLDHashOperator 1.1653 +InMemoryDataSource::ResourceEnumerator(PLDHashTable* aTable, 1.1654 + PLDHashEntryHdr* aHdr, 1.1655 + uint32_t aNumber, void* aArg) 1.1656 +{ 1.1657 + Entry* entry = reinterpret_cast<Entry*>(aHdr); 1.1658 + static_cast<nsCOMArray<nsIRDFNode>*>(aArg)->AppendObject(entry->mNode); 1.1659 + return PL_DHASH_NEXT; 1.1660 +} 1.1661 + 1.1662 + 1.1663 +NS_IMETHODIMP 1.1664 +InMemoryDataSource::GetAllResources(nsISimpleEnumerator** aResult) 1.1665 +{ 1.1666 + nsCOMArray<nsIRDFNode> nodes; 1.1667 + nodes.SetCapacity(mForwardArcs.entryCount); 1.1668 + 1.1669 + // Enumerate all of our entries into an nsCOMArray 1.1670 + PL_DHashTableEnumerate(&mForwardArcs, ResourceEnumerator, &nodes); 1.1671 + 1.1672 + return NS_NewArrayEnumerator(aResult, nodes); 1.1673 +} 1.1674 + 1.1675 +NS_IMETHODIMP 1.1676 +InMemoryDataSource::GetAllCmds(nsIRDFResource* source, 1.1677 + nsISimpleEnumerator/*<nsIRDFResource>*/** commands) 1.1678 +{ 1.1679 + return(NS_NewEmptyEnumerator(commands)); 1.1680 +} 1.1681 + 1.1682 +NS_IMETHODIMP 1.1683 +InMemoryDataSource::IsCommandEnabled(nsISupportsArray/*<nsIRDFResource>*/* aSources, 1.1684 + nsIRDFResource* aCommand, 1.1685 + nsISupportsArray/*<nsIRDFResource>*/* aArguments, 1.1686 + bool* aResult) 1.1687 +{ 1.1688 + *aResult = false; 1.1689 + return NS_OK; 1.1690 +} 1.1691 + 1.1692 +NS_IMETHODIMP 1.1693 +InMemoryDataSource::DoCommand(nsISupportsArray/*<nsIRDFResource>*/* aSources, 1.1694 + nsIRDFResource* aCommand, 1.1695 + nsISupportsArray/*<nsIRDFResource>*/* aArguments) 1.1696 +{ 1.1697 + return NS_OK; 1.1698 +} 1.1699 + 1.1700 +NS_IMETHODIMP 1.1701 +InMemoryDataSource::BeginUpdateBatch() 1.1702 +{ 1.1703 + for (int32_t i = int32_t(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) { 1.1704 + nsIRDFObserver* obs = mObservers[i]; 1.1705 + obs->OnBeginUpdateBatch(this); 1.1706 + } 1.1707 + return NS_OK; 1.1708 +} 1.1709 + 1.1710 +NS_IMETHODIMP 1.1711 +InMemoryDataSource::EndUpdateBatch() 1.1712 +{ 1.1713 + for (int32_t i = int32_t(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) { 1.1714 + nsIRDFObserver* obs = mObservers[i]; 1.1715 + obs->OnEndUpdateBatch(this); 1.1716 + } 1.1717 + return NS_OK; 1.1718 +} 1.1719 + 1.1720 + 1.1721 + 1.1722 +//////////////////////////////////////////////////////////////////////// 1.1723 +// nsIRDFInMemoryDataSource methods 1.1724 + 1.1725 +NS_IMETHODIMP 1.1726 +InMemoryDataSource::EnsureFastContainment(nsIRDFResource* aSource) 1.1727 +{ 1.1728 + Assertion *as = GetForwardArcs(aSource); 1.1729 + bool haveHash = (as) ? as->mHashEntry : false; 1.1730 + 1.1731 + // if its already a hash, then nothing to do 1.1732 + if (haveHash) return(NS_OK); 1.1733 + 1.1734 + // convert aSource in forward hash into a hash 1.1735 + Assertion *hashAssertion = new Assertion(aSource); 1.1736 + NS_ASSERTION(hashAssertion, "unable to create Assertion"); 1.1737 + if (!hashAssertion) return(NS_ERROR_OUT_OF_MEMORY); 1.1738 + 1.1739 + // Add the datasource's owning reference. 1.1740 + hashAssertion->AddRef(); 1.1741 + 1.1742 + Assertion *first = GetForwardArcs(aSource); 1.1743 + SetForwardArcs(aSource, hashAssertion); 1.1744 + 1.1745 + // mutate references of existing forward assertions into this hash 1.1746 + PLDHashTable *table = hashAssertion->u.hash.mPropertyHash; 1.1747 + Assertion *nextRef; 1.1748 + while(first) { 1.1749 + nextRef = first->mNext; 1.1750 + nsIRDFResource *prop = first->u.as.mProperty; 1.1751 + 1.1752 + PLDHashEntryHdr* hdr = PL_DHashTableOperate(table, 1.1753 + prop, PL_DHASH_LOOKUP); 1.1754 + Assertion* val = PL_DHASH_ENTRY_IS_BUSY(hdr) 1.1755 + ? reinterpret_cast<Entry*>(hdr)->mAssertions 1.1756 + : nullptr; 1.1757 + if (val) { 1.1758 + first->mNext = val->mNext; 1.1759 + val->mNext = first; 1.1760 + } 1.1761 + else { 1.1762 + PLDHashEntryHdr* hdr = PL_DHashTableOperate(table, 1.1763 + prop, PL_DHASH_ADD); 1.1764 + if (hdr) { 1.1765 + Entry* entry = reinterpret_cast<Entry*>(hdr); 1.1766 + entry->mNode = prop; 1.1767 + entry->mAssertions = first; 1.1768 + first->mNext = nullptr; 1.1769 + } 1.1770 + } 1.1771 + first = nextRef; 1.1772 + } 1.1773 + return(NS_OK); 1.1774 +} 1.1775 + 1.1776 + 1.1777 +//////////////////////////////////////////////////////////////////////// 1.1778 +// nsIRDFPropagatableDataSource methods 1.1779 +NS_IMETHODIMP 1.1780 +InMemoryDataSource::GetPropagateChanges(bool* aPropagateChanges) 1.1781 +{ 1.1782 + *aPropagateChanges = mPropagateChanges; 1.1783 + return NS_OK; 1.1784 +} 1.1785 + 1.1786 +NS_IMETHODIMP 1.1787 +InMemoryDataSource::SetPropagateChanges(bool aPropagateChanges) 1.1788 +{ 1.1789 + mPropagateChanges = aPropagateChanges; 1.1790 + return NS_OK; 1.1791 +} 1.1792 + 1.1793 + 1.1794 +//////////////////////////////////////////////////////////////////////// 1.1795 +// nsIRDFPurgeableDataSource methods 1.1796 + 1.1797 +NS_IMETHODIMP 1.1798 +InMemoryDataSource::Mark(nsIRDFResource* aSource, 1.1799 + nsIRDFResource* aProperty, 1.1800 + nsIRDFNode* aTarget, 1.1801 + bool aTruthValue, 1.1802 + bool* aDidMark) 1.1803 +{ 1.1804 + NS_PRECONDITION(aSource != nullptr, "null ptr"); 1.1805 + if (! aSource) 1.1806 + return NS_ERROR_NULL_POINTER; 1.1807 + 1.1808 + NS_PRECONDITION(aProperty != nullptr, "null ptr"); 1.1809 + if (! aProperty) 1.1810 + return NS_ERROR_NULL_POINTER; 1.1811 + 1.1812 + NS_PRECONDITION(aTarget != nullptr, "null ptr"); 1.1813 + if (! aTarget) 1.1814 + return NS_ERROR_NULL_POINTER; 1.1815 + 1.1816 + Assertion *as = GetForwardArcs(aSource); 1.1817 + if (as && as->mHashEntry) { 1.1818 + PLDHashEntryHdr* hdr = PL_DHashTableOperate(as->u.hash.mPropertyHash, 1.1819 + aProperty, PL_DHASH_LOOKUP); 1.1820 + Assertion* val = PL_DHASH_ENTRY_IS_BUSY(hdr) 1.1821 + ? reinterpret_cast<Entry*>(hdr)->mAssertions 1.1822 + : nullptr; 1.1823 + while (val) { 1.1824 + if ((val->u.as.mTarget == aTarget) && 1.1825 + (aTruthValue == (val->u.as.mTruthValue))) { 1.1826 + 1.1827 + // found it! so mark it. 1.1828 + as->Mark(); 1.1829 + *aDidMark = true; 1.1830 + 1.1831 +#ifdef PR_LOGGING 1.1832 + LogOperation("MARK", aSource, aProperty, aTarget, aTruthValue); 1.1833 +#endif 1.1834 + 1.1835 + return NS_OK; 1.1836 + } 1.1837 + val = val->mNext; 1.1838 + } 1.1839 + } 1.1840 + else for (; as != nullptr; as = as->mNext) { 1.1841 + // check target first as its most unique 1.1842 + if (aTarget != as->u.as.mTarget) 1.1843 + continue; 1.1844 + 1.1845 + if (aProperty != as->u.as.mProperty) 1.1846 + continue; 1.1847 + 1.1848 + if (aTruthValue != (as->u.as.mTruthValue)) 1.1849 + continue; 1.1850 + 1.1851 + // found it! so mark it. 1.1852 + as->Mark(); 1.1853 + *aDidMark = true; 1.1854 + 1.1855 +#ifdef PR_LOGGING 1.1856 + LogOperation("MARK", aSource, aProperty, aTarget, aTruthValue); 1.1857 +#endif 1.1858 + 1.1859 + return NS_OK; 1.1860 + } 1.1861 + 1.1862 + // If we get here, we couldn't find the assertion 1.1863 + *aDidMark = false; 1.1864 + return NS_OK; 1.1865 +} 1.1866 + 1.1867 + 1.1868 +struct SweepInfo { 1.1869 + Assertion* mUnassertList; 1.1870 + PLDHashTable* mReverseArcs; 1.1871 +}; 1.1872 + 1.1873 +NS_IMETHODIMP 1.1874 +InMemoryDataSource::Sweep() 1.1875 +{ 1.1876 + SweepInfo info = { nullptr, &mReverseArcs }; 1.1877 + 1.1878 + // Remove all the assertions, but don't notify anyone. 1.1879 + PL_DHashTableEnumerate(&mForwardArcs, SweepForwardArcsEntries, &info); 1.1880 + 1.1881 + // Now do the notification. 1.1882 + Assertion* as = info.mUnassertList; 1.1883 + while (as) { 1.1884 +#ifdef PR_LOGGING 1.1885 + LogOperation("SWEEP", as->mSource, as->u.as.mProperty, as->u.as.mTarget, as->u.as.mTruthValue); 1.1886 +#endif 1.1887 + if (!(as->mHashEntry)) 1.1888 + { 1.1889 + for (int32_t i = int32_t(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) { 1.1890 + nsIRDFObserver* obs = mObservers[i]; 1.1891 + // XXXbz other loops over mObservers null-check |obs| here! 1.1892 + obs->OnUnassert(this, as->mSource, as->u.as.mProperty, as->u.as.mTarget); 1.1893 + // XXX ignore return value? 1.1894 + } 1.1895 + } 1.1896 + 1.1897 + Assertion* doomed = as; 1.1898 + as = as->mNext; 1.1899 + 1.1900 + // Unlink, and release the datasource's reference 1.1901 + doomed->mNext = doomed->u.as.mInvNext = nullptr; 1.1902 + doomed->Release(); 1.1903 + } 1.1904 + 1.1905 + return NS_OK; 1.1906 +} 1.1907 + 1.1908 + 1.1909 +PLDHashOperator 1.1910 +InMemoryDataSource::SweepForwardArcsEntries(PLDHashTable* aTable, 1.1911 + PLDHashEntryHdr* aHdr, 1.1912 + uint32_t aNumber, void* aArg) 1.1913 +{ 1.1914 + PLDHashOperator result = PL_DHASH_NEXT; 1.1915 + Entry* entry = reinterpret_cast<Entry*>(aHdr); 1.1916 + SweepInfo* info = static_cast<SweepInfo*>(aArg); 1.1917 + 1.1918 + Assertion* as = entry->mAssertions; 1.1919 + if (as && (as->mHashEntry)) 1.1920 + { 1.1921 + // Stuff in sub-hashes must be swept recursively (max depth: 1) 1.1922 + PL_DHashTableEnumerate(as->u.hash.mPropertyHash, 1.1923 + SweepForwardArcsEntries, info); 1.1924 + 1.1925 + // If the sub-hash is now empty, clean it up. 1.1926 + if (!as->u.hash.mPropertyHash->entryCount) { 1.1927 + delete as; 1.1928 + result = PL_DHASH_REMOVE; 1.1929 + } 1.1930 + 1.1931 + return result; 1.1932 + } 1.1933 + 1.1934 + Assertion* prev = nullptr; 1.1935 + while (as) { 1.1936 + if (as->IsMarked()) { 1.1937 + prev = as; 1.1938 + as->Unmark(); 1.1939 + as = as->mNext; 1.1940 + } 1.1941 + else { 1.1942 + // remove from the list of assertions in the datasource 1.1943 + Assertion* next = as->mNext; 1.1944 + if (prev) { 1.1945 + prev->mNext = next; 1.1946 + } 1.1947 + else { 1.1948 + // it's the first one. update the hashtable entry. 1.1949 + entry->mAssertions = next; 1.1950 + } 1.1951 + 1.1952 + // remove from the reverse arcs 1.1953 + PLDHashEntryHdr* hdr = 1.1954 + PL_DHashTableOperate(info->mReverseArcs, as->u.as.mTarget, PL_DHASH_LOOKUP); 1.1955 + NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(hdr), "no assertion in reverse arcs"); 1.1956 + 1.1957 + Entry* rentry = reinterpret_cast<Entry*>(hdr); 1.1958 + Assertion* ras = rentry->mAssertions; 1.1959 + Assertion* rprev = nullptr; 1.1960 + while (ras) { 1.1961 + if (ras == as) { 1.1962 + if (rprev) { 1.1963 + rprev->u.as.mInvNext = ras->u.as.mInvNext; 1.1964 + } 1.1965 + else { 1.1966 + // it's the first one. update the hashtable entry. 1.1967 + rentry->mAssertions = ras->u.as.mInvNext; 1.1968 + } 1.1969 + as->u.as.mInvNext = nullptr; // for my sanity. 1.1970 + break; 1.1971 + } 1.1972 + rprev = ras; 1.1973 + ras = ras->u.as.mInvNext; 1.1974 + } 1.1975 + 1.1976 + // Wow, it was the _only_ one. Unhash it. 1.1977 + if (! rentry->mAssertions) 1.1978 + { 1.1979 + PL_DHashTableRawRemove(info->mReverseArcs, hdr); 1.1980 + } 1.1981 + 1.1982 + // add to the list of assertions to unassert 1.1983 + as->mNext = info->mUnassertList; 1.1984 + info->mUnassertList = as; 1.1985 + 1.1986 + // Advance to the next assertion 1.1987 + as = next; 1.1988 + } 1.1989 + } 1.1990 + 1.1991 + // if no more assertions exist for this resource, then unhash it. 1.1992 + if (! entry->mAssertions) 1.1993 + result = PL_DHASH_REMOVE; 1.1994 + 1.1995 + return result; 1.1996 +} 1.1997 + 1.1998 +//////////////////////////////////////////////////////////////////////// 1.1999 +// rdfIDataSource methods 1.2000 + 1.2001 +class VisitorClosure 1.2002 +{ 1.2003 +public: 1.2004 + VisitorClosure(rdfITripleVisitor* aVisitor) : 1.2005 + mVisitor(aVisitor), 1.2006 + mRv(NS_OK) 1.2007 + {} 1.2008 + rdfITripleVisitor* mVisitor; 1.2009 + nsresult mRv; 1.2010 +}; 1.2011 + 1.2012 +PLDHashOperator 1.2013 +SubjectEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aHdr, 1.2014 + uint32_t aNumber, void* aArg) { 1.2015 + Entry* entry = reinterpret_cast<Entry*>(aHdr); 1.2016 + VisitorClosure* closure = static_cast<VisitorClosure*>(aArg); 1.2017 + 1.2018 + nsresult rv; 1.2019 + nsCOMPtr<nsIRDFNode> subject = do_QueryInterface(entry->mNode, &rv); 1.2020 + NS_ENSURE_SUCCESS(rv, PL_DHASH_NEXT); 1.2021 + 1.2022 + closure->mRv = closure->mVisitor->Visit(subject, nullptr, nullptr, true); 1.2023 + if (NS_FAILED(closure->mRv) || closure->mRv == NS_RDF_STOP_VISIT) 1.2024 + return PL_DHASH_STOP; 1.2025 + 1.2026 + return PL_DHASH_NEXT; 1.2027 +} 1.2028 + 1.2029 +NS_IMETHODIMP 1.2030 +InMemoryDataSource::VisitAllSubjects(rdfITripleVisitor *aVisitor) 1.2031 +{ 1.2032 + // Lock datasource against writes 1.2033 + ++mReadCount; 1.2034 + 1.2035 + // Enumerate all of our entries into an nsISupportsArray. 1.2036 + VisitorClosure cls(aVisitor); 1.2037 + PL_DHashTableEnumerate(&mForwardArcs, SubjectEnumerator, &cls); 1.2038 + 1.2039 + // Unlock datasource 1.2040 + --mReadCount; 1.2041 + 1.2042 + return cls.mRv; 1.2043 +} 1.2044 + 1.2045 +class TriplesInnerClosure 1.2046 +{ 1.2047 +public: 1.2048 + TriplesInnerClosure(nsIRDFNode* aSubject, VisitorClosure* aClosure) : 1.2049 + mSubject(aSubject), mOuter(aClosure) {} 1.2050 + nsIRDFNode* mSubject; 1.2051 + VisitorClosure* mOuter; 1.2052 +}; 1.2053 + 1.2054 +PLDHashOperator 1.2055 +TriplesInnerEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aHdr, 1.2056 + uint32_t aNumber, void* aArg) { 1.2057 + Entry* entry = reinterpret_cast<Entry*>(aHdr); 1.2058 + Assertion* assertion = entry->mAssertions; 1.2059 + TriplesInnerClosure* closure = 1.2060 + static_cast<TriplesInnerClosure*>(aArg); 1.2061 + while (assertion) { 1.2062 + NS_ASSERTION(!assertion->mHashEntry, "shouldn't have to hashes"); 1.2063 + VisitorClosure* cls = closure->mOuter; 1.2064 + cls->mRv = cls->mVisitor->Visit(closure->mSubject, 1.2065 + assertion->u.as.mProperty, 1.2066 + assertion->u.as.mTarget, 1.2067 + assertion->u.as.mTruthValue); 1.2068 + if (NS_FAILED(cls->mRv) || cls->mRv == NS_RDF_STOP_VISIT) { 1.2069 + return PL_DHASH_STOP; 1.2070 + } 1.2071 + assertion = assertion->mNext; 1.2072 + } 1.2073 + return PL_DHASH_NEXT; 1.2074 +} 1.2075 +PLDHashOperator 1.2076 +TriplesEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aHdr, 1.2077 + uint32_t aNumber, void* aArg) { 1.2078 + Entry* entry = reinterpret_cast<Entry*>(aHdr); 1.2079 + VisitorClosure* closure = static_cast<VisitorClosure*>(aArg); 1.2080 + 1.2081 + nsresult rv; 1.2082 + nsCOMPtr<nsIRDFNode> subject = do_QueryInterface(entry->mNode, &rv); 1.2083 + NS_ENSURE_SUCCESS(rv, PL_DHASH_NEXT); 1.2084 + 1.2085 + if (entry->mAssertions->mHashEntry) { 1.2086 + TriplesInnerClosure cls(subject, closure); 1.2087 + PL_DHashTableEnumerate(entry->mAssertions->u.hash.mPropertyHash, 1.2088 + TriplesInnerEnumerator, &cls); 1.2089 + if (NS_FAILED(closure->mRv)) { 1.2090 + return PL_DHASH_STOP; 1.2091 + } 1.2092 + return PL_DHASH_NEXT; 1.2093 + } 1.2094 + Assertion* assertion = entry->mAssertions; 1.2095 + while (assertion) { 1.2096 + NS_ASSERTION(!assertion->mHashEntry, "shouldn't have to hashes"); 1.2097 + closure->mRv = closure->mVisitor->Visit(subject, 1.2098 + assertion->u.as.mProperty, 1.2099 + assertion->u.as.mTarget, 1.2100 + assertion->u.as.mTruthValue); 1.2101 + if (NS_FAILED(closure->mRv) || closure->mRv == NS_RDF_STOP_VISIT) { 1.2102 + return PL_DHASH_STOP; 1.2103 + } 1.2104 + assertion = assertion->mNext; 1.2105 + } 1.2106 + return PL_DHASH_NEXT; 1.2107 +} 1.2108 +NS_IMETHODIMP 1.2109 +InMemoryDataSource::VisitAllTriples(rdfITripleVisitor *aVisitor) 1.2110 +{ 1.2111 + // Lock datasource against writes 1.2112 + ++mReadCount; 1.2113 + 1.2114 + // Enumerate all of our entries into an nsISupportsArray. 1.2115 + VisitorClosure cls(aVisitor); 1.2116 + PL_DHashTableEnumerate(&mForwardArcs, TriplesEnumerator, &cls); 1.2117 + 1.2118 + // Unlock datasource 1.2119 + --mReadCount; 1.2120 + 1.2121 + return cls.mRv; 1.2122 +} 1.2123 + 1.2124 +//////////////////////////////////////////////////////////////////////// 1.2125 +