Search in sources :

Example 1 with NativeBroker

use of org.exist.storage.NativeBroker 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 NativeBroker

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

the class DOMFile method debugPageContents.

String debugPageContents(final DOMPage page) {
    final StringBuilder buf = new StringBuilder();
    buf.append("Page ").append(page.getPageNum()).append(": ");
    short count = 0;
    final int dataLength = page.getPageHeader().getDataLength();
    for (int pos = 0; pos < dataLength; count++) {
        buf.append(pos).append("/");
        final short tupleID = ByteConversion.byteToShort(page.data, pos);
        pos += LENGTH_TID;
        buf.append(ItemId.getId(tupleID));
        if (ItemId.isLink(tupleID)) {
            buf.append("L");
        } else if (ItemId.isRelocated(tupleID)) {
            buf.append("R");
        }
        if (ItemId.isLink(tupleID)) {
            final long forwardLink = ByteConversion.byteToLong(page.data, pos);
            buf.append(':').append(forwardLink).append(" ");
            pos += LENGTH_FORWARD_LOCATION;
        } else {
            final short valueLength = ByteConversion.byteToShort(page.data, pos);
            pos += LENGTH_DATA_LENGTH;
            if (valueLength < 0) {
                LOG.warn("Illegal length: {}", valueLength);
                return buf.append("[Illegal length : ").append(valueLength).append("] ").toString();
            // Probably unable to continue...
            } else if (ItemId.isRelocated(tupleID)) {
                // TODO : output to buffer ?
                pos += LENGTH_ORIGINAL_LOCATION;
            } else {
                buf.append("[");
                switch(Signatures.getType(page.data[pos])) {
                    case Node.ELEMENT_NODE:
                        {
                            buf.append("element ");
                            int readOffset = pos;
                            readOffset += 1;
                            final int children = ByteConversion.byteToInt(page.data, readOffset);
                            readOffset += ElementImpl.LENGTH_ELEMENT_CHILD_COUNT;
                            final int dlnLen = ByteConversion.byteToShort(page.data, readOffset);
                            readOffset += NodeId.LENGTH_NODE_ID_UNITS;
                            // That might happen during recovery runs : TODO, investigate
                            if (owner == null) {
                                buf.append("(Can't read data, owner is null)");
                            } else {
                                try {
                                    final NodeId nodeId = ((NativeBroker) owner).getBrokerPool().getNodeFactory().createFromData(dlnLen, page.data, readOffset);
                                    readOffset += nodeId.size();
                                    buf.append("(").append(nodeId.toString()).append(")");
                                    final short attributes = ByteConversion.byteToShort(page.data, readOffset);
                                    buf.append(" children: ").append(children);
                                    buf.append(" attributes: ").append(attributes);
                                } catch (final Exception e) {
                                    // TODO : more friendly message. Provide the array of bytes ?
                                    buf.append("(Unable to read the node ID at: ").append(readOffset);
                                    buf.append(" children : ").append(children);
                                    // Probably a wrong offset so... don't read it
                                    buf.append(" attributes : unknown");
                                }
                            }
                            break;
                        }
                    case Node.TEXT_NODE:
                    case Node.CDATA_SECTION_NODE:
                        {
                            if (Signatures.getType(page.data[pos]) == Node.TEXT_NODE) {
                                buf.append("text ");
                            } else {
                                buf.append("CDATA ");
                            }
                            int readOffset = pos;
                            readOffset += 1;
                            final int dlnLen = ByteConversion.byteToShort(page.data, readOffset);
                            readOffset += NodeId.LENGTH_NODE_ID_UNITS;
                            // That might happen during recovery runs : TODO, investigate
                            if (owner == null) {
                                buf.append("(Can't read data, owner is null)");
                            } else {
                                try {
                                    final NodeId nodeId = ((NativeBroker) owner).getBrokerPool().getNodeFactory().createFromData(dlnLen, page.data, readOffset);
                                    readOffset += nodeId.size();
                                    buf.append("(").append(nodeId.toString()).append(")");
                                    String value = new String(page.data, readOffset, valueLength - (readOffset - pos), UTF_8);
                                    if (value.length() > 15) {
                                        value = value.substring(0, 8) + "..." + value.substring(value.length() - 8);
                                    }
                                    buf.append(":'").append(value).append("'");
                                } catch (final Exception e) {
                                    // TODO : more friendly message. Provide the array of bytes ?
                                    buf.append("(unable to read the node ID at : ").append(readOffset);
                                }
                            }
                            break;
                        }
                    case Node.ATTRIBUTE_NODE:
                        {
                            buf.append("[");
                            buf.append("attribute ");
                            int readOffset = pos;
                            final byte idSizeType = (byte) (page.data[readOffset] & 0x3);
                            final boolean hasNamespace = (page.data[readOffset] & 0x10) == 0x10;
                            readOffset += 1;
                            final int dlnLen = ByteConversion.byteToShort(page.data, readOffset);
                            readOffset += NodeId.LENGTH_NODE_ID_UNITS;
                            // That might happen during recovery runs : TODO, investigate
                            if (owner == null) {
                                buf.append("(can't read data, owner is null)");
                            } else {
                                try {
                                    final NodeId nodeId = ((NativeBroker) owner).getBrokerPool().getNodeFactory().createFromData(dlnLen, page.data, readOffset);
                                    readOffset += nodeId.size();
                                    buf.append("(").append(nodeId.toString()).append(")");
                                    readOffset += Signatures.getLength(idSizeType);
                                    if (hasNamespace) {
                                        // Untested
                                        final short NSId = ByteConversion.byteToShort(page.data, readOffset);
                                        readOffset += AttrImpl.LENGTH_NS_ID;
                                        final short prefixLen = ByteConversion.byteToShort(page.data, readOffset);
                                        readOffset += AttrImpl.LENGTH_PREFIX_LENGTH + prefixLen;
                                        final String prefix = new String(page.data, readOffset, valueLength - (readOffset - prefixLen), UTF_8);
                                        final String NsURI = ((NativeBroker) owner).getBrokerPool().getSymbols().getNamespace(NSId);
                                        buf.append(prefix).append("{").append(NsURI).append("}");
                                    }
                                    String value = new String(page.data, readOffset, valueLength - (readOffset - pos), UTF_8);
                                    if (value.length() > 15) {
                                        value = value.substring(0, 8) + "..." + value.substring(value.length() - 8);
                                    }
                                    buf.append(":'").append(value).append("'");
                                } catch (final Exception e) {
                                    // TODO : more friendly message. Provide the array of bytes ?
                                    buf.append("(unable to read the node ID at : ").append(readOffset);
                                }
                            }
                            buf.append("] ");
                            break;
                        }
                    default:
                        buf.append("Unknown node type !");
                }
                buf.append("] ");
            }
            pos += valueLength;
        }
    }
    buf.append("; records in page: ").append(count).append(" (header says: ").append(page.getPageHeader().getRecordCount()).append(")");
    buf.append("; currentTupleID: ").append(page.getPageHeader().getCurrentTupleID());
    buf.append("; data length: ").append(page.getPageHeader().getDataLength());
    for (int i = page.data.length; i > 0; i--) {
        if (page.data[i - 1] != 0) {
            buf.append(" (last non-zero byte: ").append(i).append(")");
            break;
        }
    }
    return buf.toString();
}
Also used : NodeId(org.exist.numbering.NodeId) NativeBroker(org.exist.storage.NativeBroker) JournalException(org.exist.storage.journal.JournalException) TerminatedException(org.exist.xquery.TerminatedException) XMLStreamException(javax.xml.stream.XMLStreamException) DBException(org.exist.storage.btree.DBException) BTreeException(org.exist.storage.btree.BTreeException) IOException(java.io.IOException)

