MojErr MojDbSandwichDatabase::update(const MojObject& id, MojBuffer& val, MojDbStorageItem* oldVal, MojDbStorageTxn* txn) { LOG_TRACE("Entering function %s", __FUNCTION__); MojAssert(oldVal && txn); MojErr err = txn->offsetQuota(-(MojInt64) oldVal->size()); MojErrCheck(err); // add/replace with a new one err = put(id, val, txn, false); MojErrCheck(err); return MojErrNone; }
MojErr MojDbServiceHandler::handleFind(MojServiceMessage* msg, MojObject& payload, MojDbReq& req) { MojAssert(msg); MojLogTrace(s_log); bool doCount = false; payload.get(MojDbServiceDefs::CountKey, doCount); MojDbCursor cursor; MojErr err = findImpl(msg, payload, req, cursor, doCount); MojErrCheck(err); return MojErrNone; }
MojErr MojService::dispatchCancel(MojServiceMessage* msg) { MojAssert(msg); MojAssertMutexUnlocked(m_mutex); MojLogTrace(s_log); SubscriptionKey key; MojErr err = key.init(msg); MojErrCheck(err); err = dispatchCancel(key); MojErrCheck(err); return MojErrNone; }
MojErr MojDbServiceHandler::handleBatch(MojServiceMessage* msg, MojObject& payload, MojDbReq& req) { MojAssert(msg); MojLogTrace(s_log); MojObject operations; MojErr err = payload.getRequired(MojDbServiceDefs::OperationsKey, operations); MojErrCheck(err); MojObject::ArrayIterator begin; err = operations.arrayBegin(begin); MojErrCheck(err); //start the response array MojObjectVisitor& writer = msg->writer(); err = writer.beginObject(); MojErrCheck(err); err = writer.boolProp(MojServiceMessage::ReturnValueKey, true); MojErrCheck(err); err = writer.propName(MojDbServiceDefs::ResponsesKey); MojErrCheck(err); err = writer.beginArray(); MojErrCheck(err); for (MojObject* i = begin; i != operations.arrayEnd(); ++i) { MojString method; err = i->getRequired(MojDbServiceDefs::MethodKey, method); MojErrCheck(err); MojObject params; err = i->getRequired(MojDbServiceDefs::ParamsKey, params); MojErrCheck(err); // not allowed to specify watch key in a batch bool watchValue = false; if (payload.get(MojDbServiceDefs::WatchKey, watchValue) && watchValue) { MojErrThrow(MojErrDbInvalidBatch); } DbCallback cb; if (!m_batchCallbacks.get(method, cb)) { MojErrThrow(MojErrDbInvalidBatch); } err = (this->*cb)(msg, params, req); MojErrCheck(err); } err = writer.endArray(); MojErrCheck(err); err = writer.endObject(); MojErrCheck(err); return MojErrNone; }
MojErr MojDbSearchCursor::sort() { LOG_TRACE("Entering function %s", __FUNCTION__); MojAssert(!m_orderProp.empty()); // TODO: instead of parsing all objects, find the serialized field in the object and compare it directly // create extractor for sort prop MojRefCountedPtr<MojDbTextCollator> collator(new MojDbTextCollator); MojAllocCheck(collator.get()); // TODO: use real locale //MojErr err = collator->init(_T(""), MojDbCollationPrimary); MojErr err = MojErrNone; // set locale MojString locale = m_locale; if(m_dbIndex) { locale = m_dbIndex->locale(); } // set collate MojDbCollationStrength coll = m_collation; if (coll == MojDbCollationInvalid) { // default setting is primary coll = MojDbCollationPrimary; } err = collator->init(locale, coll); MojErrCheck(err); MojDbPropExtractor extractor; extractor.collator(collator.get()); err = extractor.prop(m_orderProp); MojErrCheck(err); // create sort keys MojDbKeyBuilder builder; ItemVec::Iterator begin; err = m_items.begin(begin); MojErrCheck(err); for (ItemVec::Iterator i = begin; i != m_items.end(); ++i) { KeySet keys; err = extractor.vals((*i)->obj(), keys); MojErrCheck(err); (*i)->sortKeys(keys); } // sort err = m_items.sort(); MojErrCheck(err); return MojErrNone; }
MojErr MojDbIndex::cancelWatch(MojDbWatcher* watcher) { MojAssert(isOpen()); MojAssert(watcher); MojLogTrace(s_log); MojLogInfo(s_log, _T("Index_cancelWatch: index name = %s; domain = %s\n"), this->name().data(), watcher->domain().data()); MojThreadWriteGuard guard(m_lock); MojSize idx; MojSize size = m_watcherVec.size(); for (idx = 0; idx < size; ++idx) { if (m_watcherVec.at(idx).get() == watcher) { MojErr err = m_watcherVec.erase(idx); MojErrCheck(err); WatcherMap::Iterator iter; err = m_watcherMap.find(watcher->domain(), iter); MojErrCheck(err); if (iter != m_watcherMap.end()) { iter.value() -= 1; if (iter.value() == 0) { bool found = false; m_watcherMap.del(iter.key(), found); MojAssert(found); MojLogInfo(s_log, _T("Index_cancelwatch: Domain Del found = %d; index name = %s; domain = %s\n"), (int)found, this->name().data(), watcher->domain().data()); } } break; } } if (idx == size) MojErrThrow(MojErrDbWatcherNotRegistered); return MojErrNone; }
MojErr MojDbSandwichEngine::open(const MojChar* path) { MojAssert(path); MojAssert(m_env.get()); MojAssert(!m_isOpen); MojErr err; err = m_path.assign(path); MojErrCheck(err); // TODO: We should get this options from ENV m_db->options = MojDbSandwichEngine::getOpenOptions(); m_db->writeOptions = MojDbSandwichEngine::getWriteOptions(); m_db->readOptions = MojDbSandwichEngine::getReadOptions(); leveldb::Status status = m_db->Open(path); MojLdbErrCheck(status, _T("db_create/db_open")); // open seqence db m_seqDb.reset(new MojDbSandwichDatabase(m_db.use(MojEnvSeqDbName))); MojAllocCheck(m_seqDb.get()); err = m_seqDb->open(MojEnvSeqDbName, this); MojErrCheck(err); // open index db m_indexDb.reset(new MojDbSandwichDatabase(m_db.use(MojEnvIndexDbName))); MojAllocCheck(m_indexDb.get()); err = m_indexDb->open(MojEnvIndexDbName, this); MojErrCheck(err); m_isOpen = true; return MojErrNone; }
MojErr MojDbIndex::cancelWatch(MojDbWatcher* watcher) { LOG_TRACE("Entering function %s", __FUNCTION__); MojAssert(isOpen()); MojAssert(watcher); LOG_DEBUG("[db_mojodb] Index_cancelWatch: index name = %s; domain = %s\n", this->name().data(), watcher->domain().data()); MojThreadWriteGuard guard(m_lock); MojSize idx; MojSize size = m_watcherVec.size(); for (idx = 0; idx < size; ++idx) { if (m_watcherVec.at(idx).get() == watcher) { MojErr err = m_watcherVec.erase(idx); MojErrCheck(err); WatcherMap::Iterator iter; err = m_watcherMap.find(watcher->domain(), iter); MojErrCheck(err); if (iter != m_watcherMap.end()) { iter.value() -= 1; if (iter.value() == 0) { bool found = false; m_watcherMap.del(iter.key(), found); MojAssert(found); LOG_DEBUG("[db_mojodb] Index_cancelwatch: Domain Del found = %d; index name = %s; domain = %s\n", (int)found, this->name().data(), watcher->domain().data()); } } break; } } if (idx == size) MojErrThrow(MojErrDbWatcherNotRegistered); return MojErrNone; }
MojErr MojService::cancel(MojServiceRequest* req) { MojAssert(req); MojAssertMutexUnlocked(m_mutex); MojLogTrace(s_log); bool found = false; MojErr err = removeRequest(req, found); MojErrCheck(err); if (found) { err = cancelImpl(req); MojErrCheck(err); } return MojErrNone; }
MojErr MojDbSandwichDatabase::open(const MojChar* dbName, MojDbSandwichEngine* eng) { LOG_TRACE("Entering function %s", __FUNCTION__); MojAssert(dbName && eng); // save eng and name m_engine = eng; MojErr err = m_name.assign(dbName); MojErrCheck(err); if (engine()->lazySync()) engine()->getUpdater()->open( getDb() ); return MojErrNone; }
MojErr MojDbTestStorageTxn::commitImpl() { MojErr err = m_testEngine->checkErrMap(_T("txn.commit")); if (err != MojErrNone) { MojErr errAbort = m_txn->abort(); MojErrCheck(errAbort); return err; } MojAssert(m_txn.get()); err = m_txn->commit(); MojErrCheck(err); return MojErrNone; }
MojErr MojGmainReactor::addSock(MojSockT sock) { MojAssert(sock != MojInvalidSock); MojAssert(m_mainLoop.get()); MojThreadGuard guard(m_mutex); MojAssert(!m_sources.contains(sock)); // alloc info and source SourcePtr source; MojErr err = source.resetChecked((Source*) g_source_new(&s_sourceFuncs, sizeof(Source))); MojErrCheck(err); source->m_info = new SockInfo(sock, m_mutex); MojAllocCheck(source->m_info); source->m_info->retain(); // add to vec err = m_sources.put(sock, source); MojErrCheck(err); // attach g_source_attach(source.get(), g_main_loop_get_context(m_mainLoop.get())); g_source_add_poll(source.get(), &source->m_info->m_pollFd); return MojErrNone; }
MojErr MojService::dispatchRequest(MojServiceMessage* msg) { MojAssert(msg); MojAssertMutexUnlocked(m_mutex); MojLogTrace(s_log); // get payload MojObject payload; MojErr reqErr; MojErr err = reqErr = msg->payload(payload); MojErrCatchAll(err) { return msg->replyError(reqErr); } // get callback Category* category = msg->serviceCategory(); MojAssert(category); MojAssert(category && category->m_service == this); // invoke err = reqErr = category->m_handler->invoke(msg->method(), msg, payload); MojErrCatchAll(err) { MojString payloadStr; (void) payload.toJson(payloadStr); MojString errStr; (void) MojErrToString(reqErr, errStr); MojLogError(s_log, _T("%s (%d) - sender='%s' method='%s' payload='%s'"), errStr.data(), (int) reqErr, msg->senderName(), msg->method(), payloadStr.data()); if (msg->numReplies() == 0) { return msg->replyError(reqErr); } } if (msg->numReplies() == 0 && msg->hasData()) { return msg->reply(); } return MojErrNone; }
MojErr MojDbKindState::writeObj(const MojChar* key, const MojObject& val, MojDbStorageDatabase* db, MojDbStorageTxn* txn, MojRefCountedPtr<MojDbStorageItem>& oldItem) { MojAssert(key && db && txn); MojAssertMutexLocked(m_lock); // reconstitute obj MojObject obj; if (oldItem.get()) { MojErr err = oldItem->toObject(obj, *m_kindEngine, false); MojErrCheck(err); } MojErr err = obj.put(key, val); MojErrCheck(err); // we directly use the storage engine apis because the higher-level apis depend on the kind state. MojBuffer buf; err = obj.toBytes(buf); MojErrCheck(err); txn->quotaEnabled(false); if (oldItem.get()) { err = db->update(m_kindId, buf, oldItem.get(), txn); MojErrCheck(err); } else { err = db->insert(m_kindId, buf, txn); MojErrCheck(err); // get old item so we can update it next time err = db->get(m_kindId, txn, false, oldItem); MojAssert(oldItem.get()); MojErrCheck(err); } txn->quotaEnabled(true); return MojErrNone; }
MojErr MojDbQuotaEngine::getUsage(const MojString& kindId, MojDbStorageTxn* txn, bool forUpdate, MojInt64& usageOut, MojRefCountedPtr<MojDbStorageItem>& itemOut) { MojAssert(txn); usageOut = 0; MojErr err = m_usageDb->get(kindId, txn, forUpdate, itemOut); MojErrCheck(err); if (itemOut.get()) { MojObject val; err = itemOut->toObject(val, *m_db->kindEngine(), false); MojErrCheck(err); usageOut = val.intValue(); } return MojErrNone; }
MojErr MojDecimal::assign(const MojChar* str, MojSize n) { MojAssert(str); MojNumber::Parser p; MojErr err; err = MojNumber::Lexer::parse(p, str, n); MojErrCheck( err ); err = p.toDecimal( *this ); MojErrCheck( err ); return MojErrNone; }
MojErr MojDbKind::openIndex(MojDbIndex* index, MojDbReq& req) { MojAssert(index); MojAssert(m_db); MojLogTrace(s_log); // construct storage index name MojString name; MojErr err = name.format(_T("%s-%d-%s"), m_name.data(), m_version, index->name().data()); MojErrCheck(err); // get id MojObject id; bool created = false; err = m_state->indexId(index->name(), req, id, created); MojErrCheck(err); // open MojRefCountedPtr<MojDbStorageIndex> storageIndex; err = m_db->openIndex(id, req.txn(), storageIndex); MojErrCheck(err); err = index->open(storageIndex.get(), id, req, created); MojErrCheck(err); return MojErrNone; }
MojErr MojDbServiceHandler::handleSearch(MojServiceMessage* msg, MojObject& payload, MojDbReq& req) { MojAssert(msg); MojLogTrace(s_log); MojString localeStr; MojErr err = m_db.getLocale(localeStr, req); MojErrCheck(err); MojDbSearchCursor cursor(localeStr); err = findImpl(msg, payload, req, cursor, true); MojErrCheck(err); return MojErrNone; }
MojErr MojSocketMessageParser::readFromSocket(MojSockT sock, MojRefCountedPtr<MojSocketMessage>& msgOut, bool& completeOut) { MojErr err = MojErrNone; MojAssert(sock != -1); completeOut = false; while (m_headerBytes < sizeof(m_header)) { MojInt32 sz = recv(sock, m_headerBuf+m_headerBytes, sizeof(m_header) - m_headerBytes, 0); MojParserRecvCheck(sz); m_headerBytes += sz; if (m_headerBytes == sizeof(m_header)) { MojDataReader reader(m_headerBuf, m_headerBytes); err = m_header.read(reader); MojErrCheck(err); m_messageData = new MojByte[m_header.messageLen()]; MojAllocCheck(m_messageData); } } while (m_messageBytesRead < m_header.messageLen()) { MojInt32 sz = recv(sock, m_messageData + m_messageBytesRead, m_header.messageLen() - m_messageBytesRead, 0); MojParserRecvCheck(sz); m_messageBytesRead += sz; } msgOut.reset(new MojSocketMessage); if (!msgOut.get()) { err = MojErrNoMem; MojErrGoto(err, done); } MojSize cbConsumed; err = msgOut->extract(m_messageData, m_header.messageLen(), cbConsumed); MojErrGoto(err, done); if (m_header.messageLen() != cbConsumed) { err = MojErrInvalidMsg; MojErrGoto(err, done); } completeOut = true; done: if (m_messageData) { delete[] m_messageData; m_messageData = NULL; } return err; }
MojErr MojSockAddr::fromPath(const MojChar* path) { MojAssert(path); MojSockAddrUnT addr; MojZero(&addr, sizeof(addr)); if (MojStrLen(path) > (sizeof(addr.sun_path) - 1)) MojErrThrow(MojErrPathTooLong); MojStrCpy(addr.sun_path, path); addr.sun_family = MOJ_PF_LOCAL; fromAddr((MojSockAddrT*) &addr, sizeof(addr)); return MojErrNone; }
MojErr MojDbSandwichEngine::removeSeq(MojDbSandwichSeq* seq) { MojAssert(seq); MojThreadGuard guard(m_dbMutex); MojSize idx; MojSize size = m_seqs.size(); for (idx = 0; idx < size; ++idx) { if (m_seqs.at(idx).get() == seq) { MojErr err = m_seqs.erase(idx); MojErrCheck(err); break; } } return MojErrNone; }
MojErr MojService::send(MojServiceRequest* req, const MojChar* service, const MojChar* method, Token& tokenOut) { MojAssert(req && service && method); MojAssertMutexUnlocked(m_mutex); MojLogTrace(s_log); // NOV-130089: sendImpl and addReqest must be atomic MojThreadGuard guard(m_mutex); MojErr err = sendImpl(req, service, method, tokenOut); MojErrCheck(err); err = addRequest(req); MojErrCheck(err); return MojErrNone; }
MojErr MojService::close() { MojLogTrace(s_log); // cancel all pending subscriptions MojErr err = MojErrNone; for (SubscriptionMap::ConstIterator i = m_subscriptions.begin(); i != m_subscriptions.end();) { SubscriptionKey key = (i++).key(); MojErr errClose = dispatchCancel(key); MojErrAccumulate(err, errClose); } // if you're hitting this assertion, you probably aren't releasing your message in your cancel handler MojAssert(m_subscriptions.empty()); return err; }
MojErr MojDbLevelIndex::open(const MojObject& id, MojDbLevelDatabase* db, MojDbStorageTxn* txn) { LOG_TRACE("Entering function %s", __FUNCTION__); MojAssert(db && db->engine()); m_id = id; // this is deprecated // m_db and m_primaryDb should point to the same object // leave both of them here more for debugging purposes m_db.reset(db->engine()->indexDb()); m_primaryDb.reset(db); return MojErrNone; }
MojErr MojDbKindState::readObj(const MojChar* key, MojObject& val, MojDbStorageDatabase* db, MojDbStorageTxn* txn, MojRefCountedPtr<MojDbStorageItem>& oldItem) { MojAssert(key && db); MojErr err = db->get(m_kindId, txn, false, oldItem); MojErrCheck(err); if (oldItem.get()) { // get objects MojObject obj; err = oldItem->toObject(obj, *m_kindEngine, false); MojErrCheck(err); obj.get(key, val); } return MojErrNone; }
MojErr MojGmainReactor::init() { #if !GLIB_CHECK_VERSION(2,32,0) // init glib threads - must be done BEFORE any other call to glib!!!! // glib >= 2.32.0 does this automatically if (!g_thread_supported()) { g_thread_init(NULL); } #endif /* GLIB_CHECK_VERSION */ MojAssert(!m_mainLoop.get()); m_mainLoop.reset(g_main_loop_new(NULL, false)); MojAllocCheck(m_mainLoop.get()); return MojErrNone; }
MojErr MojBuffer::write(const void* data, MojSize size) { MojAssert(data || size == 0); const MojByte* bytes = static_cast<const MojByte*>(data); while (size > 0) { Chunk* chunk; MojErr err = writeableChunk(chunk, size); MojErrCheck(err); MojSize chunkSize = MojMin(size, chunk->freeSpace()); chunk->write(bytes, chunkSize); bytes += chunkSize; size -= chunkSize; } return MojErrNone; }
const MojChar* MojMemChrReverse(const MojChar* data, MojChar c, MojSize len) { MojAssert(data || len == 0); if (data == NULL) return NULL; const MojChar* endPtr = data; const MojChar* p = endPtr + len - 1; while (p >= endPtr) { if (*p == c) { return p; } --p; } return NULL; }
MojErr MojDbKindEngine::reloadKind(const MojString& id, const MojObject& kindObj, MojDbReq& req) { MojAssert(isOpen()); MojAssertWriteLocked(m_db->m_schemaLock); MojLogTrace(s_log); // delete old one bool found = false; MojErr err = m_kinds.del(id, found); MojErrCheck(err); // replace with new one err = createKind(id, kindObj, req); MojErrCheck(err); return MojErrNone; }
MojErr MojSockSetNonblocking(MojSockT sock, bool val) { MojAssert(sock != MojInvalidSock); int flags = fcntl(sock, F_GETFL, 0); if (flags < 0) MojErrThrowErrno(_T("fcntl")); if (val) flags |= O_NONBLOCK; else flags &= ~O_NONBLOCK; if (fcntl(sock, F_SETFL, flags) < 0) MojErrThrowErrno(_T("fcntl")); return MojErrNone; }