MojErr MojDbPurgeTest::checkObjectsPurged(MojDb& db, const MojUInt32& count, const MojSize& expectedCount, const MojSize& expectedNumObjects, const MojSize& expectedNumRevTimestampObjects, const MojObject& expectedLastPurgeRevNum) { //check number of objects purged MojTestAssert(count == expectedCount); //there should still be expectedNumObjects test objects MojDbQuery query; MojErr err = query.from(_T("PurgeTest:1")); MojTestErrCheck(err); MojDbCursor cursor; err = db.find(query, cursor); MojTestErrCheck(err); MojUInt32 objCount; err = cursor.count(objCount); MojTestErrCheck(err); err = cursor.close(); MojTestErrCheck(err); MojTestAssert(objCount == expectedNumObjects); //there should be expectedNumRevTimestampObjects RevTimestamp objects MojDbQuery revQuery; err = revQuery.from(MojDbKindEngine::RevTimestampId); MojTestErrCheck(err); MojDbCursor revCursor; err = db.find(revQuery, revCursor); MojTestErrCheck(err); MojUInt32 revTimestampObjCount; err = revCursor.count(revTimestampObjCount); MojTestErrCheck(err); err = revCursor.close(); MojTestErrCheck(err); MojTestAssert(revTimestampObjCount == expectedNumRevTimestampObjects); //lastPurgedRevNum should be equal to the expectedLastPurgeRevNum MojObject revNum; err = db.purgeStatus(revNum); MojTestErrCheck(err); MojTestAssert(revNum == expectedLastPurgeRevNum); return MojErrNone; }
void checkCount() { MojDbQuery query; MojAssertNoErr( query.from(_T("LoadTest:1")) ); MojDbCursor cursor; MojAssertNoErr( db.find(query, cursor) ); MojUInt32 count = 0; MojAssertNoErr( cursor.count(count) ); EXPECT_EQ( 10LL, count ); }
MojErr MojDbServiceHandler::findImpl(MojServiceMessage* msg, MojObject& payload, MojDbReq& req, MojDbCursor& cursor, bool doCount) { MojAssert(msg); MojLogTrace(s_log); MojObject queryObj; MojErr err = payload.getRequired(MojDbServiceDefs::QueryKey, queryObj); MojErrCheck(err); bool doWatch = false; payload.get(MojDbServiceDefs::WatchKey, doWatch); MojDbQuery query; err = query.fromObject(queryObj); MojErrCheck(err); MojUInt32 limit = query.limit(); if (limit == MojDbQuery::LimitDefault){ query.limit(MaxQueryLimit); } else if (limit > MaxQueryLimit) { MojErrThrowMsg(MojErrDbInvalidQuery, _T("db: limit greater than %d not allowed"), MaxQueryLimit); } if (doWatch) { MojRefCountedPtr<Watcher> watcher(new Watcher(msg)); MojAllocCheck(watcher.get()); err = m_db.find(query, cursor, watcher->m_watchSlot, req); MojErrCheck(err); } else { err = m_db.find(query, cursor, req); MojErrCheck(err); } // append results MojObjectVisitor& writer = msg->writer(); err = writer.beginObject(); MojErrCheck(err); err = writer.boolProp(MojServiceMessage::ReturnValueKey, true); MojErrCheck(err); err = writer.propName(MojDbServiceDefs::ResultsKey); MojErrCheck(err); err = writer.beginArray(); MojErrCheck(err); err = cursor.visit(writer); MojErrCheck(err); err = writer.endArray(); MojErrCheck(err); // append next page MojDbQuery::Page page; err = cursor.nextPage(page); MojErrCheck(err); if (!page.empty()) { MojObject pageObj; err = page.toObject(pageObj); MojErrCheck(err); err = writer.objectProp(MojDbServiceDefs::NextKey, pageObj); MojErrCheck(err); } // append count if (doCount) { MojUInt32 count = 0; err = cursor.count(count); MojErrCheck(err); err = writer.intProp(MojDbServiceDefs::CountKey, (MojInt64) count); MojErrCheck(err); } err = writer.endObject(); MojErrCheck(err); if (doWatch) { // if this is a watched query, it cannot be part of a batch so it's safe to reply here err = msg->reply(); MojErrCheck(err); } // notifications can fire any time after the cursor is closed, // so don't close it until after sending the reply. err = cursor.close(); MojErrCheck(err); return MojErrNone; }
MojErr MojDbPurgeTest::delKindTest(MojDb& db) { // start from scratch - purge everything MojUInt32 count = 0; MojErr err = db.purge(count, 0); MojTestErrCheck(err); MojTestAssert(count > 0); // purge again, make sure nothing is left err = db.purge(count, 0); MojTestErrCheck(err); MojTestAssert(count == 0); // make sure at least 2 objects exist MojDbQuery q; err = q.from(_T("PurgeTest:1")); MojTestErrCheck(err); MojDbCursor cursor; err = db.find(q, cursor); MojTestErrCheck(err); MojUInt32 objCount; err = cursor.count(objCount); MojTestErrCheck(err); err = cursor.close(); MojTestErrCheck(err); if (objCount <= 1) { for (int i = objCount; i < 2; i++) { MojObject obj; err = obj.fromJson(MojTestObjStr1); MojTestErrCheck(err); err = db.put(obj); MojTestErrCheck(err); objCount++; } } // delete half the objects q.limit(objCount / 2); MojUInt32 delCount; err = db.del(q, delCount); MojTestErrCheck(err); // delete the kind MojString idStr; err = idStr.assign(_T("PurgeTest:1")); MojTestErrCheck(err); MojObject id(idStr); bool found; err = db.delKind(id, found); MojTestErrCheck(err); MojTestAssert(found); /*MojUInt32 deletedObjCount; err = q.where(_T("_del"), MojDbQuery::OpEq, true); MojTestErrCheck(err); q.includeDeleted(true); err = db.find(q, cursor); MojTestErrCheck(err); err = cursor.count(deletedObjCount); MojTestErrCheck(err); err = cursor.close(); MojTestErrCheck(err); // now all the objects should be deleted MojTestAssert(deletedObjCount == objCount);*/ // purge now err = db.purge(count, 0); MojTestErrCheck(err); return MojErrNone; }
MojErr MojDb::dump(const MojChar* path, MojUInt32& countOut, bool incDel, MojDbReqRef req, bool backup, MojUInt32 maxBytes, const MojObject* incrementalKey, MojObject* backupResponse) { MojAssert(path); MojLogTrace(s_log); MojErr err = beginReq(req); MojErrCheck(err); if (!req->admin()) { MojLogError(s_log, _T("access denied: '%s' cannot dump db to path: '%s'"), req->domain().data(), path); MojErrThrow(MojErrDbAccessDenied); } MojFile file; err = file.open(path, MOJ_O_WRONLY | MOJ_O_CREAT | MOJ_O_TRUNC, MOJ_S_IRUSR | MOJ_S_IWUSR); MojErrCheck(err); // write out kinds first, then existing objects, then deleted objects MojSize bytesWritten = 0; MojSize totalwarns = 0; MojSize newwarns = 0; MojDbQuery objQuery; MojVector<MojObject> kindVec; MojObject revParam = -1; MojObject delRevParam = -1; // if we were given an incremental key, pull out the revs now if (incrementalKey) { incrementalKey->get(MojDbServiceDefs::RevKey, revParam); incrementalKey->get(MojDbServiceDefs::DeletedRevKey, delRevParam); } err = m_kindEngine.getKinds(kindVec); MojErrCheck(err); // write kinds - if incremental, only write the kinds that have changed since the respective revs MojString countStr; for (MojVector<MojObject>::ConstIterator i = kindVec.begin(); i != kindVec.end(); ++i) { if (backup) { bool backupKind = false; i->get(MojDbKind::SyncKey, backupKind); if (!backupKind) continue; MojString id; err = i->getRequired(MojDbServiceDefs::IdKey, id); MojErrCheck(err); MojDbQuery countQuery; err = countQuery.from(id); MojErrCheck(err); MojDbCursor cursor; err = find(countQuery, cursor, req); MojErrCheck(err); MojUInt32 count = 0; err = cursor.count(count); MojErrCheck(err); if (count > 0) { if (i != kindVec.begin()) { err = countStr.appendFormat(_T(", ")); MojErrCheck(err); } err = countStr.appendFormat("%s=%u", id.data(), count); MojErrCheck(err); } } bool deleted = false; i->get(DelKey, deleted); MojObject kindRev; err = i->getRequired(RevKey, kindRev); MojErrCheck(err); if ((deleted && kindRev > delRevParam) || (!deleted && kindRev > revParam)) { err = dumpObj(file, (*i), bytesWritten, maxBytes); MojErrCheck(err); countOut++; } } // dump all the non-deleted objects err = dumpImpl(file, backup, false, revParam, delRevParam, true, countOut, req, backupResponse, MojDbServiceDefs::RevKey, bytesWritten, newwarns, maxBytes); MojErrCheck(err); totalwarns += newwarns; // If we're supposed to include deleted objects, dump the deleted objects now. // There's a chance that we may have run out of space in our backup. If that's the case, // we don't want to try to dump deleted objects - we can detect this by looking for the HasMoreKey if (incDel && backupResponse && !backupResponse->contains(MojDbServiceDefs::HasMoreKey)) { err = dumpImpl(file, backup, true, revParam, delRevParam, false, countOut, req, backupResponse, MojDbServiceDefs::DeletedRevKey, bytesWritten, newwarns, maxBytes); MojErrCheck(err); } totalwarns += newwarns; // Add the Full and Version keys if (backup && backupResponse) { bool incremental = (incrementalKey != NULL); err = backupResponse->putBool(MojDbServiceDefs::FullKey, !incremental); MojErrCheck(err); err = backupResponse->put(MojDbServiceDefs::VersionKey, DatabaseVersion); MojErrCheck(err); err = backupResponse->put(MojDbServiceDefs::WarningsKey, (MojInt32)totalwarns); MojErrCheck(err); MojString description; err = description.format(_T("incremental=%u"), countOut); MojErrCheck(err); if (!countStr.empty()) { err = description.appendFormat(_T(", %s"), countStr.data()); MojErrCheck(err); } err = backupResponse->put(_T("description"), description); MojErrCheck(err); } err = req->end(); MojErrCheck(err); return MojErrNone; }