|
1 | 1 | /*
|
2 |
| - * Copyright (c) 2012, 2014 by Farsight Security, Inc. |
| 2 | + * Copyright (c) 2022 DomainTools LLC |
| 3 | + * Copyright (c) 2012, 2014, 2017 by Farsight Security, Inc. |
3 | 4 | *
|
4 | 5 | * Licensed under the Apache License, Version 2.0 (the "License");
|
5 | 6 | * you may not use this file except in compliance with the License.
|
@@ -249,33 +250,58 @@ block_iter_seek_to_last(struct block_iter *bi)
|
249 | 250 | }
|
250 | 251 | }
|
251 | 252 |
|
252 |
| -void |
| 253 | +static int |
| 254 | +compare_restart_point(struct block_iter *bi, const uint32_t i, const uint8_t *target, size_t target_len) { |
| 255 | + uint32_t shared, non_shared, value_length; |
| 256 | + uint64_t region_offset = get_restart_point(bi, i); |
| 257 | + const uint8_t *key_ptr = decode_entry(bi->data + region_offset, |
| 258 | + bi->data + bi->restarts, |
| 259 | + &shared, &non_shared, &value_length); |
| 260 | + /* check for corruption */ |
| 261 | + assert(key_ptr != NULL && shared == 0); |
| 262 | + return bytes_compare(key_ptr, non_shared, target, target_len); |
| 263 | +} |
| 264 | + |
| 265 | +void |
253 | 266 | block_iter_seek(struct block_iter *bi, const uint8_t *target, size_t target_len)
|
254 | 267 | {
|
255 |
| - /* binary search in restart array to find the first restart point |
256 |
| - * with a key >= target |
| 268 | + /* |
| 269 | + * If the restart_index is not zero and not equal to the number of |
| 270 | + * restarts, then begin with galloping search in the restart array to find |
| 271 | + * the first restart point with a key >= target, otherwise just do binary |
| 272 | + * search from the start of the restart array |
257 | 273 | */
|
258 | 274 | uint32_t left = 0;
|
259 | 275 | uint32_t right = bi->num_restarts - 1;
|
| 276 | + if (bi->num_restarts != bi->restart_index && bi->restart_index != 0) { |
| 277 | + /* Start galloping from the current restart index */ |
| 278 | + uint32_t i = bi->restart_index; |
| 279 | + right = i; |
| 280 | + uint32_t incr = 1; |
| 281 | + while (compare_restart_point(bi, i, target, target_len) < 0) { |
| 282 | + left = i; |
| 283 | + i += incr; |
| 284 | + /* Stop galloping if i is past the end of the restart array */ |
| 285 | + if (i > bi->num_restarts - 1) { |
| 286 | + right = bi->num_restarts - 1; |
| 287 | + break; |
| 288 | + } |
| 289 | + right = i; |
| 290 | + incr *= 2; |
| 291 | + } |
| 292 | + } |
| 293 | + |
| 294 | + /* binary search */ |
260 | 295 | while (left < right) {
|
261 | 296 | uint32_t mid = (left + right + 1) / 2;
|
262 |
| - uint64_t region_offset = get_restart_point(bi, mid); |
263 |
| - uint32_t shared, non_shared, value_length; |
264 |
| - const uint8_t *key_ptr = decode_entry(bi->data + region_offset, |
265 |
| - bi->data + bi->restarts, |
266 |
| - &shared, &non_shared, &value_length); |
267 |
| - if (key_ptr == NULL || (shared != 0)) { |
268 |
| - /* corruption */ |
269 |
| - return; |
270 |
| - } |
271 |
| - if (bytes_compare(key_ptr, non_shared, target, target_len) < 0) { |
| 297 | + if (compare_restart_point(bi, mid, target, target_len) < 0) { |
272 | 298 | /* key at "mid" is smaller than "target", therefore all
|
273 | 299 | * keys before "mid" are uninteresting
|
274 | 300 | */
|
275 | 301 | left = mid;
|
276 | 302 | } else {
|
277 | 303 | /* key at "mid" is larger than "target", therefore all
|
278 |
| - * keys at or before "mid" are uninteresting |
| 304 | + * keys at or after "mid" are uninteresting |
279 | 305 | */
|
280 | 306 | right = mid - 1;
|
281 | 307 | }
|
|
0 commit comments