DATAMONGO-1480 - Add support for noCursorTimeout in Query.

We now allow setting noCursorTimeout for queries using `Query` and `@Meta`.

Query query = new Query().noCursorTimeout();

and

interface PersonRepository extends CrudRepository<Person, String> {

    @Meta(noCursorTimeout = true)
    Iterable<Person> findBy();

    @Meta(noCursorTimeout = true)
    Stream<Person> streamBy();
}

Original Pull Request: #390
This commit is contained in:
Mark Paluch
2016-09-10 16:58:24 +02:00
committed by Christoph Strobl
parent b6bc0ea316
commit 98dca5a65e
8 changed files with 99 additions and 14 deletions

View File

@@ -139,6 +139,7 @@ import com.mongodb.util.JSONParseException;
* @author Christoph Strobl
* @author Doménique Tilleuil
* @author Niko Schmuck
* @author Mark Paluch
*/
@SuppressWarnings("deprecation")
public class MongoTemplate implements MongoOperations, ApplicationContextAware {
@@ -2249,7 +2250,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
* @author Thomas Darimont
*/
static interface DbObjectCallback<T> {
interface DbObjectCallback<T> {
T doWith(DBObject object);
}
@@ -2347,23 +2348,33 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
DBCursor cursorToUse = cursor.copy();
try {
if (query.getSkip() > 0) {
cursorToUse = cursorToUse.skip(query.getSkip());
}
if (query.getLimit() > 0) {
cursorToUse = cursorToUse.limit(query.getLimit());
}
if (query.getSortObject() != null) {
DBObject sortDbo = type != null ? getMappedSortObject(query, type) : query.getSortObject();
cursorToUse = cursorToUse.sort(sortDbo);
}
if (StringUtils.hasText(query.getHint())) {
cursorToUse = cursorToUse.hint(query.getHint());
}
if (query.getMeta().hasValues()) {
for (Entry<String, Object> entry : query.getMeta().values()) {
cursorToUse = cursorToUse.addSpecial(entry.getKey(), entry.getValue());
}
if (query.getMeta().isNoCursorTimeout() != null && query.getMeta().isNoCursorTimeout().booleanValue()) {
cursorToUse = cursorToUse.addOption(Bytes.QUERYOPTION_NOTIMEOUT);
}
}
} catch (RuntimeException e) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,6 +30,7 @@ import org.springframework.util.StringUtils;
*
* @author Christoph Strobl
* @author Oliver Gierke
* @author Mark Paluch
* @since 1.6
*/
public class Meta {
@@ -39,12 +40,13 @@ public class Meta {
private String key;
private MetaKey(String key) {
MetaKey(String key) {
this.key = key;
}
}
private final Map<String, Object> values = new LinkedHashMap<String, Object>(2);
private Boolean noCursorTimeout;
/**
* @return {@literal null} if not set.
@@ -120,11 +122,29 @@ public class Meta {
return getValue(MetaKey.SNAPSHOT.key, false);
}
/**
* @return {@literal null} if not set.
* @since 1.10
*/
public Boolean isNoCursorTimeout() {
return this.noCursorTimeout;
}
/**
* Instructs the server to avoid closing a cursor automatically after a period of inactivity.
*
* @param noCursorTimeout
* @since 1.10
*/
public void setNoCursorTimeout(boolean noCursorTimeout) {
this.noCursorTimeout = noCursorTimeout;
}
/**
* @return
*/
public boolean hasValues() {
return !this.values.isEmpty();
return !this.values.isEmpty() || this.noCursorTimeout != null;
}
/**

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 the original author or authors.
* Copyright 2010-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -41,6 +41,7 @@ import com.mongodb.DBObject;
* @author Oliver Gierke
* @author Thomas Darimont
* @author Christoph Strobl
* @author Mark Paluch
*/
public class Query {
@@ -336,6 +337,17 @@ public class Query {
return this;
}
/**
* @return
* @see Meta#setNoCursorTimeout(boolean)
* @since 1.10
*/
public Query noCursorTimeout() {
meta.setNoCursorTimeout(true);
return this;
}
/**
* @return never {@literal null}.
* @since 1.6

View File

@@ -75,4 +75,12 @@ public @interface Meta {
*/
boolean snapshot() default false;
/**
* Instructs the server to avoid closing a cursor automatically after a period of inactivity.
*
* @return
* @since 1.10
*/
boolean noCursorTimeout() default false;
}

View File

@@ -248,6 +248,10 @@ public class MongoQueryMethod extends QueryMethod {
metaAttributes.setSnapshot(meta.snapshot());
}
if (meta.noCursorTimeout()) {
metaAttributes.setNoCursorTimeout(meta.noCursorTimeout());
}
return metaAttributes;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2014 the original author or authors.
* Copyright 2011-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,6 +32,7 @@ import org.springframework.data.mongodb.core.MongoTemplate.QueryCursorPreparer;
import org.springframework.data.mongodb.core.query.Meta;
import org.springframework.data.mongodb.core.query.Query;
import com.mongodb.Bytes;
import com.mongodb.DBCursor;
/**
@@ -39,6 +40,7 @@ import com.mongodb.DBCursor;
*
* @author Oliver Gierke
* @author Christoph Strobl
* @author Mark Paluch
*/
@RunWith(MockitoJUnitRunner.class)
public class QueryCursorPreparerUnitTests {
@@ -61,7 +63,7 @@ public class QueryCursorPreparerUnitTests {
Query query = query(where("foo").is("bar")).withHint("hint");
pepare(query);
prepare(query);
verify(cursorToUse).hint("hint");
}
@@ -75,7 +77,7 @@ public class QueryCursorPreparerUnitTests {
Query query = query(where("foo").is("bar"));
query.setMeta(new Meta());
pepare(query);
prepare(query);
verify(cursor, never()).copy();
verify(cursorToUse, never()).addSpecial(any(String.class), anyObject());
@@ -89,7 +91,7 @@ public class QueryCursorPreparerUnitTests {
Query query = query(where("foo").is("bar")).maxScan(100);
pepare(query);
prepare(query);
verify(cursorToUse).addSpecial(eq("$maxScan"), eq(100L));
}
@@ -102,7 +104,7 @@ public class QueryCursorPreparerUnitTests {
Query query = query(where("foo").is("bar")).maxTime(1, TimeUnit.SECONDS);
pepare(query);
prepare(query);
verify(cursorToUse).addSpecial(eq("$maxTimeMS"), eq(1000L));
}
@@ -115,7 +117,7 @@ public class QueryCursorPreparerUnitTests {
Query query = query(where("foo").is("bar")).comment("spring data");
pepare(query);
prepare(query);
verify(cursorToUse).addSpecial(eq("$comment"), eq("spring data"));
}
@@ -128,12 +130,25 @@ public class QueryCursorPreparerUnitTests {
Query query = query(where("foo").is("bar")).useSnapshot();
pepare(query);
prepare(query);
verify(cursorToUse).addSpecial(eq("$snapshot"), eq(true));
}
private DBCursor pepare(Query query) {
/**
* @see DATAMONGO-1480
*/
@Test
public void appliesNoCursorTimeoutCorrectly() {
Query query = query(where("foo").is("bar")).noCursorTimeout();
prepare(query);
verify(cursorToUse).addOption(Bytes.QUERYOPTION_NOTIMEOUT);
}
private DBCursor prepare(Query query) {
CursorPreparer preparer = new MongoTemplate(factory).new QueryCursorPreparer(query, null);
return preparer.prepare(cursor);

View File

@@ -347,7 +347,7 @@ public class AbstractMongoQueryUnitTests {
List<Person> findByFirstname(String firstname);
@Meta(comment = "comment")
@Meta(comment = "comment", noCursorTimeout = true)
Page<Person> findByFirstname(String firstnanme, Pageable pageable);
@Meta(comment = "comment")

View File

@@ -201,6 +201,18 @@ public class MongoQueryMethodUnitTests {
assertThat(method.getQueryMetaAttributes().getSnapshot(), is(true));
}
/**
* @see DATAMONGO-1480
*/
@Test
public void createsMongoQueryMethodWithNoCursorTimeoutCorrectly() throws Exception {
MongoQueryMethod method = queryMethod(PersonRepository.class, "metaWithNoCursorTimeout");
assertThat(method.hasQueryMetaAttributes(), is(true));
assertThat(method.getQueryMetaAttributes().isNoCursorTimeout(), is(true));
}
/**
* @see DATAMONGO-1266
*/
@@ -250,6 +262,9 @@ public class MongoQueryMethodUnitTests {
@Meta(snapshot = true)
List<User> metaWithSnapshotUsage();
@Meta(noCursorTimeout = true)
List<User> metaWithNoCursorTimeout();
/**
* @see DATAMONGO-1266
*/