BSONObj* DjondbConnection::findByKey(const char* db, const char* ns, const char* select, const char* id) { if (_logger->isDebug()) _logger->debug("executing findByKey db: %s, ns: %s, select: %s, id: %s", db, ns, select, id); if (!isOpen()) { throw DjondbException(D_ERROR_CONNECTION, "Not connected to any server"); } std::string filter = format("$'_id' == '%s'", id); BSONArrayObj* result = find(const_cast<char*>(db), const_cast<char*>(ns), const_cast<char*>(select), const_cast<char*>(filter.c_str())); BSONObj* res = NULL; if (result->length() == 1) { if (_logger->isDebug()) _logger->debug(2, "findByKey found 1 result"); res = *result->begin(); } else { if (result->length() > 1) { throw DjondbException(D_ERROR_TOO_MANY_RESULTS, "The result contains more than 1 result"); } } BSONObj* bsonresult = NULL; if (res != NULL) { // creates a copy of the result before deleting the temporal objects bsonresult = new BSONObj(*res); } delete result; return bsonresult; }
void testParserArray() { cout << "testParserArray" << endl; BSONArrayObj* array = BSONParser::parseArray("[{age: 1, name: 'John', salary: 3500.25, rel1: {innertext: 'inner text'}}, {age: 2, name: 'John2', salary: 23500.25, rel1: {innertext: 'inner text2'}}]"); TEST_ASSERT(array != NULL); TEST_ASSERT(array->length() == 2); BSONObj* obj = array->get(0); TEST_ASSERT(obj != NULL); TEST_ASSERT(obj->has("age")); TEST_ASSERT(obj->getInt("age") == 1); TEST_ASSERT(obj->has("name")); TEST_ASSERT(strcmp(obj->getString("name"), "John") == 0); TEST_ASSERT(obj->has("salary")); TEST_ASSERT(obj->getDouble("salary") == 3500.25); TEST_ASSERT(obj->getBSON("rel1") != NULL); TEST_ASSERT(strcmp(obj->getBSON("rel1")->getString("innertext"), "inner text") == 0); BSONArrayObj::iterator i = array->begin(); TEST_ASSERT(i != array->end()); delete array; }
void testFind(int port, int top = 10000000) { DjondbConnection* conn = DjondbConnectionManager::getConnection("localhost", port); if (!conn->open()) { cout << "Not connected" << endl; exit(0); } Logger* log = getLogger(NULL); log->startTimeRecord(); log->info("Testing find performance over: %d finds.", top); for (int x = 0; x < top; x++) { BSONArrayObj* arr = conn->executeQuery("select top 1 * from db:testperformance"); if (arr->length() == 0) { log->info("Error an id was not found"); exit(1); } delete arr; } log->stopTimeRecord(); DTime time = log->recordedTime(); cout << "Total find secs: " << time.totalSecs() << endl; if (time.totalSecs() > 0) { log->info("Found %d: throughtput: %d.", top, (top / time.totalSecs())); } else { log->info("Found :%d, throughtput too high to be measured", top); } if ((time.totalSecs() > 0) && ((top / time.totalSecs()) < 16000)) { log->info("Performance is not good enough"); } }
v8::Handle<v8::Value> find(const v8::Arguments& args) { if (args.Length() < 2) { return v8::ThrowException(v8::String::New("usage: db.find(db, namespace)\ndb.find(db, namespace, filter)\ndb.find(db, namespace, select, filter)")); } if (__djonConnection == NULL) { return v8::ThrowException(v8::String::New("You're not connected to any db, please use: connect(server, [port])")); } v8::HandleScope handle_scope; v8::String::Utf8Value strDB(args[0]); std::string db = ToCString(strDB); v8::String::Utf8Value str(args[1]); std::string ns = ToCString(str); std::string select = "*"; std::string filter = ""; if (args.Length() == 3) { v8::String::Utf8Value strFilter(args[2]); filter = ToCString(strFilter); } if (args.Length() == 4) { v8::String::Utf8Value strSelect(args[2]); select = ToCString(strSelect); v8::String::Utf8Value strFilter(args[3]); filter = ToCString(strFilter); } /* std::string json; if (args[2]->IsObject()) { json = toJson(args[2]->ToObject()); } else { json = ToCString(v8::String::Utf8Value(args[2])); } */ try { BSONArrayObj* result = __djonConnection->find(db, ns, select, filter); char* str = result->toChar(); v8::Handle<v8::Value> jsonValue = parseJSON(v8::String::New(str)); free(str); delete result; return jsonValue; } catch (ParseException e) { return v8::ThrowException(v8::String::New("the filter expression contains an error\n")); } /* v8::Handle<v8::Context> context = v8::Context::GetCurrent(); v8::Handle<v8::Object> global = context->Global(); v8::Handle<v8::Object> objresult = global->Get(v8::String::New(sresult.c_str()))->ToObject(); return objresult; //return v8::String::New(sresult.c_str()); */ }
BSONArrayObj* DBController::find(const char* db, const char* ns, const char* select, const char* filter, const BSONObj* options) throw(ParseException) { if (_logger->isDebug()) _logger->debug(2, "DBController::find db: %s, ns: %s, select: %s, filter: %s", db, ns, select, filter); BSONArrayObj* result; FilterParser* parser = FilterParser::parse(filter); std::set<std::string> tokens = parser->tokens(); if (IndexFactory::indexFactory.containsIndex(db, ns, tokens)) { IndexAlgorithm* impl = IndexFactory::indexFactory.index(db, ns, tokens); std::list<Index*> elements = impl->find(parser); std::string filedir = _dataDir + db; filedir = filedir + FILESEPARATOR; std::stringstream ss; ss << filedir << ns << ".dat"; std::string filename = ss.str(); result = new BSONArrayObj(); FileInputStream* fis = new FileInputStream(filename.c_str(), "rb"); DBFileInputStream* dbStream = new DBFileInputStream(fis); BSONInputStream* bis = new BSONInputStream(dbStream); for (std::list<Index*>::iterator it = elements.begin(); it != elements.end(); it++) { Index* index = *it; long posData = index->posData; dbStream->seek(posData); BSONObj* obj = bis->readBSON(select); result->add(*obj); delete obj; } delete bis; delete dbStream; } else { result = findFullScan(db, ns, select, parser, options); } delete parser; return result; }
void testXPath() { cout << "testXPath" << endl; BSONObj* obj1 = BSONParser::parse("{ name: 'John', age: 35, one: { data: 1 }, children: [ { name: 'Joshua', age: 15}, { name: 'Mary', age: 30}] }"); __int32 age = *obj1->getXpath("age"); TEST_ASSERT(age == 35); BSONArrayObj* children = *obj1->getXpath("children"); TEST_ASSERT(children->length() == 2); __int32 data = *obj1->getXpath("one.data"); TEST_ASSERT(data == 1); delete obj1; }
void testTransactionMergedData() { printf("%s\n", "testTransactionMergedData"); BaseTransaction* tx = new BaseTransaction(_controller); tx->dropNamespace("db", "testcommit"); BSONObj ooutTX; std::string* idOut = uuid(); ooutTX.add("_id", const_cast<char*>(idOut->c_str())); ooutTX.add("name", "JohnOut"); tx->insert("db", "testcommit", &ooutTX); // Insert out of the transaction std::string* tuid = uuid(); StdTransaction* stx = new StdTransaction(tx, *tuid); BSONObj o; std::string* id = uuid(); o.add("_id", const_cast<char*>(id->c_str())); o.add("name", "John"); stx->insert("db", "testcommit", &o); BSONArrayObj* res = stx->find("db", "testcommit", "*", ""); TEST_ASSERT(res->length() == 2); BSONArrayObj* resOut = tx->find("db", "testcommit", "*", ""); TEST_ASSERT(resOut->length() == 1); stx->commit(); delete stx; BSONArrayObj* resOut2 = tx->find("db", "testcommit", "*", ""); TEST_ASSERT(resOut2->length() == 2); delete tx; delete res; delete resOut; delete resOut2; delete tuid; printf("%s\n", "~testTransactionMergedData"); }
void testCopyBSON() { cout << "testCopyBSON" << endl; BSONObj* objOrig = new BSONObj(); // Add in objOrig->add("int", 1); objOrig->add("string", (char*)"test"); objOrig->add("long", (__int64)1L); objOrig->add("double", 1.1); BSONObj rel; rel.add("innertext", (char*)"inner text"); objOrig->add("rel1", rel); BSONArrayObj array; BSONObj b1; b1.add("b1", "test"); array.add(b1); BSONObj b2; b2.add("b1", "test2"); array.add(b2); objOrig->add("array", array); BSONObj* obj = new BSONObj(*objOrig); delete objOrig; objOrig = NULL; TEST_ASSERT(obj->has("int")); TEST_ASSERT(obj->getInt("int") == 1); TEST_ASSERT(strcmp(obj->getString("string"), "test") == 0); TEST_ASSERT(obj->has("long")); TEST_ASSERT(obj->getLong("long") == 1L); TEST_ASSERT(obj->has("double")); TEST_ASSERT(obj->getDouble("double") == 1.1); BSONObj* temp = obj->getBSON("rel1"); TEST_ASSERT(temp != NULL); TEST_ASSERT(strcmp(obj->getBSON("rel1")->getString("innertext"), "inner text") == 0); TEST_ASSERT(obj->getBSONArray("array") != NULL); BSONArrayObj* arrayR = obj->getBSONArray("array"); TEST_ASSERT(arrayR != NULL); TEST_ASSERT(arrayR->length() == 2); BSONObj* el1 = arrayR->get(0); TEST_ASSERT(el1 != NULL); BSONObj* el2 = arrayR->get(1); TEST_ASSERT(el2 != NULL); delete obj; }
BSONArrayObj* BSONParser::parseArray(const char* chrs, __int32& pos) { BSONArrayObj* result = NULL; while (chrs[pos] == ' ') { pos++; } if (chrs[pos] != '[') { // error } else { result = new BSONArrayObj(); } while ((pos < strlen(chrs)) && (chrs[pos] != ']')) { while ((pos < strlen(chrs)) && (chrs[pos] != ']') && (chrs[pos] != '{')) pos++; if (chrs[pos] == '{') { BSONObj* bson = parseBSON(chrs, pos); result->add(*bson); delete bson; } } return result; }
void testTransaction() { printf("%s\n", "testTransaction"); DummyController* controller = new DummyController(); BaseTransaction* tx = new BaseTransaction(controller); tx->dropNamespace("db", "txns"); BSONObj o; std::string* id = uuid(); o.add("_id", const_cast<char*>(id->c_str())); o.add("name", "John"); tx->insert("db", "txns", &o); BSONArrayObj* res = tx->find("db", "txns", "*", ""); TEST_ASSERT(res->length() == 1); BSONObj* test1 = *res->begin(); TEST_ASSERT(test1->getString("name").compare("John") == 0); test1->add("name", "Peter"); tx->update("db", "txns", test1); delete res; res = tx->find("db", "txns", "*", ""); TEST_ASSERT(res->length() == 1); BSONObj* test2 = *res->begin(); TEST_ASSERT(test2->getString("name").compare("Peter") == 0); delete res; printf("%s\n", "Deleting tx"); delete tx; delete controller; delete id; printf("%s\n", "~testTransaction"); }
BSONObj* BSONObj::select(const char* sel) const { std::set<std::string> columns = bson_splitSelect(sel); bool include_all = (strcmp(sel, "*") == 0); BSONObj* result = new BSONObj(); for (std::map<std::string, BSONContent* >::const_iterator i = this->_elements.begin(); i != this->_elements.end(); i++) { std::string key = i->first; if (include_all || (columns.find(key) != columns.end())) { BSONContent* origContent = i->second; switch (origContent->type()) { case BSON_TYPE: { BSONContentBSON* bbson = (BSONContentBSON*)origContent; BSONObj* inner = (BSONObj*)*bbson; if (!include_all) { char* subselect = bson_subselect(sel, key.c_str()); BSONObj* innerSubSelect = inner->select(subselect); result->add(key, *innerSubSelect); delete innerSubSelect; } else { result->add(key, *inner); } break; } case BSONARRAY_TYPE: { BSONContentBSONArray* bbsonarray = (BSONContentBSONArray*)origContent; BSONArrayObj* innerArray = (BSONArrayObj*)*bbsonarray; if (!include_all) { char* subselect = bson_subselect(sel, key.c_str()); BSONArrayObj* innerSubArray = innerArray->select(subselect); result->add(key, *innerSubArray); delete innerSubArray; } else { result->add(key, *innerArray); } break; } case BOOL_TYPE: { BSONContentBoolean* bb = (BSONContentBoolean*)origContent; bool val = *bb; result->add(key, val); break; } case INT_TYPE: { BSONContentInt* bint = (BSONContentInt*)origContent; __int32 val = *bint; result->add(key, val); break; } case LONG_TYPE: { BSONContentLong* blong = (BSONContentLong*)origContent; __int64 val = *blong; result->add(key, val); break; } case DOUBLE_TYPE: { BSONContentDouble* bdouble = (BSONContentDouble*)origContent; double val = *bdouble; result->add(key, val); break; } case PTRCHAR_TYPE: case STRING_TYPE: { BSONContentString* bstring = (BSONContentString*)origContent; djondb::string str = *bstring; const char* val = str.c_str(); __int32 len = str.length(); result->add(key, const_cast<char*>(val), len); break; } } } } return result; }
char* BSONObj::toChar() { // if the toChar was already calculated before use it if (_cBSON != NULL) { return strcpy(_cBSON); } Logger* log = getLogger(NULL); char* result = (char*)malloc(MAX_BSONOBJ_BUFFER); memset(result, 0, MAX_BSONOBJ_BUFFER); __int32 pos = 0; result[0] = '{'; pos += 1; bool first = true; for (std::map<std::string, BSONContent* >::const_iterator i = _elements.begin(); i != _elements.end(); i++) { if (!first) { result[pos] = ','; pos++; } first = false; BSONContent* content = i->second; std::string key = i->first; sprintf(result + pos, " \"%s\" : ", key.c_str()); pos += key.length() + 6; //ss << "\"" << key << "\" :"; char* chr; const char* cstr; switch (content->type()) { case BSON_TYPE: { BSONContentBSON* bbson = (BSONContentBSON*)content; BSONObj* bson = (BSONObj*)*bbson; char* chrbson = bson->toChar(); sprintf(result + pos, "%s", chrbson); free(chrbson); break; } case BSONARRAY_TYPE: { BSONContentBSONArray* bbsonarray = (BSONContentBSONArray*)content; BSONArrayObj* bsonarray = (BSONArrayObj*)*bbsonarray; char* chrbsonarray = bsonarray->toChar(); sprintf(result + pos, "%s", chrbsonarray); free(chrbsonarray); break; } case BOOL_TYPE: { BSONContentBoolean* bb = (BSONContentBoolean*)content; sprintf(result + pos, "%s", ((bool)*bb?"true": "false")); break; } case INT_TYPE: { BSONContentInt* bint = (BSONContentInt*)content; sprintf(result + pos, "%d", (__int32)*bint); break; } case LONG_TYPE: { BSONContentLong* blong = (BSONContentLong*)content; sprintf(result + pos, "%ld", (__int64)*blong); break; } case DOUBLE_TYPE: { BSONContentDouble* bdouble = (BSONContentDouble*)content; sprintf(result + pos, "%f", (double)*bdouble); break; } case STRING_TYPE: case PTRCHAR_TYPE: { BSONContentString* bstring = (BSONContentString*)content; djondb::string s = *bstring; sprintf(result + pos, "\"%.*s\"", s.length(), s.c_str()); break; } } pos = strlen(result); assert(pos < MAX_BSONOBJ_BUFFER); } result[pos] = '}'; result[pos+1] = 0; pos++; __int32 len = strlen(result); // Saves the value to cache the calculated value _cBSON = result; char* cresult = strcpy(result); if (log->isDebug()) log->debug("toChar result: %s", cresult); return cresult; }
BSONObj* BSONBufferedObj::select(const char* sel) const { std::set<std::string> columns = bson_splitSelect(sel); bool include_all = (strcmp(sel, "*") == 0); BSONObj* result = new BSONObj(); for (int x = 0; x < _elements; x++) { std::string key(_keys[x], *_keySize[x]); if (include_all || (columns.find(key) != columns.end())) { BSONTYPE type = getType(const_cast<char*>(key.c_str())); switch (type) { case BSON_TYPE: { BSONBufferedObj* inner = getBSON(key); char* subselect = "*"; if (!include_all) { subselect = bson_subselect(sel, key.c_str()); } BSONObj* innerSubSelect = inner->select(subselect); result->add(key, *innerSubSelect); delete innerSubSelect; break; } case BSONARRAY_TYPE: { BSONArrayObj* innerArray = getBSONArray(key); char* subselect = "*"; if (!include_all) { subselect = bson_subselect(sel, key.c_str()); } BSONArrayObj* innerSubArray = innerArray->select(subselect); result->add(key, *innerSubArray); delete innerSubArray; break; } case BOOL_TYPE: { bool val = getBoolean(key); result->add(key, val); break; } case INT_TYPE: { __int32 val = getInt(key); result->add(key, val); break; } case LONG_TYPE: { __int64 val = getLong(key); result->add(key, val); break; } case LONG64_TYPE: { __LONG64 val = getLong(key); result->add(key, val); break; } case DOUBLE_TYPE: { double val = getDouble(key); result->add(key, val); break; } case STRING_TYPE: case PTRCHAR_TYPE: { djondb::string val = getDJString(key); result->add(key, const_cast<char*>(val.c_str()), val.length()); break; } } } } return result; }
void testBSON() { cout << "testBSON" << endl; BSONObj* obj = new BSONObj(); // Add in obj->add("int", 1); obj->add("string", (const char*)"test"); obj->add("long", (__int64) 10000000000L); obj->add("double", 1.1); BSONObj rel; rel.add("innertext", (char*)"inner text"); obj->add("rel1", rel); BSONArrayObj array; BSONObj b1; b1.add("b1", "test"); array.add(b1); BSONObj b2; b2.add("b1", "test2"); array.add(b2); obj->add("array", array); TEST_ASSERT(obj->has("int")); TEST_ASSERT(obj->getInt("int") == 1); TEST_ASSERT(strcmp(obj->getString("string"), "test") == 0); TEST_ASSERT(obj->has("long")); cout << "long: " << obj->getLong("long") << endl; TEST_ASSERT(obj->getLong("long") == 10000000000L); TEST_ASSERT(obj->has("double")); TEST_ASSERT(obj->getDouble("double") == 1.1); TEST_ASSERT(obj->has("rel1")); TEST_ASSERT(strcmp(obj->getBSON("rel1")->getString("innertext"), "inner text") == 0); TEST_ASSERT(obj->has("array")); BSONArrayObj* arrayR = obj->getBSONArray("array"); TEST_ASSERT(arrayR != NULL); TEST_ASSERT(arrayR->length() == 2); BSONObj* el1 = arrayR->get(0); TEST_ASSERT(el1 != NULL); BSONObj* el2 = arrayR->get(1); TEST_ASSERT(el2 != NULL); // test a non existant attribute try { obj->getLong("xx"); TEST_FAIL("The getLong should throw an exception"); } catch (BSONException e) { } try { obj->getString("xxx"); TEST_FAIL("The getString should throw an exception"); } catch (BSONException e) { } delete obj; }
BSONArrayObj* DBController::findFullScan(const char* db, const char* ns, const char* select, FilterParser* parser, const BSONObj* options) throw(ParseException) { if (_logger->isDebug()) _logger->debug(2, "DBController::findFullScan with parser db: %s, ns: %s", db, ns); std::string filedir = _dataDir + db; filedir = filedir + FILESEPARATOR; std::stringstream ss; ss << filedir << ns << ".dat"; std::string filename = ss.str(); // Execute open on streammanager, just to check that the file was alrady opened StreamManager::getStreamManager()->open(db, ns, INDEX_FTYPE); // Execute open on streammanager, just to check that the file was alrady opened StreamManager::getStreamManager()->open(db, ns, DATA_FTYPE); //FileInputStream* fis = new FileInputStream(filename.c_str(), "rb"); MMapInputStream* mmis = new MMapInputStream(filename.c_str(), 0); DBFileInputStream* dbStream = new DBFileInputStream(mmis); BSONArrayObj* result = new BSONArrayObj(); BSONInputStream* bis = new BSONInputStream(dbStream); std::set<std::string> tokens = parser->xpathTokens(); std::string filterSelect; if ((strcmp(select, "*") != 0) && (tokens.size() > 0)) { // this will reserve enough space to concat the filter tokens filterSelect.reserve(tokens.size() * 100); filterSelect.append("$'_status'"); for (std::set<std::string>::iterator i = tokens.begin(); i != tokens.end(); i++) { std::string token = *i; filterSelect.append(", "); filterSelect.append("$'"); filterSelect.append(token); filterSelect.append("'"); } } else { filterSelect = "*"; } mmis->seek(29); BSONBufferedObj* obj = NULL; __int64 maxResults = 3000; if ((options != NULL) && options->has("limit")) { BSONContent* content = options->getContent("limit"); if (content->type() == INT_TYPE) { maxResults = options->getInt("limit"); } else if (content->type() == LONG_TYPE) { maxResults = options->getLong("limit"); } } else { std::string smax = getSetting("max_results"); if (smax.length() > 0) { #ifdef WINDOWS maxResults = _atoi64(smax.c_str()); #else maxResults = atoll(smax.c_str()); #endif } } __int64 count = 0; while (!mmis->eof() && (count < maxResults)) { if (obj == NULL) { obj = new BSONBufferedObj(mmis->pointer(), mmis->length() - mmis->currentPos()); } else { obj->reset(mmis->pointer(), mmis->length() - mmis->currentPos()); } mmis->seek(mmis->currentPos() + obj->bufferLength()); // Only "active" Records if (obj->getInt("_status") == 1) { bool match = false; ExpressionResult* expresult = parser->eval(*obj); if (expresult->type() == ExpressionResult::RT_BOOLEAN) { match = *expresult; } delete expresult; if (match) { BSONObj* objSubselect = obj->select(select); result->add(*objSubselect); delete objSubselect; count++; } } } if (obj != NULL) delete obj; delete bis; dbStream->close(); delete dbStream; return result; }