Search in sources :

Example 16 with Txn

use of org.exist.storage.txn.Txn in project exist by eXist-db.

the class BlobStoreImpl method add.

@Override
public Tuple2<BlobId, Long> add(final Txn transaction, final InputStream is) throws IOException {
    if (state.get() != State.OPEN) {
        throw new IOException("Blob Store is not open!");
    }
    // stage the BLOB file
    final Tuple3<Path, Long, MessageDigest> staged = stage(is);
    final BlobVacuum.RequestDeleteStagedBlobFile requestDeleteStagedBlobFile = new BlobVacuum.RequestDeleteStagedBlobFile(stagingDir, staged._1.getFileName().toString());
    // register a callback to cleanup the staged BLOB file ONLY after commit+checkpoint
    final JournalManager journalManager = database.getJournalManager().orElse(null);
    if (journalManager != null) {
        final DeleteStagedBlobFile cleanupStagedBlob = new DeleteStagedBlobFile(vacuumQueue, requestDeleteStagedBlobFile);
        journalManager.listen(cleanupStagedBlob);
        transaction.registerListener(cleanupStagedBlob);
    }
    final BlobId blobId = new BlobId(staged._3.getValue());
    // if the blob entry does not exist, we exclusively compute it as STAGED.
    BlobReference blobReference = references.computeIfAbsent(blobId, k -> new BlobReference(STAGED));
    try {
        while (true) {
            if (blobReference.count.compareAndSet(STAGED, PROMOTING)) {
                // write journal entries to the WAL
                if (journalManager != null) {
                    try {
                        journalManager.journal(new StoreBlobFileLoggable(transaction.getId(), blobId, staged._1.getFileName().toString()));
                        journalManager.journal(new UpdateBlobRefCountLoggable(transaction.getId(), blobId, 0, 1));
                        // force WAL entries to disk!
                        journalManager.flush(true, true);
                    } catch (final JournalException e) {
                        references.remove(blobId);
                        throw new IOException(e);
                    }
                }
                // promote the staged blob
                promote(staged);
                if (journalManager == null) {
                    // no journal (or recovery)... so go ahead and schedule cleanup of the staged blob file
                    enqueueVacuum(vacuumQueue, requestDeleteStagedBlobFile);
                }
                // schedule disk persist of the new value
                persistQueue.put(Tuple(blobId, blobReference, 1));
                // update memory with the new value
                blobReference.count.set(1);
                // done!
                return Tuple(blobId, staged._2);
            }
            final int count = blobReference.count.get();
            // guard against a concurrent #add or #remove
            if (count == PROMOTING || count == UPDATING_COUNT) {
                // spin whilst another thread promotes the blob, or updates the reference count
                // sleep a small time to save CPU
                Thread.sleep(10);
                continue;
            }
            // i.e. wait for the deletion of the blob to complete, and then we can add the blob again
            if (count == DELETING) {
                blobReference = references.computeIfAbsent(blobId, k -> new BlobReference(STAGED));
                // loop again
                continue;
            }
            // only increment the blob reference if the blob is active!
            if (count >= 0 && blobReference.count.compareAndSet(count, UPDATING_COUNT)) {
                // NOTE: we are the only thread that can be in this branch for the blobId
                final int newCount = count + 1;
                // write journal entries to the WAL
                if (journalManager != null) {
                    try {
                        journalManager.journal(new UpdateBlobRefCountLoggable(transaction.getId(), blobId, count, newCount));
                        // force WAL entries to disk!
                        journalManager.flush(true, true);
                    } catch (final JournalException e) {
                        // restore the state of the blobReference first!
                        blobReference.count.set(count);
                        throw new IOException(e);
                    }
                }
                // persist the new value
                persistQueue.put(Tuple(blobId, blobReference, newCount));
                // update memory with the new value, and release other spinning threads
                blobReference.count.set(newCount);
                // done!
                return Tuple(blobId, staged._2);
            }
        }
    } catch (final InterruptedException e) {
        // thrown by persistQueue.put or Thread.sleep
        Thread.currentThread().interrupt();
        throw new IOException(e);
    }
}
Also used : Path(java.nio.file.Path) Tuple3(com.evolvedbinary.j8fu.tuple.Tuple3) Tuple2(com.evolvedbinary.j8fu.tuple.Tuple2) Txn(org.exist.storage.txn.Txn) JournalException(org.exist.storage.journal.JournalException) RawDataBackup(org.exist.backup.RawDataBackup) ByteBuffer(java.nio.ByteBuffer) FileUtils(org.exist.util.FileUtils) Tuple(com.evolvedbinary.j8fu.tuple.Tuple.Tuple) ThreadUtils.nameInstanceThread(org.exist.util.ThreadUtils.nameInstanceThread) DigestInputStream(org.exist.util.crypto.digest.DigestInputStream) StreamableDigest(org.exist.util.crypto.digest.StreamableDigest) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) DigestType(org.exist.util.crypto.digest.DigestType) LOG_UPDATE_BLOB_REF_COUNT(org.exist.storage.blob.BlobLoggable.LOG_UPDATE_BLOB_REF_COUNT) Path(java.nio.file.Path) java.util.concurrent(java.util.concurrent) StandardOpenOption(java.nio.file.StandardOpenOption) FileNotFoundException(java.io.FileNotFoundException) SeekableByteChannel(java.nio.channels.SeekableByteChannel) Logger(org.apache.logging.log4j.Logger) TxnListener(org.exist.storage.txn.TxnListener) LogEntryTypes(org.exist.storage.journal.LogEntryTypes) java.util(java.util) Try(com.evolvedbinary.j8fu.Try) ThreadSafe(net.jcip.annotations.ThreadSafe) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) AtomicReference(java.util.concurrent.atomic.AtomicReference) Function(java.util.function.Function) FilterInputStream(java.io.FilterInputStream) LOG_STORE_BLOB_FILE(org.exist.storage.blob.BlobLoggable.LOG_STORE_BLOB_FILE) ThreadUtils.newInstanceSubThreadGroup(org.exist.util.ThreadUtils.newInstanceSubThreadGroup) LogException(org.exist.storage.journal.LogException) REPLACE_EXISTING(java.nio.file.StandardCopyOption.REPLACE_EXISTING) Nullable(javax.annotation.Nullable) OutputStream(java.io.OutputStream) Database(org.exist.Database) ATOMIC_MOVE(java.nio.file.StandardCopyOption.ATOMIC_MOVE) CountingInputStream(org.apache.commons.io.input.CountingInputStream) Files(java.nio.file.Files) HexEncoder.bytesToHex(org.exist.util.HexEncoder.bytesToHex) JournalManager(org.exist.storage.journal.JournalManager) IOException(java.io.IOException) BlobReference(org.exist.storage.blob.BlobStoreImpl.BlobReference) UUIDGenerator(org.exist.util.UUIDGenerator) MessageDigest(org.exist.util.crypto.digest.MessageDigest) FileUtils.fileName(org.exist.util.FileUtils.fileName) TaggedTryUnchecked(com.evolvedbinary.j8fu.Try.TaggedTryUnchecked) LogManager(org.apache.logging.log4j.LogManager) InputStream(java.io.InputStream) BlobReference(org.exist.storage.blob.BlobStoreImpl.BlobReference) JournalException(org.exist.storage.journal.JournalException) JournalManager(org.exist.storage.journal.JournalManager) IOException(java.io.IOException) MessageDigest(org.exist.util.crypto.digest.MessageDigest)

