Skip to content

Commit 8a8c3ae

Browse files
adutraolim7t
authored andcommitted
JAVA-1157: Allow asynchronous paging of Mapper Result (apache#683)
This commit also extracts a common super-interface for both ResultSet and Result, called PagingIterable.
1 parent c20f24b commit 8a8c3ae

6 files changed

Lines changed: 366 additions & 193 deletions

File tree

changelog/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
- [improvement] JAVA-1233: Update HdrHistogram to 2.1.9.
88
- [improvement] JAVA-1233: Update Snappy to 1.1.2.6.
99
- [bug] JAVA-1161: Preserve full time zone info in ZonedDateTimeCodec and DateTimeCodec.
10+
- [new feature] JAVA-1157: Allow asynchronous paging of Mapper Result.
1011

1112
Merged from 3.0.x branch:
1213

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
/*
2+
* Copyright (C) 2012-2015 DataStax Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.datastax.driver.core;
17+
18+
import com.google.common.util.concurrent.ListenableFuture;
19+
20+
import java.util.Iterator;
21+
import java.util.List;
22+
23+
/**
24+
* Defines an iterable whose elements can be remotely fetched and paged,
25+
* possibly asynchronously.
26+
*/
27+
public interface PagingIterable<S extends PagingIterable<S, T>, T> extends Iterable<T> {
28+
29+
/**
30+
* Returns whether this result set has more results.
31+
*
32+
* @return whether this result set has more results.
33+
*/
34+
boolean isExhausted();
35+
36+
/**
37+
* Whether all results from this result set have been fetched from the
38+
* database.
39+
* <p/>
40+
* Note that if {@code isFullyFetched()}, then {@link #getAvailableWithoutFetching}
41+
* will return how many rows remain in the result set before exhaustion. But
42+
* please note that {@code !isFullyFetched()} never guarantees that the result set
43+
* is not exhausted (you should call {@link #isExhausted()} to verify it).
44+
*
45+
* @return whether all results have been fetched.
46+
*/
47+
boolean isFullyFetched();
48+
49+
/**
50+
* The number of rows that can be retrieved from this result set without
51+
* blocking to fetch.
52+
*
53+
* @return the number of rows readily available in this result set. If
54+
* {@link #isFullyFetched()}, this is the total number of rows remaining
55+
* in this result set (after which the result set will be exhausted).
56+
*/
57+
int getAvailableWithoutFetching();
58+
59+
/**
60+
* Force fetching the next page of results for this result set, if any.
61+
* <p/>
62+
* This method is entirely optional. It will be called automatically while
63+
* the result set is consumed (through {@link #one}, {@link #all} or iteration)
64+
* when needed (i.e. when {@code getAvailableWithoutFetching() == 0} and
65+
* {@code isFullyFetched() == false}).
66+
* <p/>
67+
* You can however call this method manually to force the fetching of the
68+
* next page of results. This can allow to prefetch results before they are
69+
* strictly needed. For instance, if you want to prefetch the next page of
70+
* results as soon as there is less than 100 rows readily available in this
71+
* result set, you can do:
72+
* <pre>
73+
* ResultSet rs = session.execute(...);
74+
* Iterator&lt;Row&gt; iter = rs.iterator();
75+
* while (iter.hasNext()) {
76+
* if (rs.getAvailableWithoutFetching() == 100 &amp;&amp; !rs.isFullyFetched())
77+
* rs.fetchMoreResults();
78+
* Row row = iter.next()
79+
* ... process the row ...
80+
* }
81+
* </pre>
82+
* This method is not blocking, so in the example above, the call to {@code
83+
* fetchMoreResults} will not block the processing of the 100 currently available
84+
* rows (but {@code iter.hasNext()} will block once those rows have been processed
85+
* until the fetch query returns, if it hasn't yet).
86+
* <p/>
87+
* Only one page of results (for a given result set) can be
88+
* fetched at any given time. If this method is called twice and the query
89+
* triggered by the first call has not returned yet when the second one is
90+
* performed, then the 2nd call will simply return a future on the currently
91+
* in progress query.
92+
*
93+
* @return a future on the completion of fetching the next page of results.
94+
* If the result set is already fully retrieved ({@code isFullyFetched() == true}),
95+
* then the returned future will return immediately but not particular error will be
96+
* thrown (you should thus call {@link #isFullyFetched()} to know if calling this
97+
* method can be of any use}).
98+
*/
99+
ListenableFuture<S> fetchMoreResults();
100+
101+
/**
102+
* Returns the next result from this result set.
103+
*
104+
* @return the next row in this result set or null if this result set is
105+
* exhausted.
106+
*/
107+
T one();
108+
109+
/**
110+
* Returns all the remaining rows in this result set as a list.
111+
* <p/>
112+
* Note that, contrary to {@link #iterator()} or successive calls to
113+
* {@link #one()}, this method forces fetching the full content of the result set
114+
* at once, holding it all in memory in particular. It is thus recommended
115+
* to prefer iterations through {@link #iterator()} when possible, especially
116+
* if the result set can be big.
117+
*
118+
* @return a list containing the remaining results of this result set. The
119+
* returned list is empty if and only the result set is exhausted. The result set
120+
* will be exhausted after a call to this method.
121+
*/
122+
List<T> all();
123+
124+
/**
125+
* Returns an iterator over the rows contained in this result set.
126+
* <p/>
127+
* The {@link Iterator#next} method is equivalent to calling {@link #one}.
128+
* So this iterator will consume results from this result set and after a
129+
* full iteration, the result set will be empty.
130+
* <p/>
131+
* The returned iterator does not support the {@link Iterator#remove} method.
132+
*
133+
* @return an iterator that will consume and return the remaining rows of
134+
* this result set.
135+
*/
136+
Iterator<T> iterator();
137+
138+
/**
139+
* Returns information on the execution of the last query made for this result set.
140+
* <p/>
141+
* Note that in most cases, a result set is fetched with only one query, but large
142+
* result sets can be paged and thus be retrieved by multiple queries. In that
143+
* case this method return the {@link ExecutionInfo} for the last query
144+
* performed. To retrieve the information for all queries, use {@link #getAllExecutionInfo}.
145+
* <p/>
146+
* The returned object includes basic information such as the queried hosts,
147+
* but also the Cassandra query trace if tracing was enabled for the query.
148+
*
149+
* @return the execution info for the last query made for this result set.
150+
*/
151+
ExecutionInfo getExecutionInfo();
152+
153+
/**
154+
* Return the execution information for all queries made to retrieve this
155+
* result set.
156+
* <p/>
157+
* Unless the result set is large enough to get paged underneath, the returned
158+
* list will be singleton. If paging has been used however, the returned list
159+
* contains the {@link ExecutionInfo} objects for all the queries done to obtain this
160+
* result set (at the time of the call) in the order those queries were made.
161+
*
162+
* @return a list of the execution info for all the queries made for this result set.
163+
*/
164+
List<ExecutionInfo> getAllExecutionInfo();
165+
166+
}

driver-core/src/main/java/com/datastax/driver/core/ResultSet.java

Lines changed: 5 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,6 @@
1616
package com.datastax.driver.core;
1717

1818

19-
import com.google.common.util.concurrent.ListenableFuture;
20-
21-
import java.util.Iterator;
22-
import java.util.List;
23-
2419
/**
2520
* The result of a query.
2621
* <p/>
@@ -39,7 +34,11 @@
3934
* <p/>
4035
* Note that this class is not thread-safe.
4136
*/
42-
public interface ResultSet extends Iterable<Row> {
37+
public interface ResultSet extends PagingIterable<ResultSet, Row> {
38+
39+
// redeclared only to make clirr happy
40+
@Override
41+
Row one();
4342

4443
/**
4544
* Returns the columns returned in this ResultSet.
@@ -48,144 +47,6 @@ public interface ResultSet extends Iterable<Row> {
4847
*/
4948
public ColumnDefinitions getColumnDefinitions();
5049

51-
/**
52-
* Returns whether this ResultSet has more results.
53-
*
54-
* @return whether this ResultSet has more results.
55-
*/
56-
public boolean isExhausted();
57-
58-
/**
59-
* Returns the next result from this ResultSet.
60-
*
61-
* @return the next row in this resultSet or null if this ResultSet is
62-
* exhausted.
63-
*/
64-
public Row one();
65-
66-
/**
67-
* Returns all the remaining rows in this ResultSet as a list.
68-
* <p/>
69-
* Note that, contrary to {@code iterator()} or successive calls to
70-
* {@code one()}, this method forces fetching the full content of the ResultSet
71-
* at once, holding it all in memory in particular. It is thus recommended
72-
* to prefer iterations through {@code iterator()} when possible, especially
73-
* if the ResultSet can be big.
74-
*
75-
* @return a list containing the remaining results of this ResultSet. The
76-
* returned list is empty if and only the ResultSet is exhausted. The ResultSet
77-
* will be exhausted after a call to this method.
78-
*/
79-
public List<Row> all();
80-
81-
/**
82-
* Returns an iterator over the rows contained in this ResultSet.
83-
* <p/>
84-
* The {@link Iterator#next} method is equivalent to calling {@link #one}.
85-
* So this iterator will consume results from this ResultSet and after a
86-
* full iteration, the ResultSet will be empty.
87-
* <p/>
88-
* The returned iterator does not support the {@link Iterator#remove} method.
89-
*
90-
* @return an iterator that will consume and return the remaining rows of
91-
* this ResultSet.
92-
*/
93-
@Override
94-
public Iterator<Row> iterator();
95-
96-
/**
97-
* The number of rows that can be retrieved from this result set without
98-
* blocking to fetch.
99-
*
100-
* @return the number of rows readily available in this result set. If
101-
* {@link #isFullyFetched()}, this is the total number of rows remaining
102-
* in this result set (after which the result set will be exhausted).
103-
*/
104-
public int getAvailableWithoutFetching();
105-
106-
/**
107-
* Whether all results from this result set have been fetched from the
108-
* database.
109-
* <p/>
110-
* Note that if {@code isFullyFetched()}, then {@link #getAvailableWithoutFetching}
111-
* will return how many rows remain in the result set before exhaustion. But
112-
* please note that {@code !isFullyFetched()} never guarantees that the result set
113-
* is not exhausted (you should call {@code isExhausted()} to verify it).
114-
*
115-
* @return whether all results have been fetched.
116-
*/
117-
public boolean isFullyFetched();
118-
119-
/**
120-
* Force fetching the next page of results for this result set, if any.
121-
* <p/>
122-
* This method is entirely optional. It will be called automatically while
123-
* the result set is consumed (through {@link #one}, {@link #all} or iteration)
124-
* when needed (i.e. when {@code getAvailableWithoutFetching() == 0} and
125-
* {@code isFullyFetched() == false}).
126-
* <p/>
127-
* You can however call this method manually to force the fetching of the
128-
* next page of results. This can allow to prefetch results before they are
129-
* strictly needed. For instance, if you want to prefetch the next page of
130-
* results as soon as there is less than 100 rows readily available in this
131-
* result set, you can do:
132-
* <pre>
133-
* ResultSet rs = session.execute(...);
134-
* Iterator&lt;Row&gt; iter = rs.iterator();
135-
* while (iter.hasNext()) {
136-
* if (rs.getAvailableWithoutFetching() == 100 &amp;&amp; !rs.isFullyFetched())
137-
* rs.fetchMoreResults();
138-
* Row row = iter.next()
139-
* ... process the row ...
140-
* }
141-
* </pre>
142-
* This method is not blocking, so in the example above, the call to {@code
143-
* fetchMoreResults} will not block the processing of the 100 currently available
144-
* rows (but {@code iter.hasNext()} will block once those rows have been processed
145-
* until the fetch query returns, if it hasn't yet).
146-
* <p/>
147-
* Only one page of results (for a given result set) can be
148-
* fetched at any given time. If this method is called twice and the query
149-
* triggered by the first call has not returned yet when the second one is
150-
* performed, then the 2nd call will simply return a future on the currently
151-
* in progress query.
152-
*
153-
* @return a future on the completion of fetching the next page of results.
154-
* If the result set is already fully retrieved ({@code isFullyFetched() == true}),
155-
* then the returned future will return immediately but not particular error will be
156-
* thrown (you should thus call {@code isFullyFetched() to know if calling this
157-
* method can be of any use}).
158-
*/
159-
public ListenableFuture<ResultSet> fetchMoreResults();
160-
161-
/**
162-
* Returns information on the execution of the last query made for this ResultSet.
163-
* <p/>
164-
* Note that in most cases, a ResultSet is fetched with only one query, but large
165-
* result sets can be paged and thus be retrieved by multiple queries. In that
166-
* case this method return the {@code ExecutionInfo} for the last query
167-
* performed. To retrieve the information for all queries, use {@link #getAllExecutionInfo}.
168-
* <p/>
169-
* The returned object includes basic information such as the queried hosts,
170-
* but also the Cassandra query trace if tracing was enabled for the query.
171-
*
172-
* @return the execution info for the last query made for this ResultSet.
173-
*/
174-
public ExecutionInfo getExecutionInfo();
175-
176-
/**
177-
* Return the execution information for all queries made to retrieve this
178-
* ResultSet.
179-
* <p/>
180-
* Unless the ResultSet is large enough to get paged underneath, the returned
181-
* list will be singleton. If paging has been used however, the returned list
182-
* contains the {@code ExecutionInfo} for all the queries done to obtain this
183-
* ResultSet (at the time of the call) in the order those queries were made.
184-
*
185-
* @return a list of the execution info for all the queries made for this ResultSet.
186-
*/
187-
public List<ExecutionInfo> getAllExecutionInfo();
188-
18950
/**
19051
* If the query that produced this ResultSet was a conditional update,
19152
* return whether it was successfully applied.

0 commit comments

Comments
 (0)