scan: index a set fingerprint once when set_fpm1 equals set_fp1

A set with no clones has the same merged and split fingerprint.  Both
keys indexed the record twice, so the lookup returned it twice; with
its size equal to the archive's that read as two sized records and the
set fell through to a whole read.  The second key is now skipped when
it equals the first, which also keeps the index smaller.

The fingerprint's CRC list sits on the stack for sets of up to 64
members, so most archives no longer allocate for it.
This commit is contained in:
LibretroAdmin authored and libretroadmin committed 2026-11-07 22:49:22 +01:00
1 parent e9759423d6
commit d186c05fe1
3 files changed
+42 -15

No files matched your search

+5 -2
View File
@@ -1594,12 +1594,15 @@ static int db_index_collect(void *ctx, const uint8_t *key, size_t key_len,
struct db_index_build *b = (struct db_index_build*)ctx;
/* The walk reads set_fpm1 where it reads the serial. A record can
* carry both fingerprints; each indexes it. */
* carry both fingerprints; each indexes it, once when they agree, as
* for a set with no clones. */
if (b->want_setfp)
{
if (!b->crc.failed)
db_crc_collect(&b->crc, key, key_len, offset, NULL);
if (!b->crc.failed)
if ( !b->crc.failed
&& !( key_len == serial_len
&& !memcmp(key, serial, key_len)))
db_crc_collect(&b->crc, serial, serial_len, offset, NULL);
return b->crc.failed;
}
+27 -8
View File
@@ -320,7 +320,7 @@ static int write_db_archives(const char *path, bool unsized)
int i;
memset(&body, 0, sizeof(body));
for (i = 0; i < 3; i++)
for (i = 0; i < 4; i++)
{
char name[32];
uint8_t crc[4];
@@ -911,26 +911,28 @@ static void check_archive_sizes(const char *dir)
}
}
/* Three records: both fingerprints, set_fp1 alone, neither. */
/* Four records: both fingerprints, set_fp1 alone, neither, and both
* the same, as a set with no clones carries. */
static int write_db_setfp(const char *path)
{
static const uint32_t fp1[2] = { 0x5E7F0001u, 0x5E7F0003u };
static const uint32_t fp1[4] = { 0x5E7F0001u, 0x5E7F0003u, 0,
0x5E7F0004u };
buf_t body;
int i;
memset(&body, 0, sizeof(body));
for (i = 0; i < 3; i++)
for (i = 0; i < 4; i++)
{
char name[32];
uint8_t crc[4], key[4];
crc[0] = 0xA2; crc[1] = 0; crc[2] = 0; crc[3] = (uint8_t)i;
sprintf(name, "FP %d", i);
bfixmap(&body, 3 + (i < 2 ? 1 : 0) + (i == 0 ? 1 : 0));
bfixmap(&body, 3 + (fp1[i] ? 1 : 0) + (i == 0 || i == 3 ? 1 : 0));
bfixstr(&body, "name"); bfixstr(&body, name);
bfixstr(&body, "crc"); bbin(&body, crc, 4);
bfixstr(&body, "size"); buint16(&body, (uint16_t)(100 + i));
if (i < 2)
if (fp1[i])
{
key[0] = (uint8_t)(fp1[i] >> 24);
key[1] = (uint8_t)(fp1[i] >> 16);
@@ -943,6 +945,10 @@ static int write_db_setfp(const char *path)
key[0] = 0x5E; key[1] = 0x7F; key[2] = 0x00; key[3] = 0x02;
bfixstr(&body, "set_fpm1"); bbin(&body, key, 4);
}
if (i == 3)
{
bfixstr(&body, "set_fpm1"); bbin(&body, key, 4);
}
}
return write_rdb(path, &body);
}
@@ -964,8 +970,11 @@ static void check_setfp_index(const char *dir)
check(0, "set fingerprint index built", "no index");
else
{
check(database_info_crc_index_count(idx) == 3,
"set fingerprints: both keys indexed", "3 entries");
database_info_list_t *l;
check(database_info_crc_index_count(idx) == 4,
"set fingerprints: both keys indexed, a shared one once",
"4 entries");
crc_lookup(idx, path, 0x5E7F0001u, name, sizeof(name));
check(!strcmp(name, "FP 0"),
"set fingerprints: set_fp1 finds its record", name);
@@ -975,6 +984,16 @@ static void check_setfp_index(const char *dir)
crc_lookup(idx, path, 0x5E7F0003u, name, sizeof(name));
check(!strcmp(name, "FP 1"),
"set fingerprints: a second record", name);
l = database_info_list_new_crc(idx, path, 0x5E7F0004u, 0,
DB_EXTRACT_SCAN_FIELDS);
check(l && l->count == 1,
"set fingerprints: equal keys give their record once",
"0x5E7F0004");
if (l)
{
database_info_list_free(l);
free(l);
}
crc_lookup(idx, path, 0xA2000000u, name, sizeof(name));
check(!*name, "set fingerprints: not keyed on crc", name);
database_info_crc_index_free(idx);
+10 -5
View File
@@ -1287,12 +1287,16 @@ static int task_database_crc_cmp(const void *a, const void *b)
* member left in that stores no CRC means there is none. */
static uint32_t task_database_members_fp(const scan_members_t *m)
{
uint32_t fp = 0;
uint32_t *crcs;
size_t n = 0;
uint32_t local[64];
uint32_t fp = 0;
uint32_t *crcs = local;
size_t n = 0;
size_t i;
if (!m->count || !(crcs = (uint32_t*)malloc(m->count * sizeof(*crcs))))
if (!m->count)
return 0;
if ( m->count > ARRAY_SIZE(local)
&& !(crcs = (uint32_t*)malloc(m->count * sizeof(*crcs))))
return 0;
for (i = 0; i < m->count; i++)
{
@@ -1321,7 +1325,8 @@ static uint32_t task_database_members_fp(const scan_members_t *m)
be[3] = (uint8_t)(crcs[i]);
fp = encoding_crc32(fp, be, sizeof(be));
}
free(crcs);
if (crcs != local)
free(crcs);
return fp;
}