bool DjondbConnection::insert(const char* db, const char* ns, const BSONObj& bson) { if (_logger->isDebug()) _logger->debug(2, "Insert command. db: %s, ns: %s", db, ns); if (!isOpen()) { throw DjondbException(D_ERROR_CONNECTION, "Not connected to any server"); } BSONObj* obj = new BSONObj(bson); InsertCommand cmd; cmd.setDB(db); if (!obj->has("_id")) { std::string* id = uuid(); obj->add("_id", const_cast<char*>(id->c_str())); delete id; } if (!obj->has("_revision")) { std::string* rev = uuid(); obj->add("_revision", const_cast<char*>(rev->c_str())); delete rev; } cmd.setBSON(obj); cmd.setNameSpace(ns); prepareOptions((Command*)&cmd); _commandWriter->writeCommand(&cmd); cmd.readResult(_inputStream); int hasResults = false; //_inputStream->readInt(); if (hasResults) { // When the bson didnt contain an id the server will return a bson with it // At this moment this will never occur, but I will leave this code for later } return true; }
// this method is executed in a thread to simulate multiple clients void* commandClients(void* arg) { NetworkOutputStream* nos = new NetworkOutputStream(); int socket = nos->open("localhost", _port); NetworkInputStream* nis = new NetworkInputStream(socket); Logger* log = getLogger(NULL); CommandWriter* writer = new CommandWriter(nos); for (int x = 0; x < 10; x++) { log->info("client: preparing insert"); InsertCommand* cmd = new InsertCommand(); cmd->setDB("db1"); cmd->setNameSpace("ns"); BSONObj* o = new BSONObj(); std::string* id = uuid(); o->add("_id", id->c_str()); delete id; std::string* rev = uuid(); o->add("_revision", rev->c_str()); delete rev; o->add("name", "John"); cmd->setBSON(o); BSONObj* options = new BSONObj(); cmd->setOptions(options); log->info("client: writing insert command"); writer->writeCommand(cmd); log->info("client: insert command sent"); delete cmd; log->info("client: preparing showdbs command"); ShowdbsCommand* showCmd = new ShowdbsCommand(); BSONObj* options2 = new BSONObj(); showCmd->setOptions(options2); log->info("client: sending showCmd"); writer->writeCommand(showCmd); log->info("client: waiting showDbs answer"); int dbs = nis->readInt(); EXPECT_EQ(dbs, 3); char* db1 = nis->readChars(); EXPECT_TRUE(strcmp(db1, "db1") == 0); char* db2 = nis->readChars(); EXPECT_TRUE(strcmp(db2, "db2") == 0); char* db3 = nis->readChars(); EXPECT_TRUE(strcmp(db3, "db3") == 0); log->info("client: showDbs received"); free(db1); free(db2); free(db3); } log->info("client: sending ShutdownCommand"); ShutdownCommand* shut = new ShutdownCommand(); writer->writeCommand(shut); log->info("client: shutdown sent"); nis->close(); }
void DBController::remove(const char* db, const char* ns, const char* documentId, const char* revision, const BSONObj* options) { if (_logger->isDebug()) _logger->debug(2, "DBController::update db: %s, ns: %s, documentId: %s, revision: %s", db, ns, documentId, revision); StreamType* streamData = StreamManager::getStreamManager()->open(db, ns, DATA_FTYPE); IndexAlgorithm* impl = IndexFactory::indexFactory.index(db, ns, "_id"); BSONObj indexBSON; indexBSON.add("_id", documentId); Index* index = impl->find(&indexBSON); if (index != NULL) { // TODO check the revision id StreamType* out = StreamManager::getStreamManager()->open(db, ns, DATA_FTYPE); out->flush(); long currentPos = out->currentPos(); out->seek(index->posData); BSONObj* obj = readBSON(out); obj->add("_status", 2); // DELETED // Get back to the record start out->seek(index->posData); writeBSON(out, obj); // restores the last position out->seek(currentPos); //std::string id = obj->getDJString("_id"); //CacheManager::objectCache()->remove(id); delete obj; } }
TEST(TestCommand, testInsertCommand) { cout << "testInsertCommand" << endl; FileOutputStream* fos = new FileOutputStream("test.dat", "wb"); CommandWriter* commandWriter = new CommandWriter(fos); InsertCommand cmd; cmd.setDB("testdb"); cmd.setNameSpace("test.namespace.db"); BSONObj* obj = new BSONObj(); obj->add("name", "Cross"); obj->add("age", 18); cmd.setBSON(obj); commandWriter->writeCommand(&cmd); fos->close(); delete fos; delete commandWriter; FileInputStream* fis = new FileInputStream("test.dat", "rb"); CommandReader* reader = new CommandReader(fis); InsertCommand* rdCmd = (InsertCommand*) reader->readCommand(); EXPECT_TRUE(rdCmd != NULL); EXPECT_TRUE(rdCmd->nameSpace()->compare("test.namespace.db") == 0); EXPECT_TRUE(rdCmd->DB()->compare("testdb") == 0); const BSONObj* objResult = rdCmd->bson(); EXPECT_TRUE(objResult != NULL); EXPECT_TRUE(objResult->has("name")); EXPECT_TRUE(objResult->getString("name").compare("Cross") == 0); }
TEST(TestCommand, testUpdateCommand) { cout << "testUpdateCommand" << endl; FileOutputStream* fos = new FileOutputStream("test.dat", "wb"); CommandWriter* commandWriter = new CommandWriter(fos); UpdateCommand cmd; cmd.setDB("testdb"); cmd.setNameSpace("test.namespace.db"); BSONObj obj; std::string* uid = uuid(); obj.add("_id", const_cast<char*>(uid->c_str())); delete uid; obj.add("name", "Cross"); obj.add("age", 18); cmd.setBSON(obj); commandWriter->writeCommand(&cmd); fos->close(); delete fos; delete commandWriter; FileInputStream* fis = new FileInputStream("test.dat", "rb"); CommandReader* reader = new CommandReader(fis); UpdateCommand* rdCmd = (UpdateCommand*) reader->readCommand(); EXPECT_TRUE(rdCmd != NULL); EXPECT_TRUE(rdCmd->nameSpace()->compare("test.namespace.db") == 0); EXPECT_TRUE(rdCmd->DB()->compare("testdb") == 0); BSONObj* objResult = rdCmd->bson(); EXPECT_TRUE(objResult != NULL); EXPECT_TRUE(objResult->has("name")); EXPECT_TRUE(objResult->getString("name").compare("Cross") == 0); }
void testToChar() { cout << "testToChar" << endl; BSONObj obj; obj.add("int", 1); obj.add("string", (char*)"test"); obj.add("char*", (char*)"char*"); obj.add("long", (__int64)1L); obj.add("double", 1.1); char* json = obj.toChar(); int res = strcmp(json, "{ \"char*\" : \"char*\", \"double\" : 1.100000, \"int\" : 1, \"long\" : 1, \"string\" : \"test\"}"); TEST_ASSERT(res == 0); if (res != 0) { cout << "\nResult: " << json << endl; } free(json); BSONObj inner; inner.add("int", 1); inner.add("string", (char*)"test"); inner.add("char*", (char*)"char*"); inner.add("long", (__int64)1L); inner.add("double", 1.1); obj.add("inner", inner); json = obj.toChar(); cout << "\nResult: " << json << endl; free(json); }
void* producer(void* arg) { NetworkOutputStream* nos = new NetworkOutputStream(); int socket = nos->open("localhost", _port); printf("Producer started\n"); Logger* log = getLogger(NULL); log->info("Producer starter"); log->startTimeRecord(); if (socket > 0) { NetworkInputStream* nis = new NetworkInputStream(socket); std::auto_ptr<CommandWriter> writer(new CommandWriter(nos)); for (int x = 0; x < MAX_INSERT; x++) { std::auto_ptr<InsertCommand> cmd(new InsertCommand()); BSONObj* obj = new BSONObj(); std::auto_ptr<std::string> guid(uuid()); obj->add("_id", guid->c_str()); char* temp = (char*)malloc(2000); memset(temp, 0, 2000); memset(temp, 'a', 1999); int len = strlen(temp); obj->add("content", temp); free(temp); cmd->setBSON(obj); std::string db("mydb"); cmd->setDB(db); std::string ns("myns"); cmd->setNameSpace(ns); cmd->setOptions(new BSONObj()); writer->writeCommand(cmd.get()); int result = nis->readInt(); EXPECT_EQ(result, 1); if (result != 1) { break; } } nis->close(); } else { printf("Socket is 0"); } log->info("Producer end"); log->stopTimeRecord(); DTime time = log->recordedTime(); if (time.totalSecs() > 0) { log->info("Producer time: %d secs. Operations per sec: %d", time.totalSecs(), MAX_INSERT / time.totalSecs()); } else { EXPECT_TRUE(false) << "Something was wrong network could not execute " << MAX_INSERT << " in 0 secs."; } }
TEST(testIndexP, testRecoverNames) { Logger* log = getLogger(NULL); std::set<std::string> keys; keys.insert("_id"); BPlusIndexP* index = new BPlusIndexP("testIndexNames"); index->setKeys(keys); FileInputStream* fis = new FileInputStream("names.txt", "r"); cout << "Adding names to the index" << endl; std::vector<std::string> names; int x = 0; while (true) { if (fis->eof()) { cout << "No more names" << endl; break; } if (x >= 100) { break; } x++; BSONObj o; std::string* name = fis->readString(); o.add("_id", name->c_str()); char* temp = strcpy(const_cast<char*>(name->c_str()), name->length()); index->add(o, djondb::string(temp, name->length()), 100); index->debug(); if (log->isDebug()) log->debug("==============================================================================="); names.push_back(*name); delete name; } index->debug(); delete index; cout << "Finding names from the index" << endl; index = new BPlusIndexP("testIndexNames"); index->setKeys(keys); index->debug(); for (std::vector<std::string>::iterator i = names.begin(); i != names.end(); i++) { std::string name = *i; BSONObj o; o.add("_id", name.c_str()); Index* idx = index->find(&o); ASSERT_TRUE(idx != NULL) << "_id " << name.c_str() << " not found"; ASSERT_TRUE(idx->key->has("_id")) << "Retrieved index for _id " << name.c_str() << " does not returned the _id"; EXPECT_TRUE(idx->key->getString("_id").compare(name) == 0) << "Recovered a wrong key, expected: " << name.c_str() << " and retrived: " << idx->key->getString("_id").c_str(); } delete index; }
void DBController::update(const char* db, const char* ns, BSONObj* obj, const BSONObj* options) { if (_logger->isDebug()) _logger->debug(2, "DBController::update ns: %s, bson: %s", ns, obj->toChar()); StreamType* streamData = StreamManager::getStreamManager()->open(db, ns, DATA_FTYPE); Index* index = findIndex(db, ns, obj); long currentPos = streamData->currentPos(); // Moves to the record to update streamData->seek(index->posData); BSONObj* previous = readBSON(streamData); previous->add("_status", 3); // Updated streamData->seek(index->posData); writeBSON(streamData, previous); // Back to the end of the stream streamData->seek(currentPos); updateIndex(db, ns, obj, streamData->currentPos()); obj->add("_status", 1); // Active writeBSON(streamData, obj); //std::string id = obj->getDJString("_id"); //CacheManager::objectCache()->add(id, new BSONObj(*obj)); }
void DBController::updateIndex(const char* db, const char* ns, BSONObj* bson, long filePos) { BSONObj indexBSON; djondb::string id = bson->getDJString("_id"); indexBSON.add("_id", (char*)id); IndexAlgorithm* impl = IndexFactory::indexFactory.index(db, ns, "_id"); impl->update(indexBSON, id, filePos); }
Index* DBController::findIndex(const char* db, const char* ns, BSONObj* bson) { IndexAlgorithm* impl = IndexFactory::indexFactory.index(db, ns, "_id"); BSONObj indexBSON; indexBSON.add("_id", (const char*)bson->getDJString("_id")); Index* index = impl->find(&indexBSON); return index; }
TEST(TestCommand, testOptionsCommand) { cout << "testOptionsCommand" << endl; FileOutputStream* fos = new FileOutputStream("test.dat", "wb"); CommandWriter* commandWriter = new CommandWriter(fos); BSONObj* options = new BSONObj(); std::string* txId = uuid(); options->add("_transactionId", const_cast<char*>(txId->c_str())); delete txId; InsertCommand cmd; cmd.setDB("testdb"); cmd.setNameSpace("test.namespace.db"); cmd.setOptions(options); BSONObj* obj = new BSONObj(); obj->add("name", "Cross"); obj->add("age", 18); cmd.setBSON(obj); commandWriter->writeCommand(&cmd); fos->close(); delete fos; delete commandWriter; FileInputStream* fis = new FileInputStream("test.dat", "rb"); CommandReader* reader = new CommandReader(fis); InsertCommand* rdCmd = (InsertCommand*) reader->readCommand(); EXPECT_TRUE(rdCmd != NULL); EXPECT_TRUE(rdCmd->nameSpace()->compare("test.namespace.db") == 0); EXPECT_TRUE(rdCmd->DB()->compare("testdb") == 0); const BSONObj* objResult = rdCmd->bson(); EXPECT_TRUE(objResult != NULL); EXPECT_TRUE(objResult->has("name")); EXPECT_TRUE(objResult->getString("name").compare("Cross") == 0); EXPECT_TRUE(rdCmd->options() != NULL); if (rdCmd->options() != NULL) { const BSONObj* options = rdCmd->options(); EXPECT_TRUE(options->has("_transactionId")); } }
void testTransactionManager() { printf("%s\n", "testTransactionManager"); // Insert a document in wal BaseTransaction* wal = new BaseTransaction(_controller); wal->dropNamespace("db", "mtx"); TransactionManager* manager = new TransactionManager(wal); BSONObj testA; testA.add("cod", 1); testA.add("name", "William"); wal->insert("db", "mtx", &testA); std::string* t1 = uuid(); StdTransaction* transaction = manager->getTransaction(*t1); std::auto_ptr<BSONArrayObj> array(transaction->find("db", "mtx", "*", "$'cod' == 1")); BSONObj* obj1up = array->get(0); obj1up->add("lastName", "Shakespeare"); transaction->update("db", "mtx", obj1up); std::auto_ptr<BSONArrayObj> array0(wal->find("db", "mtx", "*", "$'cod' == 1")); BSONObj* origin1 = array0->get(0); TEST_ASSERT(!origin1->has("lastName")); std::auto_ptr<BSONArrayObj> array1(transaction->find("db", "mtx", "*", "$'cod' == 1")); BSONObj* objtx1 = array1->get(0); TEST_ASSERT(objtx1->has("lastName")); transaction->commit(); manager->dropTransaction(*t1); std::auto_ptr<BSONArrayObj> array2(wal->find("db", "mtx", "*", "$'cod' == 1")); BSONObj* origin2 = array2->get(0); TEST_ASSERT(origin2->has("lastName")); delete t1; delete manager; printf("%s\n", "~testTransactionManager"); }
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; }
void testAutocasting() { cout << "testAutocasting" << endl; BSONObj o; o.add("long", (__int64)1L); o.add("double", 2.0); o.add("int", 1); o.add("char*", (char*)"Test"); BSONObj inner; inner.add("text", "text"); o.add("inner", inner); TEST_ASSERT(o.getContent("long") != NULL); TEST_ASSERT((__int64)*o.getContent("long") == 1L); TEST_ASSERT(o.getContent("double") != NULL); TEST_ASSERT((double)*o.getContent("double") == 2.0); TEST_ASSERT(o.getContent("int") != NULL); TEST_ASSERT((int)*o.getContent("int") == 1); TEST_ASSERT(o.getContent("inner") != NULL); BSONObj* obj = *o.getContent("inner"); TEST_ASSERT(strcmp(obj->getString("text"), "text") == 0); }
TEST(testIndexP, testRecoverRandom) { std::set<std::string> keys; keys.insert("_id"); BPlusIndexP* index = new BPlusIndexP("testIndex2"); index->setKeys(keys); std::vector<std::string> ids; for (int x = 0; x < 10; x++) { BSONObj o; std::stringstream ss; ss << x; std::string id = ss.str(); o.add("_id", id.c_str()); int n = rand() % 100; if (n > 0) { ids.push_back(id); } char* temp = strcpy(const_cast<char*>(id.c_str()), id.length()); index->add(o, djondb::string(temp, id.length()), 100); index->debug(); } index->debug(); delete index; index = new BPlusIndexP("testIndex2"); index->setKeys(keys); index->debug(); for (std::vector<std::string>::iterator i = ids.begin(); i != ids.end(); i++) { std::string guid = *i; BSONObj o; o.add("_id", guid.c_str()); Index* idx = index->find(&o); ASSERT_TRUE(idx != NULL); ASSERT_TRUE(idx->key->has("_id")); EXPECT_TRUE(idx->key->getString("_id").compare(guid) == 0); } delete index; }
void DjondbConnection::prepareOptions(Command* cmd) { BSONObj* options; if (cmd->options() != NULL) { options = new BSONObj(*cmd->options()); } else { options = new BSONObj(); } if (_activeTransactionId != NULL) { options->add("_transactionId", _activeTransactionId); } cmd->setOptions(options); }
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* convertStruct(struct BSONStruct* param) { BSONObj* obj = new BSONObj(); struct BSONStruct* s = param; BSONStruct* head = s; while (s != NULL) { std::string name(s->name); __int32 type = s->type; void* value = s->value; __int32* val; float* val2; char* val3; BSONObj* inner; switch (type) { case 1: val = (__int32*)value; obj->add(name, *val); break; case 2: val2 = (float*)value; obj->add(name, *val2); break; case 3: val3 = (char*)value; obj->add(name, val3); break; case 4: struct BSONStruct* str = (struct BSONStruct*)value; inner = convertStruct(str); obj->add(name, *inner); delete inner; } s = s->next; } return obj; }
void testTransactionCommit() { printf("%s\n", "testTransactionCommit"); BaseTransaction* tx = new BaseTransaction(_controller); std::string* tuid = uuid(); StdTransaction* stx = new StdTransaction(tx, *tuid); stx->dropNamespace("db", "testcommit"); std::vector<std::string> idsCheck; for (int y = 0; y < 300; y++) { BSONObj o; std::string* id = uuid(); o.add("_id", const_cast<char*>(id->c_str())); o.add("name", "John"); stx->insert("db", "testcommit", &o); if ((y % 10) == 0) { idsCheck.push_back(*id); } delete id; } for (std::vector<std::string>::iterator i = idsCheck.begin(); i != idsCheck.end(); i++) { std::string id = *i; std::string filter = format("$'_id' == '%s'", id.c_str()); BSONObj* res = stx->findFirst("db", "testcommit", "*", filter.c_str()); delete res; } printf("%s\n", "Doing commit"); stx->commit(); delete stx; delete tx; printf("%s\n", "~testTransactionCommit"); }
TEST(testIndexP, testSimple) { std::set<std::string> keys; keys.insert("_id"); BPlusIndexP index("testIndex"); index.setKeys(keys); for (int x = 0; x < 1000; x++) { BSONObj o; std::string* id = uuid(); o.add("_id", id->c_str()); char* temp = strcpy(const_cast<char*>(id->c_str()), id->length()); index.add(o, djondb::string(temp, id->length()), 100); delete id; } }
void testBigBSON() { cout << "testBigBSON" << endl; BSONObj* obj = new BSONObj(); int chars = 1000; // Add in obj->add("int", 1); obj->add("long", (__int64)LONG_MAX); obj->add("long long", (__int64)LLONG_MAX); char* temp = (char*)malloc(chars+1); memset(temp, 0, chars+1); memset(temp, 'a', chars); obj->add("char*", temp); BSONObj rel; rel.add("innertext", temp); obj->add("rel1", rel); char* json = obj->toChar(); BSONObj* obj2 = BSONParser::parse(json); free(json); TEST_ASSERT(obj->has("int")); TEST_ASSERT(obj->getInt("int") == 1); TEST_ASSERT(obj->has("long")); TEST_ASSERT(obj->getLong("long") == LONG_MAX); TEST_ASSERT(obj->has("long long")); TEST_ASSERT(obj->getLong("long long") == LLONG_MAX); TEST_ASSERT(strcmp(obj->getString("char*"), temp) == 0); TEST_ASSERT(obj->has("rel1")); TEST_ASSERT(strcmp(obj->getBSON("rel1")->getString("innertext"), temp) == 0); delete obj; delete obj2; free(temp); }
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; }
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; }
BSONObj* BSONParser::parseBSON(const char* c, __int32& pos) throw(BSONException) { BSONObj* res = new BSONObj(); __int32 state = 0; // 0 - nothing, 1 - name, 2- value __int32 lenBuffer = strlen(c); char* buffer = (char*)malloc(lenBuffer); char* name = NULL; void* value = NULL; __int32 len = 0; BSONTYPE type; __int32 stringOpen = 0; // 0 - closed // 1 - Single quote opened // 2 - Double quote opened __int32 x; for (x= pos; x < strlen(c); x++) { if (c[x] == '{') { if (state == 2) { value = parseBSON(c, x); type = BSON_TYPE; } else if (state == 0) { memset(buffer, 0, lenBuffer); state = 1;// name type = LONG64_TYPE; } else { // state == 1 throw "json value is not allowed as name"; } continue; } if (c[x] == '[') { value = parseArray(c, x); type = BSONARRAY_TYPE; } if (c[x] == '}' || c[x] == ',') { if (name != NULL) { if ((type != BSON_TYPE) && (type != BSONARRAY_TYPE)) { value = (char*)malloc(len+1); memset(value, 0, len + 1); strcpy((char*)value, buffer); } len = 0; memset(buffer, 0, lenBuffer); switch (type) { case BOOL_TYPE: { bool bVal = strcmp((char*)value, "true") == 0; res->add(name, bVal); break; } case INT_TYPE: { __int32 iVal = atoi((char*)value); res->add(name, iVal); break; } case LONG_TYPE: { __int64 lVal = atol((char*)value); res->add(name, lVal); break; } case LONG64_TYPE: { #ifdef WINDOWS __LONG64 lVal = _atoi64((char*)value); #else __LONG64 lVal = atoll((char*)value); #endif if (lVal <= INT_MAX) { res->add(name, (__int32)lVal); } else if (lVal <= LONG_MAX) { res->add(name, (__int64)lVal); } else { res->add(name, lVal); } break; } case DOUBLE_TYPE: { double dVal = atof((char*)value); res->add(name, dVal); break; } case STRING_TYPE: { res->add(name, (char*)value); break; } case BSON_TYPE: { res->add(name, *((BSONObj*)value)); delete (BSONObj*)value; break; } case BSONARRAY_TYPE: { res->add(name, *((BSONArrayObj*)value)); delete (BSONArrayObj*)value; break; } } free(name); name = NULL; if ((type != BSON_TYPE) && (type != BSONARRAY_TYPE)) { free(value); value = NULL; } if (c[x] != '}') { state = 1; // name type = LONG64_TYPE; continue; } } if (c[x] == '}') { break; } } if (c[x] == ':') { name = (char*)malloc(len+1); memset(name, 0, len + 1); strcpy(name, buffer); len = 0; memset(buffer, 0, lenBuffer); state = 2; //value // default type type = LONG64_TYPE; } else { if (c[x] == '\'' || (c[x] == '\"')) { // Collect all the characters type = STRING_TYPE; char stringChar = c[x]; bool escaped = false; x++; __int32 startPos = x; while ((x < strlen(c)) && ((c[x] != stringChar) || (escaped))) { if (c[x] == '\\') { escaped = true; } else { escaped = false; } buffer[len] = c[x]; len++; x++; } if (x >= strlen(c)) { char c[100]; sprintf(c, "An error ocurred parsing the bson. Error: unclosed string at %d", startPos); throw new BSONException(c); } continue; } if (c[x] == ' ' && stringOpen == 0) { continue; } if (c[x] == '\r' || c[x] == '\n') { continue; } if (c[x] == '.' && state == 2) { type = DOUBLE_TYPE; } buffer[len] = c[x]; len++; } } pos = x; free(buffer); return res; }
void testPerfomance(int port, int top = 10000000) { DjondbConnection* conn = DjondbConnectionManager::getConnection("localhost", port); if (!conn->open()) { cout << "Not connected" << endl; exit(0); } // 1k inserts // Logger* log = getLogger(NULL); log->info("Testing performance over: %d inserts.", top); std::vector<std::string>* names = generateNames(top); std::vector<std::string*>* ids = new std::vector<std::string*>(); log->startTimeRecord(); for (int x = 0; x < top; x++) { BSONObj obj; char* text = (char*)malloc(1001); memset(text, 0, 1001); memset(text, 'a', 1000); std::string* id = uuid(); obj.add("_id", id->c_str()); int test = rand() % 100; if (test > 30) { ids->push_back(id); } else { delete id; } obj.add("t", x); obj.add("text", text); obj.add("name", const_cast<char*>(names->at(x).c_str())); conn->insert("db", "testperformance", obj); free(text); // every 10 % will print a message showing the progress if ((x % (top / 10)) == 0) { DTime timeTemp = log->recordedTime(); int progress = (x * 100) / top; if (timeTemp.totalSecs() > 0) { log->info("Inserted %d: throughtput: %d per sec. %d comnpleted", x, (x / timeTemp.totalSecs()), progress); } else { log->info("Inserted :%d, throughtput too high to be measured. %d completed.", x, progress); } } } log->stopTimeRecord(); DTime time = log->recordedTime(); cout << "Total secs: " << time.totalSecs() << endl; if (time.totalSecs() > 0) { log->info("Inserted %d: throughtput: %d.", top, (top / time.totalSecs())); } else { log->info("Inserted %d, throughtput too high to be measured", top); } if ((time.totalSecs() > 0) && ((top / time.totalSecs()) < 16000)) { log->info("Performance is not good enough"); } conn->close(); delete log; }
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; }