/** * 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 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jena.fuseki.server; import static org.apache.jena.fuseki.server.DatasetStatus.CLOSING ; import static org.apache.jena.fuseki.server.DatasetStatus.UNINITIALIZED ; import java.util.* ; import java.util.concurrent.atomic.AtomicBoolean ; import java.util.concurrent.atomic.AtomicLong ; import org.apache.jena.ext.com.google.common.collect.ArrayListMultimap; import org.apache.jena.ext.com.google.common.collect.ListMultimap; import org.apache.jena.fuseki.DEF ; import org.apache.jena.fuseki.Fuseki ; import org.apache.jena.query.ReadWrite ; import org.apache.jena.sparql.core.DatasetGraph ; import org.apache.jena.sparql.core.DatasetGraphFactory ; import org.apache.jena.sparql.core.DatasetGraphReadOnly ; import org.apache.jena.tdb.StoreConnection ; import org.apache.jena.tdb.transaction.DatasetGraphTransaction ; public class DataService { //implements DatasetMXBean { public static DataService serviceOnlyDataService() { return dummy ; } public static final DataService dummy ; static { DatasetGraph dsg = new DatasetGraphReadOnly(DatasetGraphFactory.create()) ; dummy = new DataService(dsg) ; dummy.addEndpoint(OperationName.Query, DEF.ServiceQuery) ; dummy.addEndpoint(OperationName.Query, DEF.ServiceQueryAlt) ; } private DatasetGraph dataset ; private ListMultimap<OperationName, Endpoint> operations = ArrayListMultimap.create() ; private Map<String, Endpoint> endpoints = new HashMap<>() ; private volatile DatasetStatus state = UNINITIALIZED ; // DataService-level counters. private final CounterSet counters = new CounterSet() ; private final AtomicLong requestCounter = new AtomicLong(0) ; private final AtomicBoolean offlineInProgress = new AtomicBoolean(false) ; private final AtomicBoolean acceptingRequests = new AtomicBoolean(true) ; /** Create a {@code DataService} for the given dataset. */ public DataService(DatasetGraph dataset) { this.dataset = dataset ; counters.add(CounterName.Requests) ; counters.add(CounterName.RequestsGood) ; counters.add(CounterName.RequestsBad) ; } /** * Create a {@code DataService} that has the same dataset, same operations and * endpoints as another {@code DataService}. Counters are not copied. */ public DataService(DataService other) { // Copy non-counter state of 'other'. this.dataset = other.dataset ; this.operations = ArrayListMultimap.create(other.operations) ; this.endpoints = new HashMap<>(other.endpoints) ; } public DatasetGraph getDataset() { return dataset ; } public void addEndpoint(OperationName operationName, String endpointName) { Endpoint endpoint = new Endpoint(operationName, endpointName) ; endpoints.put(endpointName, endpoint) ; operations.put(operationName, endpoint); } public Endpoint getOperation(String endpointName) { return endpoints.get(endpointName) ; } public List<Endpoint> getOperation(OperationName opName) { List<Endpoint> x = operations.get(opName) ; if ( x == null ) x = Collections.emptyList() ; return x ; } /** Return the OperationNames available here. * @see #getOperation(OperationName) to get the endpoint list */ public Collection<OperationName> getOperations() { return operations.keySet() ; } //@Override public boolean allowUpdate() { return true ; } public void goOffline() { offlineInProgress.set(true) ; acceptingRequests.set(false) ; state = DatasetStatus.OFFLINE ; } public void goActive() { offlineInProgress.set(false) ; acceptingRequests.set(true) ; state = DatasetStatus.ACTIVE ; } public boolean isAcceptingRequests() { return acceptingRequests.get() ; } //@Override public CounterSet getCounters() { return counters ; } //@Override public long getRequests() { return counters.value(CounterName.Requests) ; } //@Override public long getRequestsGood() { return counters.value(CounterName.RequestsGood) ; } //@Override public long getRequestsBad() { return counters.value(CounterName.RequestsBad) ; } /** Counter of active read transactions */ public AtomicLong activeReadTxn = new AtomicLong(0) ; /** Counter of active write transactions */ public AtomicLong activeWriteTxn = new AtomicLong(0) ; /** Cumulative counter of read transactions */ public AtomicLong totalReadTxn = new AtomicLong(0) ; /** Cumulative counter of writer transactions */ public AtomicLong totalWriteTxn = new AtomicLong(0) ; public void startTxn(ReadWrite mode) { switch(mode) { case READ: activeReadTxn.getAndIncrement() ; totalReadTxn.getAndIncrement() ; break ; case WRITE: activeWriteTxn.getAndIncrement() ; totalWriteTxn.getAndIncrement() ; break ; } } public void finishTxn(ReadWrite mode) { switch(mode) { case READ: activeReadTxn.decrementAndGet() ; break ; case WRITE: activeWriteTxn.decrementAndGet() ; break ; } checkShutdown() ; } private void checkShutdown() { if ( state == CLOSING ) { if ( activeReadTxn.get() == 0 && activeWriteTxn.get() == 0 ) shutdown() ; } } private void shutdown() { Fuseki.serverLog.info("Shutting down dataset") ; dataset.close() ; if ( dataset instanceof DatasetGraphTransaction ) { DatasetGraphTransaction dsgtxn = (DatasetGraphTransaction)dataset ; StoreConnection.release(dsgtxn.getLocation()) ; } dataset = null ; } }