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;