Example 17 with Txn

use of org.exist.storage.txn.Txn in project exist by eXist-db.

the class BinaryDoc method eval.

@Override
public Sequence eval(final Sequence[] args, final Sequence contextSequence) throws XPathException {
    final Sequence emptyParamReturnValue = (isCalledAs(FS_BINARY_DOC_NAME) || isCalledAs(FS_BINARY_DOC_CONTENT_DIGEST_NAME)) ? Sequence.EMPTY_SEQUENCE : BooleanValue.FALSE;
    if (args[0].isEmpty()) {
        return emptyParamReturnValue;
    }
    final String path = args[0].getStringValue();
    try (final LockedDocument lockedDoc = context.getBroker().getXMLResource(XmldbURI.xmldbUriFor(path), LockMode.READ_LOCK)) {
        if (lockedDoc == null) {
            return emptyParamReturnValue;
        }
        final DocumentImpl doc = lockedDoc.getDocument();
        if (doc.getResourceType() != DocumentImpl.BINARY_FILE) {
            return emptyParamReturnValue;
        } else if (isCalledAs(FS_BINARY_DOC_NAME)) {
            try (final Txn transaction = context.getBroker().continueOrBeginTransaction()) {
                final BinaryDocument bin = (BinaryDocument) doc;
                final InputStream is = context.getBroker().getBinaryResource(transaction, bin);
                final Base64BinaryDocument b64doc = Base64BinaryDocument.getInstance(context, is);
                b64doc.setUrl(path);
                transaction.commit();
                return b64doc;
            }
        } else if (isCalledAs(FS_BINARY_DOC_CONTENT_DIGEST_NAME)) {
            final String algorithm = args[1].getStringValue();
            final DigestType digestType;
            try {
                digestType = DigestType.forCommonName(algorithm);
            } catch (final IllegalArgumentException e) {
                throw new XPathException(this, "Invalid algorithm: " + algorithm, e);
            }
            try (final Txn transaction = context.getBroker().getBrokerPool().getTransactionManager().beginTransaction()) {
                final BinaryDocument bin = (BinaryDocument) doc;
                final MessageDigest messageDigest = context.getBroker().getBinaryResourceContentDigest(transaction, bin, digestType);
                final InputStream is = new UnsynchronizedByteArrayInputStream(messageDigest.getValue());
                final Sequence result = BinaryValueFromInputStream.getInstance(context, new HexBinaryValueType(), is);
                transaction.commit();
                return result;
            }
        } else {
            return BooleanValue.TRUE;
        }
    } catch (final URISyntaxException e) {
        logger.error("Invalid resource URI", e);
        throw new XPathException(this, "Invalid resource uri", e);
    } catch (final PermissionDeniedException e) {
        logger.error("{}: permission denied to read resource", path, e);
        throw new XPathException(this, path + ": permission denied to read resource");
    } catch (final IOException | TransactionException e) {
        logger.error("{}: I/O error while reading resource", path, e);
        throw new XPathException(this, path + ": I/O error while reading resource", e);
    }
}
Also used : XPathException(org.exist.xquery.XPathException) UnsynchronizedByteArrayInputStream(org.apache.commons.io.input.UnsynchronizedByteArrayInputStream) InputStream(java.io.InputStream) Txn(org.exist.storage.txn.Txn) URISyntaxException(java.net.URISyntaxException) IOException(java.io.IOException) DocumentImpl(org.exist.dom.persistent.DocumentImpl) BinaryDocument(org.exist.dom.persistent.BinaryDocument) TransactionException(org.exist.storage.txn.TransactionException) DigestType(org.exist.util.crypto.digest.DigestType) LockedDocument(org.exist.dom.persistent.LockedDocument) UnsynchronizedByteArrayInputStream(org.apache.commons.io.input.UnsynchronizedByteArrayInputStream) PermissionDeniedException(org.exist.security.PermissionDeniedException) MessageDigest(org.exist.util.crypto.digest.MessageDigest)

