diff options
author | Noel Grandin <noel.grandin@collabora.co.uk> | 2019-06-26 15:19:36 +0200 |
---|---|---|
committer | Noel Grandin <noel.grandin@collabora.co.uk> | 2019-06-28 12:47:35 +0200 |
commit | 47e04cf31c6165dd55dc20962ad9c72962b958bd (patch) | |
tree | c8c996c05d9fd8e2f611d5accc280678bcabd0de | |
parent | b399dba597c90777c0edf2c5b19d029b3bff23df (diff) |
tdf#125706 and tdf#125665 writer, speed up RDF
The RDF stuff is sloooooooow, so (a) add some caching and (b) fold a
very hot UNO_QUERY call.
To add the caching we need to add a new UNO interface, since
XEnumeration is not amenable to being cached.
Add an optimised getStatementsGraph_NoLock2 that skips the intermediate
enumeration object, and consequently a lot of locking/unlocking.
Cache by OUString key, to avoid expensive OUString<->OString conversion
when looking up entries in the cache.
For the test document in tdf#125706, this takes the time from 7s to 5s for me.
For the test document in tdf#125665, this takes the load time
from 60s to 7s for me.
Change-Id: I207387e975b4f107834edd0974134c481fb4012d
Reviewed-on: https://gerrit.libreoffice.org/74740
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
-rw-r--r-- | offapi/UnoApi_offapi.mk | 1 | ||||
-rw-r--r-- | offapi/com/sun/star/rdf/XNamedGraph2.idl | 134 | ||||
-rw-r--r-- | sfx2/source/doc/DocumentMetadataAccess.cxx | 62 | ||||
-rw-r--r-- | sw/source/core/edit/edfcol.cxx | 8 | ||||
-rw-r--r-- | unoxml/source/rdf/librdf_repository.cxx | 273 |
5 files changed, 424 insertions, 54 deletions
diff --git a/offapi/UnoApi_offapi.mk b/offapi/UnoApi_offapi.mk index c86e7d5a7800..8a567218dec1 100644 --- a/offapi/UnoApi_offapi.mk +++ b/offapi/UnoApi_offapi.mk @@ -2981,6 +2981,7 @@ $(eval $(call gb_UnoApi_add_idlfiles,offapi,com/sun/star/rdf,\ XLiteral \ XMetadatable \ XNamedGraph \ + XNamedGraph2 \ XNode \ XQuerySelectResult \ XReifiedStatement \ diff --git a/offapi/com/sun/star/rdf/XNamedGraph2.idl b/offapi/com/sun/star/rdf/XNamedGraph2.idl new file mode 100644 index 000000000000..e90254a577d3 --- /dev/null +++ b/offapi/com/sun/star/rdf/XNamedGraph2.idl @@ -0,0 +1,134 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * 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 file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef __com_sun_star_rdf_XNamedGraph_idl__ +#define __com_sun_star_rdf_XNamedGraph_idl__ + +#include <com/sun/star/rdf/XNamedGraph.idl> + + + +module com { module sun { module star { module rdf { + +/** represents an RDF named graph that is stored in an RDF Repository. + + @since LibreOffice 6.4 + */ +interface XNamedGraph2 : XNamedGraph +{ + + /** gets objects for matching RDF statements from a graph. + + <p>this call caches its results (as opposed to getStatements in XNamedGraph + which cannot because it returns a mutable object). + + <p> + Note that the ODF elements that can have metadata attached all + implement the interface XMetadatable, which inherits + from XResource, meaning that you can simply pass them + in as arguments here, and it will magically work. + </p> + + <p> + Any parameter may be `NULL`, which acts as a wildcard. + For example, to get all statements about myURI: + <code>getStatements2(myURI, null, null)</code> + </p> + + @param Subject + the subject of the RDF triple. + + @param Predicate + the predicate of the RDF triple. + + @param Object + the object of the RDF triple. + + @returns + a sequence of XURIs for the objects in RDF statements + in the graph that match + the parameters, represented as an + enumeration of Statement + + @throws com::sun::star::container::NoSuchElementException + if this graph does not exist in the repository any more + + @throws RepositoryException + if an error occurs when accessing the repository. + */ + sequence<com::sun::star::rdf::XURI> getStatementsObjects( + [in] XResource Subject, + [in] XURI Predicate, + [in] XNode Object) + raises( com::sun::star::container::NoSuchElementException, + RepositoryException ); + + /** returns true if there are matching RDF statements from a graph. + + <p>this call caches its results (as opposed to getStatements in XNamedGraph + which cannot because it returns a mutable object). + + <p> + Note that the ODF elements that can have metadata attached all + implement the interface XMetadatable, which inherits + from XResource, meaning that you can simply pass them + in as arguments here, and it will magically work. + </p> + + <p> + Any parameter may be `NULL`, which acts as a wildcard. + For example, to get all statements about myURI: + <code>getStatements2(myURI, null, null)</code> + </p> + + @param Subject + the subject of the RDF triple. + + @param Predicate + the predicate of the RDF triple. + + @param Object + the object of the RDF triple. + + @returns + a sequence of XURIs for the objects in RDF statements + in the graph that match + the parameters, represented as an + enumeration of Statement + + @throws com::sun::star::container::NoSuchElementException + if this graph does not exist in the repository any more + + @throws RepositoryException + if an error occurs when accessing the repository. + */ + boolean hasStatements( + [in] XResource Subject, + [in] XURI Predicate, + [in] XNode Object) + raises( com::sun::star::container::NoSuchElementException, + RepositoryException ); +}; + + +}; }; }; }; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sfx2/source/doc/DocumentMetadataAccess.cxx b/sfx2/source/doc/DocumentMetadataAccess.cxx index 14c5d98ca5d2..83cd4ec3f6d4 100644 --- a/sfx2/source/doc/DocumentMetadataAccess.cxx +++ b/sfx2/source/doc/DocumentMetadataAccess.cxx @@ -36,6 +36,7 @@ #include <com/sun/star/rdf/Literal.hpp> #include <com/sun/star/rdf/URI.hpp> #include <com/sun/star/rdf/Repository.hpp> +#include <com/sun/star/rdf/XNamedGraph2.hpp> #include <rtl/ustrbuf.hxx> #include <rtl/uri.hxx> @@ -220,7 +221,7 @@ struct DocumentMetadataAccess_Impl const SfxObjectShell & m_rXmlIdRegistrySupplier; uno::Reference<rdf::XURI> m_xBaseURI; uno::Reference<rdf::XRepository> m_xRepository; - uno::Reference<rdf::XNamedGraph> m_xManifest; + uno::Reference<rdf::XNamedGraph2> m_xManifest; DocumentMetadataAccess_Impl( uno::Reference<uno::XComponentContext> const& i_xContext, SfxObjectShell const & i_rRegistrySupplier) @@ -228,7 +229,6 @@ struct DocumentMetadataAccess_Impl , m_rXmlIdRegistrySupplier(i_rRegistrySupplier) , m_xBaseURI() , m_xRepository() - , m_xManifest() { OSL_ENSURE(m_xContext.is(), "context null"); } @@ -394,26 +394,12 @@ removeFile(struct DocumentMetadataAccess_Impl const & i_rImpl, } } -static ::std::vector< uno::Reference< rdf::XURI > > +static css::uno::Sequence< uno::Reference< rdf::XURI > > getAllParts(struct DocumentMetadataAccess_Impl const & i_rImpl) { - ::std::vector< uno::Reference< rdf::XURI > > ret; try { - const uno::Reference<container::XEnumeration> xEnum( - i_rImpl.m_xManifest->getStatements( i_rImpl.m_xBaseURI.get(), - getURI<rdf::URIs::PKG_HASPART>(i_rImpl.m_xContext), nullptr), - uno::UNO_SET_THROW); - while (xEnum->hasMoreElements()) { - rdf::Statement stmt; - if (!(xEnum->nextElement() >>= stmt)) { - throw uno::RuntimeException(); - } - const uno::Reference<rdf::XURI> xPart(stmt.Object, - uno::UNO_QUERY); - if (!xPart.is()) continue; - ret.push_back(xPart); - } - return ret; + return i_rImpl.m_xManifest->getStatementsObjects( i_rImpl.m_xBaseURI.get(), + getURI<rdf::URIs::PKG_HASPART>(i_rImpl.m_xContext), nullptr); } catch (const uno::RuntimeException &) { throw; } catch (const uno::Exception &) { @@ -454,27 +440,14 @@ getAllParts(struct DocumentMetadataAccess_Impl const& i_rImpl, ::std::vector<uno::Reference<rdf::XURI>> ret; try { - const uno::Reference<container::XEnumeration> xEnum( - i_rImpl.m_xManifest->getStatements(i_rImpl.m_xBaseURI.get(), + css::uno::Sequence< uno::Reference< rdf::XURI > > parts1 + = i_rImpl.m_xManifest->getStatementsObjects(i_rImpl.m_xBaseURI.get(), getURI<rdf::URIs::PKG_HASPART>(i_rImpl.m_xContext), - nullptr), - uno::UNO_SET_THROW); - while (xEnum->hasMoreElements()) + nullptr); + for (auto const & xPart : parts1) { - rdf::Statement stmt; - if (!(xEnum->nextElement() >>= stmt)) - { - throw uno::RuntimeException(); - } - const uno::Reference<rdf::XURI> xPart(stmt.Object, uno::UNO_QUERY); - if (!xPart.is()) - continue; - - const uno::Reference<container::XEnumeration> xEnum2( - i_rImpl.m_xManifest->getStatements( - xPart.get(), getURI<rdf::URIs::RDF_TYPE>(i_rImpl.m_xContext), i_xType.get()), - uno::UNO_SET_THROW); - if (xEnum2->hasMoreElements()) + if (i_rImpl.m_xManifest->hasStatements( + xPart.get(), getURI<rdf::URIs::RDF_TYPE>(i_rImpl.m_xContext), i_xType.get())) ret.emplace_back(xPart); } return ret; @@ -773,10 +746,11 @@ retry: } // init manifest graph - const uno::Reference<rdf::XNamedGraph> xManifestGraph( - i_rImpl.m_xRepository->getGraph(xManifest)); - i_rImpl.m_xManifest.set(xManifestGraph.is() ? xManifestGraph : - i_rImpl.m_xRepository->createGraph(xManifest), uno::UNO_SET_THROW); + auto xManifestGraph = i_rImpl.m_xRepository->getGraph(xManifest); + if (xManifestGraph.is()) + i_rImpl.m_xManifest.set(xManifestGraph, uno::UNO_QUERY_THROW); + else + i_rImpl.m_xManifest.set(i_rImpl.m_xRepository->createGraph(xManifest), uno::UNO_QUERY_THROW); const uno::Reference<container::XEnumeration> xEnum( i_rImpl.m_xManifest->getStatements(nullptr, getURI<rdf::URIs::RDF_TYPE>(i_rImpl.m_xContext), @@ -808,7 +782,7 @@ static void init(struct DocumentMetadataAccess_Impl & i_rImpl) i_rImpl.m_xManifest.set(i_rImpl.m_xRepository->createGraph( getURIForStream(i_rImpl, s_manifest)), - uno::UNO_SET_THROW); + uno::UNO_QUERY_THROW); // insert the document statement i_rImpl.m_xManifest->addStatement(i_rImpl.m_xBaseURI.get(), @@ -1134,7 +1108,7 @@ void SAL_CALL DocumentMetadataAccess::loadMetadataFromStorage( std::vector< OUString > MfstMetadataFiles; try { - const ::std::vector< uno::Reference< rdf::XURI > > parts( + const css::uno::Sequence< uno::Reference< rdf::XURI > > parts( getAllParts(*m_pImpl) ); const uno::Reference<rdf::XURI>& xContentFile( getURI<rdf::URIs::ODF_CONTENTFILE>(m_pImpl->m_xContext)); diff --git a/sw/source/core/edit/edfcol.cxx b/sw/source/core/edit/edfcol.cxx index 4df464ee49ed..a61964900a1d 100644 --- a/sw/source/core/edit/edfcol.cxx +++ b/sw/source/core/edit/edfcol.cxx @@ -1157,12 +1157,14 @@ void SwEditShell::SetClassification(const OUString& rName, SfxClassificationPoli } } +// We pass xParent and xNodeSubject even though they point to the same thing because the UNO_QUERY is +// on a performance-sensitive path. static void lcl_ApplyParagraphClassification(SwDoc* pDoc, const uno::Reference<frame::XModel>& xModel, const uno::Reference<text::XTextContent>& xParent, + const css::uno::Reference<css::rdf::XResource>& xNodeSubject, std::vector<svx::ClassificationResult> aResults) { - css::uno::Reference<css::rdf::XResource> xNodeSubject(xParent, uno::UNO_QUERY); if (!xNodeSubject.is()) return; @@ -1279,7 +1281,7 @@ void SwEditShell::ApplyParagraphClassification(std::vector<svx::ClassificationRe uno::Reference<frame::XModel> xModel = pDocShell->GetBaseModel(); uno::Reference<text::XTextContent> xParent = SwXParagraph::CreateXParagraph(*pNode->GetDoc(), pNode); - lcl_ApplyParagraphClassification(GetDoc(), xModel, xParent, std::move(aResults)); + lcl_ApplyParagraphClassification(GetDoc(), xModel, xParent, css::uno::Reference<css::rdf::XResource>(xParent, uno::UNO_QUERY), std::move(aResults)); } static std::vector<svx::ClassificationResult> lcl_CollectParagraphClassification(const uno::Reference<frame::XModel>& xModel, const uno::Reference<text::XTextContent>& xParagraph) @@ -1987,7 +1989,7 @@ void SwEditShell::RestoreMetadataFieldsAndValidateParagraphSignatures() } // Update classification based on results. - lcl_ApplyParagraphClassification(GetDoc(), xModel, xParagraph, aResults); + lcl_ApplyParagraphClassification(GetDoc(), xModel, xParagraph, xSubject, aResults); // Get Signatures std::map<OUString, SignatureDescr> aSignatures; diff --git a/unoxml/source/rdf/librdf_repository.cxx b/unoxml/source/rdf/librdf_repository.cxx index c04e4a0155ce..3b774b7526c9 100644 --- a/unoxml/source/rdf/librdf_repository.cxx +++ b/unoxml/source/rdf/librdf_repository.cxx @@ -51,9 +51,11 @@ #include <com/sun/star/rdf/BlankNode.hpp> #include <com/sun/star/rdf/URI.hpp> #include <com/sun/star/rdf/Literal.hpp> +#include <com/sun/star/rdf/XNamedGraph2.hpp> #include <rtl/ref.hxx> #include <rtl/strbuf.hxx> +#include <rtl/ustrbuf.hxx> #include <rtl/ustring.hxx> #include <osl/diagnose.h> #include <cppuhelper/exc_hlp.hxx> @@ -183,23 +185,23 @@ public: struct Resource : public Node { }; struct URI : public Resource { - OString const value; + OString value; explicit URI(OString const& i_rValue) : value(i_rValue) { } }; struct BlankNode : public Resource { - OString const value; + OString value; explicit BlankNode(OString const& i_rValue) : value(i_rValue) { } }; struct Literal : public Node { - OString const value; - OString const language; - ::boost::optional<OString> const type; + OString value; + OString language; + ::boost::optional<OString> type; Literal(OString const& i_rValue, OString const& i_rLanguage, ::boost::optional<OString> const& i_rType) : value(i_rValue) @@ -242,8 +244,14 @@ public: Statement const& i_rStatement); static std::shared_ptr<Resource> extractResource_NoLock( const uno::Reference< rdf::XResource > & i_xResource); + static void extractResourceToCacheKey( + const uno::Reference< rdf::XResource > & i_xResource, + OUStringBuffer& rBuf); static std::shared_ptr<Node> extractNode_NoLock( const uno::Reference< rdf::XNode > & i_xNode); + static void extractNodeToCacheKey( + const uno::Reference< rdf::XNode > & i_xNode, + OUStringBuffer& rBuffer); static Statement extractStatement_NoLock( const uno::Reference< rdf::XResource > & i_xSubject, const uno::Reference< rdf::XURI > & i_xPredicate, @@ -369,6 +377,14 @@ public: // throw (uno::RuntimeException, lang::IllegalArgumentException, // container::NoSuchElementException, rdf::RepositoryException); + // Optimised version that skips the enumeration object + std::vector<uno::Reference<rdf::XURI>> getStatementsGraph_NoLock2( + const uno::Reference< rdf::XResource > & i_xSubject, + const uno::Reference< rdf::XURI > & i_xPredicate, + const uno::Reference< rdf::XNode > & i_xObject, + const uno::Reference< rdf::XURI > & i_xName, + bool i_Internal = false ); + const librdf_TypeConverter& getTypeConverter() { return m_TypeConverter; }; private: @@ -646,7 +662,7 @@ librdf_QuerySelectResult::getBindingNames() */ class librdf_NamedGraph: public ::cppu::WeakImplHelper< - rdf::XNamedGraph> + rdf::XNamedGraph2> { public: librdf_NamedGraph(librdf_Repository * i_pRep, @@ -678,16 +694,38 @@ public: const uno::Reference< rdf::XResource > & i_xSubject, const uno::Reference< rdf::XURI > & i_xPredicate, const uno::Reference< rdf::XNode > & i_xObject) override; + // css::rdf::XNamedGraph2 + virtual uno::Sequence<uno::Reference< rdf::XURI >> SAL_CALL getStatementsObjects( + const uno::Reference< rdf::XResource > & i_xSubject, + const uno::Reference< rdf::XURI > & i_xPredicate, + const uno::Reference< rdf::XNode > & i_xObject) override; + virtual sal_Bool SAL_CALL hasStatements( + const uno::Reference< rdf::XResource > & i_xSubject, + const uno::Reference< rdf::XURI > & i_xPredicate, + const uno::Reference< rdf::XNode > & i_xObject) override; private: librdf_NamedGraph(librdf_NamedGraph const&) = delete; librdf_NamedGraph& operator=(librdf_NamedGraph const&) = delete; + static OUString createCacheKey( + const uno::Reference< rdf::XResource > & i_xSubject, + const uno::Reference< rdf::XURI > & i_xPredicate, + const uno::Reference< rdf::XNode > & i_xObject); + /// weak reference: this is needed to check if m_pRep is valid uno::WeakReference< rdf::XRepository > const m_wRep; librdf_Repository *const m_pRep; uno::Reference< rdf::XURI > const m_xName; + + // Querying is rather slow, so cache the results. + struct CacheValue + { + std::vector<uno::Reference<rdf::XURI>> maUris; + bool mbHasNodes; + }; + std::map<OUString, CacheValue> m_aStatementsCache; }; @@ -729,6 +767,7 @@ void SAL_CALL librdf_NamedGraph::clear() throw lang::WrappedTargetRuntimeException( ex.Message, *this, anyEx ); } + m_aStatementsCache.clear(); } void SAL_CALL librdf_NamedGraph::addStatement( @@ -743,6 +782,7 @@ void SAL_CALL librdf_NamedGraph::addStatement( } m_pRep->addStatementGraph_NoLock( i_xSubject, i_xPredicate, i_xObject, m_xName); + m_aStatementsCache.clear(); } void SAL_CALL librdf_NamedGraph::removeStatements( @@ -757,6 +797,7 @@ void SAL_CALL librdf_NamedGraph::removeStatements( } m_pRep->removeStatementsGraph_NoLock( i_xSubject, i_xPredicate, i_xObject, m_xName); + m_aStatementsCache.clear(); } uno::Reference< container::XEnumeration > SAL_CALL @@ -770,10 +811,86 @@ librdf_NamedGraph::getStatements( throw rdf::RepositoryException( "librdf_NamedGraph::getStatements: repository is gone", *this); } - return m_pRep->getStatementsGraph_NoLock( + auto ret = m_pRep->getStatementsGraph_NoLock( + i_xSubject, i_xPredicate, i_xObject, m_xName); + return ret; +} + +OUString librdf_NamedGraph::createCacheKey( + const uno::Reference< rdf::XResource > & i_xSubject, + const uno::Reference< rdf::XURI > & i_xPredicate, + const uno::Reference< rdf::XNode > & i_xObject) +{ + OUStringBuffer cacheKey(256); + librdf_TypeConverter::extractResourceToCacheKey(i_xSubject, cacheKey); + cacheKey.append("\t"); + librdf_TypeConverter::extractResourceToCacheKey(i_xPredicate, cacheKey); + cacheKey.append("\t"); + librdf_TypeConverter::extractNodeToCacheKey(i_xObject, cacheKey); + return cacheKey.makeStringAndClear(); +} + +uno::Sequence<uno::Reference<rdf::XURI>> SAL_CALL +librdf_NamedGraph::getStatementsObjects( + const uno::Reference< rdf::XResource > & i_xSubject, + const uno::Reference< rdf::XURI > & i_xPredicate, + const uno::Reference< rdf::XNode > & i_xObject) +{ + OUString cacheKey = createCacheKey(i_xSubject, i_xPredicate, i_xObject); + auto it = m_aStatementsCache.find(cacheKey); + if (it != m_aStatementsCache.end()) + return comphelper::containerToSequence(it->second.maUris); + + uno::Reference< rdf::XRepository > xRep( m_wRep ); + if (!xRep.is()) { + throw rdf::RepositoryException( + "librdf_NamedGraph::getStatements: repository is gone", *this); + } + std::vector<uno::Reference<rdf::XURI>> xEnum = m_pRep->getStatementsGraph_NoLock2( i_xSubject, i_xPredicate, i_xObject, m_xName); + + std::vector<uno::Reference<rdf::XURI>> uris; + bool bHasNodes = false; + for (uno::Reference<rdf::XURI> const & rPart : xEnum) + { + bHasNodes = true; + if (!rPart.is()) + continue; + uris.push_back(rPart); + } + m_aStatementsCache.emplace(cacheKey, CacheValue{ uris, bHasNodes }); + return comphelper::containerToSequence(uris); } +sal_Bool SAL_CALL +librdf_NamedGraph::hasStatements( + const uno::Reference< rdf::XResource > & i_xSubject, + const uno::Reference< rdf::XURI > & i_xPredicate, + const uno::Reference< rdf::XNode > & i_xObject) +{ + OUString cacheKey = createCacheKey(i_xSubject, i_xPredicate, i_xObject); + auto it = m_aStatementsCache.find(cacheKey); + if (it != m_aStatementsCache.end()) + return it->second.mbHasNodes; + uno::Reference< rdf::XRepository > xRep( m_wRep ); + if (!xRep.is()) { + throw rdf::RepositoryException( + "librdf_NamedGraph::getStatements: repository is gone", *this); + } + std::vector<uno::Reference<rdf::XURI>> xEnum = m_pRep->getStatementsGraph_NoLock2( + i_xSubject, i_xPredicate, i_xObject, m_xName); + std::vector<uno::Reference<rdf::XURI>> uris; + bool bHasNodes = false; + for (uno::Reference<rdf::XURI> const & rPart : xEnum) + { + bHasNodes = true; + if (!rPart.is()) + continue; + uris.push_back(rPart); + } + m_aStatementsCache.emplace(cacheKey, CacheValue{ uris, bHasNodes }); + return bHasNodes; +} std::shared_ptr<librdf_world> librdf_Repository::m_pWorld; sal_uInt32 librdf_Repository::m_NumInstances = 0; @@ -1921,6 +2038,108 @@ librdf_Repository::getStatementsGraph_NoLock( return new librdf_GraphResult(this, m_aMutex, pStream, pContext); } +// Optimised version that skips the enumeration object +std::vector<uno::Reference<rdf::XURI>> +librdf_Repository::getStatementsGraph_NoLock2( + const uno::Reference< rdf::XResource > & i_xSubject, + const uno::Reference< rdf::XURI > & i_xPredicate, + const uno::Reference< rdf::XNode > & i_xObject, + const uno::Reference< rdf::XURI > & i_xGraphName, + bool i_Internal) +//throw (uno::RuntimeException, lang::IllegalArgumentException, +// container::NoSuchElementException, rdf::RepositoryException) +{ + std::vector<uno::Reference<rdf::XURI>> ret; + + // N.B.: if any of subject, predicate, object is an XMetadatable, and + // has no metadata reference, then there cannot be any node in the graph + // representing it; in order to prevent side effect + // (ensureMetadataReference), check for this condition and return + if (isMetadatableWithoutMetadata(i_xSubject) || + isMetadatableWithoutMetadata(i_xPredicate) || + isMetadatableWithoutMetadata(i_xObject)) + { + return ret; + } + + librdf_TypeConverter::Statement const stmt( + librdf_TypeConverter::extractStatement_NoLock( + i_xSubject, i_xPredicate, i_xObject)); + const OUString contextU( i_xGraphName->getStringValue() ); + + ::osl::MutexGuard g(m_aMutex); // don't call i_x* with mutex locked + + if (!i_Internal && (m_NamedGraphs.find(contextU) == m_NamedGraphs.end())) { + throw container::NoSuchElementException( + "librdf_Repository::getStatements: " + "no graph with given URI exists", *this); + } + const OString context( + OUStringToOString(contextU, RTL_TEXTENCODING_UTF8) ); + + const std::shared_ptr<librdf_node> pContext( + librdf_new_node_from_uri_string(m_pWorld.get(), + reinterpret_cast<const unsigned char*> (context.getStr())), + safe_librdf_free_node); + if (!pContext) { + throw uno::RuntimeException( + "librdf_Repository::getStatements: " + "librdf_new_node_from_uri_string failed", *this); + } + const std::shared_ptr<librdf_statement> pStatement( + librdf_TypeConverter::mkStatement_Lock(m_pWorld.get(), stmt), + safe_librdf_free_statement); + OSL_ENSURE(pStatement, "mkStatement failed"); + + const std::shared_ptr<librdf_stream> pStream( + librdf_model_find_statements_in_context(m_pModel.get(), + pStatement.get(), pContext.get()), + safe_librdf_free_stream); + if (!pStream) { + throw rdf::RepositoryException( + "librdf_Repository::getStatements: " + "librdf_model_find_statements_in_context failed", *this); + } + + librdf_node *pCtxt1( +#if LIBRDF_VERSION >= 10012 + librdf_stream_get_context2(pStream.get()) ); +#else + static_cast<librdf_node *>(librdf_stream_get_context(pStream.get())) ); +#endif + while (!librdf_stream_end(pStream.get())) + { + auto pCtxt = pCtxt1; + librdf_statement *pStmt( librdf_stream_get_object(pStream.get()) ); + if (!pStmt) { + rdf::QueryException e( + "librdf_GraphResult::nextElement: " + "librdf_stream_get_object failed", *this); + throw lang::WrappedTargetException( + "librdf_GraphResult::nextElement: " + "librdf_stream_get_object failed", *this, + uno::makeAny(e)); + } + // NB: pCtxt may be null here if this is result of a graph query + if (pCtxt && isInternalContext(pCtxt)) { + pCtxt = nullptr; // XML ID context is implementation detail! + } + + ret.push_back( + css::uno::Reference<rdf::XURI>( + getTypeConverter().convertToXNode(librdf_statement_get_object(pStmt)), + uno::UNO_QUERY) ); + + // NB: this will invalidate current item. + librdf_stream_next(pStream.get()); + } + + return ret; + // librdf_model_find_statements_in_context is buggy and does not put + // the context into result statements; pass it to librdf_GraphResult here + //return new librdf_GraphResult(this, m_aMutex, pStream, pContext); +} + extern "C" void librdf_raptor_init(void* /*user_data*/, raptor_world* pRaptorWorld) { @@ -2031,6 +2250,21 @@ librdf_TypeConverter::extractResource_NoLock( } } +void +librdf_TypeConverter::extractResourceToCacheKey( + const uno::Reference< rdf::XResource > & i_xResource, OUStringBuffer& rBuffer) +{ + if (!i_xResource.is()) { + return; + } + uno::Reference< rdf::XBlankNode > xBlankNode(i_xResource, uno::UNO_QUERY); + if (xBlankNode.is()) { + rBuffer.append("BlankNode ").append(xBlankNode->getStringValue()); + } else { // assumption: everything else is URI + rBuffer.append("URI ").append(i_xResource->getStringValue()); + } +} + // create blank or URI node librdf_node* librdf_TypeConverter::mkResource_Lock( librdf_world* i_pWorld, Resource const*const i_pResource) @@ -2098,6 +2332,31 @@ librdf_TypeConverter::extractNode_NoLock( return std::shared_ptr<Node>(new Literal(val, lang, type)); } +// extract blank or URI or literal node - call without Mutex locked +void +librdf_TypeConverter::extractNodeToCacheKey( + const uno::Reference< rdf::XNode > & i_xNode, + OUStringBuffer& rBuffer) +{ + if (!i_xNode.is()) { + return; + } + uno::Reference< rdf::XResource > xResource(i_xNode, uno::UNO_QUERY); + if (xResource.is()) { + return extractResourceToCacheKey(xResource, rBuffer); + } + uno::Reference< rdf::XLiteral> xLiteral(i_xNode, uno::UNO_QUERY); + OSL_ENSURE(xLiteral.is(), + "mkNode: someone invented a new rdf.XNode and did not tell me"); + if (!xLiteral.is()) { + return; + } + rBuffer.append("Literal ").append(xLiteral->getValue()).append("\t").append(xLiteral->getLanguage()); + const uno::Reference< rdf::XURI > xType(xLiteral->getDatatype()); + if (xType.is()) + rBuffer.append(xType->getStringValue()); +} + // create blank or URI or literal node librdf_node* librdf_TypeConverter::mkNode_Lock( librdf_world* i_pWorld, Node const*const i_pNode) |