Beispiel #1
0
//
// Upgrade implementation
//
// NsUpgradeReader
//
NsUpgradeReader::NsUpgradeReader(
    DbWrapper &db, const DocID &docId)
    : emptyElement_(false),
      db_(db),
      encStr_(0),
      standStr_(0),
      sniffStr_(0),
      xmlDecl_(-1),
      nsInfo_(0),
      id_(docId),
      doInit_(true),
      popElement_(false),
      entityCount_(0),
      current_(NULL),
      currentBuffer_(NULL),
      cursor_(db, 0, CURSOR_READ, 0),
      cursorFlags_(0),
      reuseList_(NULL),
      freeList_(NULL)
{
    docId.setDbtFromThis(docKey_);

    initDocInfo();

    // Old root nid format -- node ID 4
    startBuf_[0] = 0x04;
    startBuf_[1] = 0;
    doElement(true /*start*/);
}
	virtual int seek(DocID &id)
	{
		if (last_ >= id) return next(id);

		id.setDbtFromThis(key_);
		// DB_SET_RANGE does >= get on the key (which is the id)
		int err = cursor_.get(key_, data_, DB_SET_RANGE);
		if(err == DB_NOTFOUND) {
			err = 0;
			done_ = true;
			id = 0;
		} else if(err == 0) {
			last_.setThisFromDbt(key_);
			DBXML_ASSERT(last_ >= id);
			id = last_; // let caller know where it landed
		}
		return err;
	}
// if toRemove is non-null, it specifies a list of Name IDs
// to remove; otherwise remove all metadata for the target document
int DocumentDatabase::removeMetaData(OperationContext &oc,
				     const DocID &id,
				     std::vector<NameID> *toRemove)
{
	Cursor cursor(const_cast<SecondaryDatabase&>(secondary_), oc.txn(),
		      CURSOR_WRITE, "DocumentMetaData_remove");

	DbtIn none;
	none.set_flags(DB_DBT_PARTIAL); // Don't pull back the data.

	id.setDbtFromThis(oc.key());

	DocID db_id;
	int err = cursor.get(oc.key(), none, DB_SET_RANGE);
	try {
		while(err == 0) {
			if (toRemove) {
				NameID nm_id;
				XmlValue::Type type;
				MetaDatum::decodeKeyDbt(oc.key(), db_id, nm_id, type);
				if ((id == db_id) && idInList(*toRemove, nm_id))
					cursor.del(0);
			} else {
				db_id.setThisFromDbt(oc.key());
				if (id == db_id)
					cursor.del(0);
			}
			if (id != db_id) // done with document?
				break;
			err = cursor.get(oc.key(), none, DB_NEXT);
		}
	} catch (...) {
		cursor.close();
		throw;
	}
	if(err == DB_NOTFOUND) {
		err = 0;
	}
	cursor.close();
	return err;
}
int DocumentDatabase::updateContentAndIndex(Document &new_document,
					    UpdateContext &context,
					    KeyStash &stash, bool validate,
					    bool updateStats)
{
	OperationContext &oc = context.getOperationContext();
	DocID id = new_document.getID();
	Indexer &indexer = context.getIndexer();
	IndexSpecification &index = context.getIndexSpecification();
	int err = 0;
	bool resetId = false;

	// Add DB_RMW if transacted to reduce deadlocks
	u_int32_t flags =  ((oc.txn() && !content_.isCDBEnv()) ? DB_RMW : 0);
	
	// Check to see if the old document exists, first
	// If ID is non-zero, let's trust it.  If not, get by name.
	// Retrieve the old document
	XmlDocument old_document;
	if (id == 0) {
		// will throw if name is bad or doc doesn't exist
		err = indexer.getContainer()->getDocument(
			oc, new_document.getName(), old_document, flags);
		if (err == 0) {
			id = ((Document&)old_document).getID();
			new_document.getIDToSet() = id;
			resetId = true;
		}
	} else {
		err = indexer.getContainer()->getDocument(
			oc, id, old_document, flags);
	}
	if(err != 0) return err;
	
	// Index the new document
	indexer.indexMetaData(index, new_document, stash, true);
	if(new_document.isContentModified()) {
		// Will need the Dbt later, so get it now.  This also
		// allows the content to be used more than once in case
		// definitiveContent_ is INPUTSTREAM
		(void) new_document.getContentAsDbt();
		// use private method that explicitly assumes Dbt content
		ScopedPtr<NsPushEventSource>
			source(new_document.dbt2events(
				       oc.txn(), /*needsValidation*/validate,
				       indexer.getContainer()->nodesIndexed()));
		if (source.get()) {
			indexer.initIndexContent(index, id,
				source.get(), stash, updateStats,
				true, /*isDelete*/false);
			source.get()->start();
		}
	}

	// Set the modified flags of the old document to the same as the
	// new document, so that when we index, we only generate keys for
	// things that have actually changed.
	MetaData::const_iterator end = new_document.metaDataEnd();
	for(MetaData::const_iterator i = new_document.metaDataBegin();
	    i != end; ++i) {
		if((*i)->isModified()) {
			const MetaDatum *md = ((Document&)old_document)
				.getMetaDataPtr((*i)->getName());
			if(md != 0) const_cast<MetaDatum*>(md)->setModified(true);
		}
	}

	// Remove the index keys for the old document
	IndexSpecification delete_index(index);
	delete_index.set(Index::INDEXER_DELETE);
	indexer.indexMetaData(delete_index, old_document, stash, true);
	if(new_document.isContentModified()) {
		ScopedPtr<NsPushEventSource>
			source(((Document&)old_document).
			       getContentAsEventSource(
				       oc.txn(),
				       /*needsValidation*/false,
				       indexer.getContainer()->nodesIndexed()));
		if (source.get()) {
			indexer.initIndexContent(delete_index, id,
				source.get(), stash, updateStats,
				false, /*isDelete*/true);
			source.get()->start();
		}
	}

	// Update the content
	if(new_document.isContentModified()) {
		OperationContext &oc = context.getOperationContext();
		id.setDbtFromThis(oc.key());
		DbXmlDbt *dbt = (DbXmlDbt*)new_document.getContentAsDbt();
		err = addContent(oc.txn(), oc.key(),dbt, 0);
	}

	if(err == 0) new_document.setContentModified(false);
	if (resetId)
		new_document.getIDToSet() = 0;
	return err;
}