From f2394e4c9cd7a27a1eb1e0e2476997fd18ae2508 Mon Sep 17 00:00:00 2001 From: Michael Stahl Date: Wed, 8 Jan 2014 23:43:03 +0100 Subject: fdo#72928: fix deadlocks in librdf_Repository MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refactor to do all calls on parameters before locking the mutex. This requires splitting up some librdf_TypeConverter methods into an extract function and a make function, with an intermediate representation between. Also rename some internal functions to make it clear which are called with Lock and which with NoLock. (cherry picked from commit 7db6b2f7968d8063b12312737136f09cb7549805) squashed: librdf_Repository: make older compilers happy (cherry picked from commit d3aad81268298c05163136e2e953e1dfe0728d9e) Change-Id: Iddc42461d95351785578ef6a80fbf5d056356c16 Reviewed-on: https://gerrit.libreoffice.org/7337 Reviewed-by: Jan-Marek Glogowski Tested-by: Jan-Marek Glogowski Reviewed-by: Caolán McNamara Tested-by: Caolán McNamara --- unoxml/source/rdf/librdf_repository.cxx | 485 ++++++++++++++++++++++---------- 1 file changed, 333 insertions(+), 152 deletions(-) diff --git a/unoxml/source/rdf/librdf_repository.cxx b/unoxml/source/rdf/librdf_repository.cxx index b3c77e55ae56..d56cfad6db9e 100644 --- a/unoxml/source/rdf/librdf_repository.cxx +++ b/unoxml/source/rdf/librdf_repository.cxx @@ -30,6 +30,7 @@ #include #include #include +#include #include @@ -93,7 +94,7 @@ const char s_nsOOo [] = "http://openoffice.org/2004/office/rdfa/"; //////////////////////////////////////////////////////////////////////////// -//FIXME: this approach is not ideal. can we use blind nodes instead? +//FIXME: this approach is not ideal. can we use blank nodes instead? bool isInternalContext(librdf_node *i_pNode) throw () { OSL_ENSURE(i_pNode, "isInternalContext: context null"); @@ -176,6 +177,53 @@ static void safe_librdf_free_uri(librdf_uri *const uri) class librdf_TypeConverter { public: + + // some wrapper classes to temporarily hold values of UNO XNodes + struct Node + { + virtual ~Node() {} + }; + struct Resource : public Node { }; + struct URI : public Resource + { + OString const value; + URI(OString const& i_rValue) + : value(i_rValue) + { } + }; + struct BlankNode : public Resource + { + OString const value; + BlankNode(OString const& i_rValue) + : value(i_rValue) + { } + }; + struct Literal : public Node + { + OString const value; + OString const language; + ::boost::optional const type; + Literal(OString const& i_rValue, OString const& i_rLanguage, + ::boost::optional const& i_rType) + : value(i_rValue) + , language(i_rLanguage) + , type(i_rType) + { } + }; + struct Statement + { + ::boost::shared_ptr const pSubject; + ::boost::shared_ptr const pPredicate; + ::boost::shared_ptr const pObject; + Statement(::boost::shared_ptr const& i_pSubject, + ::boost::shared_ptr const& i_pPredicate, + ::boost::shared_ptr const& i_pObject) + : pSubject(i_pSubject) + , pPredicate(i_pPredicate) + , pObject(i_pObject) + { } + }; + librdf_TypeConverter( uno::Reference< uno::XComponentContext > const & i_xContext, librdf_Repository &i_rRep) @@ -183,17 +231,23 @@ public: , m_rRep(i_rRep) { }; - librdf_world *createWorld() const; - librdf_storage *createStorage(librdf_world *i_pWorld) const; - librdf_model *createModel(librdf_world *i_pWorld, + librdf_world *createWorld_Lock() const; + librdf_storage *createStorage_Lock(librdf_world *i_pWorld) const; + librdf_model *createModel_Lock(librdf_world *i_pWorld, librdf_storage * i_pStorage) const; - librdf_uri* mkURI( librdf_world* i_pWorld, - const uno::Reference< rdf::XURI > & i_xURI) const; - librdf_node* mkResource( librdf_world* i_pWorld, + librdf_uri* mkURI_Lock(librdf_world* i_pWorld, + const OString & i_rURI) const; + librdf_node* mkResource_Lock(librdf_world* i_pWorld, + const Resource * i_pResource) const; + librdf_node* mkNode_Lock(librdf_world* i_pWorld, + const Node * i_pNode) const; + librdf_statement* mkStatement_Lock(librdf_world* i_pWorld, + Statement const& i_rStatement) const; + ::boost::shared_ptr extractResource_NoLock( const uno::Reference< rdf::XResource > & i_xResource) const; - librdf_node* mkNode( librdf_world* i_pWorld, + ::boost::shared_ptr extractNode_NoLock( const uno::Reference< rdf::XNode > & i_xNode) const; - librdf_statement* mkStatement( librdf_world* i_pWorld, + Statement extractStatement_NoLock( const uno::Reference< rdf::XResource > & i_xSubject, const uno::Reference< rdf::XURI > & i_xPredicate, const uno::Reference< rdf::XNode > & i_xObject) const; @@ -207,7 +261,7 @@ public: const; private: - uno::Reference< uno::XComponentContext > m_xContext; + uno::Reference< uno::XComponentContext > const m_xContext; librdf_Repository & m_rRep; }; @@ -321,10 +375,13 @@ public: throw (uno::RuntimeException, uno::Exception); // XNamedGraph forwards --------------------------------------------- - const NamedGraphMap_t::iterator SAL_CALL clearGraph( - const uno::Reference< rdf::XURI > & i_xName, + const NamedGraphMap_t::iterator clearGraph_NoLock( + const OUString & i_rGraphName, bool i_Internal = false ); - void addStatementGraph( + const NamedGraphMap_t::iterator clearGraph_Lock( + const OUString & i_rGraphName, + bool i_Internal); + void addStatementGraph_NoLock( const uno::Reference< rdf::XResource > & i_xSubject, const uno::Reference< rdf::XURI > & i_xPredicate, const uno::Reference< rdf::XNode > & i_xObject, @@ -332,14 +389,18 @@ public: bool i_Internal = false ); // throw (uno::RuntimeException, lang::IllegalArgumentException, // container::NoSuchElementException, rdf::RepositoryException); - void removeStatementsGraph( + void addStatementGraph_Lock( + librdf_TypeConverter::Statement const& i_rStatement, + OUString const& i_rGraphName, + bool i_Internal); + void removeStatementsGraph_NoLock( 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 ); // throw (uno::RuntimeException, lang::IllegalArgumentException, // container::NoSuchElementException, rdf::RepositoryException); - uno::Reference< container::XEnumeration > getStatementsGraph( + uno::Reference< container::XEnumeration > getStatementsGraph_NoLock( const uno::Reference< rdf::XResource > & i_xSubject, const uno::Reference< rdf::XURI > & i_xPredicate, const uno::Reference< rdf::XNode > & i_xObject, @@ -352,7 +413,8 @@ public: private: - uno::Reference< uno::XComponentContext > m_xContext; + /// this is const, no need to lock m_aMutex to access it + uno::Reference< uno::XComponentContext > const m_xContext; /// librdf global data /** N.B.: The redland documentation gives the impression that you can have @@ -380,7 +442,7 @@ private: /// all named graphs NamedGraphMap_t m_NamedGraphs; - /// type conversion helper + /// type conversion helper - stateless librdf_TypeConverter m_TypeConverter; /// set of xml:ids of elements with xhtml:content @@ -442,7 +504,7 @@ private: boost::shared_ptr const m_pContext; boost::shared_ptr const m_pStream; - librdf_node* getContext() const; + librdf_node* getContext_Lock() const; }; @@ -454,7 +516,7 @@ librdf_GraphResult::hasMoreElements() throw (uno::RuntimeException) return m_pStream.get() && !librdf_stream_end(m_pStream.get()); } -librdf_node* librdf_GraphResult::getContext() const +librdf_node* librdf_GraphResult::getContext_Lock() const { if (!m_pStream.get() || librdf_stream_end(m_pStream.get())) return NULL; @@ -476,7 +538,7 @@ throw (uno::RuntimeException, container::NoSuchElementException, { ::osl::MutexGuard g(m_rMutex); if (!m_pStream.get() || !librdf_stream_end(m_pStream.get())) { - librdf_node * pCtxt = getContext(); + librdf_node * pCtxt = getContext_Lock(); librdf_statement *pStmt( librdf_stream_get_object(m_pStream.get()) ); if (!pStmt) { @@ -555,9 +617,9 @@ private: ::osl::Mutex & m_rMutex; // not that the redland documentation spells this out explicity, but // queries must be freed only after all the results are completely read - boost::shared_ptr m_pQuery; - boost::shared_ptr m_pQueryResult; - uno::Sequence< OUString > m_BindingNames; + boost::shared_ptr const m_pQuery; + boost::shared_ptr const m_pQueryResult; + uno::Sequence< OUString > const m_BindingNames; }; @@ -624,6 +686,7 @@ throw (uno::RuntimeException, container::NoSuchElementException, uno::Sequence< OUString > SAL_CALL librdf_QuerySelectResult::getBindingNames() throw (uno::RuntimeException) { + // const - no lock needed return m_BindingNames; } @@ -685,9 +748,9 @@ public: private: /// weak reference: this is needed to check if m_pRep is valid - uno::WeakReference< rdf::XRepository > m_wRep; - librdf_Repository *m_pRep; - uno::Reference< rdf::XURI > m_xName; + uno::WeakReference< rdf::XRepository > const m_wRep; + librdf_Repository *const m_pRep; + uno::Reference< rdf::XURI > const m_xName; }; @@ -727,8 +790,9 @@ throw (uno::RuntimeException, throw rdf::RepositoryException( "librdf_NamedGraph::clear: repository is gone", *this); } + const OUString contextU( m_xName->getStringValue() ); try { - m_pRep->clearGraph(m_xName); + m_pRep->clearGraph_NoLock(contextU); } catch (lang::IllegalArgumentException &) { throw uno::RuntimeException(); } @@ -746,7 +810,8 @@ throw (uno::RuntimeException, lang::IllegalArgumentException, throw rdf::RepositoryException( "librdf_NamedGraph::addStatement: repository is gone", *this); } - m_pRep->addStatementGraph(i_xSubject, i_xPredicate, i_xObject, m_xName); + m_pRep->addStatementGraph_NoLock( + i_xSubject, i_xPredicate, i_xObject, m_xName); } void SAL_CALL librdf_NamedGraph::removeStatements( @@ -761,7 +826,8 @@ throw (uno::RuntimeException, throw rdf::RepositoryException( "librdf_NamedGraph::removeStatements: repository is gone", *this); } - m_pRep->removeStatementsGraph(i_xSubject, i_xPredicate, i_xObject, m_xName); + m_pRep->removeStatementsGraph_NoLock( + i_xSubject, i_xPredicate, i_xObject, m_xName); } uno::Reference< container::XEnumeration > SAL_CALL @@ -777,7 +843,7 @@ throw (uno::RuntimeException, throw rdf::RepositoryException( "librdf_NamedGraph::getStatements: repository is gone", *this); } - return m_pRep->getStatementsGraph( + return m_pRep->getStatementsGraph_NoLock( i_xSubject, i_xPredicate, i_xObject, m_xName); } @@ -801,7 +867,8 @@ librdf_Repository::librdf_Repository( ::osl::MutexGuard g(m_aMutex); if (!m_NumInstances++) { - m_pWorld.reset(m_TypeConverter.createWorld(), safe_librdf_free_world); + m_pWorld.reset(m_TypeConverter.createWorld_Lock(), + safe_librdf_free_world); } } @@ -889,7 +956,6 @@ throw (uno::RuntimeException, lang::IllegalArgumentException, container::ElementExistException, rdf::ParseException, rdf::RepositoryException, io::IOException) { - ::osl::MutexGuard g(m_aMutex); if (!i_xInStream.is()) { throw lang::IllegalArgumentException( "librdf_Repository::importGraph: stream is null", *this, 1); @@ -920,6 +986,16 @@ throw (uno::RuntimeException, lang::IllegalArgumentException, } const OUString contextU( i_xGraphName->getStringValue() ); + + uno::Sequence buf; + uno::Reference xSeekable(i_xInStream, uno::UNO_QUERY); + // UGLY: if only redland could read streams... + const sal_Int64 sz( xSeekable.is() ? xSeekable->getLength() : 1 << 20 ); + // exceptions are propagated + i_xInStream->readBytes( buf, static_cast( sz ) ); + + ::osl::MutexGuard g(m_aMutex); // don't call i_x* with mutex locked ////// + if (m_NamedGraphs.find(contextU) != m_NamedGraphs.end()) { throw container::ElementExistException( "librdf_Repository::importGraph: graph with given URI exists", *this); @@ -955,12 +1031,6 @@ throw (uno::RuntimeException, lang::IllegalArgumentException, "librdf_new_parser failed", *this); } - uno::Sequence buf; - uno::Reference xSeekable(i_xInStream, uno::UNO_QUERY); - // UGLY: if only that redland junk could read streams... - const sal_Int64 sz( xSeekable.is() ? xSeekable->getLength() : 1 << 20 ); - // exceptions are propagated - i_xInStream->readBytes( buf, static_cast( sz ) ); const boost::shared_ptr pStream( librdf_parser_parse_counted_string_as_stream(pParser.get(), reinterpret_cast(buf.getConstArray()), @@ -971,8 +1041,9 @@ throw (uno::RuntimeException, lang::IllegalArgumentException, "librdf_Repository::importGraph: " "librdf_parser_parse_counted_string_as_stream failed", *this); } - m_NamedGraphs.insert(std::make_pair(contextU, - new librdf_NamedGraph(this, i_xGraphName))); + rtl::Reference const pGraph( + new librdf_NamedGraph(this, i_xGraphName)); + m_NamedGraphs.insert(std::make_pair(contextU, pGraph)); if (librdf_model_context_add_statements(m_pModel.get(), pContext.get(), pStream.get())) { throw rdf::RepositoryException( @@ -980,7 +1051,7 @@ throw (uno::RuntimeException, lang::IllegalArgumentException, "librdf_model_context_add_statements failed", *this); } - return getGraph(i_xGraphName); + return uno::Reference(pGraph.get()); } void addChaffWhenEncryptedStorage(const uno::Reference< io::XOutputStream > &rStream, unsigned char* pBuffer, size_t length) @@ -1040,7 +1111,6 @@ throw (uno::RuntimeException, lang::IllegalArgumentException, container::NoSuchElementException, rdf::RepositoryException, io::IOException) { - ::osl::MutexGuard g(m_aMutex); if (!i_xOutStream.is()) { throw lang::IllegalArgumentException( "librdf_Repository::exportGraph: stream is null", *this, 1); @@ -1070,6 +1140,9 @@ throw (uno::RuntimeException, lang::IllegalArgumentException, } const OUString contextU( i_xGraphName->getStringValue() ); + + ::osl::ClearableMutexGuard g(m_aMutex); // don't call i_x* with mutex locked + if (m_NamedGraphs.find(contextU) == m_NamedGraphs.end()) { throw container::NoSuchElementException( "librdf_Repository::exportGraph: " @@ -1168,6 +1241,9 @@ throw (uno::RuntimeException, lang::IllegalArgumentException, "librdf_serializer_serialize_stream_to_counted_string failed", *this); } + + g.clear(); // release Mutex before calling i_xOutStream methods ////////// + addChaffWhenEncryptedStorage(i_xOutStream, pBuf.get(), length); } @@ -1189,13 +1265,14 @@ librdf_Repository::getGraph(const uno::Reference< rdf::XURI > & i_xGraphName) throw (uno::RuntimeException, lang::IllegalArgumentException, rdf::RepositoryException) { - ::osl::MutexGuard g(m_aMutex); if (!i_xGraphName.is()) { throw lang::IllegalArgumentException( "librdf_Repository::getGraph: URI is null", *this, 0); } - const NamedGraphMap_t::iterator iter( - m_NamedGraphs.find(i_xGraphName->getStringValue()) ); + const OUString contextU( i_xGraphName->getStringValue() ); + + ::osl::MutexGuard g(m_aMutex); + const NamedGraphMap_t::iterator iter( m_NamedGraphs.find(contextU) ); if (iter != m_NamedGraphs.end()) { return uno::Reference(iter->second.get()); } else { @@ -1208,21 +1285,24 @@ librdf_Repository::createGraph(const uno::Reference< rdf::XURI > & i_xGraphName) throw (uno::RuntimeException, lang::IllegalArgumentException, container::ElementExistException, rdf::RepositoryException) { - ::osl::MutexGuard g(m_aMutex); if (!i_xGraphName.is()) { throw lang::IllegalArgumentException( "librdf_Repository::createGraph: URI is null", *this, 0); } - if (i_xGraphName->getStringValue().matchAsciiL(s_nsOOo, sizeof(s_nsOOo)-1)) + + const OUString contextU( i_xGraphName->getStringValue() ); + if (contextU.matchAsciiL(s_nsOOo, sizeof(s_nsOOo)-1)) { throw lang::IllegalArgumentException( "librdf_Repository::createGraph: URI is reserved", *this, 0); } + ::osl::MutexGuard g(m_aMutex); // don't call i_x* with mutex locked ////// + // NB: librdf does not have a concept of graphs as such; // a librdf named graph exists iff the model contains a statement with // the graph name as context - const OUString contextU( i_xGraphName->getStringValue() ); + if (m_NamedGraphs.find(contextU) != m_NamedGraphs.end()) { throw container::ElementExistException( "librdf_Repository::createGraph: graph with given URI exists", *this); @@ -1239,8 +1319,15 @@ librdf_Repository::destroyGraph( throw (uno::RuntimeException, lang::IllegalArgumentException, container::NoSuchElementException, rdf::RepositoryException) { - ::osl::MutexGuard g(m_aMutex); - const NamedGraphMap_t::iterator iter( clearGraph(i_xGraphName) ); + if (!i_xGraphName.is()) { + throw lang::IllegalArgumentException( + "librdf_Repository::destroyGraph: URI is null", *this, 0); + } + const OUString contextU( i_xGraphName->getStringValue() ); + + ::osl::MutexGuard g(m_aMutex); // don't call i_x* with mutex locked ////// + + const NamedGraphMap_t::iterator iter( clearGraph_Lock(contextU, false) ); m_NamedGraphs.erase(iter); } @@ -1267,10 +1354,14 @@ throw (uno::RuntimeException, rdf::RepositoryException) ::boost::shared_ptr()); } - ::osl::MutexGuard g(m_aMutex); + librdf_TypeConverter::Statement const stmt( + m_TypeConverter.extractStatement_NoLock( + i_xSubject, i_xPredicate, i_xObject)); + + ::osl::MutexGuard g(m_aMutex); // don't call i_x* with mutex locked ////// + const boost::shared_ptr pStatement( - m_TypeConverter.mkStatement(m_pWorld.get(), - i_xSubject, i_xPredicate, i_xObject), + m_TypeConverter.mkStatement_Lock(m_pWorld.get(), stmt), safe_librdf_free_statement); OSL_ENSURE(pStatement, "mkStatement failed"); @@ -1469,18 +1560,7 @@ throw (uno::RuntimeException, lang::IllegalArgumentException, "ensureMetadataReference did not", *this); } OUString const sXmlId(mdref.First + "#" + mdref.Second); - uno::Reference xXmlId; - try { - xXmlId.set( rdf::URI::create(m_xContext, - OUString::createFromAscii(s_nsOOo) + sXmlId), - uno::UNO_QUERY_THROW); - } catch (const lang::IllegalArgumentException & iae) { - throw lang::WrappedTargetRuntimeException( - "librdf_Repository::setStatementRDFa: " - "cannot create URI for XML ID", *this, uno::makeAny(iae)); - } - - ::osl::MutexGuard g(m_aMutex); + OUString const sContext(OUString::createFromAscii(s_nsOOo) + sXmlId); OUString const content( (i_rRDFaContent.isEmpty()) ? xTextRange->getString() : i_rRDFaContent ); @@ -1499,15 +1579,37 @@ throw (uno::RuntimeException, lang::IllegalArgumentException, "librdf_Repository::setStatementRDFa: " "cannot create literal", *this, uno::makeAny(iae)); } - removeStatementRDFa(i_xObject); + + ::boost::shared_ptr const pSubject( + m_TypeConverter.extractResource_NoLock(i_xSubject)); + ::boost::shared_ptr const pContent( + m_TypeConverter.extractNode_NoLock(xContent)); + ::std::vector< ::boost::shared_ptr > + predicates; + ::std::transform(i_rPredicates.begin(), i_rPredicates.end(), + ::std::back_inserter(predicates), + ::boost::bind(&librdf_TypeConverter::extractResource_NoLock, + m_TypeConverter, _1)); + + removeStatementRDFa(i_xObject); // not atomic with insertion? + + ::osl::MutexGuard g(m_aMutex); // don't call i_x* with mutex locked ////// + if (i_rRDFaContent.isEmpty()) { m_RDFaXHTMLContentSet.erase(sXmlId); } else { m_RDFaXHTMLContentSet.insert(sXmlId); } - ::std::for_each(i_rPredicates.begin(), i_rPredicates.end(), - ::boost::bind( &librdf_Repository::addStatementGraph, - this, i_xSubject, _1, xContent, xXmlId, true)); + for (::std::vector< ::boost::shared_ptr > + ::iterator iter = predicates.begin(); iter != predicates.end(); + ++iter) + { + addStatementGraph_Lock( + librdf_TypeConverter::Statement(pSubject, + ::boost::dynamic_pointer_cast(*iter), + pContent), + sContext, true); + } } void SAL_CALL librdf_Repository::removeStatementRDFa( @@ -1525,20 +1627,11 @@ throw (uno::RuntimeException, lang::IllegalArgumentException, if ((mdref.First.isEmpty()) || (mdref.Second.isEmpty())) { return; // nothing to do... } - uno::Reference xXmlId; - try { - xXmlId.set( rdf::URI::create(m_xContext, - OUString::createFromAscii(s_nsOOo) - + mdref.First + "#" - + mdref.Second), - uno::UNO_QUERY_THROW); - } catch (const lang::IllegalArgumentException & iae) { - throw lang::WrappedTargetRuntimeException( - "librdf_Repository::removeStatementRDFa: " - "cannot create URI for XML ID", *this, uno::makeAny(iae)); - } - // clearGraph does locking, not needed here - clearGraph(xXmlId, true); + + OUString const sXmlId( + OUString::createFromAscii(s_nsOOo) + mdref.First + "#" + mdref.Second); + + clearGraph_NoLock(sXmlId, true); } beans::Pair< uno::Sequence, sal_Bool > SAL_CALL @@ -1567,10 +1660,9 @@ throw (uno::RuntimeException, lang::IllegalArgumentException, "cannot create URI for XML ID", *this, uno::makeAny(iae)); } - ::osl::MutexGuard g(m_aMutex); ::comphelper::SequenceAsVector< rdf::Statement > ret; const uno::Reference xIter( - getStatementsGraph(0, 0, 0, xXmlId, true) ); + getStatementsGraph_NoLock(0, 0, 0, xXmlId, true) ); OSL_ENSURE(xIter.is(), "getStatementRDFa: no result?"); if (!xIter.is()) throw uno::RuntimeException(); while (xIter->hasMoreElements()) { @@ -1581,6 +1673,9 @@ throw (uno::RuntimeException, lang::IllegalArgumentException, ret.push_back(stmt); } } + + ::osl::MutexGuard g(m_aMutex); // don't call i_x* with mutex locked ////// + return beans::Pair< uno::Sequence, sal_Bool >( ret.getAsConstList(), 0 != m_RDFaXHTMLContentSet.count(sXmlId)); } @@ -1621,10 +1716,14 @@ throw (uno::RuntimeException, rdf::RepositoryException) ::boost::shared_ptr()); } - ::osl::MutexGuard g(m_aMutex); + librdf_TypeConverter::Statement const stmt( + m_TypeConverter.extractStatement_NoLock( + i_xSubject, i_xPredicate, i_xObject)); + + ::osl::MutexGuard g(m_aMutex); // don't call i_x* with mutex locked ////// + const boost::shared_ptr pStatement( - m_TypeConverter.mkStatement(m_pWorld.get(), - i_xSubject, i_xPredicate, i_xObject), + m_TypeConverter.mkStatement_Lock(m_pWorld.get(), stmt), safe_librdf_free_statement); OSL_ENSURE(pStatement, "mkStatement failed"); @@ -1658,31 +1757,34 @@ throw (uno::RuntimeException, uno::Exception) ::osl::MutexGuard g(m_aMutex); // m_pWorld.reset(m_TypeConverter.createWorld(), safe_librdf_free_world); - m_pStorage.reset(m_TypeConverter.createStorage(m_pWorld.get()), + m_pStorage.reset(m_TypeConverter.createStorage_Lock(m_pWorld.get()), safe_librdf_free_storage); - m_pModel.reset(m_TypeConverter.createModel( + m_pModel.reset(m_TypeConverter.createModel_Lock( m_pWorld.get(), m_pStorage.get()), safe_librdf_free_model); } -const NamedGraphMap_t::iterator SAL_CALL librdf_Repository::clearGraph( - const uno::Reference< rdf::XURI > & i_xGraphName, bool i_Internal) +const NamedGraphMap_t::iterator librdf_Repository::clearGraph_NoLock( + OUString const& i_rGraphName, bool i_Internal) // throw (uno::RuntimeException, container::NoSuchElementException, // rdf::RepositoryException) { - if (!i_xGraphName.is()) { - throw lang::IllegalArgumentException( - "librdf_Repository::clearGraph: URI is null", *this, 0); - } ::osl::MutexGuard g(m_aMutex); - const OUString contextU( i_xGraphName->getStringValue() ); - const NamedGraphMap_t::iterator iter( m_NamedGraphs.find(contextU) ); + + return clearGraph_Lock(i_rGraphName, i_Internal); +} + +const NamedGraphMap_t::iterator librdf_Repository::clearGraph_Lock( + OUString const& i_rGraphName, bool i_Internal) +{ + // internal: must be called with mutex locked! + const NamedGraphMap_t::iterator iter( m_NamedGraphs.find(i_rGraphName) ); if (!i_Internal && iter == m_NamedGraphs.end()) { throw container::NoSuchElementException( "librdf_Repository::clearGraph: " "no graph with given URI exists", *this); } const OString context( - OUStringToOString(contextU, RTL_TEXTENCODING_UTF8) ); + OUStringToOString(i_rGraphName, RTL_TEXTENCODING_UTF8) ); const boost::shared_ptr pContext( librdf_new_node_from_uri_string(m_pWorld.get(), @@ -1702,7 +1804,7 @@ const NamedGraphMap_t::iterator SAL_CALL librdf_Repository::clearGraph( return iter; } -void librdf_Repository::addStatementGraph( +void librdf_Repository::addStatementGraph_NoLock( const uno::Reference< rdf::XResource > & i_xSubject, const uno::Reference< rdf::XURI > & i_xPredicate, const uno::Reference< rdf::XNode > & i_xObject, @@ -1725,15 +1827,31 @@ void librdf_Repository::addStatementGraph( "librdf_Repository::addStatement: Object is null", *this, 2); } - ::osl::MutexGuard g(m_aMutex); + librdf_TypeConverter::Statement const stmt( + m_TypeConverter.extractStatement_NoLock( + i_xSubject, i_xPredicate, i_xObject)); + const OUString contextU( i_xGraphName->getStringValue() ); - if (!i_Internal && (m_NamedGraphs.find(contextU) == m_NamedGraphs.end())) { + + ::osl::MutexGuard g(m_aMutex); // don't call i_x* with mutex locked ////// + + addStatementGraph_Lock(stmt, contextU, i_Internal); +} + +void librdf_Repository::addStatementGraph_Lock( + librdf_TypeConverter::Statement const& i_rStatement, + OUString const& i_rGraphName, + bool i_Internal) +{ + if (!i_Internal + && (m_NamedGraphs.find(i_rGraphName) == m_NamedGraphs.end())) + { throw container::NoSuchElementException( "librdf_Repository::addStatement: " "no graph with given URI exists", *this); } const OString context( - OUStringToOString(contextU, RTL_TEXTENCODING_UTF8) ); + OUStringToOString(i_rGraphName, RTL_TEXTENCODING_UTF8) ); const boost::shared_ptr pContext( librdf_new_node_from_uri_string(m_pWorld.get(), @@ -1745,8 +1863,7 @@ void librdf_Repository::addStatementGraph( "librdf_new_node_from_uri_string failed", *this); } const boost::shared_ptr pStatement( - m_TypeConverter.mkStatement(m_pWorld.get(), - i_xSubject, i_xPredicate, i_xObject), + m_TypeConverter.mkStatement_Lock(m_pWorld.get(), i_rStatement), safe_librdf_free_statement); OSL_ENSURE(pStatement, "mkStatement failed"); @@ -1770,7 +1887,7 @@ void librdf_Repository::addStatementGraph( } } -void librdf_Repository::removeStatementsGraph( +void librdf_Repository::removeStatementsGraph_NoLock( const uno::Reference< rdf::XResource > & i_xSubject, const uno::Reference< rdf::XURI > & i_xPredicate, const uno::Reference< rdf::XNode > & i_xObject, @@ -1785,8 +1902,13 @@ void librdf_Repository::removeStatementsGraph( return; } - ::osl::MutexGuard g(m_aMutex); + librdf_TypeConverter::Statement const stmt( + m_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 (m_NamedGraphs.find(contextU) == m_NamedGraphs.end()) { throw container::NoSuchElementException( "librdf_Repository::removeStatements: " @@ -1805,8 +1927,7 @@ void librdf_Repository::removeStatementsGraph( "librdf_new_node_from_uri_string failed", *this); } const boost::shared_ptr pStatement( - m_TypeConverter.mkStatement(m_pWorld.get(), - i_xSubject, i_xPredicate, i_xObject), + m_TypeConverter.mkStatement_Lock(m_pWorld.get(), stmt), safe_librdf_free_statement); OSL_ENSURE(pStatement, "mkStatement failed"); @@ -1839,7 +1960,7 @@ void librdf_Repository::removeStatementsGraph( } uno::Reference< container::XEnumeration > -librdf_Repository::getStatementsGraph( +librdf_Repository::getStatementsGraph_NoLock( const uno::Reference< rdf::XResource > & i_xSubject, const uno::Reference< rdf::XURI > & i_xPredicate, const uno::Reference< rdf::XNode > & i_xObject, @@ -1861,8 +1982,13 @@ librdf_Repository::getStatementsGraph( ::boost::shared_ptr()); } - ::osl::MutexGuard g(m_aMutex); + librdf_TypeConverter::Statement const stmt( + m_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: " @@ -1881,8 +2007,7 @@ librdf_Repository::getStatementsGraph( "librdf_new_node_from_uri_string failed", *this); } const boost::shared_ptr pStatement( - m_TypeConverter.mkStatement(m_pWorld.get(), - i_xSubject, i_xPredicate, i_xObject), + m_TypeConverter.mkStatement_Lock(m_pWorld.get(), stmt), safe_librdf_free_statement); OSL_ENSURE(pStatement, "mkStatement failed"); @@ -1911,7 +2036,7 @@ void librdf_raptor_init(void* /*user_data*/, raptor_world* pRaptorWorld) RAPTOR_WORLD_FLAG_LIBXML_GENERIC_ERROR_SAVE, 0); } -librdf_world *librdf_TypeConverter::createWorld() const +librdf_world *librdf_TypeConverter::createWorld_Lock() const { // create and initialize world librdf_world *pWorld( librdf_new_world() ); @@ -1935,7 +2060,7 @@ librdf_world *librdf_TypeConverter::createWorld() const } librdf_storage * -librdf_TypeConverter::createStorage(librdf_world *i_pWorld) const +librdf_TypeConverter::createStorage_Lock(librdf_world *i_pWorld) const { librdf_storage *pStorage( // librdf_new_storage(i_pWorld, "memory", NULL, "contexts='yes'") ); @@ -1949,7 +2074,7 @@ librdf_TypeConverter::createStorage(librdf_world *i_pWorld) const return pStorage; } -librdf_model *librdf_TypeConverter::createModel( +librdf_model *librdf_TypeConverter::createModel_Lock( librdf_world *i_pWorld, librdf_storage * i_pStorage) const { librdf_model *pRepository( librdf_new_model(i_pWorld, i_pStorage, NULL) ); @@ -1977,14 +2102,11 @@ librdf_model *librdf_TypeConverter::createModel( } // this does NOT create a node, only URI -librdf_uri* librdf_TypeConverter::mkURI( librdf_world* i_pWorld, - const uno::Reference< rdf::XURI > & i_xURI) const +librdf_uri* librdf_TypeConverter::mkURI_Lock( librdf_world* i_pWorld, + OString const& i_rURI) const { - const OString uri( - OUStringToOString(i_xURI->getStringValue(), - RTL_TEXTENCODING_UTF8) ); librdf_uri *pURI( librdf_new_uri(i_pWorld, - reinterpret_cast(uri.getStr()))); + reinterpret_cast(i_rURI.getStr()))); if (!pURI) { throw uno::RuntimeException( "librdf_TypeConverter::mkURI: librdf_new_uri failed", 0); @@ -1992,19 +2114,40 @@ librdf_uri* librdf_TypeConverter::mkURI( librdf_world* i_pWorld, return pURI; } -// create blank or URI node -librdf_node* librdf_TypeConverter::mkResource( librdf_world* i_pWorld, +// extract blank or URI node - call without Mutex locked +::boost::shared_ptr +librdf_TypeConverter::extractResource_NoLock( const uno::Reference< rdf::XResource > & i_xResource) const { - if (!i_xResource.is()) return 0; + if (!i_xResource.is()) { + return ::boost::shared_ptr(); + } uno::Reference< rdf::XBlankNode > xBlankNode(i_xResource, uno::UNO_QUERY); if (xBlankNode.is()) { const OString label( OUStringToOString(xBlankNode->getStringValue(), RTL_TEXTENCODING_UTF8) ); + return ::boost::shared_ptr(new BlankNode(label)); + } else { // assumption: everything else is URI + const OString uri( + OUStringToOString(i_xResource->getStringValue(), + RTL_TEXTENCODING_UTF8) ); + return ::boost::shared_ptr(new URI(uri)); + } +} + +// create blank or URI node +librdf_node* librdf_TypeConverter::mkResource_Lock( librdf_world* i_pWorld, + Resource const*const i_pResource) const +{ + if (!i_pResource) return 0; + BlankNode const*const pBlankNode( + dynamic_cast(i_pResource)); + if (pBlankNode) { librdf_node *pNode( librdf_new_node_from_blank_identifier(i_pWorld, - reinterpret_cast (label.getStr()))); + reinterpret_cast( + pBlankNode->value.getStr()))); if (!pNode) { throw uno::RuntimeException( "librdf_TypeConverter::mkResource: " @@ -2012,12 +2155,11 @@ librdf_node* librdf_TypeConverter::mkResource( librdf_world* i_pWorld, } return pNode; } else { // assumption: everything else is URI - const OString uri( - OUStringToOString(i_xResource->getStringValue(), - RTL_TEXTENCODING_UTF8) ); + URI const*const pURI(dynamic_cast(i_pResource)); + assert(pURI); librdf_node *pNode( librdf_new_node_from_uri_string(i_pWorld, - reinterpret_cast (uri.getStr()))); + reinterpret_cast(pURI->value.getStr()))); if (!pNode) { throw uno::RuntimeException( "librdf_TypeConverter::mkResource: " @@ -2027,19 +2169,24 @@ librdf_node* librdf_TypeConverter::mkResource( librdf_world* i_pWorld, } } -// create blank or URI or literal node -librdf_node* librdf_TypeConverter::mkNode( librdf_world* i_pWorld, +// extract blank or URI or literal node - call without Mutex locked +::boost::shared_ptr +librdf_TypeConverter::extractNode_NoLock( const uno::Reference< rdf::XNode > & i_xNode) const { - if (!i_xNode.is()) return 0; + if (!i_xNode.is()) { + return ::boost::shared_ptr(); + } uno::Reference< rdf::XResource > xResource(i_xNode, uno::UNO_QUERY); if (xResource.is()) { - return mkResource(i_pWorld, xResource); + return extractResource_NoLock(xResource); } 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 0; + if (!xLiteral.is()) { + return ::boost::shared_ptr(); + } const OString val( OUStringToOString(xLiteral->getValue(), RTL_TEXTENCODING_UTF8) ); @@ -2047,25 +2194,46 @@ librdf_node* librdf_TypeConverter::mkNode( librdf_world* i_pWorld, OUStringToOString(xLiteral->getLanguage(), RTL_TEXTENCODING_UTF8) ); const uno::Reference< rdf::XURI > xType(xLiteral->getDatatype()); + boost::optional type; + if (xType.is()) + { + type = + OUStringToOString(xType->getStringValue(), RTL_TEXTENCODING_UTF8); + } + return ::boost::shared_ptr(new Literal(val, lang, type)); +} + +// create blank or URI or literal node +librdf_node* librdf_TypeConverter::mkNode_Lock( librdf_world* i_pWorld, + Node const*const i_pNode) const +{ + if (!i_pNode) return 0; + Resource const*const pResource(dynamic_cast(i_pNode)); + if (pResource) { + return mkResource_Lock(i_pWorld, pResource); + } + + Literal const*const pLiteral(dynamic_cast(i_pNode)); + assert(pLiteral); librdf_node * ret(0); - if (lang.isEmpty()) { - if (!xType.is()) { + if (pLiteral->language.isEmpty()) { + if (!pLiteral->type) { ret = librdf_new_node_from_literal(i_pWorld, - reinterpret_cast (val.getStr()), - NULL, 0); + reinterpret_cast(pLiteral->value.getStr()) + , NULL, 0); } else { const boost::shared_ptr pDatatype( - mkURI(i_pWorld, xType), safe_librdf_free_uri); + mkURI_Lock(i_pWorld, *pLiteral->type), + safe_librdf_free_uri); ret = librdf_new_node_from_typed_literal(i_pWorld, - reinterpret_cast (val.getStr()), - NULL, pDatatype.get()); + reinterpret_cast(pLiteral->value.getStr()) + , NULL, pDatatype.get()); } } else { - if (!xType.is()) { + if (!pLiteral->type) { ret = librdf_new_node_from_literal(i_pWorld, - reinterpret_cast (val.getStr()), - (lang.getStr()), 0); - + reinterpret_cast(pLiteral->value.getStr()) + , pLiteral->language.getStr(), 0); } else { OSL_FAIL("mkNode: invalid literal"); return 0; @@ -2078,20 +2246,33 @@ librdf_node* librdf_TypeConverter::mkNode( librdf_world* i_pWorld, return ret; } -librdf_statement* librdf_TypeConverter::mkStatement( librdf_world* i_pWorld, +// extract statement - call without Mutex locked +librdf_TypeConverter::Statement librdf_TypeConverter::extractStatement_NoLock( const uno::Reference< rdf::XResource > & i_xSubject, const uno::Reference< rdf::XURI > & i_xPredicate, const uno::Reference< rdf::XNode > & i_xObject) const { - librdf_node* pSubject( mkResource(i_pWorld, i_xSubject) ); + ::boost::shared_ptr const pSubject( + extractResource_NoLock(i_xSubject)); + const uno::Reference xPredicate(i_xPredicate, + uno::UNO_QUERY); + ::boost::shared_ptr const pPredicate( + ::boost::dynamic_pointer_cast(extractResource_NoLock(xPredicate))); + ::boost::shared_ptr const pObject(extractNode_NoLock(i_xObject)); + return Statement(pSubject, pPredicate, pObject); +} + +librdf_statement* librdf_TypeConverter::mkStatement_Lock(librdf_world* i_pWorld, + Statement const& i_rStatement) const +{ + librdf_node *const pSubject( + mkResource_Lock(i_pWorld, i_rStatement.pSubject.get()) ); librdf_node* pPredicate(0); librdf_node* pObject(0); try { - const uno::Reference xPredicate(i_xPredicate, - uno::UNO_QUERY); - pPredicate = mkResource(i_pWorld, xPredicate); + pPredicate = mkResource_Lock(i_pWorld, i_rStatement.pPredicate.get()); try { - pObject = mkNode(i_pWorld, i_xObject); + pObject = mkNode_Lock(i_pWorld, i_rStatement.pObject.get()); } catch (...) { safe_librdf_free_node(pPredicate); throw; -- cgit v1.2.3