| 268 | } |
| 269 | |
| 270 | static int table_iter_seek_linear(struct table_iter *ti, |
| 271 | struct reftable_record *want) |
| 272 | { |
| 273 | struct reftable_buf want_key = REFTABLE_BUF_INIT; |
| 274 | struct reftable_buf got_key = REFTABLE_BUF_INIT; |
| 275 | struct reftable_record rec; |
| 276 | int err; |
| 277 | |
| 278 | err = reftable_record_init(&rec, reftable_record_type(want)); |
| 279 | if (err < 0) |
| 280 | goto done; |
| 281 | |
| 282 | err = reftable_record_key(want, &want_key); |
| 283 | if (err < 0) |
| 284 | goto done; |
| 285 | |
| 286 | /* |
| 287 | * First we need to locate the block that must contain our record. To |
| 288 | * do so we scan through blocks linearly until we find the first block |
| 289 | * whose first key is bigger than our wanted key. Once we have found |
| 290 | * that block we know that the key must be contained in the preceding |
| 291 | * block. |
| 292 | * |
| 293 | * This algorithm is somewhat unfortunate because it means that we |
| 294 | * always have to seek one block too far and then back up. But as we |
| 295 | * can only decode the _first_ key of a block but not its _last_ key we |
| 296 | * have no other way to do this. |
| 297 | */ |
| 298 | while (1) { |
| 299 | struct table_iter next = *ti; |
| 300 | |
| 301 | /* |
| 302 | * We must be careful to not modify underlying data of `ti` |
| 303 | * because we may find that `next` does not contain our desired |
| 304 | * block, but that `ti` does. In that case, we would discard |
| 305 | * `next` and continue with `ti`. |
| 306 | * |
| 307 | * This also means that we cannot reuse allocated memory for |
| 308 | * `next` here. While it would be great if we could, it should |
| 309 | * in practice not be too bad given that we should only ever |
| 310 | * end up doing linear seeks with at most three blocks. As soon |
| 311 | * as we have more than three blocks we would have an index, so |
| 312 | * we would not do a linear search there anymore. |
| 313 | */ |
| 314 | memset(&next.block.block_data, 0, sizeof(next.block.block_data)); |
| 315 | next.block.zstream = NULL; |
| 316 | next.block.uncompressed_data = NULL; |
| 317 | next.block.uncompressed_cap = 0; |
| 318 | |
| 319 | err = table_iter_next_block(&next); |
| 320 | if (err < 0) |
| 321 | goto done; |
| 322 | if (err > 0) |
| 323 | break; |
| 324 | |
| 325 | err = reftable_block_first_key(&next.block, &got_key); |
| 326 | if (err < 0) |
| 327 | goto done; |
no test coverage detected