Example 3 with NativeBroker

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

the class Repair method repair.

public void repair(String id) {
    try (final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()))) {
        BTree btree = null;
        if ("collections".equals(id)) {
            btree = ((NativeBroker) broker).getStorage(NativeBroker.COLLECTIONS_DBX_ID);
        } else if ("dom".equals(id)) {
            btree = ((NativeBroker) broker).getStorage(NativeBroker.DOM_DBX_ID);
        } else if ("range".equals(id)) {
            btree = ((NativeBroker) broker).getStorage(NativeBroker.VALUES_DBX_ID);
        } else if ("structure".equals(id)) {
            NativeStructuralIndexWorker index = (NativeStructuralIndexWorker) broker.getIndexController().getWorkerByIndexName(StructuralIndex.STRUCTURAL_INDEX_ID);
            btree = index.getStorage();
        } else {
            // use index id defined in conf.xml
            Index index = pool.getIndexManager().getIndexByName(id);
            if (index != null) {
                btree = index.getStorage();
            }
        }
        if (btree == null) {
            System.console().printf("Unkown index: %s\n", id);
            return;
        }
        final LockManager lockManager = broker.getBrokerPool().getLockManager();
        try (final ManagedLock<ReentrantLock> btreeLock = lockManager.acquireBtreeWriteLock(btree.getLockName())) {
            System.console().printf("Rebuilding %15s ...", FileUtils.fileName(btree.getFile()));
            btree.rebuild();
            System.out.println("Done");
        }
    } catch (Exception e) {
        System.console().printf("An exception occurred during repair: %s\n", e.getMessage());
        e.printStackTrace();
    }
}
Also used : ReentrantLock(java.util.concurrent.locks.ReentrantLock) LockManager(org.exist.storage.lock.LockManager) DBBroker(org.exist.storage.DBBroker) StructuralIndex(org.exist.indexing.StructuralIndex) Index(org.exist.indexing.Index) NativeBroker(org.exist.storage.NativeBroker) NativeStructuralIndexWorker(org.exist.storage.structural.NativeStructuralIndexWorker) StartException(org.exist.start.StartException) EXistException(org.exist.EXistException) DatabaseConfigurationException(org.exist.util.DatabaseConfigurationException)

Aggregations

NativeBroker (org.exist.storage.NativeBroker)3 IOException (java.io.IOException)2 XMLStreamException (javax.xml.stream.XMLStreamException)2 NodeId (org.exist.numbering.NodeId)2 TerminatedException (org.exist.xquery.TerminatedException)2 ReentrantLock (java.util.concurrent.locks.ReentrantLock)1 EXistException (org.exist.EXistException)1 Index (org.exist.indexing.Index)1 StructuralIndex (org.exist.indexing.StructuralIndex)1 PermissionDeniedException (org.exist.security.PermissionDeniedException)1 StartException (org.exist.start.StartException)1 EmbeddedXMLStreamReader (org.exist.stax.EmbeddedXMLStreamReader)1 DBBroker (org.exist.storage.DBBroker)1 BTreeException (org.exist.storage.btree.BTreeException)1 DBException (org.exist.storage.btree.DBException)1 Value (org.exist.storage.btree.Value)1 DOMFile (org.exist.storage.dom.DOMFile)1 JournalException (org.exist.storage.journal.JournalException)1 LockManager (org.exist.storage.lock.LockManager)1 NativeStructuralIndexWorker (org.exist.storage.structural.NativeStructuralIndexWorker)1