Implement a database cookie API for determining whether rpmdb has changed
Add rpmdbCookie() public function and matching python bindings. The returned value is an opaque string which changes any time the rpmdb is changed (eg packages added or removed, rebuild changes things etc). A key point is that this is entirely database backend agnostic. The actual implementation here is an SHA1 hash of RPMDBI_NAME keys and the corresponding package offsets, but this is an implementation detail that can be changed anytime and callers must not rely on. The only thing that matters is whether the string equals an earlier cookie value or not. A cryptographic hash seems like an overkill, but then it saves us the headaches of coming up with something that reflects order changes etc. Closes: #388
This commit is contained in:
parent
1d6fde768c
commit
d1ebf65598
20
lib/rpmdb.c
20
lib/rpmdb.c
|
@ -2644,3 +2644,23 @@ int rpmdbCtrl(rpmdb db, rpmdbCtrlOp ctrl)
|
|||
return dbctrl ? dbCtrl(db, dbctrl) : 1;
|
||||
}
|
||||
|
||||
char *rpmdbCookie(rpmdb db)
|
||||
{
|
||||
void *cookie = NULL;
|
||||
rpmdbIndexIterator ii = rpmdbIndexIteratorInit(db, RPMDBI_NAME);
|
||||
|
||||
if (ii) {
|
||||
DIGEST_CTX ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
|
||||
const void *key = 0;
|
||||
size_t keylen = 0;
|
||||
while ((rpmdbIndexIteratorNext(ii, &key, &keylen)) == 0) {
|
||||
const unsigned int *offsets = rpmdbIndexIteratorPkgOffsets(ii);
|
||||
unsigned int npkgs = rpmdbIndexIteratorNumPkgs(ii);
|
||||
rpmDigestUpdate(ctx, key, keylen);
|
||||
rpmDigestUpdate(ctx, offsets, sizeof(*offsets) * npkgs);
|
||||
}
|
||||
rpmDigestFinal(ctx, &cookie, NULL, 1);
|
||||
}
|
||||
rpmdbIndexIteratorFree(ii);
|
||||
return cookie;
|
||||
}
|
||||
|
|
|
@ -218,6 +218,14 @@ rpmdbIndexIterator rpmdbIndexIteratorFree(rpmdbIndexIterator ii);
|
|||
*/
|
||||
int rpmdbCtrl(rpmdb db, rpmdbCtrlOp ctrl);
|
||||
|
||||
/** \ingroup rpmdb
|
||||
* Retrieve rpm database changed-cookie.
|
||||
* Useful for eg. determining cache validity.
|
||||
* @param db rpm database
|
||||
* @return cookie string (malloced), or NULL on error
|
||||
*/
|
||||
char *rpmdbCookie(rpmdb db);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -366,6 +366,21 @@ rpmts_VerifyDB(rpmtsObject * s)
|
|||
return Py_BuildValue("i", rc);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
rpmts_dbCookie(rpmtsObject * s)
|
||||
{
|
||||
PyObject *ret = NULL;
|
||||
char *cookie = NULL;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
cookie = rpmdbCookie(rpmtsGetRdb(s->ts));
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
ret = utf8FromString(cookie);
|
||||
free(cookie);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
rpmts_HdrFromFdno(rpmtsObject * s, PyObject *arg)
|
||||
{
|
||||
|
@ -797,6 +812,9 @@ Remove all elements from the transaction set\n" },
|
|||
{"dbIndex", (PyCFunction) rpmts_index, METH_VARARGS|METH_KEYWORDS,
|
||||
"ts.dbIndex(TagN) -> ii\n\
|
||||
- Create a key iterator for the default transaction rpmdb.\n" },
|
||||
{"dbCookie", (PyCFunction) rpmts_dbCookie, METH_NOARGS,
|
||||
"dbCookie -> cookie\n\
|
||||
- Return a cookie string for determining if database has changed\n" },
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
|
|
|
@ -368,6 +368,75 @@ hi
|
|||
[])
|
||||
AT_CLEANUP
|
||||
|
||||
AT_SETUP([database cookies])
|
||||
AT_KEYWORDS([python rpmdb])
|
||||
AT_CHECK([
|
||||
RPMDB_CLEAR
|
||||
RPMDB_INIT
|
||||
],
|
||||
[0],
|
||||
[],
|
||||
[])
|
||||
|
||||
RPMPY_CHECK([
|
||||
ts = rpm.ts()
|
||||
ts.openDB()
|
||||
c1 = ts.dbCookie()
|
||||
ts.closeDB()
|
||||
ts.openDB()
|
||||
c2 = ts.dbCookie()
|
||||
myprint(c1 == c2 != None)
|
||||
open("dbcookie", "w+").write(c1)
|
||||
],
|
||||
[True
|
||||
],
|
||||
[])
|
||||
|
||||
AT_CHECK([
|
||||
runroot rpm -i \
|
||||
--justdb --nodeps --ignorearch --ignoreos \
|
||||
/data/RPMS/foo-1.0-1.noarch.rpm \
|
||||
/data/RPMS/hello-2.0-1.i686.rpm \
|
||||
],
|
||||
[0],
|
||||
[],
|
||||
[])
|
||||
|
||||
RPMPY_CHECK([
|
||||
ts = rpm.ts()
|
||||
ts.openDB()
|
||||
c1 = ts.dbCookie()
|
||||
c2 = open("dbcookie", "r").read()
|
||||
myprint(c1 != c2)
|
||||
open("dbcookie", "w+").write(c1)
|
||||
],
|
||||
[True
|
||||
],
|
||||
[])
|
||||
|
||||
AT_CHECK([
|
||||
runroot rpm -i \
|
||||
--justdb --nodeps --ignorearch --ignoreos \
|
||||
--define "_transaction_color 3" \
|
||||
--define "_prefer_color 2" \
|
||||
/data/RPMS/hello-2.0-1.x86_64.rpm
|
||||
],
|
||||
[0],
|
||||
[],
|
||||
[])
|
||||
|
||||
RPMPY_CHECK([
|
||||
ts = rpm.ts()
|
||||
ts.openDB()
|
||||
c1 = ts.dbCookie()
|
||||
c2 = open("dbcookie", "r").read()
|
||||
myprint(c1 != c2)
|
||||
],
|
||||
[True
|
||||
],
|
||||
[])
|
||||
AT_CLEANUP
|
||||
|
||||
RPMPY_TEST([dependency sets 1],[
|
||||
ts = rpm.ts()
|
||||
h = ts.hdrFromFdno('${RPMDATA}/RPMS/hello-1.0-1.ppc64.rpm')
|
||||
|
|
Loading…
Reference in New Issue