Merge pull request #29417 from yuwata/sd-journal-cleanups-for-generic-array-bisect-plus-one
sd-journal: cleanups for generic_array_bisect_plus_one()
This commit is contained in:
@@ -3104,11 +3104,9 @@ static int generic_array_bisect_plus_one(
|
||||
int (*test_object)(JournalFile *f, uint64_t p, uint64_t needle),
|
||||
direction_t direction,
|
||||
Object **ret_object,
|
||||
uint64_t *ret_offset,
|
||||
uint64_t *ret_idx) {
|
||||
uint64_t *ret_offset) {
|
||||
|
||||
int r;
|
||||
bool step_back = false;
|
||||
|
||||
assert(f);
|
||||
assert(test_object);
|
||||
@@ -3116,41 +3114,52 @@ static int generic_array_bisect_plus_one(
|
||||
if (n <= 0)
|
||||
return 0;
|
||||
|
||||
/* This bisects the array in object 'first', but first checks
|
||||
* an extra */
|
||||
/* This bisects the array in object 'first', but first checks an extra. */
|
||||
r = test_object(f, extra, needle);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (r == TEST_FOUND)
|
||||
r = direction == DIRECTION_DOWN ? TEST_RIGHT : TEST_LEFT;
|
||||
if (direction == DIRECTION_DOWN) {
|
||||
/* If we are going downwards, then we need to return the first object that passes the test.
|
||||
* When there is no object that passes the test, we need to return the first object that
|
||||
* test_object() returns TEST_RIGHT for. */
|
||||
if (IN_SET(r,
|
||||
TEST_FOUND, /* The 'extra' object passes the test. Hence, this is the first
|
||||
* object that passes the test. */
|
||||
TEST_RIGHT)) /* The 'extra' object is the first object that test_object() returns
|
||||
* TEST_RIGHT for, and no object exists even in the chained arrays
|
||||
* that passes the test. */
|
||||
goto use_extra; /* The 'extra' object is exactly the one we are looking for. It is
|
||||
* not necessary to bisect the chained arrays. */
|
||||
|
||||
/* if we are looking with DIRECTION_UP then we need to first
|
||||
see if in the actual array there is a matching entry, and
|
||||
return the last one of that. But if there isn't any we need
|
||||
to return this one. Hence remember this, and return it
|
||||
below. */
|
||||
if (r == TEST_LEFT)
|
||||
step_back = direction == DIRECTION_UP;
|
||||
/* Otherwise, the 'extra' object is not the one we are looking for. Search in the arrays. */
|
||||
|
||||
if (r == TEST_RIGHT) {
|
||||
if (direction == DIRECTION_DOWN)
|
||||
goto found;
|
||||
else
|
||||
return 0;
|
||||
} else {
|
||||
/* If we are going upwards, then we need to return the last object that passes the test.
|
||||
* When there is no object that passes the test, we need to return the the last object that
|
||||
* test_object() returns TEST_LEFT for. */
|
||||
if (r == TEST_RIGHT)
|
||||
return 0; /* Not only the 'extra' object, but also all objects in the chained arrays
|
||||
* will never get TEST_FOUND or TEST_LEFT. The object we are looking for
|
||||
* does not exist. */
|
||||
|
||||
/* Even if the 'extra' object passes the test, there may be multiple objects in the arrays
|
||||
* that also pass the test. Hence, we need to bisect the arrays for finding the last matching
|
||||
* object. */
|
||||
}
|
||||
|
||||
r = generic_array_bisect(f, first, n-1, needle, test_object, direction, ret_object, ret_offset, ret_idx);
|
||||
r = generic_array_bisect(f, first, n-1, needle, test_object, direction, ret_object, ret_offset, NULL);
|
||||
if (r != 0)
|
||||
return r; /* When > 0, the found object is the first (or last, when DIRECTION_UP) object.
|
||||
* Hence, return the found object now. */
|
||||
|
||||
if (r == 0 && step_back)
|
||||
goto found;
|
||||
/* No matching object found in the chained arrays.
|
||||
* DIRECTION_DOWN : the 'extra' object neither matches the condition. There is no matching object.
|
||||
* DIRECTION_UP : the 'extra' object matches the condition. So, return it. */
|
||||
if (direction == DIRECTION_DOWN)
|
||||
return 0;
|
||||
|
||||
if (r > 0 && ret_idx)
|
||||
(*ret_idx)++;
|
||||
|
||||
return r;
|
||||
|
||||
found:
|
||||
use_extra:
|
||||
if (ret_object) {
|
||||
r = journal_file_move_to_object(f, OBJECT_ENTRY, extra, ret_object);
|
||||
if (r < 0)
|
||||
@@ -3160,9 +3169,6 @@ found:
|
||||
if (ret_offset)
|
||||
*ret_offset = extra;
|
||||
|
||||
if (ret_idx)
|
||||
*ret_idx = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -3340,7 +3346,7 @@ int journal_file_move_to_entry_by_monotonic(
|
||||
monotonic,
|
||||
test_object_monotonic,
|
||||
direction,
|
||||
ret_object, ret_offset, NULL);
|
||||
ret_object, ret_offset);
|
||||
}
|
||||
|
||||
void journal_file_reset_location(JournalFile *f) {
|
||||
@@ -3391,7 +3397,8 @@ int journal_file_next_entry(
|
||||
Object **ret_object,
|
||||
uint64_t *ret_offset) {
|
||||
|
||||
uint64_t i, n, ofs;
|
||||
uint64_t i, n, q;
|
||||
Object *o;
|
||||
int r;
|
||||
|
||||
assert(f);
|
||||
@@ -3403,38 +3410,53 @@ int journal_file_next_entry(
|
||||
if (n <= 0)
|
||||
return 0;
|
||||
|
||||
/* When the input offset 'p' is zero, return the first (or last on DIRECTION_UP) entry. */
|
||||
if (p == 0)
|
||||
i = direction == DIRECTION_DOWN ? 0 : n - 1;
|
||||
else {
|
||||
r = generic_array_bisect(f,
|
||||
return generic_array_get(f,
|
||||
le64toh(f->header->entry_array_offset),
|
||||
le64toh(f->header->n_entries),
|
||||
p,
|
||||
test_object_offset,
|
||||
DIRECTION_DOWN,
|
||||
NULL, NULL,
|
||||
&i);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
direction == DIRECTION_DOWN ? 0 : n - 1,
|
||||
direction,
|
||||
ret_object, ret_offset);
|
||||
|
||||
r = bump_array_index(&i, direction, n);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
}
|
||||
/* Otherwise, first find the nearest entry object. */
|
||||
r = generic_array_bisect(f,
|
||||
le64toh(f->header->entry_array_offset),
|
||||
le64toh(f->header->n_entries),
|
||||
p,
|
||||
test_object_offset,
|
||||
direction,
|
||||
ret_object ? &o : NULL, &q, &i);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
assert(direction == DIRECTION_DOWN ? p <= q : q <= p);
|
||||
|
||||
/* If the input offset 'p' points to an entry object, generic_array_bisect() should provides
|
||||
* the same offset, and the index needs to be shifted. Otherwise, use the found object as is,
|
||||
* as it is the nearest entry object from the input offset 'p'. */
|
||||
|
||||
if (p != q)
|
||||
goto found;
|
||||
|
||||
r = bump_array_index(&i, direction, n);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
/* And jump to it */
|
||||
r = generic_array_get(f, le64toh(f->header->entry_array_offset), i, direction, ret_object, &ofs);
|
||||
r = generic_array_get(f, le64toh(f->header->entry_array_offset), i, direction, ret_object ? &o : NULL, &q);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
/* Ensure our array is properly ordered. */
|
||||
if (p > 0 && !check_properly_ordered(ofs, p, direction))
|
||||
if (!check_properly_ordered(q, p, direction))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG),
|
||||
"%s: entry array not properly ordered at entry %" PRIu64,
|
||||
"%s: entry array not properly ordered at entry index %" PRIu64,
|
||||
f->path, i);
|
||||
|
||||
found:
|
||||
if (ret_object)
|
||||
*ret_object = o;
|
||||
if (ret_offset)
|
||||
*ret_offset = ofs;
|
||||
*ret_offset = q;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -3523,7 +3545,7 @@ int journal_file_move_to_entry_by_offset_for_data(
|
||||
p,
|
||||
test_object_offset,
|
||||
direction,
|
||||
ret, ret_offset, NULL);
|
||||
ret, ret_offset);
|
||||
}
|
||||
|
||||
int journal_file_move_to_entry_by_monotonic_for_data(
|
||||
@@ -3535,8 +3557,8 @@ int journal_file_move_to_entry_by_monotonic_for_data(
|
||||
Object **ret_object,
|
||||
uint64_t *ret_offset) {
|
||||
|
||||
uint64_t b, z, entry_offset, entry_array_offset, n_entries;
|
||||
Object *o;
|
||||
uint64_t z, entry_offset, entry_array_offset, n_entries;
|
||||
Object *o, *entry;
|
||||
int r;
|
||||
|
||||
assert(f);
|
||||
@@ -3549,7 +3571,7 @@ int journal_file_move_to_entry_by_monotonic_for_data(
|
||||
n_entries = le64toh(READ_NOW(d->data.n_entries));
|
||||
|
||||
/* First, seek by time */
|
||||
r = find_data_object_by_boot_id(f, boot_id, &o, &b);
|
||||
r = find_data_object_by_boot_id(f, boot_id, &o, NULL);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
@@ -3560,19 +3582,16 @@ int journal_file_move_to_entry_by_monotonic_for_data(
|
||||
monotonic,
|
||||
test_object_monotonic,
|
||||
direction,
|
||||
NULL, &z, NULL);
|
||||
NULL, &z);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
/* And now, continue seeking until we find an entry that
|
||||
* exists in both bisection arrays */
|
||||
|
||||
r = journal_file_move_to_object(f, OBJECT_DATA, b, &o);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* And now, continue seeking until we find an entry that exists in both bisection arrays. */
|
||||
for (;;) {
|
||||
uint64_t p, q;
|
||||
uint64_t p;
|
||||
|
||||
/* The journal entry found by the above bisect_plus_one() may not have the specified data,
|
||||
* that is, it may not be linked in the data object. So, we need to check that. */
|
||||
|
||||
r = generic_array_bisect_plus_one(f,
|
||||
entry_offset,
|
||||
@@ -3581,9 +3600,15 @@ int journal_file_move_to_entry_by_monotonic_for_data(
|
||||
z,
|
||||
test_object_offset,
|
||||
direction,
|
||||
NULL, &p, NULL);
|
||||
ret_object ? &entry : NULL, &p);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
if (p == z)
|
||||
break; /* The journal entry has the specified data. Yay! */
|
||||
|
||||
/* If the entry does not have the data, then move to the next (or previous, depends on the
|
||||
* 'direction') entry linked to the data object. But, the next entry may be in another boot.
|
||||
* So, we need to check that the entry has the matching boot ID. */
|
||||
|
||||
r = generic_array_bisect_plus_one(f,
|
||||
le64toh(o->data.entry_offset),
|
||||
@@ -3592,26 +3617,20 @@ int journal_file_move_to_entry_by_monotonic_for_data(
|
||||
p,
|
||||
test_object_offset,
|
||||
direction,
|
||||
NULL, &q, NULL);
|
||||
|
||||
ret_object ? &entry : NULL, &z);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
if (p == z)
|
||||
break; /* The journal entry has the specified boot ID. Yay! */
|
||||
|
||||
if (p == q) {
|
||||
if (ret_object) {
|
||||
r = journal_file_move_to_object(f, OBJECT_ENTRY, q, ret_object);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (ret_offset)
|
||||
*ret_offset = q;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
z = q;
|
||||
/* If not, let's try to the next entry... */
|
||||
}
|
||||
|
||||
if (ret_object)
|
||||
*ret_object = entry;
|
||||
if (ret_offset)
|
||||
*ret_offset = z;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int journal_file_move_to_entry_by_seqnum_for_data(
|
||||
@@ -3634,7 +3653,7 @@ int journal_file_move_to_entry_by_seqnum_for_data(
|
||||
seqnum,
|
||||
test_object_seqnum,
|
||||
direction,
|
||||
ret_object, ret_offset, NULL);
|
||||
ret_object, ret_offset);
|
||||
}
|
||||
|
||||
int journal_file_move_to_entry_by_realtime_for_data(
|
||||
@@ -3656,7 +3675,7 @@ int journal_file_move_to_entry_by_realtime_for_data(
|
||||
realtime,
|
||||
test_object_realtime,
|
||||
direction,
|
||||
ret, ret_offset, NULL);
|
||||
ret, ret_offset);
|
||||
}
|
||||
|
||||
void journal_file_dump(JournalFile *f) {
|
||||
|
||||
Reference in New Issue
Block a user