use of org.exist.EXistException in project exist by eXist-db.
the class BackupSystemTask method configure.
@Override
public void configure(final Configuration config, final Properties properties) throws EXistException {
user = properties.getProperty("user", "guest");
password = properties.getProperty("password", "guest");
String collName = properties.getProperty("collection", "xmldb:exist:///db");
if (!collName.startsWith("xmldb:exist:")) {
collName = "xmldb:exist://" + collName;
}
collection = XmldbURI.create(collName);
LOG.debug("Collection to backup: {}. User: {}", collection.toString(), user);
deduplicateBlobs = Boolean.parseBoolean(properties.getProperty("deduplucate-blobs", "false"));
suffix = properties.getProperty("suffix", "");
prefix = properties.getProperty("prefix", "");
final String dir = properties.getProperty("dir", "backup");
directory = Paths.get(dir);
if (!directory.isAbsolute()) {
directory = ((Path) config.getProperty(BrokerPool.PROPERTY_DATA_DIR)).resolve(dir);
}
try {
Files.createDirectories(directory);
} catch (final IOException ioe) {
throw new EXistException("Unable to create backup directory: " + directory.toAbsolutePath().toString(), ioe);
}
// check for max zip files
final String filesMaxStr = properties.getProperty("zip-files-max");
if (LOG.isDebugEnabled()) {
LOG.debug("zip-files-max: {}", filesMaxStr);
}
if (null != filesMaxStr) {
try {
zipFilesMax = Integer.parseInt(filesMaxStr);
} catch (final NumberFormatException e) {
LOG.error("zip-files-max property error", e);
}
}
}
use of org.exist.EXistException in project exist by eXist-db.
the class BackupSystemTask method execute.
@Override
public void execute(final DBBroker broker, final Txn transaction) throws EXistException {
// see if old zip files need to be purged
if (zipFilesMax > 0) {
try {
purgeZipFiles();
} catch (final IOException ioe) {
throw new EXistException("Unable to purge zip files", ioe);
}
}
final String dateTime = creationDateFormat.format(Calendar.getInstance().getTime());
final Path dest = directory.resolve(prefix + dateTime + suffix);
final Backup backup = new Backup(user, password, dest, collection, null, deduplicateBlobs);
try {
backup.backup(false, null);
} catch (final XMLDBException | SAXException | IOException e) {
LOG.error(e.getMessage(), e);
throw new EXistException(e.getMessage(), e);
}
}
use of org.exist.EXistException in project exist by eXist-db.
the class BrokerPool method shutdown.
void shutdown(final boolean killed, final Consumer<String> shutdownInstanceConsumer) {
try {
status.process(Event.START_SHUTDOWN_MULTI_USER_MODE);
} catch (final IllegalStateException e) {
// we are not operational!
LOG.warn(e);
return;
}
// notify any BrokerPoolServices that we are about to shutdown
try {
// instruct database services that we are about to stop multi-user mode
servicesManager.stopMultiUserServices(this);
} catch (final BrokerPoolServicesManagerException e) {
for (final BrokerPoolServiceException bpse : e.getServiceExceptions()) {
LOG.error(bpse.getMessage(), bpse);
}
}
try {
status.process(Event.START_SHUTDOWN_SYSTEM_MODE);
} catch (final IllegalStateException e) {
// we are not in SHUTTING_DOWN_MULTI_USER_MODE!
LOG.warn(e);
return;
}
try {
LOG.info("Database is shutting down ...");
processMonitor.stopRunningJobs();
// Shutdown the scheduler
scheduler.shutdown(true);
try {
statusReporter = new StatusReporter(SIGNAL_SHUTDOWN);
statusObservers.forEach(statusReporter::addObserver);
synchronized (this) {
final Thread statusThread = newInstanceThread(this, "shutdown-status-reporter", statusReporter);
statusThread.start();
// DW: only in debug mode
if (LOG.isDebugEnabled()) {
notificationService.debug();
}
// Notify all running tasks that we are shutting down
// Notify all running XQueries that we are shutting down
processMonitor.killAll(500);
if (isRecoveryEnabled()) {
journalManager.ifPresent(jm -> jm.flush(true, true));
}
final long waitStart = System.currentTimeMillis();
// Are there active brokers ?
if (activeBrokers.size() > 0) {
printSystemInfo();
LOG.info("Waiting {}ms for remaining threads to shut down...", maxShutdownWait);
while (activeBrokers.size() > 0) {
try {
// Wait until they become inactive...
this.wait(1000);
} catch (final InterruptedException e) {
// nothing to be done
}
// ...or force the shutdown
if (maxShutdownWait > -1 && System.currentTimeMillis() - waitStart > maxShutdownWait) {
LOG.warn("Not all threads returned. Forcing shutdown ...");
break;
}
}
}
LOG.debug("Calling shutdown ...");
// TODO : replace the following code by get()/release() statements ?
// WM: deadlock risk if not all brokers returned properly.
DBBroker broker = null;
if (inactiveBrokers.isEmpty())
try {
broker = createBroker();
} catch (final EXistException e) {
LOG.warn("could not create instance for shutdown. Giving up.");
}
else // TODO : this broker is *not* marked as active and may be reused by another process !
// TODO : use get() then release the broker ?
// WM: deadlock risk if not all brokers returned properly.
// TODO: always createBroker? -dmitriy
{
broker = inactiveBrokers.peek();
}
try {
if (broker != null) {
broker.prepare();
broker.pushSubject(securityManager.getSystemSubject());
}
try {
// instruct all database services to stop
servicesManager.stopSystemServices(broker);
} catch (final BrokerPoolServicesManagerException e) {
for (final BrokerPoolServiceException bpse : e.getServiceExceptions()) {
LOG.error(bpse.getMessage(), bpse);
}
}
// TOUNDERSTAND (pb) : shutdown() is called on only *one* broker ?
// WM: yes, the database files are shared, so only one broker is needed to close them for all
broker.shutdown();
} finally {
if (broker != null) {
broker.popSubject();
}
}
collectionCache.invalidateAll();
// final notification to database services to shutdown
servicesManager.shutdown();
// remove all remaining inactive brokers as we have shutdown now and no longer need those
inactiveBrokers.clear();
// deregister JMX MBeans
AgentFactory.getInstance().closeDBInstance(this);
// Clear the living instances container
shutdownInstanceConsumer.accept(instanceName);
synchronized (readOnly) {
if (!readOnly) {
// release the lock on the data directory
dataLock.release();
}
}
// clearing additional resources, like ThreadLocal
clearThreadLocals();
LOG.info("shutdown complete !");
if (shutdownListener != null) {
shutdownListener.shutdown(instanceName, instancesCount());
}
}
} finally {
// clear instance variables, just to be sure they will be garbage collected
// the test suite restarts the db a few hundred times
Configurator.clear(this);
transactionManager = null;
collectionCache = null;
xQueryPool = null;
processMonitor = null;
collectionConfigurationManager = null;
notificationService = null;
indexManager = null;
xmlReaderPool = null;
shutdownListener = null;
securityManager = null;
if (lockManager != null) {
lockManager.getLockTable().shutdown();
lockManager = null;
}
notificationService = null;
statusObservers.clear();
startupTriggersManager = null;
statusReporter.terminate();
statusReporter = null;
// instanceThreadGroup.destroy();
}
} finally {
status.process(Event.FINISHED_SHUTDOWN);
}
}
use of org.exist.EXistException in project exist by eXist-db.
the class BrokerPool method _initialize.
private void _initialize() throws EXistException, DatabaseConfigurationException {
this.lockManager = new LockManager(conf, concurrencyLevel);
// Flag to indicate that we are initializing
status.process(Event.INITIALIZE);
if (LOG.isDebugEnabled()) {
LOG.debug("initializing database instance '{}'...", instanceName);
}
// register core broker pool services
this.scheduler = servicesManager.register(new QuartzSchedulerImpl(this));
// NOTE: this must occur after the scheduler, and before any other service which requires access to the data directory
this.dataLock = servicesManager.register(new FileLockService("dbx_dir.lck", BrokerPool.PROPERTY_DATA_DIR, NativeBroker.DEFAULT_DATA_DIR));
this.securityManager = servicesManager.register(new SecurityManagerImpl(this));
this.cacheManager = servicesManager.register(new DefaultCacheManager(this));
this.xQueryPool = servicesManager.register(new XQueryPool());
this.processMonitor = servicesManager.register(new ProcessMonitor());
this.xqueryStats = servicesManager.register(new PerformanceStats(this));
final XMLReaderObjectFactory xmlReaderObjectFactory = servicesManager.register(new XMLReaderObjectFactory());
this.xmlReaderPool = servicesManager.register(new XMLReaderPool(xmlReaderObjectFactory, maxBrokers, 0));
final int bufferSize = Optional.of(conf.getInteger(PROPERTY_COLLECTION_CACHE_SIZE)).filter(size -> size != -1).orElse(DEFAULT_COLLECTION_BUFFER_SIZE);
this.collectionCache = servicesManager.register(new CollectionCache());
this.notificationService = servicesManager.register(new NotificationService());
this.journalManager = recoveryEnabled ? Optional.of(new JournalManager()) : Optional.empty();
journalManager.ifPresent(servicesManager::register);
final SystemTaskManager systemTaskManager = servicesManager.register(new SystemTaskManager(this));
this.transactionManager = servicesManager.register(new TransactionManager(this, journalManager, systemTaskManager));
this.blobStoreService = servicesManager.register(new BlobStoreImplService());
this.symbols = servicesManager.register(new SymbolTable());
this.expathRepo = Optional.ofNullable(new ExistRepository());
expathRepo.ifPresent(servicesManager::register);
servicesManager.register(new ClasspathHelper());
this.indexManager = servicesManager.register(new IndexManager(this));
// prepare those services that require system (single-user) mode
this.pluginManager = servicesManager.register(new PluginsManagerImpl());
// Get a manager to handle further collections configuration
this.collectionConfigurationManager = servicesManager.register(new CollectionConfigurationManager(this));
this.startupTriggersManager = servicesManager.register(new StartupTriggersManager());
// this is just used for unit tests
final BrokerPoolService testBrokerPoolService = (BrokerPoolService) conf.getProperty("exist.testBrokerPoolService");
if (testBrokerPoolService != null) {
servicesManager.register(testBrokerPoolService);
}
// configure the registered services
try {
servicesManager.configureServices(conf);
} catch (final BrokerPoolServiceException e) {
throw new EXistException(e);
}
// calculate how much memory is reserved for caches to grow
final Runtime rt = Runtime.getRuntime();
final long maxMem = rt.maxMemory();
final long minFree = maxMem / 5;
reservedMem = cacheManager.getTotalMem() + collectionCache.getMaxCacheSize() + minFree;
LOG.debug("Reserved memory: {}; max: {}; min: {}", reservedMem, maxMem, minFree);
// prepare the registered services, before entering system (single-user) mode
try {
servicesManager.prepareServices(this);
} catch (final BrokerPoolServiceException e) {
throw new EXistException(e);
}
// setup database synchronization job
if (majorSyncPeriod > 0) {
final SyncTask syncTask = new SyncTask();
syncTask.configure(conf, null);
scheduler.createPeriodicJob(2500, new SystemTaskJobImpl(SyncTask.getJobName(), syncTask), 2500);
}
try {
statusReporter = new StatusReporter(SIGNAL_STARTUP);
statusObservers.forEach(statusReporter::addObserver);
final Thread statusThread = newInstanceThread(this, "startup-status-reporter", statusReporter);
statusThread.start();
// statusReporter may have to be terminated or the thread can/will hang.
try {
final boolean exportOnly = conf.getProperty(PROPERTY_EXPORT_ONLY, false);
// or the FileSyncThread for the journal can/will hang.
try {
// Enter System Mode
try (final DBBroker systemBroker = get(Optional.of(securityManager.getSystemSubject()))) {
status.process(Event.INITIALIZE_SYSTEM_MODE);
if (isReadOnly()) {
journalManager.ifPresent(JournalManager::disableJournalling);
}
try (final Txn transaction = transactionManager.beginTransaction()) {
servicesManager.startPreSystemServices(systemBroker, transaction);
transaction.commit();
} catch (final BrokerPoolServiceException e) {
throw new EXistException(e);
}
// Run the recovery process
boolean recovered = false;
if (isRecoveryEnabled()) {
recovered = runRecovery(systemBroker);
// TODO : extract the following from this block ? What if we are not transactional ? -pb
if (!recovered) {
try {
if (systemBroker.getCollection(XmldbURI.ROOT_COLLECTION_URI) == null) {
final Txn txn = transactionManager.beginTransaction();
try {
systemBroker.getOrCreateCollection(txn, XmldbURI.ROOT_COLLECTION_URI);
transactionManager.commit(txn);
} catch (final IOException | TriggerException | PermissionDeniedException e) {
transactionManager.abort(txn);
} finally {
transactionManager.close(txn);
}
}
} catch (final PermissionDeniedException pde) {
LOG.fatal(pde.getMessage(), pde);
}
}
}
/* initialise required collections if they don't exist yet */
if (!exportOnly) {
try {
initialiseSystemCollections(systemBroker);
} catch (final PermissionDeniedException pde) {
LOG.error(pde.getMessage(), pde);
throw new EXistException(pde.getMessage(), pde);
}
}
statusReporter.setStatus(SIGNAL_READINESS);
try (final Txn transaction = transactionManager.beginTransaction()) {
servicesManager.startSystemServices(systemBroker, transaction);
transaction.commit();
} catch (final BrokerPoolServiceException e) {
throw new EXistException(e);
}
// TODO : merge this with the recovery process ?
if (isRecoveryEnabled() && recovered) {
if (!exportOnly) {
reportStatus("Reindexing database files...");
try {
systemBroker.repair();
} catch (final PermissionDeniedException e) {
LOG.warn("Error during recovery: {}", e.getMessage(), e);
}
}
if ((Boolean) conf.getProperty(PROPERTY_RECOVERY_CHECK)) {
final ConsistencyCheckTask task = new ConsistencyCheckTask();
final Properties props = new Properties();
props.setProperty("backup", "no");
props.setProperty("output", "sanity");
task.configure(conf, props);
try (final Txn transaction = transactionManager.beginTransaction()) {
task.execute(systemBroker, transaction);
transaction.commit();
}
}
}
// OK : the DB is repaired; let's make a few RW operations
statusReporter.setStatus(SIGNAL_WRITABLE);
// initialize configurations watcher trigger
if (!exportOnly) {
try {
initialiseTriggersForCollections(systemBroker, XmldbURI.SYSTEM_COLLECTION_URI);
} catch (final PermissionDeniedException pde) {
// XXX: do not catch exception!
LOG.error(pde.getMessage(), pde);
}
}
// remove temporary docs
try {
systemBroker.cleanUpTempResources(true);
} catch (final PermissionDeniedException pde) {
LOG.error(pde.getMessage(), pde);
}
sync(systemBroker, Sync.MAJOR);
// system mode before entering multi-user mode
try (final Txn transaction = transactionManager.beginTransaction()) {
servicesManager.startPreMultiUserSystemServices(systemBroker, transaction);
transaction.commit();
} catch (final BrokerPoolServiceException e) {
throw new EXistException(e);
}
}
// Create the minimal number of brokers required by the configuration
for (int i = 1; i < minBrokers; i++) {
createBroker();
}
status.process(Event.INITIALIZE_MULTI_USER_MODE);
// register some MBeans to provide access to this instance
AgentFactory.getInstance().initDBInstance(this);
if (LOG.isDebugEnabled()) {
LOG.debug("database instance '{}' initialized", instanceName);
}
servicesManager.startMultiUserServices(this);
status.process(Event.READY);
statusReporter.setStatus(SIGNAL_STARTED);
} catch (final Throwable t) {
transactionManager.shutdown();
throw t;
}
} catch (final EXistException e) {
throw e;
} catch (final Throwable t) {
throw new EXistException(t.getMessage(), t);
}
} finally {
if (statusReporter != null) {
statusReporter.terminate();
statusReporter = null;
}
}
}
use of org.exist.EXistException in project exist by eXist-db.
the class NativeBroker method storeTempResource.
/**
* Store into the temporary collection of the database a given in-memory Document
*
* The in-memory Document is stored without a transaction and is not journalled,
* if there is no temporary collection, this will first be created with a transaction
*
* @param doc The in-memory Document to store
* @return The document stored in the temp collection
*/
@Override
public DocumentImpl storeTempResource(final org.exist.dom.memtree.DocumentImpl doc) throws EXistException, PermissionDeniedException, LockException {
try {
// elevate getUser() to DBA_USER
pushSubject(pool.getSecurityManager().getSystemSubject());
// start a transaction
final TransactionManager transact = pool.getTransactionManager();
// create a name for the temporary document
final XmldbURI docName = XmldbURI.create(MessageDigester.md5(Thread.currentThread().getName() + System.currentTimeMillis(), false) + ".xml");
// get the temp collection
try (final Txn transaction = transact.beginTransaction();
final ManagedCollectionLock tempCollectionLock = lockManager.acquireCollectionWriteLock(XmldbURI.TEMP_COLLECTION_URI)) {
// if temp collection does not exist, creates temp collection (with write lock in Txn)
final Tuple2<Boolean, Collection> createdOrExistingTemp = getOrCreateTempCollection(transaction);
if (createdOrExistingTemp == null) {
LOG.error("Failed to create temporary collection");
transact.abort(transaction);
return null;
}
final Collection temp = createdOrExistingTemp._2;
// create a temporary document
try (final ManagedDocumentLock docLock = lockManager.acquireDocumentWriteLock(temp.getURI().append(docName))) {
final int tmpDocId = getNextResourceId(transaction);
final Permission permission = PermissionFactory.getDefaultResourcePermission(getBrokerPool().getSecurityManager());
permission.setMode(Permission.DEFAULT_TEMPORARY_DOCUMENT_PERM);
final DocumentImpl targetDoc = new DocumentImpl(pool, temp, tmpDocId, docName, permission, 0, null, System.currentTimeMillis(), null, null, null);
// index the temporary document
final DOMIndexer indexer = new DOMIndexer(this, transaction, doc, targetDoc);
indexer.scan();
indexer.store();
// store the temporary document
temp.addDocument(transaction, this, targetDoc);
storeXMLResource(transaction, targetDoc);
saveCollection(transaction, temp);
// NOTE: early release of Collection lock inline with Asymmetrical Locking scheme
temp.close();
flush();
closeDocument();
// commit the transaction
transact.commit(transaction);
return targetDoc;
}
} catch (final Exception e) {
LOG.error("Failed to store temporary fragment: {}", e.getMessage(), e);
}
} finally {
// restore the user
popSubject();
}
return null;
}
Aggregations