/** Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved. Contact: SYSTAP, LLC DBA Blazegraph 2501 Calvert ST NW #106 Washington, DC 20008 licenses@blazegraph.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * Created on June 08, 2016 */ package com.bigdata.rdf.sail.webapp; import java.util.Properties; import org.openrdf.model.Statement; import org.openrdf.model.impl.LiteralImpl; import org.openrdf.model.impl.StatementImpl; import org.openrdf.model.impl.URIImpl; import org.openrdf.query.QueryLanguage; import org.openrdf.query.TupleQuery; import org.openrdf.query.TupleQueryResult; import org.openrdf.query.Update; import com.bigdata.journal.BufferMode; import com.bigdata.rdf.axioms.NoAxioms; import com.bigdata.rdf.internal.impl.extensions.GeoSpatialLiteralExtension; import com.bigdata.rdf.sail.BigdataSail; import com.bigdata.rdf.sail.BigdataSailRepository; import com.bigdata.rdf.sail.BigdataSailRepositoryConnection; import com.bigdata.rdf.sail.ProxyBigdataSailTestCase; import com.bigdata.rdf.store.AbstractTripleStore; /** * Test case for ticket BLZG-1943: thread safety issues related to reuse of * {@link GeoSpatialLiteralExtension}'s internal key builder. * * @author <a href="mailto:ms@metaphacts.com">Michael Schmidt</a> * @version $Id$ */ public class TestBLZG1943 extends ProxyBigdataSailTestCase { /** * */ public TestBLZG1943() { } /** * @param name */ public TestBLZG1943(String name) { super(name); } public void testTicketBlzg1943() throws Exception { final BigdataSail sail = getSail(); final BigdataSailRepository repo = new BigdataSailRepository(sail); try { repo.initialize(); BigdataSailRepositoryConnection conn = repo.getConnection(); // init repository conn.setAutoCommit(false); for (int i=0; i<500; i++) { final Statement s1 = new StatementImpl(new URIImpl("http://s" + i), new URIImpl("http://lat"), new LiteralImpl("10.24884")); final Statement s2 = new StatementImpl(new URIImpl("http://s" + i), new URIImpl("http://lon"), new LiteralImpl("73.24884")); conn.add(s1); conn.add(s2); } conn.commit(); // validate data has been loaded final TupleQuery validate = conn.prepareTupleQuery(QueryLanguage.SPARQL, "SELECT * WHERE { ?s ?p ?o }"); final TupleQueryResult res = validate.evaluate(); int numTriples = 0; while (res.hasNext()) { res.next(); numTriples++; } assertEquals(numTriples, 1000); res.close(); conn.close(); // submit update query inducing geospatial literal construction conn = repo.getConnection(); for (int i=0; i<100; i++) { // repeat a couple of times to increase the chance for thread collisions // send update final StringBuilder sb = new StringBuilder(); sb.append("PREFIX ogc: <http://www.opengis.net/ont/geosparql#> "); sb.append("insert { ?s ogc:asWKT ?wkt } where { " + " ?s <http://lat> ?lat. ?s <http://lon> ?long. " + " bind(strdt(concat(\"POINT(\",str(?long),\" \",str(?lat),\")\"),ogc:wktLiteral) as ?wkt) }"); final Update update = conn.prepareUpdate(QueryLanguage.SPARQL, sb.toString()); update.execute(); } conn.close(); } catch (Exception e) { System.err.println("EXCEPTION: " + e.getMessage()); throw(e); } finally { repo.shutDown(); } } @Override public Properties getProperties() { // Note: clone to avoid modifying!!! final Properties properties = (Properties) super.getProperties().clone(); // turn on quads. properties.setProperty(AbstractTripleStore.Options.QUADS, "false"); // TM not available with quads. properties.setProperty(BigdataSail.Options.TRUTH_MAINTENANCE,"false"); // turn off axioms. properties.setProperty(AbstractTripleStore.Options.AXIOMS_CLASS, NoAxioms.class.getName()); // no persistence. properties.setProperty(com.bigdata.journal.Options.BUFFER_MODE, BufferMode.Transient.toString()); // enable GeoSpatial index properties.setProperty( com.bigdata.rdf.store.AbstractLocalTripleStore.Options.GEO_SPATIAL, "true"); properties.setProperty( com.bigdata.rdf.store.AbstractLocalTripleStore.Options.GEO_SPATIAL_INCLUDE_BUILTIN_DATATYPES, "false"); // set GeoSpatial configuration: use a higher precision and range shifts; // the test accounts for this higher precision (and assert that range shifts // actually do not harm the evaluation process) properties.setProperty( com.bigdata.rdf.store.AbstractLocalTripleStore.Options.GEO_SPATIAL_DATATYPE_CONFIG + ".0", "{\"config\": " + "{ \"uri\": \"http://www.opengis.net/ont/geosparql#wktLiteral\", " + "\"literalSerializer\": \"com.bigdata.rdf.sparql.ast.eval.service.BLZG1943LiteralSerializer\", " + "\"fields\": [ " + "{ \"valueType\": \"DOUBLE\", \"multiplier\": \"1000000\", \"serviceMapping\": \"LONGITUDE\" }, " + "{ \"valueType\": \"DOUBLE\", \"multiplier\": \"1000000\", \"serviceMapping\": \"LATITUDE\" } " + "]}}"); // make our dummy WKT datatype default to ease querying properties.setProperty( com.bigdata.rdf.store.AbstractLocalTripleStore.Options.GEO_SPATIAL_DEFAULT_DATATYPE, "http://www.opengis.net/ont/geosparql#wktLiteral"); properties.setProperty( com.bigdata.rdf.store.AbstractLocalTripleStore.Options.VOCABULARY_CLASS, "com.bigdata.rdf.sparql.ast.eval.service.GeoSpatialTestVocabulary"); return properties; } }