Git fork

refs/iterator: implement seeking for packed-ref iterators

Implement seeking of `packed-ref` iterators. The implementation is again
straight forward, except that we cannot continue to use the prefix
iterator as we would otherwise not be able to reseek the iterator
anymore in case one first asks for an empty and then for a non-empty
prefix. Instead, we open-code the logic to in `advance()`.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>

authored by

Patrick Steinhardt and committed by
Junio C Hamano
22600c04 84e65691

+43 -22
+43 -22
refs/packed-backend.c
··· 819 819 820 820 struct snapshot *snapshot; 821 821 822 + char *prefix; 823 + 822 824 /* The current position in the snapshot's buffer: */ 823 825 const char *pos; 824 826 ··· 841 843 }; 842 844 843 845 /* 844 - * Move the iterator to the next record in the snapshot, without 845 - * respect for whether the record is actually required by the current 846 - * iteration. Adjust the fields in `iter` and return `ITER_OK` or 847 - * `ITER_DONE`. This function does not free the iterator in the case 848 - * of `ITER_DONE`. 846 + * Move the iterator to the next record in the snapshot. Adjust the fields in 847 + * `iter` and return `ITER_OK` or `ITER_DONE`. This function does not free the 848 + * iterator in the case of `ITER_DONE`. 849 849 */ 850 850 static int next_record(struct packed_ref_iterator *iter) 851 851 { ··· 942 942 int ok; 943 943 944 944 while ((ok = next_record(iter)) == ITER_OK) { 945 + const char *refname = iter->base.refname; 946 + const char *prefix = iter->prefix; 947 + 945 948 if (iter->flags & DO_FOR_EACH_PER_WORKTREE_ONLY && 946 949 !is_per_worktree_ref(iter->base.refname)) 947 950 continue; ··· 950 953 !ref_resolves_to_object(iter->base.refname, iter->repo, 951 954 &iter->oid, iter->flags)) 952 955 continue; 956 + 957 + while (prefix && *prefix) { 958 + if (*refname < *prefix) 959 + BUG("packed-refs backend yielded reference preceding its prefix"); 960 + else if (*refname > *prefix) 961 + return ITER_DONE; 962 + prefix++; 963 + refname++; 964 + } 953 965 954 966 return ITER_OK; 955 967 } ··· 957 969 return ok; 958 970 } 959 971 972 + static int packed_ref_iterator_seek(struct ref_iterator *ref_iterator, 973 + const char *prefix) 974 + { 975 + struct packed_ref_iterator *iter = 976 + (struct packed_ref_iterator *)ref_iterator; 977 + const char *start; 978 + 979 + if (prefix && *prefix) 980 + start = find_reference_location(iter->snapshot, prefix, 0); 981 + else 982 + start = iter->snapshot->start; 983 + 984 + free(iter->prefix); 985 + iter->prefix = xstrdup_or_null(prefix); 986 + iter->pos = start; 987 + iter->eof = iter->snapshot->eof; 988 + 989 + return 0; 990 + } 991 + 960 992 static int packed_ref_iterator_peel(struct ref_iterator *ref_iterator, 961 993 struct object_id *peeled) 962 994 { ··· 979 1011 (struct packed_ref_iterator *)ref_iterator; 980 1012 strbuf_release(&iter->refname_buf); 981 1013 free(iter->jump); 1014 + free(iter->prefix); 982 1015 release_snapshot(iter->snapshot); 983 1016 } 984 1017 985 1018 static struct ref_iterator_vtable packed_ref_iterator_vtable = { 986 1019 .advance = packed_ref_iterator_advance, 1020 + .seek = packed_ref_iterator_seek, 987 1021 .peel = packed_ref_iterator_peel, 988 1022 .release = packed_ref_iterator_release, 989 1023 }; ··· 1097 1131 { 1098 1132 struct packed_ref_store *refs; 1099 1133 struct snapshot *snapshot; 1100 - const char *start; 1101 1134 struct packed_ref_iterator *iter; 1102 1135 struct ref_iterator *ref_iterator; 1103 1136 unsigned int required_flags = REF_STORE_READ; ··· 1113 1146 */ 1114 1147 snapshot = get_snapshot(refs); 1115 1148 1116 - if (prefix && *prefix) 1117 - start = find_reference_location(snapshot, prefix, 0); 1118 - else 1119 - start = snapshot->start; 1120 - 1121 - if (start == snapshot->eof) 1122 - return empty_ref_iterator_begin(); 1123 - 1124 1149 CALLOC_ARRAY(iter, 1); 1125 1150 ref_iterator = &iter->base; 1126 1151 base_ref_iterator_init(ref_iterator, &packed_ref_iterator_vtable); ··· 1130 1155 1131 1156 iter->snapshot = snapshot; 1132 1157 acquire_snapshot(snapshot); 1133 - 1134 - iter->pos = start; 1135 - iter->eof = snapshot->eof; 1136 1158 strbuf_init(&iter->refname_buf, 0); 1137 - 1138 1159 iter->base.oid = &iter->oid; 1139 - 1140 1160 iter->repo = ref_store->repo; 1141 1161 iter->flags = flags; 1142 1162 1143 - if (prefix && *prefix) 1144 - /* Stop iteration after we've gone *past* prefix: */ 1145 - ref_iterator = prefix_ref_iterator_begin(ref_iterator, prefix, 0); 1163 + if (packed_ref_iterator_seek(&iter->base, prefix) < 0) { 1164 + ref_iterator_free(&iter->base); 1165 + return NULL; 1166 + } 1146 1167 1147 1168 return ref_iterator; 1148 1169 }