Skip to content

Commit

Permalink
Merge pull request #696 from MrCreosote/develop
Browse files Browse the repository at this point in the history
Refactor metadata setting code for reuse
  • Loading branch information
MrCreosote authored Oct 16, 2023
2 parents 37acadd + 6eba5e7 commit dcab463
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 27 deletions.
54 changes: 40 additions & 14 deletions src/us/kbase/workspace/database/mongo/MongoWorkspaceDB.java
Original file line number Diff line number Diff line change
Expand Up @@ -698,12 +698,37 @@ private void setCreatedWorkspacePermissions(

private static final Set<String> FLDS_WS_META = newHashSet(Fields.WS_META);

@FunctionalInterface
interface DocumentProvider {
Map<String, Object> getDocument()
throws WorkspaceCommunicationException, CorruptWorkspaceDBException;
}

@Override
public Optional<Instant> setWorkspaceMeta(
final ResolvedWorkspaceID rwsi,
final WorkspaceUserMetadata newMeta,
final List<String> remove)
throws WorkspaceCommunicationException, CorruptWorkspaceDBException {
return setMetadataOnDocument(
newMeta,
remove,
COL_WORKSPACES,
() -> query.queryWorkspace(rwsi, FLDS_WS_META),
new Document(Fields.WS_ID, rwsi.getID()),
Fields.WS_META,
Fields.WS_MODDATE);
}

private Optional<Instant> setMetadataOnDocument(
final WorkspaceUserMetadata newMeta,
final List<String> remove,
final String collection,
final DocumentProvider dp,
final Document identifier,
final String metaField,
final String moddateField)
throws WorkspaceCommunicationException, CorruptWorkspaceDBException {
if (remove == null && (newMeta == null || newMeta.isEmpty())) {
throw new IllegalArgumentException("No metadata changes provided");
}
Expand All @@ -713,10 +738,9 @@ public Optional<Instant> setWorkspaceMeta(
int attempts = 1;
Instant time = null;
while (time == null) {
final Map<String, Object> ws = query.queryWorkspace(rwsi, FLDS_WS_META);
final Map<String, Object> doc = dp.getDocument();
@SuppressWarnings("unchecked")
final List<Map<String, String>> mlist = (List<Map<String, String>>)
ws.get(Fields.WS_META);
final List<Map<String, String>> mlist = (List<Map<String, String>>) doc.get(metaField);
final Map<String, String> oldMeta = metaMongoArrayToHash(mlist);
final Map<String, String> updatedMeta = new HashMap<>(oldMeta);
if (newMeta != null) {
Expand All @@ -737,30 +761,32 @@ public Optional<Instant> setWorkspaceMeta(
"Updated metadata exceeds allowed size of %sB",
WorkspaceUserMetadata.MAX_METADATA_SIZE));
}
final Document query = new Document(Fields.WS_ID, rwsi.getID())
.append(Fields.WS_META, mlist);
final Document metaUpdate = new Document(
Fields.WS_META, metaHashToMongoArray(updatedMeta));
time = _internal_setWorkspaceMeta(attempts, 5, query, metaUpdate);
final Document query = identifier.append(metaField, mlist);
final Document metaUpdate = new Document(metaField, metaHashToMongoArray(updatedMeta));
time = _internal_setMeta(attempts, 5, collection, query, metaUpdate, moddateField);
attempts++;
}
return Optional.of(time);
}

// split the method for testing purposes
private Instant _internal_setWorkspaceMeta(
private Instant _internal_setMeta(
final int attempts,
final int maxattempts,
final String collection,
final Document query,
final Document metaUpdate)
final Document metaUpdate,
final String modDateField)
throws WorkspaceCommunicationException {
try {
final Instant time = clock.instant();
// only match if the metadata we pulled from the db is stil the same, so we don't
if (modDateField != null) {
metaUpdate.append(modDateField, Date.from(time));
}
// only match if the metadata we pulled from the db is still the same, so we don't
// clobber any interleaving changes
final UpdateResult ur = wsmongo.getCollection(COL_WORKSPACES).updateOne(
query,
new Document("$set", metaUpdate.append(Fields.WS_MODDATE, Date.from(time))));
final UpdateResult ur = wsmongo.getCollection(collection).updateOne(
query, new Document("$set", metaUpdate));
if (ur.getModifiedCount() == 1) { //ok, it worked
return time;
} else if (attempts >= maxattempts) {
Expand Down
73 changes: 64 additions & 9 deletions src/us/kbase/workspace/test/database/mongo/MongoInternalsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.lang.reflect.Method;
import java.nio.file.Paths;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
Expand Down Expand Up @@ -64,6 +65,7 @@
import us.kbase.workspace.database.ResolvedWorkspaceID;
import us.kbase.workspace.database.ResourceUsageConfigurationBuilder;
import us.kbase.workspace.database.Types;
import us.kbase.workspace.database.UncheckedUserMetadata;
import us.kbase.workspace.database.Workspace;
import us.kbase.workspace.database.WorkspaceIdentifier;
import us.kbase.workspace.database.WorkspaceInformation;
Expand Down Expand Up @@ -1221,18 +1223,20 @@ public void typeFieldsOnClone() throws Exception {

private Method getSetWorkspaceMetadataInternalMethod() throws Exception {
final Method m = MongoWorkspaceDB.class.getDeclaredMethod(
"_internal_setWorkspaceMeta",
"_internal_setMeta",
int.class,
int.class,
String.class,
Document.class,
Document.class);
Document.class,
String.class);
m.setAccessible(true);
return m;
}

private ResolvedWorkspaceID setWorkspaceMetadataCreateWorkspace(
Map<String, String> meta) throws Exception {
final WorkspaceUser user = new WorkspaceUser("foo");
final WorkspaceUser user = new WorkspaceUser("u");
final ResolvedWorkspaceID rwsi = new ResolvedWorkspaceID(1, "foo", false, false);
ws.createWorkspace(user, rwsi.getName(), false, null, new WorkspaceUserMetadata(meta));
return rwsi;
Expand All @@ -1243,20 +1247,67 @@ public void setWorkspaceMetadataInternalsPassAfterPreviousAttempts() throws Exce
final Method m = getSetWorkspaceMetadataInternalMethod();
final ResolvedWorkspaceID rwsi = setWorkspaceMetadataCreateWorkspace(
ImmutableMap.of("a", "b"));
final Instant wscreate = mwdb.getWorkspaceInformation(null, rwsi).getModDate();
final Instant result = (Instant) m.invoke(
mwdb,
3,
5,
"workspaces",
new Document("ws", 1).append("meta", Arrays.asList(
ImmutableMap.of("k", "a", "v", "b"))),
new Document("meta", Arrays.asList(
ImmutableMap.of("k", "a", "v", "x"), ImmutableMap.of("k", "y", "v", "z"))),
"moddate"
);
assertCloseToNow(result);
assertThat("moddate changed", result.isAfter(wscreate), is(true));
final WorkspaceInformation wi = mwdb.getWorkspaceInformation(null, rwsi);
assertThat("incorrect workspace info", wi, is(WorkspaceInformation.getBuilder()
.withID(1)
.withMaximumObjectID(0)
.withUserPermission(Permission.NONE)
.withModificationDate(result.truncatedTo(ChronoUnit.MILLIS)) // mongo truncates
.withName("foo")
.withOwner(new WorkspaceUser("u"))
.withUserMetadata(new UncheckedUserMetadata(ImmutableMap.of(
"a", "x", "y", "z")))
.build()
));
}

@Test
public void setWorkspaceMetadataInternalsPassAfterPreviousAttemptsNoModDate()
throws Exception {
final Method m = getSetWorkspaceMetadataInternalMethod();
final ResolvedWorkspaceID rwsi = setWorkspaceMetadataCreateWorkspace(
ImmutableMap.of("a", "b"));
final Instant wscreate = mwdb.getWorkspaceInformation(null, rwsi).getModDate();

final Instant result = (Instant) m.invoke(
mwdb,
3,
5,
"workspaces",
new Document("ws", 1).append("meta", Arrays.asList(
ImmutableMap.of("k", "a", "v", "b"))),
new Document("meta", Arrays.asList(
ImmutableMap.of("k", "a", "v", "x"), ImmutableMap.of("k", "y", "v", "z")))
ImmutableMap.of("k", "a", "v", "x"), ImmutableMap.of("k", "y", "v", "z"))),
null
);
assertCloseToNow(result);
final Map<String, String> meta = mwdb.getWorkspaceInformation(
new WorkspaceUser("foo"), rwsi).getUserMeta().getMetadata();
assertThat("incorrect meta", meta, is(ImmutableMap.of("a", "x", "y", "z")));
assertThat("moddate changed", result.isAfter(wscreate), is(true));
final WorkspaceInformation wi = mwdb.getWorkspaceInformation(null, rwsi);
assertThat("incorrect workspace info", wi, is(WorkspaceInformation.getBuilder()
.withID(1)
.withMaximumObjectID(0)
.withUserPermission(Permission.NONE)
.withModificationDate(wscreate)
.withName("foo")
.withOwner(new WorkspaceUser("u"))
.withUserMetadata(new UncheckedUserMetadata(ImmutableMap.of(
"a", "x", "y", "z")))
.build()
));
}

@Test
Expand All @@ -1269,10 +1320,12 @@ public void setWorkspaceMetadataInternalsNoUpdateAfterPreviousAttempts() throws
mwdb,
3,
5,
"workspaces",
new Document("ws", 1).append("meta", Arrays.asList(
ImmutableMap.of("k", "a", "v", "c"))),
new Document("meta", Arrays.asList(
ImmutableMap.of("k", "a", "v", "x"), ImmutableMap.of("k", "y", "v", "z")))
ImmutableMap.of("k", "a", "v", "x"), ImmutableMap.of("k", "y", "v", "z"))),
"moddate"
);
assertThat("incorrect time", result, is(nullValue()));
final Map<String, String> meta = mwdb.getWorkspaceInformation(
Expand All @@ -1290,11 +1343,13 @@ public void setWorkspaceMetadataInternalsFailAfterPreviousAttempts() throws Exce
mwdb,
5,
5,
"workspaces",
new Document("ws", 1).append("meta", Arrays.asList(
ImmutableMap.of("k", "a", "v", "c"))),
new Document("meta", Arrays.asList(
ImmutableMap.of("k", "a", "v", "x"),
ImmutableMap.of("k", "y", "v", "z")))
ImmutableMap.of("k", "y", "v", "z"))),
"moddate"
);
} catch (InvocationTargetException e) {
assertExceptionCorrect(e.getCause(), new WorkspaceCommunicationException(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,16 @@
import us.kbase.workspace.database.ByteArrayFileCacheManager;
import us.kbase.workspace.database.ObjectIDResolvedWS;
import us.kbase.workspace.database.ObjectInformation;
import us.kbase.workspace.database.Permission;
import us.kbase.workspace.database.Reference;
import us.kbase.workspace.database.exceptions.CorruptWorkspaceDBException;
import us.kbase.workspace.database.exceptions.NoObjectDataException;
import us.kbase.workspace.database.exceptions.WorkspaceCommunicationException;
import us.kbase.workspace.database.ResolvedObjectIDNoVer;
import us.kbase.workspace.database.ResolvedSaveObject;
import us.kbase.workspace.database.ResolvedWorkspaceID;
import us.kbase.workspace.database.UncheckedUserMetadata;
import us.kbase.workspace.database.WorkspaceInformation;
import us.kbase.workspace.database.WorkspaceObjectData;
import us.kbase.workspace.database.WorkspaceSaveObject;
import us.kbase.workspace.database.WorkspaceUser;
Expand Down Expand Up @@ -880,10 +883,19 @@ public void setWorkspaceMetadata() throws Exception {

assertThat("incorrect time", result2, is(Optional.of(inst(15000))));

final Map<String, String> m2 = mocks.mdb.getWorkspaceInformation(
user, rwsi).getUserMeta().getMetadata();
assertThat("incorrect meta", m2, is(ImmutableMap.of(
"foo", "bar", "baz", "bing", "thingy", "thinger")));
// check that the whole info is ok at least once
final WorkspaceInformation m2 = mocks.mdb.getWorkspaceInformation(user, rwsi);
assertThat("incorrect workspace info", m2, is(WorkspaceInformation.getBuilder()
.withID(1)
.withMaximumObjectID(0)
.withUserPermission(Permission.OWNER)
.withModificationDate(inst(15000))
.withName("wsn")
.withOwner(new WorkspaceUser("a"))
.withUserMetadata(new UncheckedUserMetadata(ImmutableMap.of(
"foo", "bar", "baz", "bing", "thingy", "thinger")))
.build()
));
}

@Test
Expand Down

0 comments on commit dcab463

Please sign in to comment.