Skip to content

Commit

Permalink
Merge pull request #99 from kbase/dev-mongo7_upgrade
Browse files Browse the repository at this point in the history
mongo7 upgrade
  • Loading branch information
Xiangs18 authored Oct 28, 2024
2 parents 9d204a4 + dd85c57 commit a43205e
Show file tree
Hide file tree
Showing 7 changed files with 183 additions and 257 deletions.
7 changes: 3 additions & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ jobs:
# the current production setup
- java: '8'
mongo: 'mongodb-linux-x86_64-3.6.13'
wired_tiger: 'false'
gradle_test: 'test'
- java: '11'
mongo: 'mongodb-linux-x86_64-ubuntu2204-7.0.4'
steps:
- uses: actions/checkout@v3

Expand Down Expand Up @@ -57,8 +57,7 @@ jobs:
- name: Run tests
shell: bash
run: |
./gradlew ${{matrix.gradle_test}}
run: ./gradlew test

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
Expand Down
8 changes: 7 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,10 @@ dependencies {
implementation 'org.ini4j:ini4j:0.5.2'
implementation 'com.fasterxml.jackson.core:jackson-annotations:2.2.3'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.2.3'
implementation 'org.mongodb:mongo-java-driver:3.10.1'
implementation 'org.mongodb:mongodb-driver-core:4.11.1'
implementation 'org.mongodb:mongodb-driver-sync:4.11.1'
implementation 'org.mongodb:bson-record-codec:4.11.1'
implementation 'org.mongodb:bson:4.11.1'
implementation 'org.yaml:snakeyaml:1.11'
implementation 'org.apache.velocity:velocity:1.7'
implementation 'commons-io:commons-io:2.4'
Expand All @@ -193,6 +196,9 @@ dependencies {
testImplementation 'junit:junit:4.12'
testImplementation 'org.mockito:mockito-core:3.0.0'
testImplementation 'org.apache.commons:commons-lang3:3.5'
testImplementation('com.github.kbase:java_test_utilities:0.1.0') {
exclude group: 'com.fasterxml.jackson.core' // upgrading breaks stuff
}
}

task showTestClassPath {
Expand Down

Large diffs are not rendered by default.

101 changes: 25 additions & 76 deletions src/main/java/us/kbase/narrativemethodstore/db/mongo/MongoUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,12 @@
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.bson.BSONObject;
import org.bson.LazyBSONList;
import org.bson.types.BasicBSONList;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.model.Projections;

import us.kbase.common.service.UObject;
import us.kbase.narrativemethodstore.exceptions.NarrativeMethodStoreException;
Expand All @@ -21,10 +19,8 @@
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.introspect.VisibilityChecker;
import com.mongodb.BasicDBObject;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.client.MongoCollection;
import org.bson.Document;

public class MongoUtils {
private static final String HEXES = "0123456789abcdef";
Expand All @@ -37,17 +33,21 @@ public class MongoUtils {

@SuppressWarnings({ "unchecked" })
public static <T> List<T> getProjection(
final DBCollection infos,
final DBObject whereCondition,
final MongoCollection<Document> infos,
final Document whereCondition,
final String selectField,
final Class<T> type)
throws NarrativeMethodStoreException {
final DBCursor cur = infos.find(whereCondition, new BasicDBObject(selectField, 1));
MongoCursor<Document> cursor = infos.find(whereCondition)
.projection(Projections.include(selectField))
.iterator();

final List<Map<String, Object>> data = new LinkedList<>();
for (final DBObject dbo: cur) {
data.add(toMap(dbo));
while (cursor.hasNext()) {
final Map<String, Object> map = cursor.next();
data.add(map);
}

List<T> ret = new ArrayList<T>();
for (Map<?,?> item : data) {
Object value = item.get(selectField);
Expand All @@ -58,81 +58,30 @@ public static <T> List<T> getProjection(
return ret;
}

/** Map an object to a MongoDB {@link DBObject}. The object must be serializable by
/**
* Map an object to a MongoDB {@link Document}. The object must be serializable by
* an {@link ObjectMapper} configured so private fields are visible.
*
* @param obj the object to map.
* @return the new mongo compatible object.
* @return the new mongo document.
*/
public static DBObject toDBObject(final Object obj) {
return new BasicDBObject(objToMap(obj));
public static Document toDocument(final Object obj) {
return new Document(objToMap(obj));
}

private static Map<String, Object> objToMap(final Object obj) {
return MAPPER.convertValue(obj, new TypeReference<Map<String, Object>>() {});
}


/** Map a MongoDB {@link DBObject} to a class.
* This method expects that all maps and lists in the objects are implemented as
* {@link BSONObject}s or derived classes, not standard maps, lists, or other classes.

/** Map a MongoDB {@link Document} to a class.
* The object must be deserializable by an {@link ObjectMapper} configured so private
* fields are visible.
* @param dbo the MongoDB object to transform.
* @param doc the MongoDB document to transform.
* @param clazz the class to which the object will be transformed.
* @return the transformed object.
*/
public static <T> T toObject(final DBObject dbo, final Class<T> clazz) {
return dbo == null ? null : MAPPER.convertValue(toMap(dbo), clazz);
}

/** Map a MongoDB {@link BSONObject} to a standard map.
* This method expects that all maps and lists in the objects are implemented as
* {@link BSONObject}s or derived classes, not standard maps, lists, or other classes.
* @param dbo the MongoDB object to transform to a standard map.
* @return the transformed object, or null if the argument was null.
*/
public static Map<String, Object> toMap(final BSONObject dbo) {
@SuppressWarnings("unchecked")
final Map<String, Object> ret = (Map<String, Object>) cleanObject(dbo);
return ret;
}

// this assumes there aren't BSONObjects embedded in standard objects, which should
// be the case for stuff returned from mongo

// Unimplemented error for dbo.toMap()
// dbo is read only
// can't call ObjectMapper.convertValue() on dbo since it has a 'size' field outside of
// the internal map
// and just weird shit happens when you do anyway
private static Object cleanObject(final Object dbo) {
// sometimes it's lazy, sometimes it's basic. Not sure when or why.
if (dbo instanceof LazyBSONList) {
final List<Object> ret = new LinkedList<>();
// don't stream, sometimes has issues with nulls
for (final Object obj: (LazyBSONList) dbo) {
ret.add(cleanObject(obj));
}
return ret;
} else if (dbo instanceof BasicBSONList) {
final List<Object> ret = new LinkedList<>();
// don't stream, sometimes has issues with nulls
for (final Object obj: (BasicBSONList) dbo) {
ret.add(cleanObject(obj));
}
} else if (dbo instanceof BSONObject) {
// can't stream because streams don't like null values at HashMap.merge()
final BSONObject m = (BSONObject) dbo;
final Map<String, Object> ret = new HashMap<>();
for (final String k: m.keySet()) {
if (!k.equals("_id")) {
final Object v = m.get(k);
ret.put(k, cleanObject(v));
}
}
return ret;
}
return dbo;
public static <T> T toObject(final Document doc, final Class<T> clazz) {
return doc == null ? null : MAPPER.convertValue(doc, clazz);
}

public static String stringToHex(String text) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@
import java.io.IOException;
import java.net.ServerSocket;
import java.nio.file.Files;
import java.util.Arrays;

import us.kbase.common.utils.ProcessHelper;
import us.kbase.narrativemethodstore.util.TextUtils;
import us.kbase.testutils.controllers.mongo.MongoController;

public class MongoDBHelper {
private String tempDirName = "test/temp";
Expand All @@ -17,6 +15,8 @@ public class MongoDBHelper {
private File mongoDir = null;
private int mongoPort = -1;

private static MongoController mongo;

public MongoDBHelper(String testName) {
this.testName = testName;
}
Expand All @@ -41,7 +41,7 @@ public void startup(String mongoExePath) throws Exception {
}

public void shutdown(boolean deleteTempDir) throws Exception {
killPid(mongoDir);
destroy(mongoDir);
if (deleteTempDir && mongoDir.exists())
deleteRecursively(mongoDir);
}
Expand All @@ -51,58 +51,20 @@ private static int startupMongo(String mongodExePath, File dir) throws Exception
mongodExePath = "mongod";
if (!dir.exists())
dir.mkdirs();
File dataDir = new File(dir, "data");
dataDir.mkdir();
File logFile = new File(dir, "mongodb.log");
int port = findFreePort();
File configFile = new File(dir, "mongod.conf");
TextUtils.writeLines(Arrays.asList(
"dbpath=" + dataDir.getAbsolutePath(),
"logpath=" + logFile.getAbsolutePath(),
"logappend=true",
"port=" + port,
"bind_ip=127.0.0.1"
), configFile);
File scriptFile = new File(dir, "start_mongo.sh");
TextUtils.writeLines(Arrays.asList(
"#!/bin/bash",
"cd " + dir.getAbsolutePath(),
mongodExePath + " --nojournal --config " + configFile.getAbsolutePath() + " >out.txt 2>err.txt & pid=$!",
"echo $pid > pid.txt"
), scriptFile);
ProcessHelper.cmd("bash", scriptFile.getCanonicalPath()).exec(dir);
boolean ready = false;
int waitSec = 120;
for (int n = 0; n < waitSec; n++) {
Thread.sleep(1000);
if (logFile.exists()) {
if (TextUtils.grep(TextUtils.lines(logFile), "waiting for connections on port " + port).size() > 0) {
ready = true;
break;
}
}
}
if (!ready) {
if (logFile.exists())
for (String l : TextUtils.lines(logFile))
System.err.println("MongoDB log: " + l);
throw new IllegalStateException("MongoDB couldn't startup in " + waitSec + " seconds");
}
System.out.println(dir.getName() + " was started up");
return port;
mongo = new MongoController(mongodExePath, dir.toPath(), true);
System.out.println(String.format("Testing against mongo executable %s on port %s",
mongodExePath, mongo.getServerPort()));
return mongo.getServerPort();
}

private static void killPid(File dir) {
private static void destroy(File dir) {
if (dir == null)
return;
try {
File pidFile = new File(dir, "pid.txt");
if (pidFile.exists()) {
String pid = TextUtils.lines(pidFile).get(0).trim();
ProcessHelper.cmd("kill", pid).exec(dir);
System.out.println(dir.getName() + " was stopped");
}
} catch (Exception ignore) {}
if (mongo != null) {
try {
mongo.destroy(true);
} catch (Exception ignore) {}
}
}

private static int findFreePort() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,10 @@
import org.junit.BeforeClass;
import org.junit.Test;

import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.MongoClient;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import org.bson.Document;

import us.kbase.narrativemethodstore.db.DynamicRepoDB.FileProvider;
import us.kbase.narrativemethodstore.db.DynamicRepoDB.RepoState;
Expand Down Expand Up @@ -76,12 +77,12 @@ public static void afterClass() throws Exception {

@Before
public void before() throws Exception {
final MongoClient mc = new MongoClient("localhost:" + MONGO.getMongoPort());
final DB db = mc.getDB(DB_NAME);
for (final String name: db.getCollectionNames()) {
if (!name.startsWith("system.")) {
// dropping collection also drops indexes
db.getCollection(name).remove(new BasicDBObject());
try (final MongoClient mc = MongoClients.create("mongodb://localhost:" + MONGO.getMongoPort())) {
final MongoDatabase db = mc.getDatabase(DB_NAME);
for (final String collectionName: db.listCollectionNames()) {
if (!collectionName.startsWith("system.")) {
db.getCollection(collectionName).deleteMany(new Document()); // Delete all documents without dropping the indexes
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
import org.junit.Test;

import com.fasterxml.jackson.databind.JsonNode;
import com.mongodb.DB;
import com.mongodb.MongoClient;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;

import us.kbase.common.service.UObject;
import us.kbase.narrativemethodstore.MethodBriefInfo;
Expand Down Expand Up @@ -272,10 +272,9 @@ private static boolean diffFiles(File f1, File f2, int bufferSize) throws Except
@Before
@After
public void cleanup() throws Exception {
String host = "localhost:" + dbHelper.getMongoPort();
final MongoClient mc = new MongoClient(host);
final DB db = mc.getDB(dbName);
db.dropDatabase();
mc.close();
final String host = "mongodb://localhost:" + dbHelper.getMongoPort();
try (final MongoClient mc = MongoClients.create(host)) {
mc.getDatabase(dbName).drop();
}
}
}

0 comments on commit a43205e

Please sign in to comment.