Software /
code /
prosody
Comparison
plugins/mod_storage_internal.lua @ 13136:396db0e7084f
mod_storage_internal: Use a binary search for time based ranges
Iterating over an entire archive to find a few items in the far end from
where iteration started is expensive, and probably more expensive with
the lazy-loading of items added in the previous commit.
Since we can now efficiently read items in random order, we can now use
a binary search to find a better starting point for iteration.
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Wed, 12 May 2021 01:32:03 +0200 |
parent | 13135:3fd24e1945b0 |
child | 13187:fe1229919070 |
comparison
equal
deleted
inserted
replaced
13135:3fd24e1945b0 | 13136:396db0e7084f |
---|---|
120 if not ok then return ok, err; end | 120 if not ok then return ok, err; end |
121 archive_item_count_cache:set(cache_key, item_count+1); | 121 archive_item_count_cache:set(cache_key, item_count+1); |
122 return key; | 122 return key; |
123 end | 123 end |
124 | 124 |
125 local function binary_search(haystack, test, min, max) | |
126 if min == nil then | |
127 min = 1; | |
128 end | |
129 if max == nil then | |
130 max = #haystack; | |
131 end | |
132 | |
133 local floor = math.floor; | |
134 while min < max do | |
135 local mid = floor((max + min) / 2); | |
136 | |
137 local result = test(haystack[mid]); | |
138 if result < 0 then | |
139 max = mid; | |
140 elseif result > 0 then | |
141 min = mid + 1; | |
142 else | |
143 return mid, haystack[mid]; | |
144 end | |
145 end | |
146 | |
147 return min, nil; | |
148 end | |
149 | |
125 function archive:find(username, query) | 150 function archive:find(username, query) |
126 local list, err = datamanager.list_open(username, host, self.store); | 151 local list, err = datamanager.list_open(username, host, self.store); |
127 if not list then | 152 if not list then |
128 if err then | 153 if err then |
129 return list, err; | 154 return list, err; |
169 iter = it.filter(function(item) | 194 iter = it.filter(function(item) |
170 return item.with == query.with; | 195 return item.with == query.with; |
171 end, iter); | 196 end, iter); |
172 end | 197 end |
173 if query.start then | 198 if query.start then |
174 iter = it.filter(function(item) | 199 if not query.reverse then |
175 local when = item.when or datetime.parse(item.attr.stamp); | 200 local wi, exact = binary_search(list, function(item) |
176 return when >= query.start; | 201 local when = item.when or datetime.parse(item.attr.stamp); |
177 end, iter); | 202 return query.start - when; |
203 end); | |
204 if exact then | |
205 i = wi - 1; | |
206 elseif wi then | |
207 i = wi; | |
208 end | |
209 else | |
210 iter = it.filter(function(item) | |
211 local when = item.when or datetime.parse(item.attr.stamp); | |
212 return when >= query.start; | |
213 end, iter); | |
214 end | |
178 end | 215 end |
179 if query["end"] then | 216 if query["end"] then |
180 iter = it.filter(function(item) | 217 if query.reverse then |
181 local when = item.when or datetime.parse(item.attr.stamp); | 218 local wi = binary_search(list, function(item) |
182 return when <= query["end"]; | 219 local when = item.when or datetime.parse(item.attr.stamp); |
183 end, iter); | 220 return query["end"] - when; |
221 end); | |
222 if wi then | |
223 i = wi + 1; | |
224 end | |
225 else | |
226 iter = it.filter(function(item) | |
227 local when = item.when or datetime.parse(item.attr.stamp); | |
228 return when <= query["end"]; | |
229 end, iter); | |
230 end | |
184 end | 231 end |
185 if query.after then | 232 if query.after then |
186 local found = false; | 233 local found = false; |
187 iter = it.filter(function(item) | 234 iter = it.filter(function(item) |
188 local found_after = found; | 235 local found_after = found; |