use of org.exist.storage.btree.BTreeException in project exist by eXist-db.
the class DOMFile method findValue.
/**
* Retrieve node at virtual address.
*
* @param broker the database broker
* @param node The virtual address
* @return The reference of the node
* @throws IOException if an I/O error occurs
* @throws BTreeException if an error occurs reading the tree
*/
protected long findValue(final DBBroker broker, final NodeProxy node) throws IOException, BTreeException {
if (LOG.isDebugEnabled() && !lockManager.isBtreeLocked(getLockName())) {
LOG.debug("The file doesn't own a lock");
}
final DocumentImpl doc = node.getOwnerDocument();
final NodeRef nodeRef = new NativeBroker.NodeRef(doc.getDocId(), node.getNodeId());
// first try to find the node in the index
final long pointer = findValue(nodeRef);
if (pointer == KEY_NOT_FOUND) {
// node not found in index: try to find the nearest available
// ancestor and traverse it
NodeId nodeID = node.getNodeId();
long parentPointer = KEY_NOT_FOUND;
do {
nodeID = nodeID.getParentId();
if (nodeID == null) {
SanityCheck.TRACE("Node " + node.getOwnerDocument().getDocId() + ":<null nodeID> not found.");
throw new BTreeException("Node not found.");
}
if (nodeID == NodeId.DOCUMENT_NODE) {
SanityCheck.TRACE("Node " + node.getOwnerDocument().getDocId() + ":" + nodeID + " not found.");
return KEY_NOT_FOUND;
}
final NativeBroker.NodeRef parentRef = new NativeBroker.NodeRef(doc.getDocId(), nodeID);
try {
parentPointer = findValue(parentRef);
} catch (final BTreeException bte) {
LOG.error("report me", bte);
}
} while (parentPointer == KEY_NOT_FOUND);
try {
final int thisLevel = nodeID.getTreeLevel();
// lazily initialized below
Integer childLevel = null;
final NodeProxy parent = new NodeProxy(doc, nodeID, parentPointer);
final EmbeddedXMLStreamReader reader = (EmbeddedXMLStreamReader) broker.getXMLStreamReader(parent, true);
while (reader.hasNext()) {
final int status = reader.next();
if (status != XMLStreamReader.END_ELEMENT) {
if (childLevel == null) {
childLevel = reader.getNode().getNodeType() == Node.ELEMENT_NODE ? thisLevel + 1 : thisLevel;
}
final NodeId otherId = (NodeId) reader.getProperty(ExtendedXMLStreamReader.PROPERTY_NODE_ID);
if (otherId.equals(node.getNodeId())) {
return reader.getCurrentPosition();
}
}
if (status == XMLStreamConstants.END_ELEMENT) {
final NodeId otherId = (NodeId) reader.getProperty(ExtendedXMLStreamReader.PROPERTY_NODE_ID);
final int otherLevel = otherId.getTreeLevel();
if (childLevel != null && childLevel != otherLevel && otherLevel == thisLevel) {
// exit-while
break;
}
}
}
if (LOG.isDebugEnabled()) {
LOG.debug("Node {} could not be found. Giving up. This is usually not an error.", node.getNodeId());
}
return KEY_NOT_FOUND;
} catch (final XMLStreamException e) {
SanityCheck.TRACE("Node " + node.getOwnerDocument().getDocId() + ":" + node.getNodeId() + " not found.");
throw new BTreeException("Node " + node.getNodeId() + " not found.");
}
} else {
return pointer;
}
}
use of org.exist.storage.btree.BTreeException in project exist by eXist-db.
the class DOMFile method getNodeValue.
/**
* Retrieve the string value of the specified node. This is an optimized low-level method
* which will directly traverse the stored DOM nodes and collect the string values of
* the specified root node and all its descendants. By directly scanning the stored
* node data, we do not need to create a potentially large amount of node objects
* and thus save memory and time for garbage collection.
*
* @param broker the database broker
* @param node the node
* @param addWhitespace true if whitespace should be added to the node value
* @return string value of the specified node
*/
public String getNodeValue(final DBBroker broker, final IStoredNode node, final boolean addWhitespace) {
if (LOG.isDebugEnabled() && !lockManager.isBtreeLocked(getLockName())) {
LOG.debug("The file doesn't own a lock");
}
try {
long address = node.getInternalAddress();
RecordPos recordPos = null;
// try to directly locate the root node through its storage address
if (StorageAddress.hasAddress(address)) {
recordPos = findRecord(address);
}
if (recordPos == null) {
// fallback to a BTree lookup if the node could not be found
// by its storage address
address = findValue(broker, new NodeProxy(node));
if (address == BTree.KEY_NOT_FOUND) {
LOG.error("Node value not found: {}", node);
// TODO : throw exception ? -pb
return null;
}
recordPos = findRecord(address);
SanityCheck.THROW_ASSERT(recordPos != null, "Node data could not be found!");
// TODO : throw exception ? -pb
}
// we collect the string values in binary format and append them to a ByteArrayOutputStream
try (final UnsynchronizedByteArrayOutputStream os = new UnsynchronizedByteArrayOutputStream(32)) {
// now traverse the tree
getNodeValue(broker.getBrokerPool(), os, recordPos, true, addWhitespace);
final byte[] data = os.toByteArray();
final XMLString str = UTF8.decode(data);
if (str != null) {
return str.toString();
} else {
return "";
}
}
} catch (final BTreeException e) {
LOG.error("BTree error while reading node value", e);
// TODO : rethrow exception ? -pb
} catch (final Exception e) {
LOG.error("IO error while reading node value", e);
// TODO : rethrow exception ? -pb
}
// TODO : remove if exceptions thrown...
return null;
}
use of org.exist.storage.btree.BTreeException in project exist by eXist-db.
the class NodeIterator method next.
/**
* Returns the next node in document order.
*/
@Override
public IStoredNode next() {
try (final ManagedLock<ReentrantLock> domFileLock = lockManager.acquireBtreeReadLock(db.getLockName())) {
db.setOwnerObject(broker);
IStoredNode nextNode = null;
if (gotoNextPosition()) {
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 nextPageNum = pageHeader.getNextDataPage();
if (nextPageNum == Page.NO_PAGE) {
SanityCheck.TRACE("bad link to next " + page.page.getPageInfo() + "; previous: " + pageHeader.getPreviousDataPage() + "; offset = " + offset + "; lastTupleID = " + lastTupleID);
if (LOG.isDebugEnabled()) {
LOG.debug(db.debugPageContents(page));
}
// TODO : throw exception here ? -pb
return null;
}
pageNum = nextPageNum;
page = db.getDOMPage(nextPageNum);
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 the iteration
continue;
}
// Read data length
short vlen = ByteConversion.byteToShort(page.data, offset);
offset += DOMFile.LENGTH_DATA_LENGTH;
if (vlen < 0) {
LOG.error("Got negative length{} at offset {}!!!", vlen, offset);
if (LOG.isDebugEnabled()) {
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 (vlen == DOMFile.OVERFLOW) {
vlen = DOMFile.LENGTH_OVERFLOW_LOCATION;
final long overflow = ByteConversion.byteToLong(page.data, offset);
offset += DOMFile.LENGTH_OVERFLOW_LOCATION;
try {
final byte[] overflowValue = db.getOverflowValue(overflow);
nextNode = StoredNode.deserialize(overflowValue, 0, overflowValue.length, doc, useNodePool);
} catch (final Exception e) {
LOG.warn("Exception while loading overflow value: {}; originating page: {}", e.getMessage(), page.page.getPageInfo());
// TODO : rethrow exception ? -pb
}
// Normal node
} else {
try {
nextNode = StoredNode.deserialize(page.data, offset, vlen, doc, useNodePool);
offset += vlen;
} catch (final Exception e) {
LOG.error("Error while deserializing node: {}", e.getMessage(), e);
LOG.error("Reading from offset: {}; len = {}", offset, vlen);
if (LOG.isDebugEnabled()) {
LOG.debug(db.debugPageContents(page));
}
throw new RuntimeException(e);
}
}
if (nextNode == null) {
LOG.error("illegal node on page {}; tid = {}; next = {}; prev = {}; offset = {}; len = {}", page.getPageNum(), ItemId.getId(lastTupleID), page.getPageHeader().getNextDataPage(), page.getPageHeader().getPreviousDataPage(), offset - vlen, page.getPageHeader().getDataLength());
if (LOG.isDebugEnabled()) {
LOG.debug(db.debugPageContents(page));
}
// TODO : throw an exception here ? -pb
return null;
}
if (ItemId.isRelocated(lastTupleID)) {
nextNode.setInternalAddress(backLink);
} else {
nextNode.setInternalAddress(StorageAddress.createPointer((int) pageNum, ItemId.getId(lastTupleID)));
}
nextNode.setOwnerDocument(doc);
} while (nextNode == null);
}
return nextNode;
} catch (final LockException e) {
LOG.warn("Failed to acquire read lock on {}", FileUtils.fileName(db.getFile()));
// TODO : throw exception here ? -pb
return null;
} catch (final BTreeException | IOException e) {
LOG.error(e.getMessage(), e);
// TODO : re-throw exception ? -pb
}
return null;
}
use of org.exist.storage.btree.BTreeException in project exist by eXist-db.
the class NativeValueIndex method dropIndex.
@Override
public void dropIndex(final Collection collection) {
try (final ManagedLock<ReentrantLock> bfileLock = lockManager.acquireBtreeWriteLock(dbValues.getLockName())) {
flush();
// remove generic index
Value ref = new SimpleValue(collection.getId());
dbValues.removeAll(null, new IndexQuery(IndexQuery.TRUNC_RIGHT, ref));
// remove QName index
ref = new QNameValue(collection.getId());
dbValues.removeAll(null, new IndexQuery(IndexQuery.TRUNC_RIGHT, ref));
} catch (final LockException e) {
LOG.warn("Failed to acquire lock for '{}'", FileUtils.fileName(dbValues.getFile()), e);
} catch (final BTreeException | IOException e) {
LOG.error(e.getMessage(), e);
}
}
use of org.exist.storage.btree.BTreeException in project exist by eXist-db.
the class NativeValueIndex method findAll.
/**
* find.
*
* @param comparison The type of comparison the search is performing
* @param docs The documents to search for matches within
* @param contextSet DOCUMENT ME!
* @param axis DOCUMENT ME!
* @param qnames DOCUMENT ME!
* @param value right hand comparison value
* @param result DOCUMENT ME!
* @return DOCUMENT ME!
* @throws TerminatedException DOCUMENT ME!
*/
private NodeSet findAll(final XQueryWatchDog watchDog, final Comparison comparison, final DocumentSet docs, final NodeSet contextSet, final int axis, final List<QName> qnames, final Indexable value, final NodeSet result) throws TerminatedException {
final SearchCallback cb = new SearchCallback(docs, contextSet, result, axis == NodeSet.ANCESTOR);
final int idxOp = toIndexQueryOp(comparison);
for (final Iterator<Collection> iter = docs.getCollectionIterator(); iter.hasNext(); ) {
final int collectionId = iter.next().getId();
watchDog.proceed(null);
if (qnames == null) {
try (final ManagedLock<ReentrantLock> bfileLock = lockManager.acquireBtreeReadLock(dbValues.getLockName())) {
final Value searchKey = new SimpleValue(collectionId, value);
final IndexQuery query = new IndexQuery(idxOp, searchKey);
if (idxOp == IndexQuery.EQ) {
dbValues.query(query, cb);
} else {
final Value prefixKey = new SimplePrefixValue(collectionId, value.getType());
dbValues.query(query, prefixKey, cb);
}
} catch (final EXistException | BTreeException | IOException e) {
LOG.error(e.getMessage(), e);
} catch (final LockException e) {
LOG.warn("Failed to acquire lock for '{}'", FileUtils.fileName(dbValues.getFile()), e);
}
} else {
for (final QName qname : qnames) {
try (final ManagedLock<ReentrantLock> bfileLock = lockManager.acquireBtreeReadLock(dbValues.getLockName())) {
// Compute a key for the value in the collection
final Value searchKey = new QNameValue(collectionId, qname, value, broker.getBrokerPool().getSymbols());
final IndexQuery query = new IndexQuery(idxOp, searchKey);
if (idxOp == IndexQuery.EQ) {
dbValues.query(query, cb);
} else {
final Value prefixKey = new QNamePrefixValue(collectionId, qname, value.getType(), broker.getBrokerPool().getSymbols());
dbValues.query(query, prefixKey, cb);
}
} catch (final EXistException | BTreeException | IOException e) {
LOG.error(e.getMessage(), e);
} catch (final LockException e) {
LOG.warn("Failed to acquire lock for '{}'", FileUtils.fileName(dbValues.getFile()), e);
}
}
}
}
return result;
}
Aggregations