bool DictionaryDatabase::stringCacheLookup(OperationContext &context, DbXmlDbt &dbt, NameID &id) const { nameId_t *nid = 0; Transaction *txn = getTxn(context); if (txn) { DictionaryStringCache *dsc = txn->getStringCache(const_cast<DictionaryDatabase*>(this), false); if (dsc) { nid = dsc->lookup(&dbt); if (nid) { DbXmlDbt dbt((void *)nid, sizeof(nameId_t)); id.setThisFromDbtAsId(dbt); return true; } } } nid = stringCache_.lookup(&dbt); if (nid) { DbXmlDbt tdbt((void *)nid, sizeof(nameId_t)); id.setThisFromDbtAsId(tdbt); return true; } return false; }
int DictionaryDatabase::lookupIDFromName(OperationContext &context, const Name &name, NameID &id, bool define) { int err = 0; if (name == Name::dbxml_colon_name) { id = nidName_; } else if (name == Name::dbxml_colon_root) { id = nidRoot_; } if (id == 0) { MutexLock ml(mutex_); u_int32_t flags = (getTxn(context) && !define) ? DB_READ_COMMITTED : 0; name.setDbtFromThis_SecondaryKey(context.key()); if (stringCacheLookup(context, context.key(), id)) return 0; err = secondary_->get(getTxn(context), &context.key(), &context.data(), flags); if (err == 0) { id.setThisFromDbt(context.data()); stringCache_.insert(&context.key(), id.raw()); } else if (err == DB_NOTFOUND && define) { err = defineName(context, name, id); // define from name:uri } else { id.reset(); } } return err; }
void DictionaryDatabase::display(OperationContext &context, ostream &out) const { { Cursor myCursor(const_cast<PrimaryDatabase&>(*primary_.get()), getTxn(context), CURSOR_READ, 0); if(myCursor.error() != 0) throw XmlException(myCursor.error()); int err = 0; NameID id; while((err = myCursor.get(context.key(), context.data(), DB_NEXT)) == 0) { id.setThisFromDbtAsId(context.key()); Buffer val(context.data().data, context.data().size, true); out << id << " -> " << val.asString(true) << endl; } } { Cursor myCursor(const_cast<SecondaryDatabase&>(*secondary_.get()), getTxn(context), CURSOR_READ, 0); if(myCursor.error() != 0) throw XmlException(myCursor.error()); int err = 0; NameID id; while((err = myCursor.get(context.key(), context.data(), DB_NEXT)) == 0) { Buffer val(context.key().data, context.key().size, true); id.setThisFromDbt(context.data()); out << val.asString(true) << " -> " << id << endl; } } }
static void unmarshalKey(const DbtOut &dbt, NameID &id1, NameID &id2) { const xmlbyte_t *ptr = (const xmlbyte_t*)dbt.data; const xmlbyte_t *end = ptr + dbt.size; ++ptr; // Skip the prefix if(ptr < end) ptr += id1.unmarshal(ptr); if(ptr < end) ptr += id2.unmarshal(ptr); }
static void marshalKey(const NameID &id1, const NameID &id2, DbtOut &dbt) { DBXML_ASSERT(id1 != 0 || id2 == 0); int size = 1; if(id1 != 0) size += id1.marshalSize(); if(id2 != 0) size += id2.marshalSize(); dbt.set(0, size); xmlbyte_t *ptr = (xmlbyte_t*)dbt.data; *ptr++ = KEY_PREFIX_BYTE; if(id1 != 0) ptr += id1.marshal(ptr); if(id2 != 0) ptr += id2.marshal(ptr); }
int DictionaryDatabase::lookupNameFromID(OperationContext &context, const NameID &id, Name &name) const { int err = 0; nameId_t raw = id.raw() - 1; // id space is 1-based, not 0 if (id == nidName_) { name = Name::dbxml_colon_name; return 0; } else if (id == nidRoot_) { name = Name::dbxml_colon_root; return 0; } if ((raw < DICTIONARY_RESERVE_SIZE) && usePreloads_) { name = preloadNames[raw]; } else { err = lookupFromID(context, context.data(), id); if (err == 0) { name.setThisFromDbt(context.data()); } else { name.reset(); } } return err; }
// Basic lookup, returning a pointer that will be valid // until this object is deleted. Lookup does not require locking // because entries are never removed, and they are only added // at the beginning of the hash chain with a simple pointer update. // A race condition could theoretically happen if a compiler reorders // some of the code in insert bool DictionaryCache::lookup(OperationContext &context, const NameID &id, DbtOut &dbt, bool useDictionary) { while (true) { // will only ever loop once nameId_t nid = id.raw(); int bucket = hash(nid); DictionaryCacheEntry *current = htable_[bucket]; while (current && (current->getNid() != nid)) current = current->getNext(); if (current) { dbt.set(current->getValue(), current->getLen()); return true; } if (!useDictionary) return false; // read through the dictionary int ret = ddb_->lookupStringNameFromID(context, id, dbt); if (ret == 0) { DBXML_ASSERT(dbt.size); insert(nid, dbt); } else { // this should never happen, but if it does, // be silent (for now) return false; } } }
int PrimaryDatabase::appendPrimary(OperationContext &context, NameID &id, const DbXmlDbt &data, u_int32_t flags) { int err = put(context.txn(), &context.key(), &(const_cast<DbXmlDbt&>(data)), flags | DB_APPEND); if (err == 0) id.setThisFromDbtAsId(context.key()); return err; }
// puts result in dbt, which may be context.data(), or may be user-provided int DictionaryDatabase::lookupFromID( OperationContext &context, DbtOut &dbt, const NameID &id) const { int err = 0; if (cache_.lookup(context, id, dbt, false)) return 0; u_int32_t flags = (getTxn(context)) ? DB_READ_COMMITTED : 0; // primary key is the integer value of the id (database is // recno) id.setDbtFromThisAsId(context.key()); MutexLock ml(mutex_); err = primary_->get(getTxn(context), &context.key(), &dbt, flags); if (err == 0) cache_.insert(id.raw(), dbt); return err; }
// mutex is locked if present and necessary int DictionaryDatabase::defineStringName(OperationContext &context, const char *name, size_t namelen, NameID &id) { // Primary { id -> name\0 } // Secondary { name -> id } int err = 0; id.reset(); DbtIn primaryData((void*)name, namelen + 1); // add null DbtIn secondaryKey((void*)name, namelen); // don't add null err = primary_->appendPrimary(context, id, primaryData, /*no flags*/0); if (err == 0) { /* Cache after insert. This prevents the cache from returning bad answers * on a transaction abort, and speeds up access to newly inserted element * and attribute names that are needed for indexing after an insert. */ cache_.insert(id.raw(), primaryData); id.setDbtFromThis(context.key()); Transaction *txn = getTxn(context); err = secondary_->put(txn, &secondaryKey, &context.key(), /*no flags*/0); if (err == 0) { /* Add to the transaction's string cache, that way if an abort occurs * the values can be removed from the cache. */ if (txn) { DictionaryStringCache *dsc = txn->getStringCache(this, true); dsc->insert(&secondaryKey, id.raw()); } if (Log::isLogEnabled(Log::C_DICTIONARY, Log::L_INFO)) { ostringstream oss; oss << "Define new name " << id << " -> " << name; Log::log(environment_, Log::C_DICTIONARY, Log::L_INFO, name_.c_str(), oss.str().c_str()); } } } return err; }
int DictionaryDatabase::lookupIDFromStringNameInternal( OperationContext &context, DbXmlDbt &dbt, NameID &id, bool define) const { if (!dbt.size) { id.reset(); return 0; } u_int32_t flags = (getTxn(context) && !define) ? DB_READ_COMMITTED : 0; if (stringCacheLookup(context, dbt, id)) return 0; int err = secondary_->get(getTxn(context), &dbt, &context.data(), flags); if (err == 0) { id.setThisFromDbt(context.data()); stringCache_.insert(&dbt, id.raw()); } else id.reset(); return err; }
int DictionaryDatabase::lookupStringNameFromID( OperationContext &context, const NameID &id, DbtOut &dbt) const { int err = 0; nameId_t raw = id.raw() - 1; // id space is 1-based, not 0 if ((raw < DICTIONARY_RESERVE_SIZE) && usePreloads_) { const char *name = preloadNames[raw]; dbt.set((const void *)name, ::strlen(name) + 1); } else err = lookupFromID(context, dbt, id); return err; }
int DictionaryDatabase::lookupStringNameFromID( OperationContext &context, const NameID &id, const char **name) const { int err = 0; nameId_t raw = id.raw() - 1; // id space is 1-based, not 0 if ((raw < DICTIONARY_RESERVE_SIZE) && usePreloads_) { *name = preloadNames[raw]; } else { err = lookupFromID(context, context.data(), id); if (err == 0) *name = (const char *)context.data().data; } return err; }
// use DB prefix iterator to remove all index entries for the specified index. // do both index and statistics databases. // The prefix is <indexKeyPrefix>[<nameId>] int SyntaxDatabase::removeIndex(OperationContext &context, const Index &index, const NameID &id) { // key is <indexType><name ID>, which is one byte plus a marshaled integer. unsigned char keybuf[10]; keybuf[0] = index.getKeyPrefix(); u_int32_t sz = 1; if (id != 0) { // not a default index sz += id.marshal(keybuf+1); } int err = removeIndexEntries(context, *index_.get(), keybuf, sz); if (err == 0) err = removeIndexEntries(context, *statistics_.get(), keybuf, sz); return err; }
int PrimaryDatabase::getPrimary(OperationContext &context, const NameID &id, DbtOut *data, u_int32_t flags) const { id.setDbtFromThis(context.key()); return get(context.txn(), &context.key(), data, flags); }
int PrimaryDatabase::deletePrimary(OperationContext &context, const NameID &id, u_int32_t flags) { id.setDbtFromThis(context.key()); return del(context.txn(), &context.key(), flags); }
int PrimaryDatabase::putPrimary(OperationContext &context, const NameID &id, const DbXmlDbt &data, u_int32_t flags) { id.setDbtFromThis(context.key()); return put(context.txn(), &context.key(), &(const_cast<DbXmlDbt&>(data)), flags); }