Exemplo n.º 1
0
MojErr MojDbServiceHandler::handleWatch(MojServiceMessage* msg, MojObject& payload, MojDbReq& req)
{
	MojAssert(msg);
	MojLogTrace(s_log);

	MojObject queryObj;
	MojErr err = payload.getRequired(MojDbServiceDefs::QueryKey, queryObj);
	MojErrCheck(err);
	
	MojRefCountedPtr<Watcher> watcher(new Watcher(msg));
	MojAllocCheck(watcher.get());

	MojDbQuery query;
	err = query.fromObject(queryObj);
	MojErrCheck(err);
	bool fired = false;
	MojDbCursor cursor;
	err = m_db.watch(query, cursor, watcher->m_watchSlot, fired, req);
	MojErrCheck(err);

	MojLogInfo(s_log, _T("handleWatch: %s, err: (%d); sender= %s;\n fired=%d; \n"),
				msg->method(), (int)err, msg->senderName(), (int)fired);

	if (!fired) {
		err = msg->replySuccess();
		MojErrCheck(err);
	}

	err = cursor.close();
	MojErrCheck(err);

	return MojErrNone;
}
Exemplo n.º 2
0
MojErr MojDb::watch(const MojDbQuery& query, MojDbCursor& cursor, WatchSignal::SlotRef watchHandler, bool& firedOut, MojDbReqRef req)
{
	MojLogTrace(s_log);

	firedOut = false;

	MojErr err = beginReq(req);
	MojErrCheck(err);

	MojRefCountedPtr<MojDbWatcher> watcher(new MojDbWatcher(watchHandler));
	MojAllocCheck(watcher.get());

	MojDbQuery limitedQuery = query;
	limitedQuery.limit(1);
	err = findImpl(limitedQuery, cursor, watcher.get(), req, OpRead);
	MojErrCheck(err);

	MojDbStorageItem* item = NULL;
	bool found = false;
	cursor.verifymode(false);
	err = cursor.get(item, found);
	MojErrCheck(err);

	if (found) {
       const MojDbKey& key = cursor.storageQuery()->endKey();
       err = watcher->fire(key);
       MojErrCheck(err);
       firedOut = true;
	}

	err = req->end(false);
	MojErrCheck(err);

	return MojErrNone;
}
Exemplo n.º 3
0
MojErr MojDbPutHandler::open(const MojObject& conf, MojDb* db, MojDbReq& req)
{
    LOG_TRACE("Entering function %s", __FUNCTION__);
    MojAssertWriteLocked(db->schemaLock());

    m_db = db;
    // configure
    MojErr err = configure(conf, req);
    MojErrCheck(err);
    // load permissions from db
    MojDbQuery query;
    err = query.from(m_kindId);
    MojErrCheck(err);
    MojDbCursor cursor;
    err = db->find(query, cursor, req);
    MojErrCheck(err);
    for (;;) {
        bool found = false;
        MojObject perm;
        err = cursor.get(perm, found);
        MojErrCheck(err);
        if (!found)
            break;
        err = put(perm, req, false);
        MojErrCheck(err);
    }
    return MojErrNone;
}
Exemplo n.º 4
0
/**
 * verifyRecords
 */
MojErr MojDbShardManagerTest::verifyRecords (const MojChar* strKind, MojDb& db, const MojDbShardInfo&, MojUInt32& count)
{
    MojDbQuery query;
    MojDbCursor cursor;
    count = 0;

    MojErr err = query.from(strKind);
    MojErrCheck(err);

    err = db.find(query, cursor);
    MojErrCheck(err);

    while (true)
    {
        bool found;
        MojObject dbObj;

        err = cursor.get(dbObj, found);
        MojErrCheck(err);
        if (!found)
            break;

        ++count;
    }

    return MojErrNone;
}
Exemplo n.º 5
0
    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 );
    }
Exemplo n.º 6
0
MojErr MojDb::merge(const MojDbQuery& query, const MojObject& props, MojUInt32& countOut, MojUInt32 flags, MojDbReqRef req)
{
	MojLogTrace(s_log);

	countOut = 0;
	MojErr err = beginReq(req);
	MojErrCheck(err);

	MojDbCursor cursor;
	err = findImpl(query, cursor, NULL, req, OpUpdate);
	MojErrCheck(err);
	MojAssert(cursor.txn());

	MojUInt32 count = 0;
	MojUInt32 warns = 0;
	bool found = false;
	MojObject prev;
	for (;;) {
		// get prev rev from cursor
		MojDbStorageItem* prevItem = NULL;
		err = cursor.get(prevItem, found);
		if (err == MojErrInternalIndexOnFind) {
			warns++;
			continue;
		}
		MojErrCheck(err);
		if (!found)
			break;
		err = prevItem->toObject(prev, m_kindEngine);
		MojErrCheck(err);
		// merge obj into prev
		MojObject merged;
		err = mergeInto(merged, props, prev);
		MojErrCheck(err);
		// and update the db
		const MojObject& id = prevItem->id();
		err = putObj(id, merged, &prev, prevItem, req, OpUpdate);
		MojErrCheck(err);
		++count;
	}
	if (warns > 0)
		MojLogWarning(s_log, _T("Merge index_warnings: %s; count: %d\n"), query.from().data(), warns);
	err = cursor.close();
	MojErrCheck(err);
	err = req->end();
	MojErrCheck(err);

	countOut = count;

	return MojErrNone;
}
Exemplo n.º 7
0
MojErr MojDbWatchTest::cancelTest(MojDb& db)
{
    // cancel find
    MojDbQuery query;
    MojErr err = query.from(_T("WatchTest:1"));
    MojTestErrCheck(err);
    err = query.where(_T("foo"), MojDbQuery::OpLessThanEq, 45);
    MojTestErrCheck(err);
    MojRefCountedPtr<TestWatcher> watcher(new TestWatcher);
    MojTestAssert(watcher.get());
    watcher->m_slot.cancel();
    MojDbCursor cursor;
    err = db.find(query, cursor, watcher->m_slot);
    MojTestErrCheck(err);
    err = cursor.close();
    MojTestErrCheck(err);
    MojTestAssert(watcher->m_count == 0);
    watcher->m_slot.cancel();
    MojTestAssert(watcher->m_count == 0);
    MojObject id;
    err = put(db, 1, 1, id, m_rev);
    MojTestErrCheck(err);
    MojTestAssert(watcher->m_count == 0);
    // cancel watch
    watcher.reset(new TestWatcher);
    MojTestAssert(watcher.get());
    MojDbQuery queryWithRev;
    err = queryWithRev.from(_T("WatchTest:1"));
    MojTestErrCheck(err);
    err = queryWithRev.where(_T("foo"), MojDbQuery::OpEq, 45);
    MojTestErrCheck(err);
    err = queryWithRev.where(_T("_rev"), MojDbQuery::OpGreaterThan, m_rev);
    MojTestErrCheck(err);
    bool fired = false;
    err = db.watch(queryWithRev, cursor, watcher->m_slot, fired);
    MojTestErrCheck(err);
    err = cursor.close();
    MojTestErrCheck(err);
    MojTestAssert(!fired);
    MojTestAssert(watcher->m_count == 0);
    watcher->m_slot.cancel();
    MojTestAssert(watcher->m_count == 0);
    err = put(db, 45, 45, id, m_rev);
    MojTestErrCheck(err);
    MojTestAssert(watcher->m_count == 0);

    return MojErrNone;
}
Exemplo n.º 8
0
MojErr MojDbDistinctTest::simpleTest(MojDb& db)
{
	MojErr err;
	MojDbQuery query;
	const MojChar* queryString;
	const MojChar* expectedIdsJson;
    MojString str;
    MojDbSearchCursor searchCursor(str);
    MojDbCursor cursor;

	//1st test
	queryString = _T("bar");
	expectedIdsJson = _T("[\"a\",\"b\",\"c\",\"d\"]");
	err = initQuery(query, queryString);
	MojTestErrCheck(err);
    err = check(db, query, searchCursor, queryString, expectedIdsJson);
	MojTestErrCheck(err);
    searchCursor.close();

	//test for find
    err = check(db, query, cursor, queryString, expectedIdsJson);
    MojTestErrCheck(err);
    cursor.close();

	//2nd test
	queryString = _T("foo");
	expectedIdsJson = _T("[\"e\",\"f\",\"g\"]");
	err = initQuery(query, queryString);
	MojTestErrCheck(err);

    err = check(db, query, searchCursor, queryString, expectedIdsJson);
    MojTestErrCheck(err);
    searchCursor.close();

	//test for find
    err = check(db, query, cursor, queryString, expectedIdsJson);
    MojTestErrCheck(err);
    cursor.close();

	return MojErrNone;
}
Exemplo n.º 9
0
MojErr MojDbWatchTest::rangeTest(MojDb& db)
{
    MojDbQuery query;
    MojErr err = query.from(_T("WatchTest:1"));
    MojTestErrCheck(err);
    err = query.where(_T("foo"), MojDbQuery::OpGreaterThan, 5);
    MojTestErrCheck(err);
    err = query.where(_T("foo"), MojDbQuery::OpLessThan, 100);
    MojTestErrCheck(err);
    MojRefCountedPtr<TestWatcher> watcher(new TestWatcher);
    MojTestAssert(watcher.get());
    MojDbCursor cursor;
    err = db.find(query, cursor, watcher->m_slot);
    MojTestErrCheck(err);
    err = cursor.close();
    MojTestErrCheck(err);
    MojTestAssert(watcher->m_count == 0);
    MojObject id;
    MojInt64 rev;
    err = put(db, 5, 5, id, rev);
    MojTestErrCheck(err);
    MojTestAssert(watcher->m_count == 0);
    err = put(db, 100, 100, id, rev);
    MojTestErrCheck(err);
    MojTestAssert(watcher->m_count == 0);
    err = put(db, 6, 6, id, rev);
    MojTestErrCheck(err);
    MojTestAssert(watcher->m_count == 1);
    watcher.reset(new TestWatcher);
    MojTestAssert(watcher.get());
    err = db.find(query, cursor, watcher->m_slot);
    MojTestErrCheck(err);
    err = cursor.close();
    MojTestErrCheck(err);
    MojTestAssert(watcher->m_count == 0);
    err = put(db, 99, 99, id, rev);
    MojTestErrCheck(err);
    MojTestAssert(watcher->m_count == 1);

    return MojErrNone;
}
Exemplo n.º 10
0
MojErr MojDb::findImpl(const MojDbQuery& query, MojDbCursor& cursor, MojDbWatcher* watcher, MojDbReq& req, MojDbOp op)
{
	MojLogTrace(s_log);

	if (cursor.isOpen())
		MojErrThrow(MojErrDbCursorAlreadyOpen);

	MojErr err = m_kindEngine.find(query, cursor, watcher, req, op);
	MojErrCheck(err);

	return MojErrNone;
}
Exemplo n.º 11
0
MojErr MojDbIndex::find(MojDbCursor& cursor, MojDbWatcher* watcher, MojDbReq& req)
{
    LOG_TRACE("Entering function %s", __FUNCTION__);
	MojAssert(isOpen());

	MojAutoPtr<MojDbQueryPlan> plan(new MojDbQueryPlan(*m_kindEngine));
	MojAllocCheck(plan.get());
	MojErr err = plan->init(cursor.query(), *this);
	MojErrCheck(err);
	if (watcher) {
		// we have to add the watch before beginning the txn or we may miss events
		MojAssert(cursor.txn() == NULL);
		err = addWatch(*plan, cursor, watcher, req);
		MojErrCheck(err);
	}
	if (!cursor.txn()) {
		MojDbStorageTxn* txn = req.txn();
		bool cursorOwnsTxn = !(req.batch() || txn);
		if (txn) {
			cursor.txn(txn, cursorOwnsTxn);
		} else {
			MojRefCountedPtr<MojDbStorageTxn> localTxn;
			err = m_collection->beginTxn(localTxn);
			MojErrCheck(err);
			cursor.txn(localTxn.get(), cursorOwnsTxn);
			req.txn(localTxn.get());
		}
	}
	cursor.m_dbIndex = this;	// for debugging
	err = m_collection->find(plan, cursor.txn(), cursor.m_storageQuery);
	MojErrCheck(err);
	cursor.m_watcher = watcher;
	
	return MojErrNone;
}
Exemplo n.º 12
0
MojErr MojDbKindEngine::find(const MojDbQuery& query, MojDbCursor& cursor, MojDbWatcher* watcher, MojDbReq& req, MojDbOp op)
{
	MojAssert(isOpen());
	MojLogTrace(s_log);

	MojErr err = query.validate();
	MojErrCheck(err);
    // In order to find collate index, cursor needs kindEngine
    cursor.kindEngine(this);
	err = cursor.init(query);
	MojErrCheck(err);

	MojDbKind* kind = NULL;
	err = getKind(query.from().data(), kind);
	MojErrCheck(err);
	MojAssert(kind);
	err = kind->find(cursor, watcher, req, op);
	MojErrCheck(err);
	cursor.kindEngine(this);

	return MojErrNone;
}
Exemplo n.º 13
0
MojErr MojDbIndex::build(MojDbStorageTxn* txn)
{
    LOG_TRACE("Entering function %s", __FUNCTION__);
	MojAssert(isOpen());
	MojAssert(m_kind && m_kindEngine);
	MojAssert(m_props.size() > 1);

	// query for all existing objects of this type and add them to the index.
	MojDbQuery query;
	MojErr err = query.from(m_kind->id());
	MojErrCheck(err);
	if (m_includeDeleted) {
		err = query.includeDeleted();
		MojErrCheck(err);
	}

	MojDbCursor cursor;
	MojDbReq adminRequest(true);
	adminRequest.txn(txn);
	err = m_kindEngine->find(query, cursor, NULL, adminRequest, OpRead);
	MojErrCheck(err);

	for (;;) {
		MojObject obj;
		bool found = false;
		err = cursor.get(obj, found);
		MojErrCheck(err);
		if (!found)
			break;
		// add this object to the index
		err = update(&obj, NULL, txn, false);
		MojErrCheck(err);
	}
	err = cursor.close();
	MojErrCheck(err);

	return MojErrNone;
}
Exemplo n.º 14
0
MojErr MojDbDistinctTest::check(MojDb& db, const MojDbQuery& query, MojDbCursor& cursor, const MojChar* queryString, const MojChar* expectedIdsJson)
{
	MojErr err = db.find(query, cursor);
	MojTestErrCheck(err);

	MojObjectBuilder builder;
	err = builder.beginArray();
	MojTestErrCheck(err);
	err = cursor.visit(builder);
	MojTestErrCheck(err);
	err = cursor.close();
	MojTestErrCheck(err);
	err = builder.endArray();
	MojTestErrCheck(err);
	MojObject results = builder.object();

	MojString json;
	err = results.toJson(json);
	MojTestErrCheck(err);

	MojObject expected;
	err = expected.fromJson(expectedIdsJson);
	MojTestErrCheck(err);

	// size check
	MojTestAssert(expected.size() == results.size());

	// value check
	MojObject::ConstArrayIterator j = results.arrayBegin();
	for (MojObject::ConstArrayIterator i = expected.arrayBegin();
			i != expected.arrayEnd(); ++i, ++j) {
		MojObject value;
		err = j->getRequired(queryString, value);
		MojTestErrCheck(err);
		MojTestAssert(*i == value);
	}
	return MojErrNone;
}
Exemplo n.º 15
0
MojErr MojDbKindEngine::loadKinds(MojDbReq& req)
{
	MojAssert(isOpen());
	MojAssertWriteLocked(m_db->m_schemaLock);
	MojLogTrace(s_log);

	MojDbQuery query;
	MojErr err = query.from(KindKindId);
	MojErrCheck(err);
	MojDbCursor cursor;
	err = m_db->find(query, cursor, req);
	MojErrCheck(err);

	for (;;) {
		MojObject obj;
		bool found = false;
		err = cursor.get(obj, found);
		MojErrCheck(err);
		if (!found)
			break;
		// load kind
		MojErr loadErr = err = putKind(obj, req);
		MojErrCatchAll(err) {
			MojString id;
			bool found = false;
			MojErr err = obj.get(MojDbServiceDefs::IdKey, id, found);
			MojErrCheck(err);
			MojString errStr;
			MojErrToString(loadErr, errStr);
			MojLogError(s_log, _T("error loading kind '%s' - %s"), id.data(), errStr.data());
		}
	}
	err = cursor.close();
	MojErrCheck(err);

	return MojErrNone;
}
Exemplo n.º 16
0
MojErr MojDbKind::find(MojDbCursor& cursor, MojDbWatcher* watcher, MojDbReq& req, MojDbOp op)
{
	MojLogTrace(s_log);

	MojErr err = checkPermission(op, req);
	MojErrCheck(err);
	const MojDbQuery& query = cursor.query();
	MojDbIndex* index = indexForQuery(query);
	if (index == NULL)
		MojErrThrow(MojErrDbNoIndexForQuery);

	cursor.m_dbIndex = index;
	MojLogInfo(s_log, _T("Dbkind_find: Kind: %s, UsingIndex: %s, order: %s, limit: %d \n"), m_id.data(), index->name().data(), 
				query.order().data(), (int)query.limit());
	err = index->find(cursor, watcher, req);
	MojErrCheck(err);

	return MojErrNone;
}
Exemplo n.º 17
0
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;
}
Exemplo n.º 18
0
MojErr MojDbWatchTest::eqTest(MojDb& db)
{
    MojDbQuery query;
    MojErr err = query.from(_T("WatchTest:1"));
    MojTestErrCheck(err);
    err = query.where(_T("foo"), MojDbQuery::OpEq, 1);
    MojTestErrCheck(err);
    MojRefCountedPtr<TestWatcher> watcher(new TestWatcher);
    MojTestAssert(watcher.get());
    MojDbCursor cursor;
    err = db.find(query, cursor, watcher->m_slot);
    MojTestErrCheck(err);
    err = cursor.close();
    MojTestErrCheck(err);
    MojTestAssert(watcher->m_count == 0);
    MojRefCountedPtr<TestWatcher> watcher2(new TestWatcher);
    MojTestAssert(watcher2.get());
    bool fired = false;
    err = db.watch(query, cursor, watcher2->m_slot, fired);
    MojTestErrCheck(err);
    err = cursor.close();
    MojTestErrCheck(err);
    MojTestAssert(!fired);
    // puts
    MojObject id;
    err = put(db, 0, 0, id, m_rev);
    MojTestErrCheck(err);
    MojTestAssert(watcher->m_count == 0);
    MojTestAssert(watcher2->m_count == 0);
    err = put(db, 2, 2, id, m_rev);
    MojTestErrCheck(err);
    MojTestAssert(watcher->m_count == 0);
    MojTestAssert(watcher2->m_count == 0);
    err = put(db, 1, 1, id, m_rev);
    MojTestErrCheck(err);
    MojTestAssert(watcher->m_count == 1);
    MojTestAssert(watcher2->m_count == 1);
    err = put(db, 1, 1, id, m_rev);
    MojTestErrCheck(err);
    MojTestAssert(watcher->m_count == 1);
    MojTestAssert(watcher2->m_count == 1);
    // put, changing property not in index
    watcher.reset(new TestWatcher);
    MojTestAssert(watcher.get());
    err = db.find(query, cursor, watcher->m_slot);
    MojTestErrCheck(err);
    err = cursor.close();
    MojTestErrCheck(err);
    err = put(db, 1, 2, id, m_rev);
    MojTestErrCheck(err);
    MojTestAssert(watcher->m_count == 1);
    // dels
    watcher.reset(new TestWatcher);
    MojTestAssert(watcher.get());
    err = db.find(query, cursor, watcher->m_slot);
    MojTestErrCheck(err);
    err = cursor.close();
    MojTestErrCheck(err);
    watcher2.reset(new TestWatcher);
    MojTestAssert(watcher2.get());
    MojDbQuery queryWithRev;
    err = queryWithRev.from(_T("WatchTest:1"));
    MojTestErrCheck(err);
    err = queryWithRev.where(_T("foo"), MojDbQuery::OpEq, 1);
    MojTestErrCheck(err);
    err = queryWithRev.where(_T("_rev"), MojDbQuery::OpGreaterThan, m_rev);
    MojTestErrCheck(err);
    err = queryWithRev.includeDeleted();
    MojTestErrCheck(err);
    fired = false;
    err = db.watch(queryWithRev, cursor, watcher2->m_slot, fired);
    MojTestErrCheck(err);
    err = cursor.close();
    MojTestErrCheck(err);
    MojTestAssert(!fired);
    MojTestAssert(watcher->m_count == 0);
    MojTestAssert(watcher2->m_count == 0);
    bool found;
    err = db.del(id, found);
    MojTestErrCheck(err);
    MojTestAssert(found);
    MojTestAssert(watcher->m_count == 1);
    MojTestAssert(watcher2->m_count == 1);
    // ordering
    watcher.reset(new TestWatcher);
    MojTestAssert(watcher.get());
    err = db.find(query, cursor, watcher->m_slot);
    MojTestErrCheck(err);
    err = put(db, 1, 1, id, m_rev);
    MojTestErrCheck(err);
    MojTestAssert(watcher->m_count == 0);
    err = cursor.close();
    MojTestErrCheck(err);
    MojTestAssert(watcher->m_count == 1);

    return MojErrNone;
}
Exemplo n.º 19
0
MojErr MojDbWatchTest::pageTest(MojDb& db)
{
    MojObject id;
    MojObject idFirst;
    MojObject idFourth;
    MojObject idLast;
    MojInt64 rev;
    for (int i = 100; i < 150; ++i) {
        MojErr err = put(db, 100, i, id, rev);
        MojTestErrCheck(err);
        if (i == 100) {
            idFirst = id;
        } else if (i == 103) {
            idFourth = id;
        } else if (i == 149) {
            idLast = id;
        }
    }
    MojDbQuery query;
    MojErr err = query.from(_T("WatchTest:1"));
    MojTestErrCheck(err);
    err = query.where(_T("foo"), MojDbQuery::OpGreaterThanEq, 100);
    MojTestErrCheck(err);
    query.limit(3);
    MojRefCountedPtr<TestWatcher> watcher(new TestWatcher);
    MojTestAssert(watcher.get());
    MojDbCursor cursor;
    err = db.find(query, cursor, watcher->m_slot);
    MojTestErrCheck(err);
    bool found = false;
    MojUInt32 count = 0;
    do {
        MojObject obj;
        err = cursor.get(obj, found);
        MojTestErrCheck(err);
        if (found)
            ++count;
    } while (found);
    MojTestAssert(count == 3);
    MojDbQuery::Page page;
    err = cursor.nextPage(page);
    MojTestErrCheck(err);
    err = cursor.close();
    MojTestErrCheck(err);

    err = merge(db, idFourth, 53);
    MojTestErrCheck(err);
    MojTestAssert(watcher->m_count == 0);

    query.page(page);
    MojRefCountedPtr<TestWatcher> watcher2(new TestWatcher);
    MojTestAssert(watcher2.get());
    err = db.find(query, cursor, watcher2->m_slot);
    MojTestErrCheck(err);
    found = false;
    count = 0;
    do {
        MojObject obj;
        err = cursor.get(obj, found);
        MojTestErrCheck(err);
        if (found)
            ++count;
    } while (found);
    MojTestAssert(count == 3);
    err = cursor.close();
    MojTestErrCheck(err);
    err = db.del(idFirst, found);
    MojTestErrCheck(err);
    MojTestAssert(found);
    MojTestAssert(watcher->m_count == 1);
    MojTestAssert(watcher2->m_count == 0);
    err = db.del(idFourth, found);
    MojTestErrCheck(err);
    MojTestAssert(found);
    MojTestAssert(watcher->m_count == 1);
    MojTestAssert(watcher2->m_count == 1);

    // desc order
    query.page(MojDbQuery::Page());
    query.desc(true);
    MojRefCountedPtr<TestWatcher> watcher3(new TestWatcher);
    MojTestAssert(watcher3.get());
    err = db.find(query, cursor, watcher3->m_slot);
    MojTestErrCheck(err);

    found = false;
    count = 0;
    do {
        MojObject obj;
        err = cursor.get(obj, found);
        MojTestErrCheck(err);
        if (found)
            ++count;
    } while (found);
    MojTestAssert(count == 3);
    err = cursor.close();
    MojTestErrCheck(err);

    err = merge(db, idLast, 53);
    MojTestErrCheck(err);
    MojTestAssert(watcher3->m_count == 1);

    MojRefCountedPtr<TestWatcher> watcher4(new TestWatcher);
    MojTestAssert(watcher4.get());
    err = db.find(query, cursor, watcher4->m_slot);
    MojTestErrCheck(err);

    found = false;
    count = 0;
    do {
        MojObject obj;
        err = cursor.get(obj, found);
        MojTestErrCheck(err);
        if (found)
            ++count;
    } while (found);
    MojTestAssert(count == 3);

    err = cursor.close();
    MojTestErrCheck(err);
    err = merge(db, idLast, 54);
    MojTestErrCheck(err);
    MojTestAssert(watcher4->m_count == 1);

    return MojErrNone;
}
Exemplo n.º 20
0
MojErr MojDb::dumpImpl(MojFile& file, bool backup, bool incDel, const MojObject& revParam, const MojObject& delRevParam, bool skipKinds, MojUInt32& countOut, MojDbReq& req,
		MojObject* response, const MojChar* keyName, MojSize& bytesWritten, MojSize& warns, MojUInt32 maxBytes)
{
	// query for objects, adding the backup key and rev key if necessary
	MojDbQuery query;
	MojErr err = query.from(MojDbKindEngine::RootKindId);
	MojErrCheck(err);
	err = query.where(MojDb::DelKey, MojDbQuery::OpEq, incDel);
	MojErrCheck(err);
	if (backup) {
		err = query.where(MojDb::SyncKey, MojDbQuery::OpEq, true);
		MojErrCheck(err);
		if (incDel) {
			err = query.where(MojDb::RevKey, MojDbQuery::OpGreaterThan, delRevParam);
			MojErrCheck(err);
		} else {
			err = query.where(MojDb::RevKey, MojDbQuery::OpGreaterThan, revParam);
			MojErrCheck(err);
		}
	}

	MojDbCursor cursor;
	err = findImpl(query, cursor, NULL, req, OpRead);
	MojErrCheck(err);
	warns = 0;

	MojObject curRev;
	for(;;) {
		bool found = false;
		MojObject obj;
		err = cursor.get(obj, found);
		// So that we can get as much data as possible from a corrupt database
		// We simply skip ghost keys and continue
		if (err == MojErrInternalIndexOnFind) {
			warns++;
			continue;
		}
		MojErrCheck(err);
		if (!found)
			break;

		if (skipKinds) {
			MojString kind;
			err = obj.getRequired(KindKey, kind);
			MojErrCheck(err);
			if (kind == MojDbKindEngine::KindKindId) {
				continue;
			}
		}

		// write out each object, if the backup is full, insert the appropriate incremental key
		err = dumpObj(file, obj, bytesWritten, maxBytes);
		MojErrCatch(err, MojErrDbBackupFull) {
			if (response) {
				MojErr errBackup = MojErrNone;
				if (!curRev.undefined()) {
					errBackup = insertIncrementalKey(*response, keyName, curRev);
					MojErrCheck(errBackup);
				} else {
					errBackup = insertIncrementalKey(*response, keyName, incDel ? delRevParam: revParam);
					MojErrCheck(errBackup);
				}
				errBackup = handleBackupFull(revParam, delRevParam, *response, keyName);
				MojErrCheck(errBackup);
			}
			return MojErrNone;
		}
		MojErrCheck(err);
		err = obj.getRequired(MojDb::RevKey, curRev);
		MojErrCheck(err);
		countOut++;
	}
	err = cursor.close();
	MojErrCheck(err);

    if (warns > 0) {
        MojLogWarning(s_log, _T("Finished Backup with %d warnings \n"), (int)warns);
    } else {
        MojLogDebug(s_log, _T("Finished Backup with no warnings \n"));
    }

	// construct the next incremental key
	if (response && !curRev.undefined()) {
		err = insertIncrementalKey(*response, keyName, curRev);
		MojErrCheck(err);
	}
	return MojErrNone;
}
Exemplo n.º 21
0
MojErr MojDbKind::verifyIndex(MojDbIndex *pIndex, MojObject &iinfo, MojDbReq& req)
{
	// Goes throudh each index entry and verifies that it points to a valid object
	// For debugging purposes as stats for indexes does not access the target objects
	// Index->stats function does not have enough context to find the object
	// db/stats usage '{"verify":true,"kind":"xyz"}' - each optional
	
	MojDbQuery query;
	MojErr err = query.from(m_id);
	MojErrCheck(err);
	err = query.includeDeleted(true);
	MojErrCheck(err);
	MojDbCursor cursor;
	query.m_forceIndex = pIndex;		// Important: Otherwise, it will pick the default index
	cursor.verifymode(true);		// to get the errors
	err = m_kindEngine->find(query, cursor, NULL, req, OpRead);
	MojLogInfo(s_log, _T("Kind_verifyIndex: Kind: %s; Index: %s; idIndex: %zX; size: %zu; CursorIndex: %s \n"), m_name.data(), 
					pIndex->name().data(), pIndex->idIndex(), pIndex->size(), cursor.m_dbIndex->name().data());
	MojErrCheck(err);
	MojSize count = 0;
	MojSize delCount = 0;
	MojSize warnCount = 0;
	char s[1024];
	for (;;) {
		MojDbStorageItem* item = NULL;
		bool found = false;
		err = cursor.get(item, found);
		if (err == MojErrInternalIndexOnFind) {
			warnCount++;
			MojDbIsamQuery *iquery = (MojDbIsamQuery *)cursor.m_storageQuery.get();
			MojErr err2 =  MojByteArrayToHex(iquery->m_keyData, iquery->m_keySize, s); 
			MojErrCheck(err2);
			MojChar *ids = (iquery->m_keySize > 18) ? (MojChar *)(iquery->m_keyData + iquery->m_keySize - 17) : NULL; 
			MojLogInfo(s_log, _T("VerifyIndex Warning: %s; KeySize: %zu; %s ;id: %s \n"), 
					cursor.m_dbIndex->name().data(), iquery->m_keySize, s, ids);
			continue;
		}
		MojErrCheck(err);
		if (!found)
			break;
		MojObject obj;
		err = item->toObject(obj, *m_kindEngine, true);
		MojErrCheck(err);
		bool deleted = false;
		if (obj.get(MojDb::DelKey, deleted) && deleted) {
			delCount++;
		} else {
			count++;
		}
	}

	MojLogInfo(s_log, _T("Kind_verifyIndex Counts: Kind: %s; Index: %s; count: %zu; delcount: %zu; warnings: %zu \n"), m_name.data(), 
					pIndex->name().data(), count, delCount, warnCount);
	
	err = iinfo.put(VerifyCountKey, (MojInt64)count);
	MojErrCheck(err);
	err = iinfo.put(VerifyWarnCountKey, (MojInt64) warnCount);
	MojErrCheck(err);
	err = iinfo.put(VerifyDelCountKey, (MojInt64) delCount);
	MojErrCheck(err);

	return MojErrNone;
}
Exemplo n.º 22
0
MojErr MojDbKind::updateSupers(const KindMap& map, const StringVec& superIds, bool updating, MojDbReq& req)
{
	MojLogTrace(s_log);
	MojInt32 indexes = 0;
	if (updating) {
		KindVec addedSupers;
		MojErr err = diffSupers(map, superIds, m_superIds, addedSupers);
		MojErrCheck(err);
		KindVec removedSupers;
		err = diffSupers(map, m_superIds, superIds, removedSupers);
		MojErrCheck(err);

		// remove/add our objects from new/removed supers
		if (!addedSupers.empty() || !removedSupers.empty()) {
			MojDbQuery query;
			err = query.from(m_id);
			MojErrCheck(err);
			err = query.includeDeleted(true);
			MojErrCheck(err);
			MojDbCursor cursor;
			cursor.kindEngine(m_kindEngine);
			err = find(cursor, NULL, req, OpKindUpdate);
			MojErrCheck(err);
			for (;;) {
				MojObject obj;
				bool found = false;
				err = cursor.get(obj, found);
				MojErrCheck(err);
				if (!found)
					break;

				for (KindVec::ConstIterator i = addedSupers.begin(); i != addedSupers.end(); ++i) {
					err = (*i)->updateOwnIndexes(&obj, NULL, req, indexes);
					MojErrCheck(err);
				}
				for (KindVec::ConstIterator i = removedSupers.begin(); i != removedSupers.end(); ++i) {
					err = (*i)->updateOwnIndexes(NULL, &obj, req, indexes);
					MojErrCheck(err);
				}
			}
		}
	}

	// remove old supers
	m_superIds = superIds;
	MojErr err = clearSupers();
	MojErrCheck(err);
	// look for new supers
	for (StringVec::ConstIterator i = m_superIds.begin(); i != m_superIds.end(); ++i) {
		KindMap::ConstIterator mapIter = map.find(*i);
		if (mapIter != map.end()) {
			err = addSuper(mapIter->get());
			MojErrCheck(err);
		}
	}
	// look for kinds that extend us
	for (KindMap::ConstIterator i = map.begin(); i != map.end(); ++i) {
		if ((*i)->m_superIds.find(m_id) != MojInvalidIndex) {
			err = (*i)->addSuper(this);
			MojErrCheck(err);
		}
	}
	// add root kind if we have no supers
	if (m_supers.empty()) {
		KindMap::ConstIterator mapIter = map.find(MojDbKindEngine::RootKindId);
		if (mapIter != map.end()) {
			err = addSuper(mapIter->get());
			MojErrCheck(err);
		}
	}
	return MojErrNone;
}
Exemplo n.º 23
0
MojErr MojDbPermissionTest::checkPermissions(MojDb& db)
{
	MojDbReq reqOwner(false);
	MojErr err = reqOwner.domain(_T("com.foo"));
	MojTestErrCheck(err);
	MojDbReq reqFooBar(false);
	err = reqFooBar.domain(_T("com.foo.bar"));
	MojTestErrCheck(err);
	MojDbReq reqFooBarBad(false);
	err = reqFooBarBad.domain(_T("com.foobar"));
	MojTestErrCheck(err);
	MojDbReq reqGranted(false);
	err = reqGranted.domain("com.granted");
	MojTestErrCheck(err);
	MojDbReq reqEmpty(false);
	MojDbReq reqBad(false);
	err = reqBad.domain("com.bad");
	MojTestErrCheck(err);

	MojObject objNoId;
	err = objNoId.putString(MojDb::KindKey, _T("PermissionTest:1"));
	MojTestErrCheck(err);
	MojObject obj2NoId;
	err = obj2NoId.putString(MojDb::KindKey, _T("PermissionTest2:1"));
	MojTestErrCheck(err);

	// put new obj
	MojObject obj1 = objNoId;
	err = db.put(obj1, MojDb::FlagNone, reqOwner);
	MojTestErrCheck(err);
	MojObject obj2 = objNoId;
	err = db.put(obj2, MojDb::FlagNone, reqGranted);
	MojTestErrCheck(err);
	MojObject obj3 = objNoId;
	err = db.put(obj3, MojDb::FlagNone, reqBad);
	MojTestErrExpected(err, MojErrDbPermissionDenied);
	obj3 = objNoId;
	err = db.put(obj3, MojDb::FlagNone, reqFooBarBad);
	MojTestErrExpected(err, MojErrDbPermissionDenied);
	obj3 = objNoId;
	err = db.put(obj3, MojDb::FlagNone, reqFooBar);
	MojTestErrCheck(err);
	err = db.put(obj2NoId, MojDb::FlagNone, reqEmpty);
	MojTestErrCheck(err);
	// put existing obj
	err = obj1.put(_T("foo"), 1);
	MojTestErrCheck(err);
	err = db.put(obj1, MojDb::FlagNone, reqOwner);
	MojTestErrCheck(err);
	err = obj2.put(_T("foo"), 2);
	MojTestErrCheck(err);
	err = db.put(obj2, MojDb::FlagNone, reqGranted);
	MojTestErrCheck(err);
	err = obj2.put(_T("foo"), 3);
	MojTestErrCheck(err);
	err = db.put(obj2, MojDb::FlagNone, reqBad);
	MojTestErrExpected(err, MojErrDbPermissionDenied);

	// find
	MojDbQuery query;
	err = query.from(_T("PermissionTest:1"));
	MojTestErrCheck(err);
	MojDbCursor cursor;
	err = db.find(query, cursor, reqOwner);
	MojTestErrCheck(err);
	err = cursor.close();
	MojTestErrCheck(err);
	err = db.find(query, cursor, reqGranted);
	MojTestErrCheck(err);
	err = cursor.close();
	MojTestErrCheck(err);
	err = db.find(query, cursor, reqBad);
	MojTestErrExpected(err, MojErrDbPermissionDenied);
	err = cursor.close();
	MojTestErrCheck(err);

	// get
	MojObject id1;
	MojTestAssert(obj1.get(MojDb::IdKey, id1));
	bool found = false;
	MojObject gotten;
	err = db.get(id1, gotten, found, reqOwner);
	MojTestErrCheck(err);
	err = db.get(id1, gotten, found, reqGranted);
	MojTestErrCheck(err);
	err = db.get(id1, gotten, found, reqBad);
	MojTestErrExpected(err, MojErrDbPermissionDenied);

	// del by id
	err = db.del(id1, found, MojDb::FlagNone, reqBad);
	MojTestErrExpected(err, MojErrDbPermissionDenied);
	MojTestAssert(!found);
	err = db.del(id1, found, MojDb::FlagNone, reqOwner);
	MojTestErrCheck(err);
	MojTestAssert(found);
	MojObject id2;
	MojTestAssert(obj2.get(MojDb::IdKey, id2));
	err = db.del(id2, found, MojDb::FlagNone, reqGranted);
	MojTestErrCheck(err);
	MojTestAssert(found);

	// del query
	MojUInt32 count = 0;
	err = db.del(query, count, MojDb::FlagNone, reqOwner);
	MojTestErrCheck(err);
	err = db.del(query, count, MojDb::FlagNone, reqGranted);
	MojTestErrCheck(err);
	err = db.del(query, count, MojDb::FlagNone, reqBad);
	MojTestErrExpected(err, MojErrDbPermissionDenied);

	return MojErrNone;
}
Exemplo n.º 24
0
MojErr MojDbKind::stats(MojObject& objOut, MojSize& usageOut, MojDbReq& req, bool verify)
{
	MojLogTrace(s_log);

#if defined(TESTDBKIND)
	MojLogInfo(s_log, _T("Subkinds for - %s ; count = %d\n"), m_id.data(), m_subs.size());
	int n = 0;
	for (KindVec::ConstIterator i = m_subs.begin(); i != m_subs.end(); ++i) {
		MojLogInfo(s_log, _T("SubKind %d: %s"), n++, (*i)->id().data());
	}
	MojLogInfo(s_log, _T("Supers for - %s ; count = %d\n"), m_id.data(), m_supers.size());
	n = 0;
	for (KindVec::ConstIterator i = m_supers.begin(); i != m_supers.end(); ++i) {
		MojLogInfo(s_log, _T("Super %d: %s"), n++, (*i)->id().data());
	}
#endif 
	// analyze objects
	MojDbQuery query;
	MojErr err = query.from(m_id);
	MojErrCheck(err);
	err = query.includeDeleted(true);
	MojErrCheck(err);
	MojDbCursor cursor;
	err = m_kindEngine->find(query, cursor, NULL, req, OpRead);
	MojLogInfo(s_log, _T("KindStats start: %s ; Indexes = %zu; Using Index: %s; \n"), 
				m_id.data(), m_indexes.size(), cursor.m_dbIndex->name().data());

	MojErrCheck(err);
	MojSize count = 0;
	MojSize size = 0;
	MojSize delCount = 0;
	MojSize delSize = 0;
	MojSize warnings = 0;
	for (;;) {
		MojDbStorageItem* item = NULL;
		bool found = false;
		cursor.verifymode(true);
		err = cursor.get(item, found);
		if (err == MojErrInternalIndexOnFind) {
			warnings++;
			continue;
		}
		if (err != MojErrNone)		// for all other errors break and dump current stats 
			break;	
		if (!found)
			break;
		MojObject obj;
		err = item->toObject(obj, *m_kindEngine, true);
		if (err != MojErrNone)
			break;
		bool deleted = false;
		if (obj.get(MojDb::DelKey, deleted) && deleted) {
			delSize += item->size();
			delCount++;
		} else {
			size += item->size();
			count++;
		}
	}

	MojLogInfo(s_log, _T("KindStats Summary: %s : Count: %zu; delCount: %zu; warnings: %zu \n"), m_id.data(), count, delCount, warnings);
	
	usageOut += size + delSize;
	MojObject info;
	err = info.put(SizeKey, (MojInt64) size);
	MojErrCheck(err);
	err = info.put(CountKey, (MojInt64) count);
	MojErrCheck(err);
	if (delCount > 0) {
		err = info.put(DelSizeKey, (MojInt64) delSize);
		MojErrCheck(err);
		err = info.put(DelCountKey, (MojInt64) delCount);
		MojErrCheck(err);
	}
	if (warnings > 0) {
		err = info.put(WarnKey, (MojInt64) warnings);
		MojErrCheck(err);
	}
	err = objOut.put(ObjectsKey, info);
	MojErrCheck(err);

	// and indexes
	MojObject indexes;
	
	for (IndexVec::ConstIterator i = m_indexes.begin(); i != m_indexes.end(); ++i) {
		MojObject indexInfo;
		err = (*i)->stats(indexInfo, usageOut, req);
		MojErrCheck(err);

		if (verify) {
			MojDbIndex *pi = i->get();
			MojErr err2 = verifyIndex(pi, indexInfo, req);
			MojErrCheck(err2);
		}

		err = indexes.put((*i)->name(), indexInfo);
		MojErrCheck(err);
	}
	err = objOut.put(IndexesKey, indexes);
	MojErrCheck(err);

	return MojErrNone;
}
Exemplo n.º 25
0
MojErr MojDbPurgeTest::run()
{
	MojDb db;
	MojErr err = db.open(MojDbTestDir);
	MojTestErrCheck(err);

	// put type
	MojObject obj;
	err = obj.fromJson(MojKindStr);
	MojTestErrCheck(err);
	err = db.putKind(obj);
	MojTestErrCheck(err);

	MojObject revNums[10];
	MojObject ids[10];
	//put 10 objects in the db
	for(int i = 0; i < 10; i++) {
		err = obj.fromJson(MojTestObjStr1);
		MojTestErrCheck(err);
		err = db.put(obj);
		MojTestErrCheck(err);
		// get _rev and id
		MojObject rev;
		err = obj.getRequired(MojDb::RevKey, rev);
		MojTestErrCheck(err);
		revNums[i] = rev;
		MojObject id;
		err = obj.getRequired(MojDb::IdKey, id);
		MojTestErrCheck(err);
		ids[i] = id;
	}

	//purge now, there are no RevTimestamp entries
	MojUInt32 count = 0;
	err = db.purge(count, 30);
	MojTestErrCheck(err);

	err = checkObjectsPurged(db, count, 0, 10, 1, -1);
	MojTestErrCheck(err);

	//create a RevTimestamp entry - that's not more than PurgeNumDays days ago
	MojTime time;
	err = MojGetCurrentTime(time);
	MojTestErrCheck(err);
	err = createRevTimestamp(db, revNums[0], time.microsecs());
	MojTestErrCheck(err);

	//purge now, there are no RevTimestamp entries that are more than
	//PurgeNumDays ago, so nothing should be purged
	count = 0;
	err = db.purge(count, 30);
	MojTestErrCheck(err);

	err = checkObjectsPurged(db, count, 0, 10, 3, -1);
	MojTestErrCheck(err);

	//create a RevTimestamp entry for more than PurgeNumDays days ago
	err = MojGetCurrentTime(time);
	MojTestErrCheck(err);
	err = createRevTimestamp(db, revNums[9], time.microsecs() - (((MojInt64)40) * MojTime::UnitsPerDay));
	MojTestErrCheck(err);

	//purge now, since nothing has been deleted, nothing should be purged,
	//but the RevTimestamp object should be deleted
	count = 0;
	err = db.purge(count, 30);
	MojTestErrCheck(err);

	err = checkObjectsPurged(db, count, 0, 10, 4, -1);
	MojTestErrCheck(err);

	//delete something - this will set its revision number higher
	bool found;
	err = db.del(ids[0], found);
	MojTestErrCheck(err);
	MojTestAssert(found == true);

	//purge now, since nothing has been deleted prior to the revision
	//number, nothing should be purged
	count = 0;
	err = db.purge(count, 30);
	MojTestErrCheck(err);

	err = checkObjectsPurged(db, count, 0, 9, 5, -1);
	MojTestErrCheck(err);

	//delete another object
	err = db.del(ids[1], found);
	MojTestErrCheck(err);
	MojTestAssert(found == true);

	//create a RevTimestamp entry for more than PurgeNumDays days ago,
	//with the rev number of the 1st obj we deleted
	MojDbQuery query;
	err = query.from(_T("PurgeTest:1"));
	MojTestErrCheck(err);
	err = query.where(MojDb::IdKey, MojDbQuery::OpEq, ids[0]);
	MojTestErrCheck(err);
	err = query.includeDeleted();
	MojTestErrCheck(err);

	MojDbCursor cursor;
	err = db.find(query, cursor);
	MojTestErrCheck(err);

	MojObject objFromDb;
	err = cursor.get(objFromDb, found);
	MojTestErrCheck(err);
	err = cursor.close();
	MojTestErrCheck(err);
	MojTestAssert(found == true);

	MojObject revFromDb;
	err = objFromDb.getRequired(MojDb::RevKey, revFromDb);
	MojTestErrCheck(err);

	err = MojGetCurrentTime(time);
	MojTestErrCheck(err);
	err = createRevTimestamp(db, revFromDb, time.microsecs() - (((MojInt64)35) * MojTime::UnitsPerDay));
	MojTestErrCheck(err);

	//now purge, only id[0] should be purged
	count = 0;
	err = db.purge(count, 30);
	MojTestErrCheck(err);

	err = checkObjectsPurged(db, count, 1, 8, 6, revFromDb);
	MojTestErrCheck(err);

	//TODO 2.12.10 - this test does not pass yet, we need to fix calling delKind after a purge
	//err = delKindTest(db);
	//MojTestErrCheck(err);

	err = db.close();
	MojTestErrCheck(err);

	return MojErrNone;
}
Exemplo n.º 26
0
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;
}
Exemplo n.º 27
0
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;
}
Exemplo n.º 28
0
MojErr MojDb::delImpl(const MojDbQuery& quer, MojUInt32& countOut, MojDbReq& req, MojUInt32 flags)
{
	MojLogTrace(s_log);

	countOut = 0;
	MojInt32 warns = 0;
    MojDbQuery newQuery = quer;
    MojUInt32 queryLimit = newQuery.limit();

    if(newQuery.limit() == MojDbQuery::LimitDefault)
        newQuery.limit(AutoBatchSize);

    while(queryLimit > 0)
    {
        MojDbCursor cursor;
        MojErr err = findImpl(newQuery, cursor, NULL, req, OpDelete);

        MojErrCheck(err);
        MojAssert(cursor.txn());

        MojUInt32 count = 0;
        MojUInt32 numberInBatch = 0;

        bool found = false;

        MojObject obj;
        for (;;) {
            MojDbStorageItem* item = NULL;
            err = cursor.get(item, found);
            // We simply skip ghost keys and continue; A warning is already written to the system log earlier
            if (err == MojErrInternalIndexOnFind) {
                warns++;
                numberInBatch++;
                continue;
            }
            MojErrCheck(err);
            if (!found)
                break;
            err = item->toObject(obj, m_kindEngine);
            MojErrCheck(err);
            const MojObject& id = item->id();
            MojObject deleted;
            err = delObj(id, obj, item, deleted, req, flags);
            MojErrCheck(err);
            ++count;
            numberInBatch++;
        }

        if (warns > 0)
            MojLogInfo(s_log, _T("delquery index_warnings: %s, count: %d\n"), newQuery.from().data(), warns);
        countOut += count;

        err = cursor.close();
        MojErrCheck(err);

        if(numberInBatch >= AutoBatchSize) // sing > - just in case something messed up
        {
            err = commitBatch(req);
            MojErrCheck(err);
        }

        if(count == 0)
            break;

        queryLimit -= newQuery.limit();
        if(queryLimit > AutoBatchSize)
            newQuery.limit(AutoBatchSize);
        else
            newQuery.limit(queryLimit);
    }

    return MojErrNone;
}
Exemplo n.º 29
0
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;
}
Exemplo n.º 30
0
MojErr MojDb::purge(MojUInt32& countOut, MojInt64 numDays, MojDbReqRef req)
{
	MojLogTrace(s_log);

	countOut = 0;
	if (numDays <= -1) {
		numDays = m_purgeWindow;
	}

	MojErr err = beginReq(req);
	MojErrCheck(err);

	MojLogDebug(s_log, _T("purging objects deleted more than %lld days ago..."), numDays);

	MojTime time;
	err = MojGetCurrentTime(time);
	MojErrCheck(err);

	// store the revision number to current timestamp mapping
	MojObject revTimeMapping;
	MojInt64 rev;
	err = nextId(rev);
	MojErrCheck(err);
	err = revTimeMapping.put(RevNumKey, rev);
	MojErrCheck(err);
	err = revTimeMapping.put(TimestampKey, time.microsecs());
	MojErrCheck(err);
	err = revTimeMapping.putString(KindKey, MojDbKindEngine::RevTimestampId);
	MojErrCheck(err);

	err = putImpl(revTimeMapping, MojDb::FlagNone, req);
	MojErrCheck(err);

	// find the revision number for numDays prior to now
	MojInt64 purgeTime = time.microsecs() - (MojTime::UnitsPerDay * numDays);
	MojDbQuery query;
	err = query.from(MojDbKindEngine::RevTimestampId);
	MojErrCheck(err);
	query.limit(1);
	err = query.where(TimestampKey, MojDbQuery::OpLessThanEq, purgeTime);
	MojErrCheck(err);
	err = query.order(TimestampKey);
	MojErrCheck(err);
	query.desc(true);

	MojDbCursor cursor;
	err = findImpl(query, cursor, NULL, req, OpDelete);
	MojErrCheck(err);
	bool found = false;
	MojObject obj;
	err = cursor.get(obj, found);
	MojErrCheck(err);
	err = cursor.close();
	MojErrCheck(err);

	MojUInt32 batchCount = 0;
	MojUInt32 totalCount = 0;

	while ((found))
	{
		// Do it in AutoBatchSize batches
		batchCount = 0;
		req->fixmode(true);		// purge even if index mis-matches
		err = purgeImpl(obj, batchCount, req);
		MojLogDebug(s_log, _T("purge batch processed: batch: %d; total: %d; err = %d\n"),
					batchCount, (totalCount + batchCount), err);
		MojErrCheck(err);
		totalCount += batchCount;
		countOut = totalCount;
		if (batchCount < AutoBatchSize)	// last batch
			break;
		err = commitBatch(req);
		MojErrCheck(err);
		continue;
	}

	// end request
	err = req->end();
	MojErrCheck(err);

	MojLogDebug(s_log, _T("purged %d objects"), countOut);


	return MojErrNone;
}