Example 18 with Txn

use of org.exist.storage.txn.Txn in project exist by eXist-db.

the class EmbeddedXMLStreamReaderTest method assertNodesIn.

public void assertNodesIn(final NamedEvent[] expected, final Function<Document, NodeHandle> initialNodeFun, final Optional<Function<Document, NodeHandle>> containerFun) throws EXistException, PermissionDeniedException, IOException, XMLStreamException {
    final BrokerPool pool = existEmbeddedServer.getBrokerPool();
    try (final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()));
        final Txn transaction = pool.getTransactionManager().beginTransaction()) {
        try (final LockedDocument lockedDocument = broker.getXMLResource(TEST_MIXED_XML_COLLECTION.append(MIXED_XML_NAME), Lock.LockMode.WRITE_LOCK)) {
            assertNotNull(lockedDocument);
            final Document document = lockedDocument.getDocument();
            assertNotNull(document);
            final NodeHandle initialNode = initialNodeFun.apply(document);
            final Optional<NodeHandle> maybeContainerNode = containerFun.map(f -> f.apply(document));
            final IEmbeddedXMLStreamReader xmlStreamReader = broker.getXMLStreamReader(initialNode, false);
            final NamedEvent[] actual = readAllEvents(maybeContainerNode, xmlStreamReader);
            assertArrayEquals(formatExpectedActual(expected, actual), expected, actual);
        }
        transaction.commit();
    }
}
Also used : DBBroker(org.exist.storage.DBBroker) NodeHandle(org.exist.dom.persistent.NodeHandle) LockedDocument(org.exist.dom.persistent.LockedDocument) Txn(org.exist.storage.txn.Txn) Document(org.w3c.dom.Document) LockedDocument(org.exist.dom.persistent.LockedDocument) NamedEvent(org.exist.stax.EmbeddedXMLStreamReaderTest.NamedEvent) BrokerPool(org.exist.storage.BrokerPool)

Example 19 with Txn

use of org.exist.storage.txn.Txn in project exist by eXist-db.

the class EmbeddedXMLStreamReaderTest method cleanup.

@AfterClass
public static void cleanup() throws EXistException, PermissionDeniedException, IOException, TriggerException {
    final BrokerPool pool = existEmbeddedServer.getBrokerPool();
    try (final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()));
        final Txn transaction = pool.getTransactionManager().beginTransaction()) {
        deleteCollection(broker, transaction, TEST_MIXED_XML_COLLECTION);
        transaction.commit();
    }
}
Also used : DBBroker(org.exist.storage.DBBroker) Txn(org.exist.storage.txn.Txn) BrokerPool(org.exist.storage.BrokerPool) AfterClass(org.junit.AfterClass)

Example 20 with Txn

use of org.exist.storage.txn.Txn in project exist by eXist-db.

the class AbstractUpdateTest method init.

protected DocumentImpl init(final DBBroker broker, final TransactionManager transact) throws PermissionDeniedException, IOException, SAXException, LockException, EXistException {
    DocumentImpl doc = null;
    try (final Txn transaction = transact.beginTransaction()) {
        final Collection root = broker.getOrCreateCollection(transaction, TEST_COLLECTION_URI);
        broker.saveCollection(transaction, root);
        final Collection test = broker.getOrCreateCollection(transaction, TEST_COLLECTION_URI.append("test2"));
        broker.saveCollection(transaction, test);
        broker.storeDocument(transaction, XmldbURI.create("test.xml"), new StringInputSource(TEST_XML), MimeType.XML_TYPE, test);
        doc = test.getDocument(broker, XmldbURI.create("test.xml"));
        // TODO : unlock the collection here ?
        transact.commit(transaction);
    }
    return doc;
}
Also used : StringInputSource(org.exist.util.StringInputSource) Collection(org.exist.collections.Collection) Txn(org.exist.storage.txn.Txn) DocumentImpl(org.exist.dom.persistent.DocumentImpl)

Aggregations

Txn (org.exist.storage.txn.Txn)358 DBBroker (org.exist.storage.DBBroker)215 BrokerPool (org.exist.storage.BrokerPool)179 Collection (org.exist.collections.Collection)162 TransactionManager (org.exist.storage.txn.TransactionManager)129 Sequence (org.exist.xquery.value.Sequence)84 StringInputSource (org.exist.util.StringInputSource)83 Test (org.junit.Test)80 XmldbURI (org.exist.xmldb.XmldbURI)55 EXistException (org.exist.EXistException)50 PermissionDeniedException (org.exist.security.PermissionDeniedException)38 Source (org.exist.source.Source)37 StringSource (org.exist.source.StringSource)37 DocumentImpl (org.exist.dom.persistent.DocumentImpl)35 InputSource (org.xml.sax.InputSource)33 XQuery (org.exist.xquery.XQuery)32 IOException (java.io.IOException)31 LockedDocument (org.exist.dom.persistent.LockedDocument)28 InputStream (java.io.InputStream)27 Path (java.nio.file.Path)24