From commits-return-43688-apmail-directory-commits-archive=directory.apache.org@directory.apache.org Wed Nov 4 08:25:30 2015 Return-Path: X-Original-To: apmail-directory-commits-archive@www.apache.org Delivered-To: apmail-directory-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id A00E418C1D for ; Wed, 4 Nov 2015 08:25:28 +0000 (UTC) Received: (qmail 32562 invoked by uid 500); 4 Nov 2015 08:25:28 -0000 Delivered-To: apmail-directory-commits-archive@directory.apache.org Received: (qmail 32432 invoked by uid 500); 4 Nov 2015 08:25:27 -0000 Mailing-List: contact commits-help@directory.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@directory.apache.org Delivered-To: mailing list commits@directory.apache.org Received: (qmail 31936 invoked by uid 99); 4 Nov 2015 08:25:27 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 04 Nov 2015 08:25:27 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 7E90CE03C8; Wed, 4 Nov 2015 08:25:27 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: plusplusjiajia@apache.org To: commits@directory.apache.org Date: Wed, 04 Nov 2015 08:25:42 -0000 Message-Id: In-Reply-To: References: X-Mailer: ASF-Git Admin Mailer Subject: [16/48] directory-kerby git commit: DIRKRB-422. Enhance json backend to support transaction for reasonable efficiency, allowing flush only when commit DIRKRB-422. Enhance json backend to support transaction for reasonable efficiency, allowing flush only when commit Project: http://git-wip-us.apache.org/repos/asf/directory-kerby/repo Commit: http://git-wip-us.apache.org/repos/asf/directory-kerby/commit/3dd63f3b Tree: http://git-wip-us.apache.org/repos/asf/directory-kerby/tree/3dd63f3b Diff: http://git-wip-us.apache.org/repos/asf/directory-kerby/diff/3dd63f3b Branch: refs/heads/pkinit-support Commit: 3dd63f3b8a931e6a9ca44c6e70ff95ff48202c8b Parents: cd135c0 Author: Kai Zheng Authored: Mon Sep 28 22:27:09 2015 +0800 Committer: Kai Zheng Committed: Mon Sep 28 22:27:09 2015 +0800 ---------------------------------------------------------------------- .../identitybackend/JsonIdentityBackend.java | 202 ++++++++++++++----- 1 file changed, 150 insertions(+), 52 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/3dd63f3b/kerby-backend/json-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/JsonIdentityBackend.java ---------------------------------------------------------------------- diff --git a/kerby-backend/json-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/JsonIdentityBackend.java b/kerby-backend/json-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/JsonIdentityBackend.java index 37e210d..7aadf43 100644 --- a/kerby-backend/json-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/JsonIdentityBackend.java +++ b/kerby-backend/json-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/JsonIdentityBackend.java @@ -27,6 +27,7 @@ import org.apache.kerby.kerberos.kdc.identitybackend.typeAdapter.EncryptionKeyAd import org.apache.kerby.kerberos.kdc.identitybackend.typeAdapter.KerberosTimeAdapter; import org.apache.kerby.kerberos.kdc.identitybackend.typeAdapter.PrincipalNameAdapter; import org.apache.kerby.kerberos.kerb.KrbException; +import org.apache.kerby.kerberos.kerb.identity.BatchTrans; import org.apache.kerby.kerberos.kerb.identity.KrbIdentity; import org.apache.kerby.kerberos.kerb.identity.backend.AbstractIdentityBackend; import org.apache.kerby.kerberos.kerb.spec.KerberosTime; @@ -45,13 +46,16 @@ import java.util.List; import java.util.Map; import java.util.TreeMap; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; /** * A Json file based backend implementation. - * */ public class JsonIdentityBackend extends AbstractIdentityBackend { - private static final Logger LOG = LoggerFactory.getLogger(JsonIdentityBackend.class); + private static final Logger LOG = + LoggerFactory.getLogger(JsonIdentityBackend.class); + public static final String JSON_IDENTITY_BACKEND_DIR = "backend.json.dir"; private File jsonKdbFile; private Gson gson; @@ -61,6 +65,8 @@ public class JsonIdentityBackend extends AbstractIdentityBackend { new ConcurrentHashMap<>(new TreeMap()); private long kdbFileUpdateTime = -1; + private Lock lock = new ReentrantLock(); + public JsonIdentityBackend() { } @@ -78,69 +84,90 @@ public class JsonIdentityBackend extends AbstractIdentityBackend { * {@inheritDoc} */ @Override - protected void doInitialize() throws KrbException { - LOG.info("Initializing the Json identity backend."); - createGson(); - load(); + public boolean supportBatchTrans() { + return true; } /** - * Load identities from file + * {@inheritDoc} */ - private void load() throws KrbException { - LOG.info("Loading the identities from json file."); - String jsonFile = getConfig().getString(JSON_IDENTITY_BACKEND_DIR); + @Override + public BatchTrans startBatchTrans() throws KrbException { + if (lock.tryLock()) { + checkAndReload(); + return new JsonBatchTrans(); + } + return null; + } + + /** + * {@inheritDoc} + */ + @Override + protected void doInitialize() throws KrbException { + LOG.info("Initializing the Json identity backend."); + + initGsonBuilder(); + + String dirPath = getConfig().getString(JSON_IDENTITY_BACKEND_DIR); File jsonFileDir; - if (jsonFile == null || jsonFile.isEmpty()) { + if (dirPath == null || dirPath.isEmpty()) { jsonFileDir = getBackendConfig().getConfDir(); } else { - jsonFileDir = new File(jsonFile); + jsonFileDir = new File(dirPath); if (!jsonFileDir.exists() && !jsonFileDir.mkdirs()) { - throw new KrbException("could not create json file dir " + jsonFileDir); + throw new KrbException("Failed to create json file dir " + jsonFileDir); } } jsonKdbFile = new File(jsonFileDir, "json-backend.json"); - if (!jsonKdbFile.exists()) { try { jsonKdbFile.createNewFile(); } catch (IOException e) { - e.printStackTrace(); + throw new KrbException("Failed to create " + jsonKdbFile.getAbsolutePath()); } } - - checkAndReload(); } - /** - * Check kdb file timestamp to see if it's changed or not. If - * necessary load the kdb again. - */ - private synchronized void checkAndReload() throws KrbException { - long nowTimeStamp = jsonKdbFile.lastModified(); + private void load() throws KrbException { + LOG.info("Loading the identities from json file."); - if (kdbFileUpdateTime < 0 || - nowTimeStamp != kdbFileUpdateTime) { - //load identities - String reloadedJsonContent; + long nowTimeStamp = jsonKdbFile.lastModified(); + String reloadedJsonContent; + if (lock.tryLock()) { try { - reloadedJsonContent = IOUtil.readFile(jsonKdbFile); - } catch (IOException e) { - throw new KrbException("Failed to read file", e); - } + try { + reloadedJsonContent = IOUtil.readFile(jsonKdbFile); + } catch (IOException e) { + throw new KrbException("Failed to read file", e); + } - Map reloadedEntries = - gson.fromJson(reloadedJsonContent, - new TypeToken>() { - }.getType()); + Map reloadedEntries = + gson.fromJson(reloadedJsonContent, + new TypeToken>() { + }.getType()); - if (reloadedEntries != null) { - identities.clear(); - identities.putAll(reloadedEntries); + if (reloadedEntries != null) { + identities.clear(); + identities.putAll(reloadedEntries); + } + + kdbFileUpdateTime = nowTimeStamp; + } finally { + lock.unlock(); } + } + } - kdbFileUpdateTime = nowTimeStamp; + /** + * Check kdb file timestamp to see if it's changed or not. If + * necessary load the kdb again. + */ + private void checkAndReload() throws KrbException { + long nowTimeStamp = jsonKdbFile.lastModified(); + if (nowTimeStamp != kdbFileUpdateTime) { + load(); } } @@ -160,8 +187,14 @@ public class JsonIdentityBackend extends AbstractIdentityBackend { protected KrbIdentity doAddIdentity(KrbIdentity identity) throws KrbException { checkAndReload(); - identities.put(identity.getPrincipalName(), identity); - persistToFile(); + if (lock.tryLock()) { + try { + identities.put(identity.getPrincipalName(), identity); + persistToFile(); + } finally { + lock.unlock(); + } + } return doGetIdentity(identity.getPrincipalName()); } @@ -172,8 +205,15 @@ public class JsonIdentityBackend extends AbstractIdentityBackend { @Override protected KrbIdentity doUpdateIdentity(KrbIdentity identity) throws KrbException { checkAndReload(); - identities.put(identity.getPrincipalName(), identity); - persistToFile(); + + if (lock.tryLock()) { + try { + identities.put(identity.getPrincipalName(), identity); + persistToFile(); + } finally { + lock.unlock(); + } + } return doGetIdentity(identity.getPrincipalName()); } @@ -184,10 +224,19 @@ public class JsonIdentityBackend extends AbstractIdentityBackend { @Override protected void doDeleteIdentity(String principalName) throws KrbException { checkAndReload(); - if (identities.containsKey(principalName)) { - identities.remove(principalName); + + if (!identities.containsKey(principalName)) { + return; + } + + if (lock.tryLock()) { + try { + identities.remove(principalName); + persistToFile(); + } finally { + lock.unlock(); + } } - persistToFile(); } /** @@ -201,10 +250,7 @@ public class JsonIdentityBackend extends AbstractIdentityBackend { return principals; } - /** - *Create a gson - */ - private void createGson() { + private void initGsonBuilder() { GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.registerTypeAdapter(EncryptionKey.class, new EncryptionKeyAdapter()); gsonBuilder.registerTypeAdapter(PrincipalName.class, new PrincipalNameAdapter()); @@ -214,14 +260,66 @@ public class JsonIdentityBackend extends AbstractIdentityBackend { gson = gsonBuilder.create(); } - private synchronized void persistToFile() throws KrbException { + private void persistToFile() throws KrbException { String newJsonContent = gson.toJson(identities); try { - IOUtil.writeFile(newJsonContent, jsonKdbFile); + File newJsonKdbFile = File.createTempFile("kerby-kdb", + ".json", jsonKdbFile.getParentFile()); + IOUtil.writeFile(newJsonContent, newJsonKdbFile); + newJsonKdbFile.renameTo(jsonKdbFile); kdbFileUpdateTime = jsonKdbFile.lastModified(); } catch (IOException e) { LOG.error("Error occurred while writing identities to file: " + jsonKdbFile); throw new KrbException("Failed to write file", e); } } + + class JsonBatchTrans implements BatchTrans { + + @Override + public void commit() throws KrbException { + try { + // Force to persist memory states to disk file. + persistToFile(); + } finally { + lock.unlock(); + } + } + + @Override + public void rollback() throws KrbException { + // Force to reload from disk file and disgard the memory states. + try { + load(); + } finally { + lock.unlock(); + } + } + + @Override + public BatchTrans addIdentity(KrbIdentity identity) throws KrbException { + if (identity != null && + identities.containsKey(identity.getPrincipalName())) { + identities.put(identity.getPrincipalName(), identity); + } + return this; + } + + @Override + public BatchTrans updateIdentity(KrbIdentity identity) throws KrbException { + if (identity != null && + identities.containsKey(identity.getPrincipalName())) { + identities.put(identity.getPrincipalName(), identity); + } + return this; + } + + @Override + public BatchTrans deleteIdentity(String principalName) throws KrbException { + if (principalName != null && identities.containsKey(principalName)) { + identities.remove(principalName); + } + return this; + } + } }