mirror of
https://github.com/pgpainless/pgpainless.git
synced 2025-12-16 09:11:08 +01:00
SubkeyLookup: Switch to batch inserting
This commit is contained in:
parent
d53d62a6e9
commit
1495baaf6e
9 changed files with 110 additions and 86 deletions
|
|
@ -4,27 +4,44 @@
|
|||
|
||||
package pgp.cert_d.jdbc.sqlite;
|
||||
|
||||
/**
|
||||
* Subkey-ID database entry.
|
||||
*/
|
||||
public class Entry {
|
||||
|
||||
private final int id;
|
||||
private final String identifier;
|
||||
private final String certificate;
|
||||
private final long subkeyId;
|
||||
|
||||
public Entry(int id, long subkeyId, String identifier) {
|
||||
public Entry(int id, long subkeyId, String certificate) {
|
||||
this.id = id;
|
||||
this.subkeyId = subkeyId;
|
||||
this.identifier = identifier;
|
||||
this.certificate = certificate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internal ID of this entry in the database.
|
||||
*
|
||||
* @return internal id
|
||||
*/
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the key-ID of the subkey.
|
||||
*
|
||||
* @return subkey id
|
||||
*/
|
||||
public long getSubkeyId() {
|
||||
return subkeyId;
|
||||
}
|
||||
|
||||
public String getIdentifier() {
|
||||
return identifier;
|
||||
/**
|
||||
* Return the fingerprint of the certificate the subkey belongs to.
|
||||
* @return fingerprint
|
||||
*/
|
||||
public String getCertificate() {
|
||||
return certificate;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,16 +28,18 @@ public class SqliteSubkeyLookup implements SubkeyLookup {
|
|||
|
||||
private static final String CREATE_TABLE_STMT = "" +
|
||||
"CREATE TABLE IF NOT EXISTS subkey_lookup (\n" +
|
||||
" id integer PRIMARY KEY,\n" +
|
||||
" identifier text NOT NULL,\n" +
|
||||
" subkey_id integer NOT NULL,\n" +
|
||||
" UNIQUE(identifier, subkey_id)\n" +
|
||||
" id integer PRIMARY KEY,\n" + // id (internal to the database)
|
||||
" certificate text NOT NULL,\n" + // certificate fingerprint
|
||||
" subkey_id integer NOT NULL,\n" + // subkey id
|
||||
" UNIQUE(certificate, subkey_id)\n" +
|
||||
")";
|
||||
|
||||
private static final String INSERT_STMT = "" +
|
||||
"INSERT INTO subkey_lookup(identifier, subkey_id) VALUES (?,?)";
|
||||
"INSERT INTO subkey_lookup(certificate, subkey_id) " +
|
||||
"VALUES (?,?)";
|
||||
private static final String QUERY_STMT = "" +
|
||||
"SELECT * FROM subkey_lookup WHERE subkey_id=?";
|
||||
"SELECT * FROM subkey_lookup " +
|
||||
"WHERE subkey_id=?";
|
||||
|
||||
public SqliteSubkeyLookup(String databaseURL) throws SQLException {
|
||||
this.databaseUrl = databaseURL;
|
||||
|
|
@ -54,21 +56,27 @@ public class SqliteSubkeyLookup implements SubkeyLookup {
|
|||
return new SqliteSubkeyLookup("jdbc:sqlite:" + databaseFile.getAbsolutePath());
|
||||
}
|
||||
|
||||
public void insert(long subkeyId, String identifier, boolean ignoreDuplicates) throws SQLException {
|
||||
public void insertValues(String certificate, List<Long> subkeyIds) throws SQLException {
|
||||
try (Connection connection = getConnection(); PreparedStatement statement = connection.prepareStatement(INSERT_STMT)) {
|
||||
statement.setString(1, identifier);
|
||||
statement.setLong(2, subkeyId);
|
||||
statement.executeUpdate();
|
||||
} catch (SQLiteException e) {
|
||||
// throw any exception, except:
|
||||
// ignore unique constraint-related exceptions if we ignoreDuplicates
|
||||
if (!ignoreDuplicates || e.getResultCode().code != SQLiteErrorCode.SQLITE_CONSTRAINT_UNIQUE.code) {
|
||||
throw e;
|
||||
for (long subkeyId : subkeyIds) {
|
||||
try {
|
||||
statement.setString(1, certificate);
|
||||
statement.setLong(2, subkeyId);
|
||||
statement.executeUpdate();
|
||||
} catch (SQLiteException e) {
|
||||
// throw any exception, except:
|
||||
// ignore unique constraint-related exceptions if we ignoreDuplicates
|
||||
if (e.getResultCode().code == SQLiteErrorCode.SQLITE_CONSTRAINT_UNIQUE.code) {
|
||||
// ignore duplicates
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<Entry> get(long subkeyId) throws SQLException {
|
||||
public List<Entry> selectValues(long subkeyId) throws SQLException {
|
||||
List<Entry> results = new ArrayList<>();
|
||||
try (Connection connection = getConnection(); PreparedStatement statement = connection.prepareStatement(QUERY_STMT)) {
|
||||
statement.setLong(1, subkeyId);
|
||||
|
|
@ -77,7 +85,7 @@ public class SqliteSubkeyLookup implements SubkeyLookup {
|
|||
Entry entry = new Entry(
|
||||
resultSet.getInt("id"),
|
||||
resultSet.getLong("subkey_id"),
|
||||
resultSet.getString("identifier"));
|
||||
resultSet.getString("certificate"));
|
||||
results.add(entry);
|
||||
}
|
||||
}
|
||||
|
|
@ -86,27 +94,26 @@ public class SqliteSubkeyLookup implements SubkeyLookup {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getIdentifiersForSubkeyId(long subkeyId) throws IOException {
|
||||
public Set<String> getCertificatesForSubkeyId(long subkeyId) throws IOException {
|
||||
try {
|
||||
List<Entry> entries = get(subkeyId);
|
||||
Set<String> identifiers = new HashSet<>();
|
||||
List<Entry> entries = selectValues(subkeyId);
|
||||
Set<String> certificates = new HashSet<>();
|
||||
for (Entry entry : entries) {
|
||||
identifiers.add(entry.getIdentifier());
|
||||
certificates.add(entry.getCertificate());
|
||||
}
|
||||
|
||||
return Collections.unmodifiableSet(identifiers);
|
||||
return Collections.unmodifiableSet(certificates);
|
||||
} catch (SQLException e) {
|
||||
throw new IOException("Cannot query for subkey lookup entries.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void storeIdentifierForSubkeyId(long subkeyId, String identifier)
|
||||
throws IOException {
|
||||
public void storeCertificateSubkeyIds(String certificate, List<Long> subkeyIds) throws IOException {
|
||||
try {
|
||||
insert(subkeyId, identifier, true);
|
||||
insertValues(certificate, subkeyIds);
|
||||
} catch (SQLException e) {
|
||||
throw new IOException("Cannot store subkey lookup entry in database.", e);
|
||||
throw new IOException("Cannot store subkey lookup entries in database.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,6 @@ public class EntryTest {
|
|||
|
||||
assertEquals(1, entry.getId());
|
||||
assertEquals(123L, entry.getSubkeyId());
|
||||
assertEquals("eb85bb5fa33a75e15e944e63f231550c4f47e38e", entry.getIdentifier());
|
||||
assertEquals("eb85bb5fa33a75e15e944e63f231550c4f47e38e", entry.getCertificate());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
package pgp.cert_d.jdbc.sqlite;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.io.File;
|
||||
|
|
@ -34,40 +33,35 @@ public class SqliteSubkeyLookupTest {
|
|||
|
||||
@Test
|
||||
public void simpleInsertAndGet() throws IOException {
|
||||
lookup.storeIdentifierForSubkeyId(123L, "eb85bb5fa33a75e15e944e63f231550c4f47e38e");
|
||||
lookup.storeIdentifierForSubkeyId(234L, "eb85bb5fa33a75e15e944e63f231550c4f47e38e");
|
||||
lookup.storeIdentifierForSubkeyId(234L, "d1a66e1a23b182c9980f788cfbfcc82a015e7330");
|
||||
lookup.storeCertificateSubkeyIds("eb85bb5fa33a75e15e944e63f231550c4f47e38e", Arrays.asList(123L, 234L));
|
||||
lookup.storeCertificateSubkeyIds("d1a66e1a23b182c9980f788cfbfcc82a015e7330", Collections.singletonList(234L));
|
||||
|
||||
assertEquals(Collections.singleton("eb85bb5fa33a75e15e944e63f231550c4f47e38e"), lookup.getIdentifiersForSubkeyId(123L));
|
||||
assertEquals(Collections.singleton("eb85bb5fa33a75e15e944e63f231550c4f47e38e"), lookup.getCertificatesForSubkeyId(123L));
|
||||
assertEquals(
|
||||
new HashSet<>(Arrays.asList("eb85bb5fa33a75e15e944e63f231550c4f47e38e", "d1a66e1a23b182c9980f788cfbfcc82a015e7330")),
|
||||
lookup.getIdentifiersForSubkeyId(234L));
|
||||
lookup.getCertificatesForSubkeyId(234L));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNonExistingSubkeyYieldsNull() throws IOException, SQLException {
|
||||
assertTrue(lookup.get(6666666).isEmpty());
|
||||
assertTrue(lookup.getIdentifiersForSubkeyId(6666666).isEmpty());
|
||||
assertTrue(lookup.selectValues(6666666).isEmpty());
|
||||
assertTrue(lookup.getCertificatesForSubkeyId(6666666).isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void secondInstanceLookupTest() throws IOException, SQLException {
|
||||
lookup.storeIdentifierForSubkeyId(1337, "eb85bb5fa33a75e15e944e63f231550c4f47e38e");
|
||||
assertEquals(Collections.singleton("eb85bb5fa33a75e15e944e63f231550c4f47e38e"), lookup.getIdentifiersForSubkeyId(1337));
|
||||
lookup.storeCertificateSubkeyIds("eb85bb5fa33a75e15e944e63f231550c4f47e38e", Collections.singletonList(1337L));
|
||||
assertEquals(Collections.singleton("eb85bb5fa33a75e15e944e63f231550c4f47e38e"), lookup.getCertificatesForSubkeyId(1337));
|
||||
|
||||
// do the lookup using a second db instance on the same file
|
||||
SqliteSubkeyLookup secondInstance = SqliteSubkeyLookup.forDatabaseFile(databaseFile);
|
||||
assertEquals(Collections.singleton("eb85bb5fa33a75e15e944e63f231550c4f47e38e"), secondInstance.getIdentifiersForSubkeyId(1337));
|
||||
assertEquals(Collections.singleton("eb85bb5fa33a75e15e944e63f231550c4f47e38e"), secondInstance.getCertificatesForSubkeyId(1337));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ignoreInsertDuplicates() throws IOException {
|
||||
lookup.storeIdentifierForSubkeyId(123L, "d1a66e1a23b182c9980f788cfbfcc82a015e7330");
|
||||
lookup.storeCertificateSubkeyIds("d1a66e1a23b182c9980f788cfbfcc82a015e7330", Arrays.asList(123L, 234L));
|
||||
// per default we ignore duplicates
|
||||
lookup.storeIdentifierForSubkeyId(123L, "d1a66e1a23b182c9980f788cfbfcc82a015e7330");
|
||||
|
||||
// if we choose not to ignore duplicates, we raise an exception
|
||||
assertThrows(SQLException.class, () ->
|
||||
lookup.insert(123L, "d1a66e1a23b182c9980f788cfbfcc82a015e7330", false));
|
||||
lookup.storeCertificateSubkeyIds("d1a66e1a23b182c9980f788cfbfcc82a015e7330", Arrays.asList(123L, 512L));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue