123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965 |
- /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- *
- *
- * This Original Code has been modified by IBM Corporation.
- * Modifications made by IBM described herein are
- * Copyright (c) International Business Machines
- * Corporation, 2000
- *
- * Modifications to Mozilla code or documentation
- * identified per MPL Section 3.3
- *
- * Date Modified by Description of modification
- * 03/27/2000 IBM Corp. Added PR_CALLBACK for Optlink
- * use in OS2
- */
- /*
- Implementation for an in-memory RDF data store.
- TO DO
- 1) Instrument this code to gather space and time performance
- characteristics.
- 2) Optimize lookups for datasources which have a small number
- of properties + fanning out to a large number of targets.
- 3) Complete implementation of thread-safety; specifically, make
- assertions be reference counted objects (so that a cursor can
- still refer to an assertion that gets removed from the graph).
- */
- #include "nsAgg.h"
- #include "nsCOMPtr.h"
- #include "nscore.h"
- #include "nsArrayEnumerator.h"
- #include "nsIOutputStream.h"
- #include "nsIRDFDataSource.h"
- #include "nsIRDFLiteral.h"
- #include "nsIRDFNode.h"
- #include "nsIRDFObserver.h"
- #include "nsIRDFInMemoryDataSource.h"
- #include "nsIRDFPropagatableDataSource.h"
- #include "nsIRDFPurgeableDataSource.h"
- #include "nsIRDFService.h"
- #include "nsIServiceManager.h"
- #include "nsCOMArray.h"
- #include "nsEnumeratorUtils.h"
- #include "nsTArray.h"
- #include "nsCRT.h"
- #include "nsRDFCID.h"
- #include "nsRDFBaseDataSources.h"
- #include "nsString.h"
- #include "nsReadableUtils.h"
- #include "nsXPIDLString.h"
- #include "rdfutil.h"
- #include "PLDHashTable.h"
- #include "plstr.h"
- #include "mozilla/Logging.h"
- #include "rdf.h"
- #include "rdfIDataSource.h"
- #include "rdfITripleVisitor.h"
- using mozilla::LogLevel;
- // This struct is used as the slot value in the forward and reverse
- // arcs hash tables.
- //
- // Assertion objects are reference counted, because each Assertion's
- // ownership is shared between the datasource and any enumerators that
- // are currently iterating over the datasource.
- //
- class Assertion
- {
- public:
- Assertion(nsIRDFResource* aSource, // normal assertion
- nsIRDFResource* aProperty,
- nsIRDFNode* aTarget,
- bool aTruthValue);
- explicit Assertion(nsIRDFResource* aSource); // PLDHashTable assertion variant
- private:
- ~Assertion();
- public:
- void AddRef() {
- if (mRefCnt == UINT16_MAX) {
- NS_WARNING("refcount overflow, leaking Assertion");
- return;
- }
- ++mRefCnt;
- }
- void Release() {
- if (mRefCnt == UINT16_MAX) {
- NS_WARNING("refcount overflow, leaking Assertion");
- return;
- }
- if (--mRefCnt == 0)
- delete this;
- }
- // For nsIRDFPurgeableDataSource
- inline void Mark() { u.as.mMarked = true; }
- inline bool IsMarked() { return u.as.mMarked; }
- inline void Unmark() { u.as.mMarked = false; }
- // public for now, because I'm too lazy to go thru and clean this up.
- // These are shared between hash/as (see the union below)
- nsIRDFResource* mSource;
- Assertion* mNext;
- union
- {
- struct hash
- {
- PLDHashTable* mPropertyHash;
- } hash;
- struct as
- {
- nsIRDFResource* mProperty;
- nsIRDFNode* mTarget;
- Assertion* mInvNext;
- // make sure bool are final elements
- bool mTruthValue;
- bool mMarked;
- } as;
- } u;
- // also shared between hash/as (see the union above)
- // but placed after union definition to ensure that
- // all 32-bit entries are long aligned
- uint16_t mRefCnt;
- bool mHashEntry;
- };
- struct Entry : PLDHashEntryHdr {
- nsIRDFNode* mNode;
- Assertion* mAssertions;
- };
- Assertion::Assertion(nsIRDFResource* aSource)
- : mSource(aSource),
- mNext(nullptr),
- mRefCnt(0),
- mHashEntry(true)
- {
- MOZ_COUNT_CTOR(Assertion);
- NS_ADDREF(mSource);
- u.hash.mPropertyHash =
- new PLDHashTable(PLDHashTable::StubOps(), sizeof(Entry));
- }
- Assertion::Assertion(nsIRDFResource* aSource,
- nsIRDFResource* aProperty,
- nsIRDFNode* aTarget,
- bool aTruthValue)
- : mSource(aSource),
- mNext(nullptr),
- mRefCnt(0),
- mHashEntry(false)
- {
- MOZ_COUNT_CTOR(Assertion);
- u.as.mProperty = aProperty;
- u.as.mTarget = aTarget;
- NS_ADDREF(mSource);
- NS_ADDREF(u.as.mProperty);
- NS_ADDREF(u.as.mTarget);
- u.as.mInvNext = nullptr;
- u.as.mTruthValue = aTruthValue;
- u.as.mMarked = false;
- }
- Assertion::~Assertion()
- {
- if (mHashEntry && u.hash.mPropertyHash) {
- for (auto i = u.hash.mPropertyHash->Iter(); !i.Done(); i.Next()) {
- auto entry = static_cast<Entry*>(i.Get());
- Assertion* as = entry->mAssertions;
- while (as) {
- Assertion* doomed = as;
- as = as->mNext;
- // Unlink, and release the datasource's reference.
- doomed->mNext = doomed->u.as.mInvNext = nullptr;
- doomed->Release();
- }
- }
- delete u.hash.mPropertyHash;
- u.hash.mPropertyHash = nullptr;
- }
- MOZ_COUNT_DTOR(Assertion);
- #ifdef DEBUG_REFS
- --gInstanceCount;
- fprintf(stdout, "%d - RDF: Assertion\n", gInstanceCount);
- #endif
- NS_RELEASE(mSource);
- if (!mHashEntry)
- {
- NS_RELEASE(u.as.mProperty);
- NS_RELEASE(u.as.mTarget);
- }
- }
- ////////////////////////////////////////////////////////////////////////
- // InMemoryDataSource
- class InMemoryArcsEnumeratorImpl;
- class InMemoryAssertionEnumeratorImpl;
- class InMemoryResourceEnumeratorImpl;
- class InMemoryDataSource : public nsIRDFDataSource,
- public nsIRDFInMemoryDataSource,
- public nsIRDFPropagatableDataSource,
- public nsIRDFPurgeableDataSource,
- public rdfIDataSource
- {
- protected:
- // These hash tables are keyed on pointers to nsIRDFResource
- // objects (the nsIRDFService ensures that there is only ever one
- // nsIRDFResource object per unique URI). The value of an entry is
- // an Assertion struct, which is a linked list of (subject
- // predicate object) triples.
- PLDHashTable mForwardArcs;
- PLDHashTable mReverseArcs;
- nsCOMArray<nsIRDFObserver> mObservers;
- uint32_t mNumObservers;
- // VisitFoo needs to block writes, [Un]Assert only allowed
- // during mReadCount == 0
- uint32_t mReadCount;
- friend class InMemoryArcsEnumeratorImpl;
- friend class InMemoryAssertionEnumeratorImpl;
- friend class InMemoryResourceEnumeratorImpl; // b/c it needs to enumerate mForwardArcs
- // Thread-safe writer implementation methods.
- nsresult
- LockedAssert(nsIRDFResource* source,
- nsIRDFResource* property,
- nsIRDFNode* target,
- bool tv);
- nsresult
- LockedUnassert(nsIRDFResource* source,
- nsIRDFResource* property,
- nsIRDFNode* target);
- explicit InMemoryDataSource(nsISupports* aOuter);
- virtual ~InMemoryDataSource();
- friend nsresult
- NS_NewRDFInMemoryDataSource(nsISupports* aOuter, const nsIID& aIID, void** aResult);
- public:
- NS_DECL_CYCLE_COLLECTING_AGGREGATED
- NS_DECL_AGGREGATED_CYCLE_COLLECTION_CLASS(InMemoryDataSource)
- // nsIRDFDataSource methods
- NS_DECL_NSIRDFDATASOURCE
- // nsIRDFInMemoryDataSource methods
- NS_DECL_NSIRDFINMEMORYDATASOURCE
- // nsIRDFPropagatableDataSource methods
- NS_DECL_NSIRDFPROPAGATABLEDATASOURCE
- // nsIRDFPurgeableDataSource methods
- NS_DECL_NSIRDFPURGEABLEDATASOURCE
- // rdfIDataSource methods
- NS_DECL_RDFIDATASOURCE
- protected:
- struct SweepInfo {
- Assertion* mUnassertList;
- PLDHashTable* mReverseArcs;
- };
- static void
- SweepForwardArcsEntries(PLDHashTable* aTable, SweepInfo* aArg);
- public:
- // Implementation methods
- Assertion*
- GetForwardArcs(nsIRDFResource* u) {
- PLDHashEntryHdr* hdr = mForwardArcs.Search(u);
- return hdr ? static_cast<Entry*>(hdr)->mAssertions : nullptr;
- }
- Assertion*
- GetReverseArcs(nsIRDFNode* v) {
- PLDHashEntryHdr* hdr = mReverseArcs.Search(v);
- return hdr ? static_cast<Entry*>(hdr)->mAssertions : nullptr;
- }
- void
- SetForwardArcs(nsIRDFResource* u, Assertion* as) {
- if (as) {
- auto entry =
- static_cast<Entry*>(mForwardArcs.Add(u, mozilla::fallible));
- if (entry) {
- entry->mNode = u;
- entry->mAssertions = as;
- }
- }
- else {
- mForwardArcs.Remove(u);
- }
- }
- void
- SetReverseArcs(nsIRDFNode* v, Assertion* as) {
- if (as) {
- auto entry =
- static_cast<Entry*>(mReverseArcs.Add(v, mozilla::fallible));
- if (entry) {
- entry->mNode = v;
- entry->mAssertions = as;
- }
- }
- else {
- mReverseArcs.Remove(v);
- }
- }
- void
- LogOperation(const char* aOperation,
- nsIRDFResource* asource,
- nsIRDFResource* aProperty,
- nsIRDFNode* aTarget,
- bool aTruthValue = true);
- bool mPropagateChanges;
- private:
- static mozilla::LazyLogModule gLog;
- };
- mozilla::LazyLogModule InMemoryDataSource::gLog("InMemoryDataSource");
- //----------------------------------------------------------------------
- //
- // InMemoryAssertionEnumeratorImpl
- //
- /**
- * InMemoryAssertionEnumeratorImpl
- */
- class InMemoryAssertionEnumeratorImpl : public nsISimpleEnumerator
- {
- private:
- InMemoryDataSource* mDataSource;
- nsIRDFResource* mSource;
- nsIRDFResource* mProperty;
- nsIRDFNode* mTarget;
- nsIRDFNode* mValue;
- bool mTruthValue;
- Assertion* mNextAssertion;
- virtual ~InMemoryAssertionEnumeratorImpl();
- public:
- InMemoryAssertionEnumeratorImpl(InMemoryDataSource* aDataSource,
- nsIRDFResource* aSource,
- nsIRDFResource* aProperty,
- nsIRDFNode* aTarget,
- bool aTruthValue);
- // nsISupports interface
- NS_DECL_ISUPPORTS
- // nsISimpleEnumerator interface
- NS_DECL_NSISIMPLEENUMERATOR
- };
- ////////////////////////////////////////////////////////////////////////
- InMemoryAssertionEnumeratorImpl::InMemoryAssertionEnumeratorImpl(
- InMemoryDataSource* aDataSource,
- nsIRDFResource* aSource,
- nsIRDFResource* aProperty,
- nsIRDFNode* aTarget,
- bool aTruthValue)
- : mDataSource(aDataSource),
- mSource(aSource),
- mProperty(aProperty),
- mTarget(aTarget),
- mValue(nullptr),
- mTruthValue(aTruthValue),
- mNextAssertion(nullptr)
- {
- NS_ADDREF(mDataSource);
- NS_IF_ADDREF(mSource);
- NS_ADDREF(mProperty);
- NS_IF_ADDREF(mTarget);
- if (mSource) {
- mNextAssertion = mDataSource->GetForwardArcs(mSource);
- if (mNextAssertion && mNextAssertion->mHashEntry) {
- // its our magical HASH_ENTRY forward hash for assertions
- PLDHashEntryHdr* hdr =
- mNextAssertion->u.hash.mPropertyHash->Search(aProperty);
- mNextAssertion =
- hdr ? static_cast<Entry*>(hdr)->mAssertions : nullptr;
- }
- }
- else {
- mNextAssertion = mDataSource->GetReverseArcs(mTarget);
- }
- // Add an owning reference from the enumerator
- if (mNextAssertion)
- mNextAssertion->AddRef();
- }
- InMemoryAssertionEnumeratorImpl::~InMemoryAssertionEnumeratorImpl()
- {
- #ifdef DEBUG_REFS
- --gInstanceCount;
- fprintf(stdout, "%d - RDF: InMemoryAssertionEnumeratorImpl\n", gInstanceCount);
- #endif
- if (mNextAssertion)
- mNextAssertion->Release();
- NS_IF_RELEASE(mDataSource);
- NS_IF_RELEASE(mSource);
- NS_IF_RELEASE(mProperty);
- NS_IF_RELEASE(mTarget);
- NS_IF_RELEASE(mValue);
- }
- NS_IMPL_ADDREF(InMemoryAssertionEnumeratorImpl)
- NS_IMPL_RELEASE(InMemoryAssertionEnumeratorImpl)
- NS_IMPL_QUERY_INTERFACE(InMemoryAssertionEnumeratorImpl, nsISimpleEnumerator)
- NS_IMETHODIMP
- InMemoryAssertionEnumeratorImpl::HasMoreElements(bool* aResult)
- {
- if (mValue) {
- *aResult = true;
- return NS_OK;
- }
- while (mNextAssertion) {
- bool foundIt = false;
- if ((mProperty == mNextAssertion->u.as.mProperty) &&
- (mTruthValue == mNextAssertion->u.as.mTruthValue)) {
- if (mSource) {
- mValue = mNextAssertion->u.as.mTarget;
- NS_ADDREF(mValue);
- }
- else {
- mValue = mNextAssertion->mSource;
- NS_ADDREF(mValue);
- }
- foundIt = true;
- }
- // Remember the last assertion we were holding on to
- Assertion* as = mNextAssertion;
- // iterate
- mNextAssertion = (mSource) ? mNextAssertion->mNext : mNextAssertion->u.as.mInvNext;
- // grab an owning reference from the enumerator to the next assertion
- if (mNextAssertion)
- mNextAssertion->AddRef();
- // ...and release the reference from the enumerator to the old one.
- as->Release();
- if (foundIt) {
- *aResult = true;
- return NS_OK;
- }
- }
- *aResult = false;
- return NS_OK;
- }
- NS_IMETHODIMP
- InMemoryAssertionEnumeratorImpl::GetNext(nsISupports** aResult)
- {
- nsresult rv;
- bool hasMore;
- rv = HasMoreElements(&hasMore);
- if (NS_FAILED(rv)) return rv;
- if (! hasMore)
- return NS_ERROR_UNEXPECTED;
- // Don't AddRef: we "transfer" ownership to the caller
- *aResult = mValue;
- mValue = nullptr;
- return NS_OK;
- }
- ////////////////////////////////////////////////////////////////////////
- //
- /**
- * This class is a little bit bizarre in that it implements both the
- * <tt>nsIRDFArcsOutCursor</tt> and <tt>nsIRDFArcsInCursor</tt> interfaces.
- * Because the structure of the in-memory graph is pretty flexible, it's
- * fairly easy to parameterize this class. The only funky thing to watch
- * out for is the multiple inheritance clashes.
- */
- class InMemoryArcsEnumeratorImpl : public nsISimpleEnumerator
- {
- private:
- InMemoryDataSource* mDataSource;
- nsIRDFResource* mSource;
- nsIRDFNode* mTarget;
- AutoTArray<nsCOMPtr<nsIRDFResource>, 8> mAlreadyReturned;
- nsIRDFResource* mCurrent;
- Assertion* mAssertion;
- nsCOMArray<nsIRDFNode>* mHashArcs;
- virtual ~InMemoryArcsEnumeratorImpl();
- public:
- InMemoryArcsEnumeratorImpl(InMemoryDataSource* aDataSource,
- nsIRDFResource* aSource,
- nsIRDFNode* aTarget);
- // nsISupports interface
- NS_DECL_ISUPPORTS
- // nsISimpleEnumerator interface
- NS_DECL_NSISIMPLEENUMERATOR
- };
- InMemoryArcsEnumeratorImpl::InMemoryArcsEnumeratorImpl(InMemoryDataSource* aDataSource,
- nsIRDFResource* aSource,
- nsIRDFNode* aTarget)
- : mDataSource(aDataSource),
- mSource(aSource),
- mTarget(aTarget),
- mCurrent(nullptr),
- mHashArcs(nullptr)
- {
- NS_ADDREF(mDataSource);
- NS_IF_ADDREF(mSource);
- NS_IF_ADDREF(mTarget);
- if (mSource) {
- // cast okay because it's a closed system
- mAssertion = mDataSource->GetForwardArcs(mSource);
- if (mAssertion && mAssertion->mHashEntry) {
- // its our magical HASH_ENTRY forward hash for assertions
- mHashArcs = new nsCOMArray<nsIRDFNode>();
- for (auto i = mAssertion->u.hash.mPropertyHash->Iter();
- !i.Done();
- i.Next()) {
- auto entry = static_cast<Entry*>(i.Get());
- mHashArcs->AppendElement(entry->mNode);
- }
- mAssertion = nullptr;
- }
- }
- else {
- mAssertion = mDataSource->GetReverseArcs(mTarget);
- }
- }
- InMemoryArcsEnumeratorImpl::~InMemoryArcsEnumeratorImpl()
- {
- #ifdef DEBUG_REFS
- --gInstanceCount;
- fprintf(stdout, "%d - RDF: InMemoryArcsEnumeratorImpl\n", gInstanceCount);
- #endif
- NS_RELEASE(mDataSource);
- NS_IF_RELEASE(mSource);
- NS_IF_RELEASE(mTarget);
- NS_IF_RELEASE(mCurrent);
- delete mHashArcs;
- }
- NS_IMPL_ADDREF(InMemoryArcsEnumeratorImpl)
- NS_IMPL_RELEASE(InMemoryArcsEnumeratorImpl)
- NS_IMPL_QUERY_INTERFACE(InMemoryArcsEnumeratorImpl, nsISimpleEnumerator)
- NS_IMETHODIMP
- InMemoryArcsEnumeratorImpl::HasMoreElements(bool* aResult)
- {
- NS_PRECONDITION(aResult != nullptr, "null ptr");
- if (! aResult)
- return NS_ERROR_NULL_POINTER;
- if (mCurrent) {
- *aResult = true;
- return NS_OK;
- }
- if (mHashArcs) {
- if (!mHashArcs->IsEmpty()) {
- const uint32_t last = mHashArcs->Length() - 1;
- nsCOMPtr<nsIRDFResource> tmp(do_QueryInterface(mHashArcs->ObjectAt(last)));
- tmp.forget(&mCurrent);
- mHashArcs->RemoveElementAt(last);
- *aResult = true;
- return NS_OK;
- }
- }
- else
- while (mAssertion) {
- nsIRDFResource* next = mAssertion->u.as.mProperty;
- // "next" is the property arc we are tentatively going to return
- // in a subsequent GetNext() call. It is important to do two
- // things, however, before that can happen:
- // 1) Make sure it's not an arc we've already returned.
- // 2) Make sure that |mAssertion| is not left pointing to
- // another assertion that has the same property as this one.
- // The first is a practical concern; the second a defense against
- // an obscure crash and other erratic behavior. To ensure the
- // second condition, skip down the chain until we find the next
- // assertion with a property that doesn't match the current one.
- // (All these assertions would be skipped via mAlreadyReturned
- // checks anyways; this is even a bit faster.)
- do {
- mAssertion = (mSource ? mAssertion->mNext :
- mAssertion->u.as.mInvNext);
- }
- while (mAssertion && (next == mAssertion->u.as.mProperty));
- bool alreadyReturned = false;
- for (int32_t i = mAlreadyReturned.Length() - 1; i >= 0; --i) {
- if (mAlreadyReturned[i] == next) {
- alreadyReturned = true;
- break;
- }
- }
- if (! alreadyReturned) {
- mCurrent = next;
- NS_ADDREF(mCurrent);
- *aResult = true;
- return NS_OK;
- }
- }
- *aResult = false;
- return NS_OK;
- }
- NS_IMETHODIMP
- InMemoryArcsEnumeratorImpl::GetNext(nsISupports** aResult)
- {
- nsresult rv;
- bool hasMore;
- rv = HasMoreElements(&hasMore);
- if (NS_FAILED(rv)) return rv;
- if (! hasMore)
- return NS_ERROR_UNEXPECTED;
- // Add this to the set of things we've already returned so that we
- // can ensure uniqueness
- mAlreadyReturned.AppendElement(mCurrent);
- // Don't AddRef: we "transfer" ownership to the caller
- *aResult = mCurrent;
- mCurrent = nullptr;
- return NS_OK;
- }
- ////////////////////////////////////////////////////////////////////////
- // InMemoryDataSource
- nsresult
- NS_NewRDFInMemoryDataSource(nsISupports* aOuter, const nsIID& aIID, void** aResult)
- {
- NS_PRECONDITION(aResult != nullptr, "null ptr");
- if (! aResult)
- return NS_ERROR_NULL_POINTER;
- *aResult = nullptr;
- if (aOuter && !aIID.Equals(NS_GET_IID(nsISupports))) {
- NS_ERROR("aggregation requires nsISupports");
- return NS_ERROR_ILLEGAL_VALUE;
- }
- InMemoryDataSource* datasource = new InMemoryDataSource(aOuter);
- NS_ADDREF(datasource);
- datasource->fAggregated.AddRef();
- nsresult rv = datasource->AggregatedQueryInterface(aIID, aResult); // This'll AddRef()
- datasource->fAggregated.Release();
- NS_RELEASE(datasource);
- return rv;
- }
- InMemoryDataSource::InMemoryDataSource(nsISupports* aOuter)
- : mForwardArcs(PLDHashTable::StubOps(), sizeof(Entry))
- , mReverseArcs(PLDHashTable::StubOps(), sizeof(Entry))
- , mNumObservers(0)
- , mReadCount(0)
- {
- NS_INIT_AGGREGATED(aOuter);
- mPropagateChanges = true;
- MOZ_COUNT_CTOR(InMemoryDataSource);
- }
- InMemoryDataSource::~InMemoryDataSource()
- {
- #ifdef DEBUG_REFS
- --gInstanceCount;
- fprintf(stdout, "%d - RDF: InMemoryDataSource\n", gInstanceCount);
- #endif
- if (mForwardArcs.EntryCount() > 0) {
- // This'll release all of the Assertion objects that are
- // associated with this data source. We only need to do this
- // for the forward arcs, because the reverse arcs table
- // indexes the exact same set of resources.
- for (auto iter = mForwardArcs.Iter(); !iter.Done(); iter.Next()) {
- auto entry = static_cast<Entry*>(iter.Get());
- Assertion* as = entry->mAssertions;
- while (as) {
- Assertion* doomed = as;
- as = as->mNext;
- // Unlink, and release the datasource's reference.
- doomed->mNext = doomed->u.as.mInvNext = nullptr;
- doomed->Release();
- }
- }
- }
- MOZ_LOG(gLog, LogLevel::Debug,
- ("InMemoryDataSource(%p): destroyed.", this));
- MOZ_COUNT_DTOR(InMemoryDataSource);
- }
- ////////////////////////////////////////////////////////////////////////
- NS_IMPL_CYCLE_COLLECTION_CLASS(InMemoryDataSource)
- NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(InMemoryDataSource)
- NS_IMPL_CYCLE_COLLECTION_UNLINK(mObservers)
- NS_IMPL_CYCLE_COLLECTION_UNLINK_END
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_AGGREGATED(InMemoryDataSource)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mObservers)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
- NS_IMPL_CYCLE_COLLECTING_AGGREGATED(InMemoryDataSource)
- NS_INTERFACE_MAP_BEGIN_AGGREGATED(InMemoryDataSource)
- NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION_AGGREGATED(InMemoryDataSource)
- NS_INTERFACE_MAP_ENTRY(nsIRDFDataSource)
- NS_INTERFACE_MAP_ENTRY(nsIRDFInMemoryDataSource)
- NS_INTERFACE_MAP_ENTRY(nsIRDFPropagatableDataSource)
- NS_INTERFACE_MAP_ENTRY(nsIRDFPurgeableDataSource)
- NS_INTERFACE_MAP_ENTRY(rdfIDataSource)
- NS_INTERFACE_MAP_END
- ////////////////////////////////////////////////////////////////////////
- void
- InMemoryDataSource::LogOperation(const char* aOperation,
- nsIRDFResource* aSource,
- nsIRDFResource* aProperty,
- nsIRDFNode* aTarget,
- bool aTruthValue)
- {
- if (! MOZ_LOG_TEST(gLog, LogLevel::Debug))
- return;
- nsXPIDLCString uri;
- aSource->GetValue(getter_Copies(uri));
- PR_LogPrint
- ("InMemoryDataSource(%p): %s", this, aOperation);
- PR_LogPrint
- (" [(%p)%s]--", aSource, (const char*) uri);
- aProperty->GetValue(getter_Copies(uri));
- char tv = (aTruthValue ? '-' : '!');
- PR_LogPrint
- (" --%c[(%p)%s]--", tv, aProperty, (const char*) uri);
- nsCOMPtr<nsIRDFResource> resource;
- nsCOMPtr<nsIRDFLiteral> literal;
- if ((resource = do_QueryInterface(aTarget)) != nullptr) {
- resource->GetValue(getter_Copies(uri));
- PR_LogPrint
- (" -->[(%p)%s]", aTarget, (const char*) uri);
- }
- else if ((literal = do_QueryInterface(aTarget)) != nullptr) {
- nsXPIDLString value;
- literal->GetValue(getter_Copies(value));
- nsAutoString valueStr(value);
- char* valueCStr = ToNewCString(valueStr);
- PR_LogPrint
- (" -->(\"%s\")\n", valueCStr);
- free(valueCStr);
- }
- else {
- PR_LogPrint
- (" -->(unknown-type)\n");
- }
- }
- NS_IMETHODIMP
- InMemoryDataSource::GetURI(char* *uri)
- {
- NS_PRECONDITION(uri != nullptr, "null ptr");
- if (! uri)
- return NS_ERROR_NULL_POINTER;
- *uri = nullptr;
- return NS_OK;
- }
- NS_IMETHODIMP
- InMemoryDataSource::GetSource(nsIRDFResource* property,
- nsIRDFNode* target,
- bool tv,
- nsIRDFResource** source)
- {
- NS_PRECONDITION(source != nullptr, "null ptr");
- if (! source)
- return NS_ERROR_NULL_POINTER;
- NS_PRECONDITION(property != nullptr, "null ptr");
- if (! property)
- return NS_ERROR_NULL_POINTER;
- NS_PRECONDITION(target != nullptr, "null ptr");
- if (! target)
- return NS_ERROR_NULL_POINTER;
- for (Assertion* as = GetReverseArcs(target); as; as = as->u.as.mInvNext) {
- if ((property == as->u.as.mProperty) && (tv == as->u.as.mTruthValue)) {
- *source = as->mSource;
- NS_ADDREF(*source);
- return NS_OK;
- }
- }
- *source = nullptr;
- return NS_RDF_NO_VALUE;
- }
- NS_IMETHODIMP
- InMemoryDataSource::GetTarget(nsIRDFResource* source,
- nsIRDFResource* property,
- bool tv,
- nsIRDFNode** target)
- {
- NS_PRECONDITION(source != nullptr, "null ptr");
- if (! source)
- return NS_ERROR_NULL_POINTER;
- NS_PRECONDITION(property != nullptr, "null ptr");
- if (! property)
- return NS_ERROR_NULL_POINTER;
- NS_PRECONDITION(target != nullptr, "null ptr");
- if (! target)
- return NS_ERROR_NULL_POINTER;
- Assertion *as = GetForwardArcs(source);
- if (as && as->mHashEntry) {
- PLDHashEntryHdr* hdr = as->u.hash.mPropertyHash->Search(property);
- Assertion* val = hdr ? static_cast<Entry*>(hdr)->mAssertions : nullptr;
- while (val) {
- if (tv == val->u.as.mTruthValue) {
- *target = val->u.as.mTarget;
- NS_IF_ADDREF(*target);
- return NS_OK;
- }
- val = val->mNext;
- }
- }
- else
- for (; as != nullptr; as = as->mNext) {
- if ((property == as->u.as.mProperty) && (tv == (as->u.as.mTruthValue))) {
- *target = as->u.as.mTarget;
- NS_ADDREF(*target);
- return NS_OK;
- }
- }
- // If we get here, then there was no target with for the specified
- // property & truth value.
- *target = nullptr;
- return NS_RDF_NO_VALUE;
- }
- NS_IMETHODIMP
- InMemoryDataSource::HasAssertion(nsIRDFResource* source,
- nsIRDFResource* property,
- nsIRDFNode* target,
- bool tv,
- bool* hasAssertion)
- {
- if (! source)
- return NS_ERROR_NULL_POINTER;
- if (! property)
- return NS_ERROR_NULL_POINTER;
- if (! target)
- return NS_ERROR_NULL_POINTER;
- Assertion *as = GetForwardArcs(source);
- if (as && as->mHashEntry) {
- PLDHashEntryHdr* hdr = as->u.hash.mPropertyHash->Search(property);
- Assertion* val = hdr ? static_cast<Entry*>(hdr)->mAssertions : nullptr;
- while (val) {
- if ((val->u.as.mTarget == target) && (tv == (val->u.as.mTruthValue))) {
- *hasAssertion = true;
- return NS_OK;
- }
- val = val->mNext;
- }
- }
- else
- for (; as != nullptr; as = as->mNext) {
- // check target first as its most unique
- if (target != as->u.as.mTarget)
- continue;
- if (property != as->u.as.mProperty)
- continue;
- if (tv != (as->u.as.mTruthValue))
- continue;
- // found it!
- *hasAssertion = true;
- return NS_OK;
- }
- // If we get here, we couldn't find the assertion
- *hasAssertion = false;
- return NS_OK;
- }
- NS_IMETHODIMP
- InMemoryDataSource::GetSources(nsIRDFResource* aProperty,
- nsIRDFNode* aTarget,
- bool aTruthValue,
- nsISimpleEnumerator** aResult)
- {
- NS_PRECONDITION(aProperty != nullptr, "null ptr");
- if (! aProperty)
- return NS_ERROR_NULL_POINTER;
- NS_PRECONDITION(aTarget != nullptr, "null ptr");
- if (! aTarget)
- return NS_ERROR_NULL_POINTER;
- NS_PRECONDITION(aResult != nullptr, "null ptr");
- if (! aResult)
- return NS_ERROR_NULL_POINTER;
- InMemoryAssertionEnumeratorImpl* result =
- new InMemoryAssertionEnumeratorImpl(this, nullptr, aProperty,
- aTarget, aTruthValue);
- if (! result)
- return NS_ERROR_OUT_OF_MEMORY;
- NS_ADDREF(result);
- *aResult = result;
- return NS_OK;
- }
- NS_IMETHODIMP
- InMemoryDataSource::GetTargets(nsIRDFResource* aSource,
- nsIRDFResource* aProperty,
- bool aTruthValue,
- nsISimpleEnumerator** aResult)
- {
- NS_PRECONDITION(aSource != nullptr, "null ptr");
- if (! aSource)
- return NS_ERROR_NULL_POINTER;
- NS_PRECONDITION(aProperty != nullptr, "null ptr");
- if (! aProperty)
- return NS_ERROR_NULL_POINTER;
- NS_PRECONDITION(aResult != nullptr, "null ptr");
- if (! aResult)
- return NS_ERROR_NULL_POINTER;
- InMemoryAssertionEnumeratorImpl* result =
- new InMemoryAssertionEnumeratorImpl(this, aSource, aProperty,
- nullptr, aTruthValue);
- if (! result)
- return NS_ERROR_OUT_OF_MEMORY;
- NS_ADDREF(result);
- *aResult = result;
- return NS_OK;
- }
- nsresult
- InMemoryDataSource::LockedAssert(nsIRDFResource* aSource,
- nsIRDFResource* aProperty,
- nsIRDFNode* aTarget,
- bool aTruthValue)
- {
- LogOperation("ASSERT", aSource, aProperty, aTarget, aTruthValue);
- Assertion* next = GetForwardArcs(aSource);
- Assertion* prev = next;
- Assertion* as = nullptr;
- bool haveHash = (next) ? next->mHashEntry : false;
- if (haveHash) {
- PLDHashEntryHdr* hdr = next->u.hash.mPropertyHash->Search(aProperty);
- Assertion* val = hdr ? static_cast<Entry*>(hdr)->mAssertions : nullptr;
- while (val) {
- if (val->u.as.mTarget == aTarget) {
- // Wow, we already had the assertion. Make sure that the
- // truth values are correct and bail.
- val->u.as.mTruthValue = aTruthValue;
- return NS_OK;
- }
- val = val->mNext;
- }
- }
- else
- {
- while (next) {
- // check target first as its most unique
- if (aTarget == next->u.as.mTarget) {
- if (aProperty == next->u.as.mProperty) {
- // Wow, we already had the assertion. Make sure that the
- // truth values are correct and bail.
- next->u.as.mTruthValue = aTruthValue;
- return NS_OK;
- }
- }
- prev = next;
- next = next->mNext;
- }
- }
- as = new Assertion(aSource, aProperty, aTarget, aTruthValue);
- if (! as)
- return NS_ERROR_OUT_OF_MEMORY;
- // Add the datasource's owning reference.
- as->AddRef();
- if (haveHash)
- {
- PLDHashEntryHdr* hdr = next->u.hash.mPropertyHash->Search(aProperty);
- Assertion *asRef =
- hdr ? static_cast<Entry*>(hdr)->mAssertions : nullptr;
- if (asRef)
- {
- as->mNext = asRef->mNext;
- asRef->mNext = as;
- }
- else
- {
- hdr = next->u.hash.mPropertyHash->Add(aProperty, mozilla::fallible);
- if (hdr)
- {
- Entry* entry = static_cast<Entry*>(hdr);
- entry->mNode = aProperty;
- entry->mAssertions = as;
- }
- }
- }
- else
- {
- // Link it in to the "forward arcs" table
- if (!prev) {
- SetForwardArcs(aSource, as);
- } else {
- prev->mNext = as;
- }
- }
- // Link it in to the "reverse arcs" table
- next = GetReverseArcs(aTarget);
- as->u.as.mInvNext = next;
- next = as;
- SetReverseArcs(aTarget, next);
- return NS_OK;
- }
- NS_IMETHODIMP
- InMemoryDataSource::Assert(nsIRDFResource* aSource,
- nsIRDFResource* aProperty,
- nsIRDFNode* aTarget,
- bool aTruthValue)
- {
- NS_PRECONDITION(aSource != nullptr, "null ptr");
- if (! aSource)
- return NS_ERROR_NULL_POINTER;
- NS_PRECONDITION(aProperty != nullptr, "null ptr");
- if (! aProperty)
- return NS_ERROR_NULL_POINTER;
- NS_PRECONDITION(aTarget != nullptr, "null ptr");
- if (! aTarget)
- return NS_ERROR_NULL_POINTER;
- if (mReadCount) {
- NS_WARNING("Writing to InMemoryDataSource during read\n");
- return NS_RDF_ASSERTION_REJECTED;
- }
- nsresult rv;
- rv = LockedAssert(aSource, aProperty, aTarget, aTruthValue);
- if (NS_FAILED(rv)) return rv;
- // notify observers
- for (int32_t i = (int32_t)mNumObservers - 1; mPropagateChanges && i >= 0; --i) {
- nsIRDFObserver* obs = mObservers[i];
- // XXX this should never happen, but it does, and we can't figure out why.
- NS_ASSERTION(obs, "observer array corrupted!");
- if (! obs)
- continue;
- obs->OnAssert(this, aSource, aProperty, aTarget);
- // XXX ignore return value?
- }
- return NS_RDF_ASSERTION_ACCEPTED;
- }
- nsresult
- InMemoryDataSource::LockedUnassert(nsIRDFResource* aSource,
- nsIRDFResource* aProperty,
- nsIRDFNode* aTarget)
- {
- LogOperation("UNASSERT", aSource, aProperty, aTarget);
- Assertion* next = GetForwardArcs(aSource);
- Assertion* prev = next;
- Assertion* root = next;
- Assertion* as = nullptr;
- bool haveHash = (next) ? next->mHashEntry : false;
- if (haveHash) {
- PLDHashEntryHdr* hdr = next->u.hash.mPropertyHash->Search(aProperty);
- prev = next = hdr ? static_cast<Entry*>(hdr)->mAssertions : nullptr;
- bool first = true;
- while (next) {
- if (aTarget == next->u.as.mTarget) {
- break;
- }
- first = false;
- prev = next;
- next = next->mNext;
- }
- // We don't even have the assertion, so just bail.
- if (!next)
- return NS_OK;
- as = next;
- if (first) {
- root->u.hash.mPropertyHash->RawRemove(hdr);
- if (next && next->mNext) {
- PLDHashEntryHdr* hdr =
- root->u.hash.mPropertyHash->Add(aProperty,
- mozilla::fallible);
- if (hdr) {
- Entry* entry = static_cast<Entry*>(hdr);
- entry->mNode = aProperty;
- entry->mAssertions = next->mNext;
- }
- }
- else {
- // If this second-level hash empties out, clean it up.
- if (!root->u.hash.mPropertyHash->EntryCount()) {
- root->Release();
- SetForwardArcs(aSource, nullptr);
- }
- }
- }
- else {
- prev->mNext = next->mNext;
- }
- }
- else
- {
- while (next) {
- // check target first as its most unique
- if (aTarget == next->u.as.mTarget) {
- if (aProperty == next->u.as.mProperty) {
- if (prev == next) {
- SetForwardArcs(aSource, next->mNext);
- } else {
- prev->mNext = next->mNext;
- }
- as = next;
- break;
- }
- }
- prev = next;
- next = next->mNext;
- }
- }
- // We don't even have the assertion, so just bail.
- if (!as)
- return NS_OK;
- #ifdef DEBUG
- bool foundReverseArc = false;
- #endif
- next = prev = GetReverseArcs(aTarget);
- while (next) {
- if (next == as) {
- if (prev == next) {
- SetReverseArcs(aTarget, next->u.as.mInvNext);
- } else {
- prev->u.as.mInvNext = next->u.as.mInvNext;
- }
- #ifdef DEBUG
- foundReverseArc = true;
- #endif
- break;
- }
- prev = next;
- next = next->u.as.mInvNext;
- }
- #ifdef DEBUG
- NS_ASSERTION(foundReverseArc, "in-memory db corrupted: unable to find reverse arc");
- #endif
- // Unlink, and release the datasource's reference
- as->mNext = as->u.as.mInvNext = nullptr;
- as->Release();
- return NS_OK;
- }
- NS_IMETHODIMP
- InMemoryDataSource::Unassert(nsIRDFResource* aSource,
- nsIRDFResource* aProperty,
- nsIRDFNode* aTarget)
- {
- NS_PRECONDITION(aSource != nullptr, "null ptr");
- if (! aSource)
- return NS_ERROR_NULL_POINTER;
- NS_PRECONDITION(aProperty != nullptr, "null ptr");
- if (! aProperty)
- return NS_ERROR_NULL_POINTER;
- NS_PRECONDITION(aTarget != nullptr, "null ptr");
- if (! aTarget)
- return NS_ERROR_NULL_POINTER;
- if (mReadCount) {
- NS_WARNING("Writing to InMemoryDataSource during read\n");
- return NS_RDF_ASSERTION_REJECTED;
- }
- nsresult rv;
- rv = LockedUnassert(aSource, aProperty, aTarget);
- if (NS_FAILED(rv)) return rv;
- // Notify the world
- for (int32_t i = int32_t(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
- nsIRDFObserver* obs = mObservers[i];
- // XXX this should never happen, but it does, and we can't figure out why.
- NS_ASSERTION(obs, "observer array corrupted!");
- if (! obs)
- continue;
- obs->OnUnassert(this, aSource, aProperty, aTarget);
- // XXX ignore return value?
- }
- return NS_RDF_ASSERTION_ACCEPTED;
- }
- NS_IMETHODIMP
- InMemoryDataSource::Change(nsIRDFResource* aSource,
- nsIRDFResource* aProperty,
- nsIRDFNode* aOldTarget,
- nsIRDFNode* aNewTarget)
- {
- NS_PRECONDITION(aSource != nullptr, "null ptr");
- if (! aSource)
- return NS_ERROR_NULL_POINTER;
- NS_PRECONDITION(aProperty != nullptr, "null ptr");
- if (! aProperty)
- return NS_ERROR_NULL_POINTER;
- NS_PRECONDITION(aOldTarget != nullptr, "null ptr");
- if (! aOldTarget)
- return NS_ERROR_NULL_POINTER;
- NS_PRECONDITION(aNewTarget != nullptr, "null ptr");
- if (! aNewTarget)
- return NS_ERROR_NULL_POINTER;
- if (mReadCount) {
- NS_WARNING("Writing to InMemoryDataSource during read\n");
- return NS_RDF_ASSERTION_REJECTED;
- }
- nsresult rv;
- // XXX We can implement LockedChange() if we decide that this
- // is a performance bottleneck.
- rv = LockedUnassert(aSource, aProperty, aOldTarget);
- if (NS_FAILED(rv)) return rv;
- rv = LockedAssert(aSource, aProperty, aNewTarget, true);
- if (NS_FAILED(rv)) return rv;
- // Notify the world
- for (int32_t i = int32_t(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
- nsIRDFObserver* obs = mObservers[i];
- // XXX this should never happen, but it does, and we can't figure out why.
- NS_ASSERTION(obs, "observer array corrupted!");
- if (! obs)
- continue;
- obs->OnChange(this, aSource, aProperty, aOldTarget, aNewTarget);
- // XXX ignore return value?
- }
- return NS_RDF_ASSERTION_ACCEPTED;
- }
- NS_IMETHODIMP
- InMemoryDataSource::Move(nsIRDFResource* aOldSource,
- nsIRDFResource* aNewSource,
- nsIRDFResource* aProperty,
- nsIRDFNode* aTarget)
- {
- NS_PRECONDITION(aOldSource != nullptr, "null ptr");
- if (! aOldSource)
- return NS_ERROR_NULL_POINTER;
- NS_PRECONDITION(aNewSource != nullptr, "null ptr");
- if (! aNewSource)
- return NS_ERROR_NULL_POINTER;
- NS_PRECONDITION(aProperty != nullptr, "null ptr");
- if (! aProperty)
- return NS_ERROR_NULL_POINTER;
- NS_PRECONDITION(aTarget != nullptr, "null ptr");
- if (! aTarget)
- return NS_ERROR_NULL_POINTER;
- if (mReadCount) {
- NS_WARNING("Writing to InMemoryDataSource during read\n");
- return NS_RDF_ASSERTION_REJECTED;
- }
- nsresult rv;
- // XXX We can implement LockedMove() if we decide that this
- // is a performance bottleneck.
- rv = LockedUnassert(aOldSource, aProperty, aTarget);
- if (NS_FAILED(rv)) return rv;
- rv = LockedAssert(aNewSource, aProperty, aTarget, true);
- if (NS_FAILED(rv)) return rv;
- // Notify the world
- for (int32_t i = int32_t(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
- nsIRDFObserver* obs = mObservers[i];
- // XXX this should never happen, but it does, and we can't figure out why.
- NS_ASSERTION(obs, "observer array corrupted!");
- if (! obs)
- continue;
- obs->OnMove(this, aOldSource, aNewSource, aProperty, aTarget);
- // XXX ignore return value?
- }
- return NS_RDF_ASSERTION_ACCEPTED;
- }
- NS_IMETHODIMP
- InMemoryDataSource::AddObserver(nsIRDFObserver* aObserver)
- {
- NS_PRECONDITION(aObserver != nullptr, "null ptr");
- if (! aObserver)
- return NS_ERROR_NULL_POINTER;
- mObservers.AppendObject(aObserver);
- mNumObservers = mObservers.Count();
- return NS_OK;
- }
- NS_IMETHODIMP
- InMemoryDataSource::RemoveObserver(nsIRDFObserver* aObserver)
- {
- NS_PRECONDITION(aObserver != nullptr, "null ptr");
- if (! aObserver)
- return NS_ERROR_NULL_POINTER;
- mObservers.RemoveObject(aObserver);
- // note: use Count() instead of just decrementing
- // in case aObserver wasn't in list, for example
- mNumObservers = mObservers.Count();
- return NS_OK;
- }
- NS_IMETHODIMP
- InMemoryDataSource::HasArcIn(nsIRDFNode *aNode, nsIRDFResource *aArc, bool *result)
- {
- Assertion* ass = GetReverseArcs(aNode);
- while (ass) {
- nsIRDFResource* elbow = ass->u.as.mProperty;
- if (elbow == aArc) {
- *result = true;
- return NS_OK;
- }
- ass = ass->u.as.mInvNext;
- }
- *result = false;
- return NS_OK;
- }
- NS_IMETHODIMP
- InMemoryDataSource::HasArcOut(nsIRDFResource *aSource, nsIRDFResource *aArc, bool *result)
- {
- Assertion* ass = GetForwardArcs(aSource);
- if (ass && ass->mHashEntry) {
- PLDHashEntryHdr* hdr = ass->u.hash.mPropertyHash->Search(aArc);
- Assertion* val = hdr ? static_cast<Entry*>(hdr)->mAssertions : nullptr;
- if (val) {
- *result = true;
- return NS_OK;
- }
- ass = ass->mNext;
- }
- while (ass) {
- nsIRDFResource* elbow = ass->u.as.mProperty;
- if (elbow == aArc) {
- *result = true;
- return NS_OK;
- }
- ass = ass->mNext;
- }
- *result = false;
- return NS_OK;
- }
- NS_IMETHODIMP
- InMemoryDataSource::ArcLabelsIn(nsIRDFNode* aTarget, nsISimpleEnumerator** aResult)
- {
- NS_PRECONDITION(aTarget != nullptr, "null ptr");
- if (! aTarget)
- return NS_ERROR_NULL_POINTER;
- InMemoryArcsEnumeratorImpl* result =
- new InMemoryArcsEnumeratorImpl(this, nullptr, aTarget);
- if (! result)
- return NS_ERROR_OUT_OF_MEMORY;
- NS_ADDREF(result);
- *aResult = result;
- return NS_OK;
- }
- NS_IMETHODIMP
- InMemoryDataSource::ArcLabelsOut(nsIRDFResource* aSource, nsISimpleEnumerator** aResult)
- {
- NS_PRECONDITION(aSource != nullptr, "null ptr");
- if (! aSource)
- return NS_ERROR_NULL_POINTER;
- InMemoryArcsEnumeratorImpl* result =
- new InMemoryArcsEnumeratorImpl(this, aSource, nullptr);
- if (! result)
- return NS_ERROR_OUT_OF_MEMORY;
- NS_ADDREF(result);
- *aResult = result;
- return NS_OK;
- }
- NS_IMETHODIMP
- InMemoryDataSource::GetAllResources(nsISimpleEnumerator** aResult)
- {
- nsCOMArray<nsIRDFNode> nodes;
- nodes.SetCapacity(mForwardArcs.EntryCount());
- // Get all of our entries into an nsCOMArray
- for (auto iter = mForwardArcs.Iter(); !iter.Done(); iter.Next()) {
- auto entry = static_cast<Entry*>(iter.Get());
- nodes.AppendObject(entry->mNode);
- }
- return NS_NewArrayEnumerator(aResult, nodes);
- }
- NS_IMETHODIMP
- InMemoryDataSource::GetAllCmds(nsIRDFResource* source,
- nsISimpleEnumerator/*<nsIRDFResource>*/** commands)
- {
- return(NS_NewEmptyEnumerator(commands));
- }
- NS_IMETHODIMP
- InMemoryDataSource::IsCommandEnabled(nsISupports* aSources,
- nsIRDFResource* aCommand,
- nsISupports* aArguments,
- bool* aResult)
- {
- return NS_ERROR_NOT_IMPLEMENTED;
- }
- NS_IMETHODIMP
- InMemoryDataSource::DoCommand(nsISupports* aSources,
- nsIRDFResource* aCommand,
- nsISupports* aArguments)
- {
- return NS_ERROR_NOT_IMPLEMENTED;
- }
- NS_IMETHODIMP
- InMemoryDataSource::BeginUpdateBatch()
- {
- for (int32_t i = int32_t(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
- nsIRDFObserver* obs = mObservers[i];
- obs->OnBeginUpdateBatch(this);
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- InMemoryDataSource::EndUpdateBatch()
- {
- for (int32_t i = int32_t(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
- nsIRDFObserver* obs = mObservers[i];
- obs->OnEndUpdateBatch(this);
- }
- return NS_OK;
- }
- ////////////////////////////////////////////////////////////////////////
- // nsIRDFInMemoryDataSource methods
- NS_IMETHODIMP
- InMemoryDataSource::EnsureFastContainment(nsIRDFResource* aSource)
- {
- Assertion *as = GetForwardArcs(aSource);
- bool haveHash = (as) ? as->mHashEntry : false;
- // if its already a hash, then nothing to do
- if (haveHash) return(NS_OK);
- // convert aSource in forward hash into a hash
- Assertion *hashAssertion = new Assertion(aSource);
- NS_ASSERTION(hashAssertion, "unable to create Assertion");
- if (!hashAssertion) return(NS_ERROR_OUT_OF_MEMORY);
- // Add the datasource's owning reference.
- hashAssertion->AddRef();
- Assertion *first = GetForwardArcs(aSource);
- SetForwardArcs(aSource, hashAssertion);
- // mutate references of existing forward assertions into this hash
- PLDHashTable *table = hashAssertion->u.hash.mPropertyHash;
- Assertion *nextRef;
- while(first) {
- nextRef = first->mNext;
- nsIRDFResource *prop = first->u.as.mProperty;
- PLDHashEntryHdr* hdr = table->Search(prop);
- Assertion* val = hdr ? static_cast<Entry*>(hdr)->mAssertions : nullptr;
- if (val) {
- first->mNext = val->mNext;
- val->mNext = first;
- }
- else {
- PLDHashEntryHdr* hdr = table->Add(prop, mozilla::fallible);
- if (hdr) {
- Entry* entry = static_cast<Entry*>(hdr);
- entry->mNode = prop;
- entry->mAssertions = first;
- first->mNext = nullptr;
- }
- }
- first = nextRef;
- }
- return(NS_OK);
- }
- ////////////////////////////////////////////////////////////////////////
- // nsIRDFPropagatableDataSource methods
- NS_IMETHODIMP
- InMemoryDataSource::GetPropagateChanges(bool* aPropagateChanges)
- {
- *aPropagateChanges = mPropagateChanges;
- return NS_OK;
- }
- NS_IMETHODIMP
- InMemoryDataSource::SetPropagateChanges(bool aPropagateChanges)
- {
- mPropagateChanges = aPropagateChanges;
- return NS_OK;
- }
- ////////////////////////////////////////////////////////////////////////
- // nsIRDFPurgeableDataSource methods
- NS_IMETHODIMP
- InMemoryDataSource::Mark(nsIRDFResource* aSource,
- nsIRDFResource* aProperty,
- nsIRDFNode* aTarget,
- bool aTruthValue,
- bool* aDidMark)
- {
- NS_PRECONDITION(aSource != nullptr, "null ptr");
- if (! aSource)
- return NS_ERROR_NULL_POINTER;
- NS_PRECONDITION(aProperty != nullptr, "null ptr");
- if (! aProperty)
- return NS_ERROR_NULL_POINTER;
- NS_PRECONDITION(aTarget != nullptr, "null ptr");
- if (! aTarget)
- return NS_ERROR_NULL_POINTER;
- Assertion *as = GetForwardArcs(aSource);
- if (as && as->mHashEntry) {
- PLDHashEntryHdr* hdr = as->u.hash.mPropertyHash->Search(aProperty);
- Assertion* val = hdr ? static_cast<Entry*>(hdr)->mAssertions : nullptr;
- while (val) {
- if ((val->u.as.mTarget == aTarget) &&
- (aTruthValue == (val->u.as.mTruthValue))) {
- // found it! so mark it.
- as->Mark();
- *aDidMark = true;
- LogOperation("MARK", aSource, aProperty, aTarget, aTruthValue);
- return NS_OK;
- }
- val = val->mNext;
- }
- }
- else for (; as != nullptr; as = as->mNext) {
- // check target first as its most unique
- if (aTarget != as->u.as.mTarget)
- continue;
- if (aProperty != as->u.as.mProperty)
- continue;
- if (aTruthValue != (as->u.as.mTruthValue))
- continue;
- // found it! so mark it.
- as->Mark();
- *aDidMark = true;
- LogOperation("MARK", aSource, aProperty, aTarget, aTruthValue);
- return NS_OK;
- }
- // If we get here, we couldn't find the assertion
- *aDidMark = false;
- return NS_OK;
- }
- NS_IMETHODIMP
- InMemoryDataSource::Sweep()
- {
- SweepInfo info = { nullptr, &mReverseArcs };
- // Remove all the assertions, but don't notify anyone.
- SweepForwardArcsEntries(&mForwardArcs, &info);
- // Now do the notification.
- Assertion* as = info.mUnassertList;
- while (as) {
- LogOperation("SWEEP", as->mSource, as->u.as.mProperty, as->u.as.mTarget, as->u.as.mTruthValue);
- if (!(as->mHashEntry))
- {
- for (int32_t i = int32_t(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
- nsIRDFObserver* obs = mObservers[i];
- // XXXbz other loops over mObservers null-check |obs| here!
- obs->OnUnassert(this, as->mSource, as->u.as.mProperty, as->u.as.mTarget);
- // XXX ignore return value?
- }
- }
- Assertion* doomed = as;
- as = as->mNext;
- // Unlink, and release the datasource's reference
- doomed->mNext = doomed->u.as.mInvNext = nullptr;
- doomed->Release();
- }
- return NS_OK;
- }
- void
- InMemoryDataSource::SweepForwardArcsEntries(PLDHashTable* aTable,
- SweepInfo* aInfo)
- {
- for (auto iter = aTable->Iter(); !iter.Done(); iter.Next()) {
- auto entry = static_cast<Entry*>(iter.Get());
- Assertion* as = entry->mAssertions;
- if (as && (as->mHashEntry)) {
- // Stuff in sub-hashes must be swept recursively (max depth: 1)
- SweepForwardArcsEntries(as->u.hash.mPropertyHash, aInfo);
- // If the sub-hash is now empty, clean it up.
- if (!as->u.hash.mPropertyHash->EntryCount()) {
- as->Release();
- iter.Remove();
- }
- continue;
- }
- Assertion* prev = nullptr;
- while (as) {
- if (as->IsMarked()) {
- prev = as;
- as->Unmark();
- as = as->mNext;
- }
- else {
- // remove from the list of assertions in the datasource
- Assertion* next = as->mNext;
- if (prev) {
- prev->mNext = next;
- }
- else {
- // it's the first one. update the hashtable entry.
- entry->mAssertions = next;
- }
- // remove from the reverse arcs
- PLDHashEntryHdr* hdr =
- aInfo->mReverseArcs->Search(as->u.as.mTarget);
- NS_ASSERTION(hdr, "no assertion in reverse arcs");
- Entry* rentry = static_cast<Entry*>(hdr);
- Assertion* ras = rentry->mAssertions;
- Assertion* rprev = nullptr;
- while (ras) {
- if (ras == as) {
- if (rprev) {
- rprev->u.as.mInvNext = ras->u.as.mInvNext;
- }
- else {
- // it's the first one. update the hashtable entry.
- rentry->mAssertions = ras->u.as.mInvNext;
- }
- as->u.as.mInvNext = nullptr; // for my sanity.
- break;
- }
- rprev = ras;
- ras = ras->u.as.mInvNext;
- }
- // Wow, it was the _only_ one. Unhash it.
- if (! rentry->mAssertions) {
- aInfo->mReverseArcs->RawRemove(hdr);
- }
- // add to the list of assertions to unassert
- as->mNext = aInfo->mUnassertList;
- aInfo->mUnassertList = as;
- // Advance to the next assertion
- as = next;
- }
- }
- // if no more assertions exist for this resource, then unhash it.
- if (! entry->mAssertions) {
- iter.Remove();
- }
- }
- }
- ////////////////////////////////////////////////////////////////////////
- // rdfIDataSource methods
- NS_IMETHODIMP
- InMemoryDataSource::VisitAllSubjects(rdfITripleVisitor *aVisitor)
- {
- // Lock datasource against writes
- ++mReadCount;
- // Enumerate all of our entries.
- nsresult rv = NS_OK;
- for (auto iter = mForwardArcs.Iter(); !iter.Done(); iter.Next()) {
- auto entry = static_cast<Entry*>(iter.Get());
- nsresult rv2;
- nsCOMPtr<nsIRDFNode> subject = do_QueryInterface(entry->mNode, &rv2);
- if (NS_FAILED(rv2)) {
- NS_WARNING("QI to nsIRDFNode failed");
- continue;
- }
- rv = aVisitor->Visit(subject, nullptr, nullptr, true);
- if (NS_FAILED(rv) || rv == NS_RDF_STOP_VISIT) {
- break;
- }
- }
- // Unlock datasource
- --mReadCount;
- return rv;
- }
- NS_IMETHODIMP
- InMemoryDataSource::VisitAllTriples(rdfITripleVisitor *aVisitor)
- {
- // Lock datasource against writes
- ++mReadCount;
- // Enumerate all of our entries.
- nsresult rv = NS_OK;
- for (auto iter = mForwardArcs.Iter(); !iter.Done(); iter.Next()) {
- auto entry = static_cast<Entry*>(iter.Get());
- nsresult rv2;
- nsCOMPtr<nsIRDFNode> subject = do_QueryInterface(entry->mNode, &rv2);
- if (NS_FAILED(rv2)) {
- NS_WARNING("QI to nsIRDFNode failed");
- } else if (entry->mAssertions->mHashEntry) {
- for (auto iter = entry->mAssertions->u.hash.mPropertyHash->Iter();
- !iter.Done();
- iter.Next()) {
- auto entry = static_cast<Entry*>(iter.Get());
- Assertion* assertion = entry->mAssertions;
- while (assertion) {
- NS_ASSERTION(!assertion->mHashEntry, "shouldn't have to hashes");
- rv = aVisitor->Visit(subject, assertion->u.as.mProperty,
- assertion->u.as.mTarget,
- assertion->u.as.mTruthValue);
- if (NS_FAILED(rv)) {
- goto end;
- }
- if (rv == NS_RDF_STOP_VISIT) {
- goto inner_end;
- }
- assertion = assertion->mNext;
- }
- }
- } else {
- Assertion* assertion = entry->mAssertions;
- while (assertion) {
- NS_ASSERTION(!assertion->mHashEntry, "shouldn't have to hashes");
- rv = aVisitor->Visit(subject, assertion->u.as.mProperty,
- assertion->u.as.mTarget,
- assertion->u.as.mTruthValue);
- if (NS_FAILED(rv) || rv == NS_RDF_STOP_VISIT) {
- goto end;
- }
- assertion = assertion->mNext;
- }
- }
- inner_end:
- (void) 0;
- }
- end:
- // Unlock datasource
- --mReadCount;
- return rv;
- }
- ////////////////////////////////////////////////////////////////////////
|