rdf/base/src/nsInMemoryDataSource.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial