Search in sources :

Example 1 with Value

use of org.exist.storage.btree.Value in project exist by eXist-db.

the class ConsistencyCheck method checkXMLTree.

/**
 * Check the persistent DOM of a document. The method traverses the entire node tree and checks it for consistency, including node relationships,
 * child and attribute counts etc.
 *
 * @param doc the document to check
 * @return null if the document is consistent, an error report otherwise.
 */
public ErrorReport checkXMLTree(final DocumentImpl doc) {
    final DOMFile domDb = ((NativeBroker) broker).getDOMFile();
    return new DOMTransaction<ErrorReport>(this, domDb, () -> broker.getBrokerPool().getLockManager().acquireBtreeWriteLock(domDb.getLockName()), doc) {

        public ErrorReport start() {
            EmbeddedXMLStreamReader reader = null;
            try {
                final Node root = doc.getFirstChild();
                reader = (EmbeddedXMLStreamReader) broker.getXMLStreamReader((NodeHandle) root, true);
                boolean attribsAllowed = false;
                int expectedAttribs = 0;
                int attributeCount = 0;
                while (reader.hasNext()) {
                    final int status = reader.next();
                    final NodeId nodeId = (NodeId) reader.getProperty(EmbeddedXMLStreamReader.PROPERTY_NODE_ID);
                    if ((status != XMLStreamReader.END_ELEMENT) && !elementStack.isEmpty()) {
                        final ElementNode parent = elementStack.peek();
                        parent.childCount++;
                        // test parent-child relation
                        if (!nodeId.isChildOf(parent.elem.getNodeId())) {
                            return new ErrorReport.ResourceError(ErrorReport.NODE_HIERARCHY, "Node " + nodeId + " is not a child of " + parent.elem.getNodeId());
                        }
                        // test sibling relation
                        if ((parent.prevSibling != null) && !(nodeId.isSiblingOf(parent.prevSibling) && (nodeId.compareTo(parent.prevSibling) > 0))) {
                            return new ErrorReport.ResourceError(ErrorReport.INCORRECT_NODE_ID, "Node " + nodeId + " is not a sibling of " + parent.prevSibling);
                        }
                        parent.prevSibling = nodeId;
                    }
                    switch(status) {
                        case XMLStreamReader.ATTRIBUTE:
                            {
                                attributeCount++;
                                break;
                            }
                        case XMLStreamReader.END_ELEMENT:
                            {
                                if (elementStack.isEmpty()) {
                                    return new org.exist.backup.ErrorReport.ResourceError(ErrorReport.NODE_HIERARCHY, "Error in node hierarchy: received END_ELEMENT event " + "but stack was empty!");
                                }
                                final ElementNode lastElem = elementStack.pop();
                                if (lastElem.childCount != lastElem.elem.getChildCount()) {
                                    return new ErrorReport.ResourceError(org.exist.backup.ErrorReport.NODE_HIERARCHY, "Element reports incorrect child count: expected " + lastElem.elem.getChildCount() + " but found " + lastElem.childCount);
                                }
                                break;
                            }
                        case XMLStreamReader.START_ELEMENT:
                            {
                                if (nodeId.getTreeLevel() <= defaultIndexDepth) {
                                    // check dom.dbx btree, which maps the node
                                    // id to the node's storage address
                                    // look up the node id and check if the
                                    // returned storage address is correct
                                    final NativeBroker.NodeRef nodeRef = new NativeBroker.NodeRef(doc.getDocId(), nodeId);
                                    try {
                                        final long p = domDb.findValue(nodeRef);
                                        if (p != reader.getCurrentPosition()) {
                                            final Value v = domDb.get(p);
                                            if (v == null) {
                                                return new ErrorReport.IndexError(ErrorReport.DOM_INDEX, "Failed to access node " + nodeId + " through dom.dbx index. Wrong storage address. Expected: " + p + "; got: " + reader.getCurrentPosition() + " - ", doc.getDocId());
                                            }
                                        }
                                    } catch (final Exception e) {
                                        e.printStackTrace();
                                        return new ErrorReport.IndexError(ErrorReport.DOM_INDEX, "Failed to access node " + nodeId + " through dom.dbx index.", e, doc.getDocId());
                                    }
                                }
                                final IStoredNode node = reader.getNode();
                                if (node.getNodeType() != Node.ELEMENT_NODE) {
                                    return new org.exist.backup.ErrorReport.ResourceError(ErrorReport.INCORRECT_NODE_TYPE, "Expected an element node, received node of type " + node.getNodeType());
                                }
                                elementStack.push(new ElementNode((ElementImpl) node));
                                attribsAllowed = true;
                                attributeCount = 0;
                                expectedAttribs = reader.getAttributeCount();
                                break;
                            }
                        default:
                            {
                                if (attribsAllowed) {
                                    if (attributeCount != expectedAttribs) {
                                        return new org.exist.backup.ErrorReport.ResourceError(ErrorReport.INCORRECT_NODE_TYPE, "Wrong number of attributes. Expected: " + expectedAttribs + "; found: " + attributeCount);
                                    }
                                }
                                attribsAllowed = false;
                                break;
                            }
                    }
                }
                if (!elementStack.isEmpty()) {
                    return new org.exist.backup.ErrorReport.ResourceError(ErrorReport.NODE_HIERARCHY, "Error in node hierarchy: reached end of tree but " + "stack was not empty!");
                }
                return null;
            } catch (final IOException | XMLStreamException e) {
                e.printStackTrace();
                return new org.exist.backup.ErrorReport.ResourceError(ErrorReport.RESOURCE_ACCESS_FAILED, e.getMessage(), e);
            } finally {
                elementStack.clear();
                if (reader != null) {
                    try {
                        reader.close();
                    } catch (final XMLStreamException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }.run();
}
Also used : Node(org.w3c.dom.Node) EmbeddedXMLStreamReader(org.exist.stax.EmbeddedXMLStreamReader) DOMFile(org.exist.storage.dom.DOMFile) NativeBroker(org.exist.storage.NativeBroker) PermissionDeniedException(org.exist.security.PermissionDeniedException) TerminatedException(org.exist.xquery.TerminatedException) XMLStreamException(javax.xml.stream.XMLStreamException) IOException(java.io.IOException) XMLStreamException(javax.xml.stream.XMLStreamException) NodeId(org.exist.numbering.NodeId) Value(org.exist.storage.btree.Value)

Example 2 with Value

use of org.exist.storage.btree.Value in project exist by eXist-db.

the class WriteOverflowPageLoggable method read.

@Override
public void read(final ByteBuffer in) {
    pageNum = in.getInt();
    nextPage = in.getInt();
    final int len = in.getShort();
    final byte[] data = new byte[len];
    in.get(data);
    value = new Value(data);
}
Also used : Value(org.exist.storage.btree.Value)

Example 3 with Value

use of org.exist.storage.btree.Value in project exist by eXist-db.

the class BFile method get.

/**
 * Retrieve value at logical address pointer from page
 *
 * @param page the data page
 * @param pointer the pointer to the value
 *
 * @return the value or null if there is no value
 *
 * @throws IOException if an I/O error occurs
 */
protected Value get(final DataPage page, final long pointer) throws IOException {
    final short tid = StorageAddress.tidFromPointer(pointer);
    final int offset = page.findValuePosition(tid);
    final byte[] data = page.getData();
    if (offset < 0 || offset > data.length) {
        LOG.error("wrong pointer (tid: {}{}) in file {}; offset = {}", tid, page.getPageInfo(), FileUtils.fileName(getFile()), offset);
        return null;
    }
    final int l = ByteConversion.byteToInt(data, offset);
    if (l + 6 > data.length) {
        LOG.error("{} wrong data length in page {}: expected={}; found={}", FileUtils.fileName(getFile()), page.getPageNum(), l + 6, data.length);
        return null;
    }
    dataCache.add(page.getFirstPage());
    final Value v = new Value(data, offset + 4, l);
    v.setAddress(pointer);
    return v;
}
Also used : Value(org.exist.storage.btree.Value)

Example 4 with Value

use of org.exist.storage.btree.Value in project exist by eXist-db.

the class RawNodeIterator method next.

@Override
public Value next() {
    Value nextValue = null;
    try (final ManagedLock<ReentrantLock> domFileLock = lockManager.acquireBtreeReadLock(db.getLockName())) {
        db.setOwnerObject(broker);
        long backLink = 0;
        do {
            final DOMFile.DOMFilePageHeader pageHeader = page.getPageHeader();
            // Next value larger than length of the current page?
            if (offset >= pageHeader.getDataLength()) {
                // Load next page in chain
                long nextPage = pageHeader.getNextDataPage();
                if (nextPage == Paged.Page.NO_PAGE) {
                    SanityCheck.TRACE("Bad link to next page " + page.page.getPageInfo() + "; previous: " + pageHeader.getPreviousDataPage() + "; offset = " + offset + "; lastTupleID = " + lastTupleID);
                    // TODO : throw exception here ? -pb
                    return null;
                }
                pageNum = nextPage;
                page = db.getDOMPage(nextPage);
                db.addToBuffer(page);
                offset = 0;
            }
            // Extract the tuple id
            lastTupleID = ByteConversion.byteToShort(page.data, offset);
            offset += DOMFile.LENGTH_TID;
            // Check if this is just a link to a relocated node
            if (ItemId.isLink(lastTupleID)) {
                // Skip this
                offset += DOMFile.LENGTH_FORWARD_LOCATION;
                continue;
            }
            // Read data length
            short valueLength = ByteConversion.byteToShort(page.data, offset);
            offset += DOMFile.LENGTH_DATA_LENGTH;
            if (valueLength < 0) {
                LOG.error("Got negative length{} at offset {}!!!", valueLength, offset);
                LOG.debug(db.debugPageContents(page));
            // TODO : throw an exception right now ?
            }
            if (ItemId.isRelocated(lastTupleID)) {
                // found a relocated node. Read the original address
                backLink = ByteConversion.byteToLong(page.data, offset);
                offset += DOMFile.LENGTH_ORIGINAL_LOCATION;
            }
            // Overflow page? load the overflow value
            if (valueLength == DOMFile.OVERFLOW) {
                valueLength = DOMFile.LENGTH_OVERFLOW_LOCATION;
                final long overflow = ByteConversion.byteToLong(page.data, offset);
                offset += DOMFile.LENGTH_OVERFLOW_LOCATION;
                try {
                    final byte[] odata = db.getOverflowValue(overflow);
                    nextValue = new Value(odata);
                } catch (final Exception e) {
                    LOG.error("Exception while loading overflow value: {}; originating page: {}", e.getMessage(), page.page.getPageInfo());
                }
            // normal node
            } else {
                try {
                    nextValue = new Value(page.data, offset, valueLength);
                    offset += valueLength;
                } catch (final Exception e) {
                    LOG.error("Error while deserializing node: {}", e.getMessage(), e);
                    LOG.error("Reading from offset: {}; len = {}", offset, valueLength);
                    LOG.debug(db.debugPageContents(page));
                    throw new RuntimeException(e);
                }
            }
            if (nextValue == null) {
                LOG.error("illegal node on page {}; tupleID = {}; next = {}; prev = {}; offset = {}; len = {}", page.getPageNum(), ItemId.getId(lastTupleID), page.getPageHeader().getNextDataPage(), page.getPageHeader().getPreviousDataPage(), offset - valueLength, page.getPageHeader().getDataLength());
                // TODO : throw exception here ? -pb
                return null;
            }
            if (ItemId.isRelocated(lastTupleID)) {
                nextValue.setAddress(backLink);
            } else {
                nextValue.setAddress(StorageAddress.createPointer((int) pageNum, ItemId.getId(lastTupleID)));
            }
        } while (nextValue == null);
        return nextValue;
    } catch (final LockException e) {
        LOG.error("Failed to acquire read lock on {}", FileUtils.fileName(db.getFile()));
        // TODO : throw exception here ? -pb
        return null;
    }
}
Also used : ReentrantLock(java.util.concurrent.locks.ReentrantLock) LockException(org.exist.util.LockException) Value(org.exist.storage.btree.Value) BTreeException(org.exist.storage.btree.BTreeException) IOException(java.io.IOException) LockException(org.exist.util.LockException)

Example 5 with Value

use of org.exist.storage.btree.Value in project exist by eXist-db.

the class EmbeddedXMLStreamReader method readAttributes.

private void readAttributes() {
    if (attributes == null) {
        final ElementEvent parent = elementStack.peek();
        final int count = getAttributeCount();
        attributes = new AttrList();
        for (int i = 0; i < count; i++) {
            final Value v = iterator.next();
            AttrImpl.addToList(broker, v.data(), v.start(), v.getLength(), attributes);
            parent.incrementChild();
        }
    }
}
Also used : AttrList(org.exist.util.serializer.AttrList) Value(org.exist.storage.btree.Value)

Aggregations

Value (org.exist.storage.btree.Value)44 ReentrantLock (java.util.concurrent.locks.ReentrantLock)28 IOException (java.io.IOException)19 IndexQuery (org.exist.storage.btree.IndexQuery)19 BTreeException (org.exist.storage.btree.BTreeException)16 EXistException (org.exist.EXistException)13 PermissionDeniedException (org.exist.security.PermissionDeniedException)11 LockException (org.exist.util.LockException)11 QName (org.exist.dom.QName)10 DatabaseConfigurationException (org.exist.util.DatabaseConfigurationException)10 NodeId (org.exist.numbering.NodeId)8 AtomicValue (org.exist.xquery.value.AtomicValue)8 StringValue (org.exist.xquery.value.StringValue)8 Test (org.junit.Test)8 TerminatedException (org.exist.xquery.TerminatedException)7 Collection (org.exist.collections.Collection)5 NodeProxy (org.exist.dom.persistent.NodeProxy)5 DocumentImpl (org.exist.dom.persistent.DocumentImpl)4 NewArrayNodeSet (org.exist.dom.persistent.NewArrayNodeSet)4 BFile (org.exist.storage.index.BFile)4