* Compact all tables in the range `[first, last)` into a single new table. * * This function returns `0` on success or a code `< 0` on failure. When the * stack or any of the tables in the specified range are already locked then * this function returns `REFTABLE_LOCK_ERROR`. This is a benign error that * callers can either ignore, or they may choose to retry compaction after some * amount of
| 1148 | * amount of time. |
| 1149 | */ |
| 1150 | static int stack_compact_range(struct reftable_stack *st, |
| 1151 | size_t first, size_t last, |
| 1152 | struct reftable_log_expiry_config *expiry, |
| 1153 | unsigned int flags) |
| 1154 | { |
| 1155 | struct reftable_buf tables_list_buf = REFTABLE_BUF_INIT; |
| 1156 | struct reftable_buf new_table_name = REFTABLE_BUF_INIT; |
| 1157 | struct reftable_buf new_table_path = REFTABLE_BUF_INIT; |
| 1158 | struct reftable_buf table_name = REFTABLE_BUF_INIT; |
| 1159 | struct reftable_flock tables_list_lock = REFTABLE_FLOCK_INIT; |
| 1160 | struct reftable_flock *table_locks = NULL; |
| 1161 | struct reftable_tmpfile new_table = REFTABLE_TMPFILE_INIT; |
| 1162 | int is_empty_table = 0, err = 0; |
| 1163 | size_t first_to_replace, last_to_replace; |
| 1164 | size_t i, nlocks = 0; |
| 1165 | char **names = NULL; |
| 1166 | |
| 1167 | if (first > last || (!expiry && first == last)) { |
| 1168 | err = 0; |
| 1169 | goto done; |
| 1170 | } |
| 1171 | |
| 1172 | st->stats.attempts++; |
| 1173 | |
| 1174 | /* |
| 1175 | * Hold the lock so that we can read "tables.list" and lock all tables |
| 1176 | * which are part of the user-specified range. |
| 1177 | */ |
| 1178 | err = flock_acquire(&tables_list_lock, st->list_file, st->opts.lock_timeout_ms); |
| 1179 | if (err < 0) |
| 1180 | goto done; |
| 1181 | |
| 1182 | /* |
| 1183 | * Check whether the stack is up-to-date. We unfortunately cannot |
| 1184 | * handle the situation gracefully in case it's _not_ up-to-date |
| 1185 | * because the range of tables that the user has requested us to |
| 1186 | * compact may have been changed. So instead we abort. |
| 1187 | * |
| 1188 | * We could in theory improve the situation by having the caller not |
| 1189 | * pass in a range, but instead the list of tables to compact. If so, |
| 1190 | * we could check that relevant tables still exist. But for now it's |
| 1191 | * good enough to just abort. |
| 1192 | */ |
| 1193 | err = stack_uptodate(st); |
| 1194 | if (err < 0) |
| 1195 | goto done; |
| 1196 | if (err > 0) { |
| 1197 | err = REFTABLE_OUTDATED_ERROR; |
| 1198 | goto done; |
| 1199 | } |
| 1200 | |
| 1201 | /* |
| 1202 | * Lock all tables in the user-provided range. This is the slice of our |
| 1203 | * stack which we'll compact. |
| 1204 | * |
| 1205 | * Note that we lock tables in reverse order from last to first. The |
| 1206 | * intent behind this is to allow a newer process to perform best |
| 1207 | * effort compaction of tables that it has added in the case where an |
no test coverage detected