Skip to content

Commit

Permalink
✨ Allow to specify hint index by name
Browse files Browse the repository at this point in the history
  • Loading branch information
ujibang committed Jan 8, 2025
1 parent 6f753fd commit 5204ab5
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 44 deletions.
25 changes: 13 additions & 12 deletions commons/src/main/java/org/restheart/exchange/MongoRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@

import org.bson.BsonArray;
import org.bson.BsonDocument;
import org.bson.BsonInt32;
import org.bson.BsonInvalidOperationException;
import org.bson.BsonString;
import org.bson.BsonValue;
Expand Down Expand Up @@ -74,6 +73,7 @@
import static org.restheart.exchange.ExchangeKeys._TRANSACTIONS;
import org.restheart.mongodb.RSOps;
import org.restheart.mongodb.db.sessions.ClientSessionImpl;
import static org.restheart.utils.BsonUtils.array;
import static org.restheart.utils.BsonUtils.document;
import org.restheart.utils.MongoServiceAttachments;
import org.restheart.utils.URLUtils;
Expand Down Expand Up @@ -883,35 +883,36 @@ public BsonDocument getSortByDocument() throws JsonParseException {
}

/**
*
* @return @throws JsonParseException
* hints can be either an index document as {"key":1} or an index name
* the compact format is allowed, eg. +key means {"key":1}
* if the value is a string (not starting with + or -) than it is taken into account as an index name
* @return an array of hints, either documents or strings (index names)
*/
public BsonDocument getHintDocument() throws JsonParseException {
public BsonArray getHintValue() {
if (hint == null || hint.isEmpty()) {
return null;
} else {
var ret = new BsonDocument();
var ret = array();

hint.stream().forEach(s -> {
var _s = s.strip(); // the + sign is decoded into a space, in case remove it

// manage the case where hint is a json object
try {
var _hint = BsonDocument.parse(_s);

ret.putAll(_hint);
ret.add(BsonDocument.parse(_s));
} catch (JsonParseException e) {
// ret is just a string, i.e. an index name
if (_s.startsWith("-")) {
ret.put(_s.substring(1), new BsonInt32(-1));
ret.add(document().put(_s.substring(1), -1));
} else if (_s.startsWith("+")) {
ret.put(_s.substring(1), new BsonInt32(11));
ret.add(document().put(_s.substring(1), 1));
} else {
ret.put(_s, new BsonInt32(1));
ret.add(_s);
}
}
});

return ret;
return ret.get();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,6 @@
*/
package org.restheart.test.integration;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;

import java.net.URI;

import org.apache.http.HttpEntity;
Expand All @@ -33,6 +28,10 @@
import org.apache.http.client.fluent.Request;
import org.apache.http.client.fluent.Response;
import org.apache.http.util.EntityUtils;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.restheart.exchange.Exchange;
Expand All @@ -42,6 +41,7 @@
import com.eclipsesource.json.JsonArray;
import com.eclipsesource.json.JsonObject;
import com.eclipsesource.json.JsonValue;

import kong.unirest.Unirest;

/**
Expand Down Expand Up @@ -211,7 +211,7 @@ public void createTestData() throws Exception {
@SuppressWarnings("rawtypes")
public void testGetHintStringFormat() throws Exception {
kong.unirest.HttpResponse resp = Unirest.get(url(DB, COLL))
.queryString("hint", "a")
.queryString("hint", "+a")
.queryString("sort", "{}")
.basicAuth(ADMIN_ID, ADMIN_PWD)
.asString();
Expand Down
34 changes: 23 additions & 11 deletions mongodb/src/main/java/org/restheart/mongodb/db/Collections.java
Original file line number Diff line number Diff line change
Expand Up @@ -166,18 +166,29 @@ FindIterable<BsonDocument> findIterable(
final MongoCollection<BsonDocument> coll,
final BsonDocument sortBy,
final BsonDocument filters,
final BsonDocument hint,
final BsonArray hints,
final BsonDocument keys,
final int batchSize) throws JsonParseException {
var ret = cs.isPresent()
? coll.find(cs.get(), filters)
: coll.find(filters);

return ret.projection(keys)
var find = ret.projection(keys)
.sort(sortBy)
.batchSize(batchSize)
.hint(hint)
.maxTime(MongoServiceConfiguration.get().getQueryTimeLimit(), TimeUnit.MILLISECONDS);

if (hints != null) {
for (var hint : hints) {
find = switch(hint) {
case BsonString hintStr -> find.hintString(hintStr.getValue());
case BsonDocument hintDoc -> find.hint(hintDoc);
default -> find;
};
}
}

return find;
}

/**
Expand All @@ -190,7 +201,7 @@ FindIterable<BsonDocument> findIterable(
* @param pagesize
* @param sortBy
* @param filter
* @param hint
* @param hints
* @param keys
* @param cursorAllocationPolicy
* @return the documents in the collection as a BsonArray
Expand All @@ -204,23 +215,23 @@ BsonArray getCollectionData(
final int pagesize,
final BsonDocument sortBy,
final BsonDocument filters,
final BsonDocument hint,
final BsonArray hints,
final BsonDocument keys,
final boolean useCache)
throws JsonParseException {
var coll = collection(rsOps, dbName, collName);
var ret = new BsonArray();

if (!useCache) {
return getCollectionDataFromDb(cs, coll, rsOps, dbName, collName, page, pagesize, sortBy, filters, hint, keys, useCache);
return getCollectionDataFromDb(cs, coll, rsOps, dbName, collName, page, pagesize, sortBy, filters, hints, keys, useCache);
} else {
var from = pagesize * (page - 1);
var to = from + pagesize;

var match = GetCollectionCache.getInstance().find(new GetCollectionCacheKey(cs, coll, sortBy, filters, hint, keys, from, to, 0, false));
var match = GetCollectionCache.getInstance().find(new GetCollectionCacheKey(cs, coll, sortBy, filters, keys, hints, from, to, 0, false));

if (match == null) {
return getCollectionDataFromDb(cs, coll, rsOps, dbName, collName, page, pagesize, sortBy, filters, hint, keys, useCache);
return getCollectionDataFromDb(cs, coll, rsOps, dbName, collName, page, pagesize, sortBy, filters, hints, keys, useCache);
} else {
var maxToIndex = match.getKey().to() - match.getKey().from();
var fromIndex = from - match.getKey().from();
Expand Down Expand Up @@ -279,15 +290,15 @@ private BsonArray getCollectionDataFromDb(final Optional<ClientSession> cs,
final int pagesize,
final BsonDocument sortBy,
final BsonDocument filters,
final BsonDocument hint,
final BsonArray hints,
final BsonDocument keys,
final boolean useCache) {
var ret = new BsonArray();
int from = pagesize * (page - 1);

var batchSize = useCache ? GET_COLLECTION_CACHE_BATCH_SIZE : pagesize;

try (var cursor = findIterable(cs, coll, sortBy, filters, hint, keys, batchSize).skip(from).cursor()) {
try (var cursor = findIterable(cs, coll, sortBy, filters, hints, keys, batchSize).skip(from).cursor()) {
int added = 0;
while(added < pagesize) {
var next = cursor.tryNext();
Expand All @@ -304,7 +315,8 @@ private BsonArray getCollectionDataFromDb(final Optional<ClientSession> cs,
var count = cursorCount(cursor);
var to = from + count;
var exhausted = count < GET_COLLECTION_CACHE_BATCH_SIZE;
var newkey = new GetCollectionCacheKey(cs, coll, sortBy, filters, hint, keys, from, to, System.nanoTime(), exhausted);

var newkey = new GetCollectionCacheKey(cs, coll, sortBy, filters, keys, hints, from, to, System.nanoTime(), exhausted);
LOGGER.debug("{} entry in collection cache: {}", ansi().fg(YELLOW).bold().a("new").reset().toString(), newkey);

var cursorDocs = cursorDocs(cursor);
Expand Down
12 changes: 6 additions & 6 deletions mongodb/src/main/java/org/restheart/mongodb/db/Databases.java
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ public long getCollectionSize(final Optional<ClientSession> cs, Optional<RSOps>
* @param pagesize
* @param sortBy
* @param filters
* @param hint
* @param hints
* @param keys
* @param useCache
* @return the documents in the collection as a BsonArray
Expand All @@ -490,11 +490,11 @@ public BsonArray getCollectionData(
final int pagesize,
final BsonDocument sortBy,
final BsonDocument filters,
final BsonDocument hint,
final BsonArray hints,
final BsonDocument keys,
final boolean useCache)
throws JsonParseException {
return collections.getCollectionData(cs, rsOps, dbName, collName, page, pagesize, sortBy, filters, hint, keys, useCache);
return collections.getCollectionData(cs, rsOps, dbName, collName, page, pagesize, sortBy, filters, hints, keys, useCache);
}

/**
Expand Down Expand Up @@ -600,7 +600,7 @@ public List<BsonDocument> getCollectionIndexes(
* @param collName the collection name
* @param sortBy
* @param filters
* @param hint
* @param hints
* @param keys
* @param batchSize
* @return the FindIterable
Expand All @@ -612,15 +612,15 @@ public FindIterable<BsonDocument> findIterable(
final String collName,
final BsonDocument sortBy,
final BsonDocument filters,
final BsonDocument hint,
final BsonArray hints,
final BsonDocument keys,
final int batchSize) {
return collections.findIterable(
cs,
collections.collection(rsOps, dbName, collName),
sortBy,
filters,
hint,
hints,
keys,
batchSize);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,15 @@
*/
package org.restheart.mongodb.db;

import com.mongodb.client.ClientSession;
import com.mongodb.client.MongoCollection;
import java.util.Formatter;
import java.util.Optional;

import org.bson.BsonArray;
import org.bson.BsonDocument;
import org.restheart.utils.BsonUtils;

import com.mongodb.client.ClientSession;
import com.mongodb.client.MongoCollection;

/**
*
Expand All @@ -37,7 +40,7 @@ public record GetCollectionCacheKey(
BsonDocument sort,
BsonDocument filter,
BsonDocument keys,
BsonDocument hint,
BsonArray hints,
int from,
int to,
long cursorId,
Expand All @@ -50,10 +53,10 @@ public static GetCollectionCacheKey clone(GetCollectionCacheKey key) {
return new GetCollectionCacheKey(
key.session,
key.collection,
key.sort,
key.filter,
key.keys,
key.hint,
key.sort,
key.hints,
key.from,
key.to,
key.cursorId,
Expand All @@ -66,7 +69,7 @@ String getCacheStatsGroup() {
+ " - "
+ (sort == null ? "no sort" : sort.toString())
+ " - "
+ (hint == null ? "no hint" : hint.toString())
+ (hints == null ? "no hints" : BsonUtils.toJson(hints))
+ " - "
+ f.format("%10d", from)
+ " - "
Expand All @@ -77,13 +80,13 @@ String getCacheStatsGroup() {
@Override
public String toString() {
return String.format(
"[session=%s, collection=%s, sort=%s, filter=%s, keys=%s, hint=%s, from=%s, to=%s, cursorId=%s, exhausted=%s]",
"[session=%s, collection=%s, sort=%s, filter=%s, keys=%s, hints=%s, from=%s, to=%s, cursorId=%s, exhausted=%s]",
session,
collection.getNamespace(),
sort,
filter,
keys,
hint,
hints,
from,
to,
cursorId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ public void handleRequest(HttpServerExchange exchange) throws Exception {
request.getPagesize(),
sort,
filter,
request.getHintDocument(),
request.getHintValue(),
request.getProjectionDocument(),
request.isCache() && isGetCollectionCacheEnabled);
}
Expand Down

0 comments on commit 5204ab5

Please sign in to comment.