src/pgp_sequoia.c
branchneal/tpk-cache
changeset 3798 8c5a4548b7d1
parent 3797 657dc02b1cc3
     1.1 --- a/src/pgp_sequoia.c	Sat Jun 01 10:54:32 2019 +0200
     1.2 +++ b/src/pgp_sequoia.c	Sat Jun 01 14:50:15 2019 +0200
     1.3 @@ -528,6 +528,94 @@
     1.4      return status;
     1.5  }
     1.6  
     1.7 +struct tpk_cache {
     1.8 +    // The TPK's (primary key's) fingerprint.
     1.9 +    pgp_fingerprint_t fpr;
    1.10 +    pgp_tpk_t tpk;
    1.11 +    int inserts;
    1.12 +    int hits;
    1.13 +    int misses;
    1.14 +};
    1.15 +
    1.16 +#define TPK_CACHE_FMT "(%d hits, %d misses, %d%% hit rate, %d inserts)"
    1.17 +#define TPK_CACHE_PRINTF(o) \
    1.18 +    (o.hits), (o.misses), (((o.hits + 1) * 100) / (o.misses + 1)), (o.inserts)
    1.19 +
    1.20 +static __thread struct tpk_cache tpk_cache;
    1.21 +
    1.22 +static pgp_tpk_t tpk_cache_lookup(pgp_fingerprint_t fpr)
    1.23 +{
    1.24 +    if (tpk_cache.fpr && pgp_fingerprint_equal(tpk_cache.fpr, fpr)) {
    1.25 +        T("HIT: found %s in tpk cache! "TPK_CACHE_FMT,
    1.26 +          pgp_fingerprint_to_string(fpr), TPK_CACHE_PRINTF(tpk_cache));
    1.27 +        tpk_cache.hits ++;
    1.28 +        return pgp_tpk_clone(tpk_cache.tpk);
    1.29 +    } else {
    1.30 +        T("MISS: %s not in tpk cache (%s)! "TPK_CACHE_FMT,
    1.31 +          pgp_fingerprint_to_string(fpr),
    1.32 +          tpk_cache.fpr ? pgp_fingerprint_to_string(tpk_cache.fpr) : " (empty)",
    1.33 +          TPK_CACHE_PRINTF(tpk_cache));
    1.34 +        tpk_cache.misses ++;
    1.35 +        return NULL;
    1.36 +    }
    1.37 +}
    1.38 +
    1.39 +static pgp_tpk_t tpk_cache_lookup_keyid(pgp_keyid_t keyid)
    1.40 +{
    1.41 +    if (! tpk_cache.fpr) {
    1.42 +        tpk_cache.hits ++;
    1.43 +        T("MISS: %s not in tpk cache (empty)! "TPK_CACHE_FMT,
    1.44 +          pgp_keyid_to_string(keyid),
    1.45 +          TPK_CACHE_PRINTF(tpk_cache));
    1.46 +        return NULL;
    1.47 +    }
    1.48 +
    1.49 +    pgp_keyid_t cache_keyid = pgp_fingerprint_to_keyid(tpk_cache.fpr);
    1.50 +    if (pgp_keyid_equal(cache_keyid, keyid)) {
    1.51 +        T("HIT: found %s in tpk cache! "TPK_CACHE_FMT,
    1.52 +          pgp_keyid_to_string(keyid),
    1.53 +          TPK_CACHE_PRINTF(tpk_cache));
    1.54 +        return pgp_tpk_clone(tpk_cache.tpk);
    1.55 +    } else {
    1.56 +        T("MISS: %s not in tpk cache (%s)! "TPK_CACHE_FMT,
    1.57 +          pgp_keyid_to_string(keyid),
    1.58 +          pgp_fingerprint_to_string(tpk_cache.fpr),
    1.59 +          TPK_CACHE_PRINTF(tpk_cache));
    1.60 +        tpk_cache.misses ++;
    1.61 +        return NULL;
    1.62 +    }
    1.63 +}
    1.64 +
    1.65 +static void tpk_cache_clear(void)
    1.66 +{
    1.67 +    T("Clearing tpk cache. "TPK_CACHE_FMT, TPK_CACHE_PRINTF(tpk_cache));
    1.68 +
    1.69 +    if (tpk_cache.fpr) {
    1.70 +        // Evict the old entry.
    1.71 +        pgp_fingerprint_free(tpk_cache.fpr);
    1.72 +        tpk_cache.fpr = NULL;
    1.73 +
    1.74 +        pgp_tpk_free(tpk_cache.tpk);
    1.75 +        tpk_cache.tpk = NULL;
    1.76 +    }
    1.77 +}
    1.78 +
    1.79 +static void tpk_cache_insert(pgp_tpk_t tpk)
    1.80 +{
    1.81 +    pgp_fingerprint_t fpr = pgp_tpk_fingerprint(tpk);
    1.82 +    if (! fpr)
    1.83 +        return;
    1.84 +
    1.85 +    tpk_cache_clear();
    1.86 +
    1.87 +    T("Inserting %s into tpk cache", pgp_fingerprint_to_string(fpr));
    1.88 +    tpk_cache.inserts ++;
    1.89 +
    1.90 +    // Insert the new one.
    1.91 +    tpk_cache.fpr = fpr;
    1.92 +    tpk_cache.tpk = pgp_tpk_clone(tpk);
    1.93 +}
    1.94 +
    1.95  // Returns the TPK identified by the provided fingerprint.
    1.96  //
    1.97  // This function only matches on the primary key!
    1.98 @@ -539,18 +627,28 @@
    1.99  {
   1.100      PEP_STATUS status = PEP_STATUS_OK;
   1.101      char *fpr_str = pgp_fingerprint_to_hex(fpr);
   1.102 +    sqlite3_stmt *stmt = NULL;
   1.103  
   1.104      T("(%s, %d)", fpr_str, private_only);
   1.105  
   1.106 -    sqlite3_stmt *stmt
   1.107 -        = private_only ? session->sq_sql.tsk_find : session->sq_sql.tpk_find;
   1.108 +    if (! private_only && tpk) {
   1.109 +        *tpk = tpk_cache_lookup(fpr);
   1.110 +        if (*tpk)
   1.111 +            goto out;
   1.112 +    }
   1.113 +
   1.114 +    stmt = private_only ? session->sq_sql.tsk_find : session->sq_sql.tpk_find;
   1.115      sqlite3_bind_text(stmt, 1, fpr_str, -1, SQLITE_STATIC);
   1.116  
   1.117      status = key_load(session, stmt, tpk, secret);
   1.118      ERROR_OUT(NULL, status, "Looking up %s", fpr_str);
   1.119  
   1.120 +    if (tpk && *tpk)
   1.121 +        tpk_cache_insert(*tpk);
   1.122 +
   1.123   out:
   1.124 -    sqlite3_reset(stmt);
   1.125 +    if (stmt)
   1.126 +        sqlite3_reset(stmt);
   1.127      T("(%s, %d) -> %s", fpr_str, private_only, pEp_status_to_string(status));
   1.128      free(fpr_str);
   1.129      return status;
   1.130 @@ -574,17 +672,30 @@
   1.131          pgp_tpk_t *tpkp, int *secretp)
   1.132  {
   1.133      PEP_STATUS status = PEP_STATUS_OK;
   1.134 +    sqlite3_stmt *stmt = NULL;
   1.135 +
   1.136      T("(%s, %d)", keyid_hex, private_only);
   1.137  
   1.138 -    sqlite3_stmt *stmt
   1.139 -        = private_only ? session->sq_sql.tsk_find_by_keyid : session->sq_sql.tpk_find_by_keyid;
   1.140 +    if (! private_only && tpkp) {
   1.141 +        pgp_keyid_t keyid = pgp_keyid_from_hex(keyid_hex);
   1.142 +        *tpkp = tpk_cache_lookup_keyid(keyid);
   1.143 +        pgp_keyid_free(keyid);
   1.144 +        if (*tpkp)
   1.145 +            goto out;
   1.146 +    }
   1.147 +
   1.148 +    stmt = private_only ? session->sq_sql.tsk_find_by_keyid : session->sq_sql.tpk_find_by_keyid;
   1.149      sqlite3_bind_text(stmt, 1, keyid_hex, -1, SQLITE_STATIC);
   1.150  
   1.151      status = key_load(session, stmt, tpkp, secretp);
   1.152      ERROR_OUT(NULL, status, "Looking up %s", keyid_hex);
   1.153  
   1.154 +    if (tpkp && *tpkp)
   1.155 +        tpk_cache_insert(*tpkp);
   1.156 +
   1.157   out:
   1.158 -    sqlite3_reset(stmt);
   1.159 +    if (stmt)
   1.160 +        sqlite3_reset(stmt);
   1.161      T("(%s, %d) -> %s", keyid_hex, private_only, pEp_status_to_string(status));
   1.162      return status;
   1.163  }
   1.164 @@ -670,6 +781,9 @@
   1.165      status = key_loadn(session, stmt, tpksp, countp);
   1.166      ERROR_OUT(NULL, status, "Searching for '%s'", pattern);
   1.167  
   1.168 +    if (*tpksp && *countp > 0)
   1.169 +        tpk_cache_insert((*tpksp)[0]);
   1.170 +
   1.171   out:
   1.172      sqlite3_reset(stmt);
   1.173      T("(%s) -> %s (%d results)", pattern, pEp_status_to_string(status), *countp);
   1.174 @@ -697,6 +811,10 @@
   1.175      char *email = NULL;
   1.176      char *name = NULL;
   1.177  
   1.178 +    pgp_fpr = pgp_tpk_fingerprint(tpk);
   1.179 +    fpr = pgp_fingerprint_to_hex(pgp_fpr);
   1.180 +    T("(%s, private_idents: %s)", fpr, private_idents ? "yes" : "no");
   1.181 +
   1.182      sqlite3_stmt *stmt = session->sq_sql.begin_transaction;
   1.183      int sqlite_result = Sqlite3_step(stmt);
   1.184      sqlite3_reset(stmt);
   1.185 @@ -705,9 +823,8 @@
   1.186                    "begin transaction failed: %s",
   1.187                    sqlite3_errmsg(session->key_db));
   1.188  
   1.189 -    pgp_fpr = pgp_tpk_fingerprint(tpk);
   1.190 -    fpr = pgp_fingerprint_to_hex(pgp_fpr);
   1.191 -    T("(%s, private_idents: %s)", fpr, private_idents ? "yes" : "no");
   1.192 +    // Make sure we read from the DB.
   1.193 +    tpk_cache_clear();
   1.194  
   1.195      // Merge any existing data into TPK.
   1.196      pgp_tpk_t current = NULL;
   1.197 @@ -836,6 +953,8 @@
   1.198      pgp_user_id_binding_iter_free(user_id_iter);
   1.199      user_id_iter = NULL;
   1.200  
   1.201 +    // It's essential that we at least clear the cache.
   1.202 +    tpk_cache_insert(tpk);
   1.203   out:
   1.204      // Prevent ERROR_OUT from causing an infinite loop.
   1.205      if (! tried_commit) {
   1.206 @@ -1858,6 +1977,8 @@
   1.207      if (! fpr)
   1.208          ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "out of memory");
   1.209  
   1.210 +    tpk_cache_clear();
   1.211 +
   1.212      T("Deleting %s", fpr);
   1.213  
   1.214      sqlite3_stmt *stmt = session->sq_sql.delete_keypair;
   1.215 @@ -1889,6 +2010,8 @@
   1.216      if (private_idents)
   1.217          *private_idents = NULL;
   1.218  
   1.219 +    tpk_cache_clear();
   1.220 +
   1.221      T("parsing %zd bytes", size);
   1.222  
   1.223      pgp_packet_parser_result_t ppr