@@ -17,79 +17,88 @@ class HistoryQueries(val historyIndex: suspend () -> Object<HistoryIndexNode>) :
17
17
override suspend fun sessions (
18
18
timeRange : ClosedRange <Instant >? ,
19
19
delay : Duration ,
20
+ pagination : PaginationParameters ,
20
21
): List <HistoryInterval > {
21
22
val index: Object <HistoryIndexNode > = historyIndex()
22
23
val sessions = ArrayList <HistoryInterval >()
23
- var previousMinTime = Instant .Companion . fromEpochSeconds(Long .MAX_VALUE )
24
+ var previousMinTime = Instant .fromEpochSeconds(Long .MAX_VALUE )
24
25
25
26
// In the worst case two adjacent intervals contain a single entry directly at the border.
26
27
// The maximum difference between these two entries is less than two times the interval.
27
28
val interval = delay / 2
28
29
29
- index.data.splitAtInterval(EquidistantIntervalsSpec (interval).withTimeRangeFilter(timeRange)).iterateSuspending(index.graph) {
30
- if (previousMinTime - it.maxTime >= delay) {
31
- sessions + = HistoryInterval (
32
- firstVersionHash = it.firstVersion.getHash(),
33
- lastVersionHash = it.lastVersion.getHash(),
34
- size = it.size,
35
- minTime = it.minTime,
36
- maxTime = it.maxTime,
37
- authors = it.authors,
38
- )
39
- } else {
40
- val entry = sessions[sessions.lastIndex]
41
- sessions[sessions.lastIndex] = HistoryInterval (
42
- firstVersionHash = it.firstVersion.getHash(),
43
- lastVersionHash = entry.lastVersionHash,
44
- size = entry.size + it.size,
45
- minTime = minOf(entry.minTime, it.minTime),
46
- maxTime = maxOf(entry.maxTime, it.maxTime),
47
- authors = entry.authors + it.authors,
48
- )
30
+ runUntilLimit {
31
+ index.data.splitAtInterval(EquidistantIntervalsSpec (interval).withTimeRangeFilter(timeRange)).iterateSuspending(index.graph) {
32
+ if (previousMinTime - it.maxTime >= delay) {
33
+ if (sessions.lastIndex >= pagination.asRange().last) throw LimitReached ()
34
+ sessions + = HistoryInterval (
35
+ firstVersionHash = it.firstVersion.getHash(),
36
+ lastVersionHash = it.lastVersion.getHash(),
37
+ size = it.size,
38
+ minTime = it.minTime,
39
+ maxTime = it.maxTime,
40
+ authors = it.authors,
41
+ )
42
+ } else {
43
+ val entry = sessions[sessions.lastIndex]
44
+ sessions[sessions.lastIndex] = HistoryInterval (
45
+ firstVersionHash = it.firstVersion.getHash(),
46
+ lastVersionHash = entry.lastVersionHash,
47
+ size = entry.size + it.size,
48
+ minTime = minOf(entry.minTime, it.minTime),
49
+ maxTime = maxOf(entry.maxTime, it.maxTime),
50
+ authors = entry.authors + it.authors,
51
+ )
52
+ }
53
+ previousMinTime = it.minTime
49
54
}
50
- previousMinTime = it.minTime
51
55
}
52
56
53
- return sessions
57
+ return pagination. apply ( sessions)
54
58
}
55
59
56
60
override suspend fun intervals (
57
61
timeRange : ClosedRange <Instant >? ,
58
62
interval : Duration ,
63
+ pagination : PaginationParameters ,
59
64
): List <HistoryInterval > {
60
- return intervals(EquidistantIntervalsSpec (interval).withTimeRangeFilter(timeRange))
65
+ return intervals(EquidistantIntervalsSpec (interval).withTimeRangeFilter(timeRange), pagination )
61
66
}
62
67
63
68
suspend fun intervals (
64
69
intervalsSpec : IntervalsSpec ,
70
+ pagination : PaginationParameters ,
65
71
): List <HistoryInterval > {
66
72
val index: Object <HistoryIndexNode > = historyIndex()
67
73
val mergedEntries = ArrayList <HistoryInterval >()
68
74
var previousIntervalId: Long = Long .MAX_VALUE
69
75
70
- index.data.splitAtInterval(intervalsSpec).iterateSuspending(index.graph) {
71
- val intervalId = intervalsSpec.getIntervalIndex(it.maxTime)
72
- check(intervalId <= previousIntervalId)
73
- if (intervalId == previousIntervalId) {
74
- val entry = mergedEntries[mergedEntries.lastIndex]
75
- mergedEntries[mergedEntries.lastIndex] = HistoryInterval (
76
- firstVersionHash = it.firstVersion.getHash(),
77
- lastVersionHash = entry.lastVersionHash,
78
- size = entry.size + it.size,
79
- minTime = minOf(entry.minTime, it.minTime),
80
- maxTime = maxOf(entry.maxTime, it.maxTime),
81
- authors = entry.authors + it.authors,
82
- )
83
- } else {
84
- previousIntervalId = intervalId
85
- mergedEntries + = HistoryInterval (
86
- firstVersionHash = it.firstVersion.getHash(),
87
- lastVersionHash = it.lastVersion.getHash(),
88
- size = it.size,
89
- minTime = it.minTime,
90
- maxTime = it.maxTime,
91
- authors = it.authors,
92
- )
76
+ runUntilLimit {
77
+ index.data.splitAtInterval(intervalsSpec).iterateSuspending(index.graph) {
78
+ val intervalId = intervalsSpec.getIntervalIndex(it.maxTime)
79
+ check(intervalId <= previousIntervalId)
80
+ if (intervalId == previousIntervalId) {
81
+ val entry = mergedEntries[mergedEntries.lastIndex]
82
+ mergedEntries[mergedEntries.lastIndex] = HistoryInterval (
83
+ firstVersionHash = it.firstVersion.getHash(),
84
+ lastVersionHash = entry.lastVersionHash,
85
+ size = entry.size + it.size,
86
+ minTime = minOf(entry.minTime, it.minTime),
87
+ maxTime = maxOf(entry.maxTime, it.maxTime),
88
+ authors = entry.authors + it.authors,
89
+ )
90
+ } else {
91
+ if (mergedEntries.lastIndex >= pagination.asRange().last) throw LimitReached ()
92
+ previousIntervalId = intervalId
93
+ mergedEntries + = HistoryInterval (
94
+ firstVersionHash = it.firstVersion.getHash(),
95
+ lastVersionHash = it.lastVersion.getHash(),
96
+ size = it.size,
97
+ minTime = it.minTime,
98
+ maxTime = it.maxTime,
99
+ authors = it.authors,
100
+ )
101
+ }
93
102
}
94
103
}
95
104
@@ -98,13 +107,12 @@ class HistoryQueries(val historyIndex: suspend () -> Object<HistoryIndexNode>) :
98
107
99
108
override suspend fun range (
100
109
timeRange : ClosedRange <Instant >? ,
101
- skip : Long ,
102
- limit : Long ,
110
+ pagination : PaginationParameters ,
103
111
): List <HistoryEntry > {
104
112
val index: Object <HistoryIndexNode > = historyIndex()
105
113
val inTimeRange = if (timeRange == null ) index else index.getRange(timeRange).orNull().getSuspending(index.graph)
106
114
if (inTimeRange == null ) return emptyList()
107
- return inTimeRange.data.getRange(skip until (limit + skip ))
115
+ return inTimeRange.data.getRange(pagination.asRange( ))
108
116
.flatMapOrdered { it.getAllVersionsReversed() }
109
117
.flatMapOrdered { it.resolve() }
110
118
.map {
@@ -120,6 +128,14 @@ class HistoryQueries(val historyIndex: suspend () -> Object<HistoryIndexNode>) :
120
128
}
121
129
122
130
override suspend fun splitAt (splitPoints : List <Instant >): List <HistoryInterval > {
123
- return intervals(SplitPointsIntervalSpec (splitPoints))
131
+ return intervals(SplitPointsIntervalSpec (splitPoints), PaginationParameters . ALL )
124
132
}
125
133
}
134
+
135
+ private class LimitReached : RuntimeException (" limit reached" )
136
+
137
+ private inline fun runUntilLimit (body : () -> Unit ) {
138
+ try {
139
+ body()
140
+ } catch (ex: LimitReached ) {}
141
+ }
0 commit comments