http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/c8c88786/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/FileLog.java
----------------------------------------------------------------------
diff --git 
a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/FileLog.java
 
b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/FileLog.java
new file mode 100644
index 0000000..9ace37c
--- /dev/null
+++ 
b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/FileLog.java
@@ -0,0 +1,236 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.sentry.provider.db.service.persistent;
+
+import java.io.EOFException;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+
+import org.apache.hadoop.conf.Configuration;
+import 
org.apache.sentry.provider.db.service.thrift.SentryConfigurationException;
+import org.apache.sentry.provider.db.service.thrift.TSentryStoreRecord;
+import org.apache.sentry.provider.db.service.thrift.TStoreSnapshot;
+import org.apache.thrift.TDeserializer;
+import org.apache.thrift.TException;
+import org.apache.thrift.TSerializer;
+import org.apache.thrift.protocol.TCompactProtocol;
+import org.apache.thrift.protocol.TProtocolFactory;
+
+/**
+ * The FileLog class abstracts out the log file and all operations on it
+ * When the FileLog is instantiated, It first checks if there is an existing
+ * log file associated at the configured path. If yes, then the Client will
+ * not be allowed to write to the log unless all existing LogEntries have been
+ * iterated over using the standard iterator abstractions of {@link #hasNext()}
+ * and {@link #next()}. Once all the entries are read out, it will open an
+ * Output stream to the log file and clients can start logging.
+ * The FileLog also support Log snapshots. If it see a special snapshot
+ * record, the current log file is first closed and renamed. Once the snapshot
+ * entry has been successfully written to a new log, it will delete the
+ * old log file. 
+ */
+public class FileLog {
+
+  // The default Java ObjectOutputStream cannot be appended to since it
+  // writes a special header whenever you open the stream. We need this header
+  // only when a new file is opened. When a store is shutdown and re-opened
+  // again, subsequent appends should not write the header, else reading the
+  // file again will throw a StreamCorruptedException.
+  public class AppendingObjectOutputStream extends ObjectOutputStream {
+
+    public AppendingObjectOutputStream(OutputStream out) throws IOException {
+      super(out);
+    }
+
+    @Override
+    protected void writeStreamHeader() throws IOException {
+      // do not write a header
+      reset();
+    }
+  }
+
+  public static String SENTRY_FILE_LOG_STORE_LOCATION =
+      "sentry.file.log.store.location";
+
+  private static String COMMIT_LOG_FILE = "commit.log";
+
+  public static class Entry {
+    public final long seqId;
+    public final TSentryStoreRecord record;
+    public Entry(long seqId, TSentryStoreRecord record) {
+      this.seqId = seqId;
+      this.record = record;
+    }
+  }
+
+  private volatile boolean isReady = false;
+  private ObjectInputStream commitOis = null;
+  private Entry nextEntry = null;
+  private File logDir;
+
+  private ObjectOutputStream commitLog;
+  private final TSerializer serializer;
+  private final TDeserializer deserializer;
+
+  public FileLog(Configuration conf)
+      throws SentryConfigurationException, FileNotFoundException, IOException {
+    String currentDir = System.getProperty("user.dir");
+    logDir = new File(conf.get(SENTRY_FILE_LOG_STORE_LOCATION, currentDir));
+    TProtocolFactory protoFactory = new TCompactProtocol.Factory();
+    serializer = new TSerializer(protoFactory);
+    deserializer = new TDeserializer(protoFactory);
+    if (logDir.exists()) {
+      if (!logDir.isDirectory()) {
+        throw new SentryConfigurationException(
+            "Dir [" + logDir.getAbsolutePath() + "] exists and is not a 
directory !!");
+      } else {
+        if (new File(logDir, COMMIT_LOG_FILE).exists()) {
+          commitOis =
+              new ObjectInputStream(
+                  new FileInputStream(new File(logDir, COMMIT_LOG_FILE)));
+        } else {
+          commitLog =
+              new ObjectOutputStream(
+                  new FileOutputStream(new File(logDir, COMMIT_LOG_FILE)));
+          isReady = true;
+        }
+      }
+    } else {
+      isReady = true;
+      boolean created = logDir.mkdirs();
+      if (!created) {
+        throw new RuntimeException(
+            "Could not create store directory [" + logDir.getAbsolutePath() + 
"]");
+      }
+      commitLog =
+          new ObjectOutputStream(new FileOutputStream(new File(logDir,
+              COMMIT_LOG_FILE)));
+    }
+  }
+
+  public boolean hasNext() {
+    if (isReady) {
+      return false;
+    }
+    if (nextEntry != null) {
+      return true;
+    }
+    try {
+      nextEntry = getNextEntry();
+    } catch (EOFException e) {
+      isReady = true;
+      try {
+        commitOis.close();
+      } catch (Exception e2) {
+        System.out.println("Got ex : " + e2.getMessage());
+      }
+    } catch (IOException e) {
+      throw new RuntimeException(e);
+    } catch (TException e) {
+      throw new RuntimeException(e);
+    }
+    return !isReady;
+  }
+
+  private Entry getNextEntry() throws IOException, TException {
+    long seqId = commitOis.readLong();
+    int numRecordBytes = commitOis.readInt();
+    byte[] recBytes = new byte[numRecordBytes];
+    commitOis.readFully(recBytes);
+    TSentryStoreRecord record = new TSentryStoreRecord();
+    deserializer.deserialize(record, recBytes); 
+    return new Entry(seqId, record);
+  }
+
+  // Must be called only after a hasNext();
+  public Entry next() {
+    Entry e = nextEntry;
+    nextEntry = null;
+    return e;
+  }
+
+  public void log(long seqId, TSentryStoreRecord record) {
+    if (!isReady) {
+      throw new RuntimeException("FileLog is not ready for writing yet !!");
+    }
+    try {
+      prepareForSnapshotIfNeeded(seqId, record);
+      if (commitLog == null) {
+        commitLog =
+            new AppendingObjectOutputStream(
+                new FileOutputStream(new File(logDir, COMMIT_LOG_FILE), true));
+      }
+      byte[] recBytes = serializer.serialize(record);
+      commitLog.writeLong(seqId);
+      commitLog.writeInt(recBytes.length);
+      commitLog.write(recBytes);
+      commitLog.flush();
+    } catch (Exception e) {
+      throw new RuntimeException(
+          "Could not log record with id [" + seqId + "] !!", e);
+    }
+    commitIfSnapshot(seqId, record);
+  }
+
+  // Truncate current log file and write the snapshot record
+  private void prepareForSnapshotIfNeeded(long seqId, TSentryStoreRecord 
record)
+      throws IOException {
+    if (record.getSnapshot() != null) {
+      // Close current log
+      if (commitLog != null) {
+        commitLog.flush();
+        commitLog.close();
+      }
+
+      // Copy current log to temp
+      boolean renameSuccess =
+          new File(logDir, COMMIT_LOG_FILE)
+              .renameTo(
+              new File(logDir, COMMIT_LOG_FILE + "_tmp_" + seqId));
+      if (!renameSuccess) {
+        throw new IOException("Could not Prepare for snapshot !!");
+      }
+      commitLog = new ObjectOutputStream(
+          new FileOutputStream(new File(logDir, COMMIT_LOG_FILE), true));;
+    }
+  }
+
+  private void commitIfSnapshot(long seqId, TSentryStoreRecord record) {
+    if (record.getSnapshot() != null) {
+      new File(logDir, COMMIT_LOG_FILE + "_tmp_" + seqId).delete();
+    }
+  }
+
+  public void close() {
+    if (commitLog != null) {
+      try {
+        commitLog.flush();
+        commitLog.close();
+      } catch (IOException e) {
+        System.out.println("Cound not close file : " + e.getMessage());
+      }
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/c8c88786/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/HAContext.java
----------------------------------------------------------------------
diff --git 
a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/HAContext.java
 
b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/HAContext.java
index 523261e..b95ab52 100644
--- 
a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/HAContext.java
+++ 
b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/HAContext.java
@@ -51,6 +51,17 @@ public class HAContext {
   private static final Logger LOGGER = 
LoggerFactory.getLogger(HAContext.class);
 
   public final static String SENTRY_SERVICE_REGISTER_NAMESPACE = 
"sentry-service";
+
+  // Implement singleton
+  private static HAContext haContext;
+
+  public synchronized static HAContext get(Configuration conf) throws 
Exception {
+    if (haContext == null) {
+      haContext = new HAContext(conf);
+    }
+    return haContext;
+  }
+
   private final String zookeeperQuorum;
   private final int retriesMaxCount;
   private final int sleepMsBetweenRetries;
@@ -62,7 +73,7 @@ public class HAContext {
   private final CuratorFramework curatorFramework;
   private final RetryPolicy retryPolicy;
 
-  public HAContext(Configuration conf) throws Exception {
+  HAContext(Configuration conf) throws Exception {
     this.zookeeperQuorum = conf.get(ServerConfig.SENTRY_HA_ZOOKEEPER_QUORUM,
         ServerConfig.SENTRY_HA_ZOOKEEPER_QUORUM_DEFAULT);
     this.retriesMaxCount = 
conf.getInt(ServerConfig.SENTRY_HA_ZOOKEEPER_RETRIES_MAX_COUNT,

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/c8c88786/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/InMemSentryStore.java
----------------------------------------------------------------------
diff --git 
a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/InMemSentryStore.java
 
b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/InMemSentryStore.java
new file mode 100644
index 0000000..0f42c7b
--- /dev/null
+++ 
b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/InMemSentryStore.java
@@ -0,0 +1,1216 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.sentry.provider.db.service.persistent;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.sentry.SentryUserException;
+import org.apache.sentry.core.common.utils.PathUtils;
+import org.apache.sentry.core.model.db.AccessConstants;
+import org.apache.sentry.provider.db.SentryAccessDeniedException;
+import org.apache.sentry.provider.db.SentryAlreadyExistsException;
+import org.apache.sentry.provider.db.SentryGrantDeniedException;
+import org.apache.sentry.provider.db.SentryInvalidInputException;
+import org.apache.sentry.provider.db.SentryNoSuchObjectException;
+import org.apache.sentry.provider.db.service.thrift.SentryPolicyStoreProcessor;
+import org.apache.sentry.provider.db.service.thrift.TSentryActiveRoleSet;
+import org.apache.sentry.provider.db.service.thrift.TSentryAuthorizable;
+import org.apache.sentry.provider.db.service.thrift.TSentryGrantOption;
+import org.apache.sentry.provider.db.service.thrift.TSentryGroup;
+import org.apache.sentry.provider.db.service.thrift.TSentryPrivilege;
+import org.apache.sentry.provider.db.service.thrift.TSentryPrivilegeMap;
+import org.apache.sentry.provider.db.service.thrift.TSentryRole;
+import org.apache.sentry.provider.db.service.thrift.TStoreAuthorizable;
+import org.apache.sentry.provider.db.service.thrift.TStorePrivilege;
+import org.apache.sentry.provider.db.service.thrift.TStoreSnapshot;
+import org.apache.sentry.service.thrift.ServiceConstants.ServerConfig;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
+/**
+ * In memory implementation of the SentryStore. The privilege model is
+ * implemented as a Tree of {@link Authorizable} objects, this serves two
+ * purposes :
+ * 1) Since all objects have a parent <-> child relationship, using a tree
+ *    data-structure makes it easier to traverse and aggregate privilege
+ *    information for a request
+ * 2) Improve in-memory storage efficiency since names of the parents are
+ *    not duplicated for large number of leaf node.
+ * Each {@link Authorizable} object, in addition to maintaining a list of
+ * children, also maintains a map of all roles and the associated Privileges
+ * Granted to the role for the Authorizable object.
+ * 
+ * The Store also maintains a reverse-mapping of role To {@link Authorizable}
+ * to eliminate the need to traverse the tree for requests
+ * that are keyed to a role.
+ *
+ */
+public class InMemSentryStore implements SentryStore {
+
+  static enum GrantOption {
+    UNSET, TRUE, FALSE
+  }
+
+  /**
+   * The Privilege is maintained as a bitset which makes it easier to
+   * handle addition / removal and aggregation of privileges for a role
+   *
+   */
+  static enum Privilege {
+    ALL((short)63),
+    CREATE((short)32),
+    DROP((short)16),
+    INDEX((short)8),
+    LOCK((short)4),
+    SELECT((short)2),
+    INSERT((short)1),
+    NONE((short)0);
+
+    private short code;
+    private Privilege(short code) {
+      this.code = code;
+    }
+
+    static boolean includedIn(Privilege priv, short bitset) {
+      return (bitset & ((short) priv.code)) == priv.code;
+    }
+
+    static short addTo(Privilege priv, short bitset) {
+      return (short)(bitset | ((short) priv.code));
+    }
+
+    static short removeFrom(Privilege priv, short bitset) {
+      return (short)(bitset & ~((short) priv.code));
+    }
+
+    static Privilege fromTSentryPrivilege(TSentryPrivilege priv) {
+      // TODO: maybe better way of doing this ?
+      if (AccessConstants.ACTION_ALL.equalsIgnoreCase(
+          Strings.nullToEmpty(priv.getAction()))) {
+        return ALL;
+      } else if (AccessConstants.ALL.equalsIgnoreCase(
+          Strings.nullToEmpty(priv.getAction()))) {
+        return ALL;
+      } else if (AccessConstants.CREATE.equalsIgnoreCase(
+          Strings.nullToEmpty(priv.getAction()))) {
+        return CREATE;
+      } else if (AccessConstants.DROP.equalsIgnoreCase(
+          Strings.nullToEmpty(priv.getAction()))) {
+        return DROP;
+      } else if (AccessConstants.INDEX.equalsIgnoreCase(
+          Strings.nullToEmpty(priv.getAction()))) {
+        return INDEX;
+      } else if (AccessConstants.LOCK.equalsIgnoreCase(
+          Strings.nullToEmpty(priv.getAction()))) {
+        return LOCK;
+      } else if (AccessConstants.SELECT.equalsIgnoreCase(
+          Strings.nullToEmpty(priv.getAction()))) {
+        return SELECT;
+      } else if (AccessConstants.INSERT.equalsIgnoreCase(
+          Strings.nullToEmpty(priv.getAction()))) {
+        return INSERT;
+      } else {
+        return NONE;
+      }
+    }
+  };
+
+  static class AuthPrivilege {
+    private GrantOption grantOption;
+    private short privilege;
+    AuthPrivilege(short privilege) {
+      this.grantOption = GrantOption.UNSET;
+      this.privilege = privilege;
+    }
+    public GrantOption getGrantOption() {
+      return grantOption;
+    }
+    public void setGrantOption(GrantOption grantOption) {
+      this.grantOption = grantOption;
+    }
+    public short getPrivilege() {
+      return privilege;
+    }
+    public void setPrivilege(short privilege) {
+      this.privilege = privilege;
+    }
+    public boolean implies(Authorizable auth, TSentryPrivilege priv) {
+      if (checkHierarchy(auth, priv)) {
+        if (!Privilege.includedIn(Privilege.ALL, privilege)
+            && !Privilege.includedIn(Privilege.fromTSentryPrivilege(priv), 
privilege)) {
+          return false;
+        }
+        return true;
+      }
+      return false;
+    }
+  }
+
+  static enum AuthType {
+    SERVER, DB, URI, TABLE, COLUMN;
+  };
+
+  static Map<AuthType, Set<AuthType>> permissableChildren =
+      ImmutableMap.<AuthType, Set<AuthType>>builder()
+      .put(AuthType.SERVER, Sets.newHashSet(AuthType.DB, AuthType.URI))
+      .put(AuthType.URI, Collections.<AuthType>emptySet())
+      .put(AuthType.DB, Sets.newHashSet(AuthType.TABLE))
+      .put(AuthType.TABLE, Sets.newHashSet(AuthType.COLUMN))
+      .put(AuthType.COLUMN, Collections.<AuthType>emptySet())
+      .build();
+
+  static class Authorizable {
+    private String name;
+    private final AuthType type;
+    private Map<String, AuthPrivilege> privileges = new HashMap<String, 
AuthPrivilege>();
+    private volatile Map<String, Authorizable> children = new HashMap<String, 
Authorizable>();
+    private Authorizable parent;
+
+    Authorizable(String name, AuthType type, Authorizable parent) {
+      this.name = name;
+      this.type = type;
+      this.parent = parent;
+    }
+
+    Authorizable addChild(String name, AuthType authType) {
+      Authorizable child = children.get(name);
+      if (child == null) {
+        child = new Authorizable(name, authType, this);
+        children.put(name, child);
+      }
+      return child;
+    }
+
+    Authorizable getChild(String name) {
+      return children.get(name);
+    }
+
+    Authorizable getChild(String name, AuthType type) {
+      if (type == AuthType.URI) {
+        for (Authorizable child : children.values()) {
+          if (child.getAuthType() == AuthType.URI) {
+            if (PathUtils.impliesURI(child.getName(), name)) {
+              return child;
+            }
+          }
+        }
+      }
+      return children.get(name);
+    }
+
+    String getName() {
+      return name;
+    }
+
+    // Needed for rename
+    void setName(String name) {
+      this.name = name;
+    }
+
+    Authorizable getParent() {
+      return parent;
+    }
+
+    AuthType getAuthType() {
+      return type;
+    }
+
+    void addPrivilege(String role, Privilege priv) {
+      AuthPrivilege authPriv = privileges.get(role);
+      if (authPriv == null) {
+        authPriv = new AuthPrivilege(Privilege.NONE.code);
+        privileges.put(role, authPriv);
+      }
+      authPriv.setPrivilege(Privilege.addTo(priv, authPriv.privilege));
+    }
+
+    void setPrivilege(String role, short privBits) {
+      AuthPrivilege authPriv = privileges.get(role);
+      if (authPriv == null) {
+        authPriv = new AuthPrivilege(Privilege.NONE.code);
+        privileges.put(role, authPriv);
+      }
+      authPriv.setPrivilege(privBits);
+    }
+
+    boolean delPrivilege(String role, Privilege priv) {
+      AuthPrivilege authPriv = privileges.get(role);
+      if (authPriv != null) {
+        short newPriv = Privilege.removeFrom(priv, authPriv.privilege);
+        if (newPriv == Privilege.NONE.code) {
+          privileges.remove(role);
+          return true;
+        } else {
+          authPriv.setPrivilege(newPriv);
+        }
+      }
+      return false;
+    }
+
+    AuthPrivilege getPrivilege(String role) {
+      return privileges.get(role);
+    }
+
+    Map<String, AuthPrivilege> getAllPrivileges() {
+      return privileges;
+    }
+
+    Map<String, Authorizable> getChildren() {
+      return children;
+    }
+  }
+
+  
+  static class GroupMapper {
+    final Configuration conf;
+
+    @VisibleForTesting
+    GroupMapper(Configuration conf) {
+      this.conf = conf;
+    }
+
+    protected Set<String> getGroupsForUser(String user)
+        throws SentryUserException {
+      return SentryPolicyStoreProcessor.getGroupsFromUserName(conf, user);
+    }
+    
+    // get adminGroups from conf
+    protected Set<String> getAdminGroups() {
+      return Sets.newHashSet(conf.getStrings(
+          ServerConfig.ADMIN_GROUPS, new String[]{}));
+    }
+
+    // is Admin group
+    protected boolean isInAdminGroup(Set<String> groups)
+        throws SentryUserException {
+      Set<String> admins = getAdminGroups();
+      if (admins != null && !admins.isEmpty()) {
+        for (String g : groups) {
+          if (admins.contains(g)) {
+            return true;
+          }
+        }
+      }
+      return false;
+    }
+  }
+  
+//  private static String LOG_FILE = "inmem.log";
+//  private final OutputStream logStream;
+  private final UUID serverId = UUID.randomUUID();
+  private final AtomicLong seqId = new AtomicLong(0);
+  private final Configuration conf;
+  private final GroupMapper groupMapper;
+  private String schemaVersion;
+
+  private Map<String, Authorizable> rootAuthrizables =
+      new HashMap<String, Authorizable>();
+  private Map<String, Set<Authorizable>> roleToAuthorizable =
+      new HashMap<String, Set<Authorizable>>();
+  private Map<String, Set<String>> roleToGroups =
+      new HashMap<String, Set<String>>();
+  private Map<String, Set<String>> groupToRoles =
+      new HashMap<String, Set<String>>();
+
+  InMemSentryStore(Configuration conf) throws SentryAccessDeniedException{
+    this(conf, new GroupMapper(conf));
+  }
+
+  @VisibleForTesting
+  InMemSentryStore(Configuration conf, GroupMapper groupMapper)
+      throws SentryAccessDeniedException{
+    this.conf = conf;
+    this.groupMapper = groupMapper;
+  }
+
+  public Configuration getConfiguration() {
+    return conf;
+  }
+
+  @Override
+  public CommitContext createSentryRole(String roleName)
+      throws SentryAlreadyExistsException {
+    if (!doesRoleExists(roleName)) {
+      roleToGroups.put(roleName, new HashSet<String>());
+      roleToAuthorizable.put(roleName, new HashSet<Authorizable>());
+      return new CommitContext(serverId, seqId.getAndIncrement());
+    }
+    throw new SentryAlreadyExistsException(
+        "Role [" + roleName + "] already exists !!");
+  }
+
+  private boolean doesRoleExists(String roleName) {
+    return roleToGroups.containsKey(roleName)
+        || roleToAuthorizable.containsKey(roleName);
+  }
+
+  private static boolean checkHierarchy(Authorizable auth, TSentryPrivilege 
tPriv) {
+    if (auth == null) return true;
+    if ((auth.getAuthType() == AuthType.COLUMN)
+        
&&(!auth.getName().equals(Strings.nullToEmpty(tPriv.getColumnName())))) {
+      return false;
+    }
+    if ((auth.getAuthType() == AuthType.TABLE)
+        &&(!auth.getName().equals(Strings.nullToEmpty(tPriv.getTableName())))) 
{
+      return false;
+    }
+    if ((auth.getAuthType() == AuthType.DB)
+        &&(!auth.getName().equals(Strings.nullToEmpty(tPriv.getDbName())))) {
+      return false;
+    }
+    if ((auth.getAuthType() == AuthType.URI)
+        &&(!Strings.isNullOrEmpty(tPriv.getURI()))) {
+      if (!PathUtils.impliesURI(auth.getName(), tPriv.getURI())) {
+        return false;
+      }
+    }
+    if ((auth.getAuthType() == AuthType.SERVER)
+        
&&(!auth.getName().equals(Strings.nullToEmpty(tPriv.getServerName())))) {
+      return false;
+    }
+    return checkHierarchy(auth.getParent(), tPriv);
+  }
+
+  private LinkedHashMap<AuthType, String> toAuthorizableHierarchy(
+      TSentryAuthorizable tAuthHier) {
+    // TODO : fix this for generic model
+    TSentryPrivilege temp = new TSentryPrivilege("", tAuthHier.getServer(), 
"");
+    temp.setDbName(tAuthHier.getDb());
+    temp.setURI(tAuthHier.getUri());
+    temp.setTableName(tAuthHier.getTable());
+    temp.setColumnName(tAuthHier.getColumn());
+    return toAuthorizableHierarchy(temp);
+  }
+
+  private LinkedHashMap<AuthType, String> toAuthorizableHierarchy(
+      TSentryPrivilege tPriv) {
+    // TODO : fix this for generic model
+    LinkedHashMap<AuthType, String> map = new LinkedHashMap<AuthType, 
String>();
+    map.put(AuthType.SERVER, tPriv.getServerName().toLowerCase());
+    if (Strings.nullToEmpty(tPriv.getDbName()) != "") {
+      map.put(AuthType.DB, tPriv.getDbName().toLowerCase());
+      if (Strings.nullToEmpty(tPriv.getTableName()) != "") {
+        map.put(AuthType.TABLE, tPriv.getTableName().toLowerCase());
+        if (Strings.nullToEmpty(tPriv.getColumnName()) != "") {
+          map.put(AuthType.COLUMN, tPriv.getColumnName().toLowerCase());
+        }
+      }
+    } else {
+      if (Strings.nullToEmpty(tPriv.getURI()) != "") {
+        map.put(AuthType.URI, tPriv.getURI());
+      }
+    }
+    return map;
+  }
+
+  private void fillPrivMap(HashMap<String, String> pUpdate, Authorizable auth) 
{
+    for (Map.Entry<String, AuthPrivilege> e : 
auth.getAllPrivileges().entrySet()) {
+      String outPriv = "";
+      if (Privilege.includedIn(Privilege.SELECT, e.getValue().privilege)) {
+        outPriv = Privilege.SELECT.toString();
+      }
+      if (Privilege.includedIn(Privilege.INSERT, e.getValue().privilege)) {
+        outPriv = (outPriv.equals("") ? outPriv : ",");
+        outPriv = outPriv + Privilege.INSERT.toString();
+      }
+      pUpdate.put(e.getKey(), outPriv);
+    }
+  }
+
+  private void grantOptionCheck(String grantorPrincipal, TSentryPrivilege 
inPriv)
+      throws SentryUserException {
+    if (grantorPrincipal == null) {
+      throw new SentryInvalidInputException("grantorPrincipal should not be 
null");
+    }
+    Set<String> groups = groupMapper.getGroupsForUser(grantorPrincipal);
+    if (groups == null || groups.isEmpty()) {
+      throw new SentryGrantDeniedException(grantorPrincipal
+          + " has no grant!");
+    }
+    // if grantor is in adminGroup, don't need to do check
+    if (!groupMapper.isInAdminGroup(groups)) {
+      boolean hasGrant = false;
+      Set<String> roles = getRoleNamesForGroups(groups);
+      for (String role : roles) {
+        Set<Authorizable> authorizables = roleToAuthorizable.get(role);
+        for (Authorizable auth : authorizables) {
+          AuthPrivilege authPriv = auth.getPrivilege(role);
+          if ((authPriv.getGrantOption() == GrantOption.TRUE)
+              && authPriv.implies(auth, inPriv)) {
+            hasGrant = true;
+            break;
+          }
+        }
+      }
+      if (!hasGrant) {
+        throw new SentryGrantDeniedException(grantorPrincipal
+            + " has no grant!");
+      }
+    }
+  }
+
+  private Authorizable getLeaf(TSentryPrivilege inPriv, boolean createNodes)
+      throws SentryUserException {
+    LinkedHashMap<AuthType,String> authHierarchy =
+        toAuthorizableHierarchy(inPriv);
+    return getLeafCore(createNodes, false, authHierarchy);
+  }
+
+  private Authorizable getLeafCore(boolean createNodes, boolean isParentOk,
+      LinkedHashMap<AuthType, String> authHierarchy) throws 
SentryUserException {
+    Authorizable parent = null;
+    Authorizable current = null;
+    for (Map.Entry<AuthType, String> e : authHierarchy.entrySet()) {
+      if (e.getKey() == AuthType.SERVER) {
+        current = rootAuthrizables.get(e.getValue());
+        if (current == null) {
+          if (createNodes) {
+            current = new Authorizable(e.getValue(), e.getKey(), null);
+            rootAuthrizables.put(e.getValue(), current);
+          } else {
+            if (isParentOk) {
+              return parent;
+            }
+            throw new SentryUserException(
+                "Invalid authHierarchy [" + authHierarchy + "]");
+          } 
+        }
+      } else {
+        // parent cannot be null here
+        if (parent == null) {
+          throw new SentryUserException(
+              "Invalid authHierarchy [" + authHierarchy + "]");
+        } else {
+          current = parent.getChild(e.getValue(), e.getKey());
+          if (current == null) {
+            if (createNodes) {
+              current = parent.addChild(e.getValue(), e.getKey());
+            } else {
+              if (isParentOk) {
+                return parent;
+              }
+              throw new SentryUserException(
+                  "Invalid authHierarchy [" + authHierarchy + "]");
+            }
+          }
+        }
+      }
+      parent = current;
+    }
+    return current;
+  }
+
+  public Set<String> getGroupsForRole(String roleName) {
+    return roleToGroups.get(roleName);
+  }
+
+  private Map<String, Set<TSentryPrivilege>> collectPrivileges(Set<String> 
roleSet,
+      TSentryAuthorizable inAuthHier, boolean isAdmin)
+      throws SentryUserException {
+    // This collects all privileges applicable for the role for
+    // 1) All child objects from the leaf of authHierarchy
+    // 2) All nodes in parent chain of the leaf of authHierarchy
+    Map<String, Set<TSentryPrivilege>> resultMap =
+        new HashMap<String, Set<TSentryPrivilege>>();
+    if (inAuthHier != null) {
+      LinkedHashMap<AuthType,String> authHierarchy =
+          toAuthorizableHierarchy(inAuthHier);
+      Authorizable current = getLeafCore(false, true, authHierarchy);
+      if (current != null) {
+        // If returned node is a parent.. we should not
+        // recurse down..
+        collectPrivileges(current, roleSet, isAdmin, resultMap,
+            !isAParent(authHierarchy, current));
+        Authorizable parent = current.parent;
+        while (parent != null) {
+          collectPrivileges(parent, roleSet, isAdmin, resultMap, false);
+          parent = parent.getParent();
+        }
+        
+      }
+    } else {
+      for (Authorizable root : rootAuthrizables.values()) {
+        collectPrivileges(root, roleSet, isAdmin, resultMap, true);
+      }
+    }
+    return resultMap;
+  }
+
+  private boolean isAParent(LinkedHashMap<AuthType, String> authHierarchy,
+      Authorizable current) {
+    Iterator<Entry<AuthType, String>> iterator = 
authHierarchy.entrySet().iterator();
+    Entry<AuthType, String> ent = null;
+    // get last element
+    while (iterator.hasNext()) {
+      ent = iterator.next();
+    }
+    return (ent.getKey() != current.getAuthType()); 
+  }
+
+  private void collectPrivileges(Authorizable current, Set<String> roleSet,
+      boolean isAdmin, Map<String, Set<TSentryPrivilege>> resultMap, boolean 
recurse)
+      throws SentryUserException {
+    addToPrivSet(current, roleSet, isAdmin, resultMap);
+    if (recurse) {
+      for (Authorizable child : current.getChildren().values()) {
+        collectPrivileges(child, roleSet, isAdmin, resultMap, recurse);
+      }
+    }
+  }
+
+  private void addToPrivSet(Authorizable current, Set<String> roleSet,
+      boolean isAdmin, Map<String, Set<TSentryPrivilege>> resultMap) {
+    for (Map.Entry<String, AuthPrivilege> e : 
current.getAllPrivileges().entrySet()) {
+      String roleName = e.getKey();
+      if (isAdmin || (roleSet.contains(roleName))) {
+        Set<TSentryPrivilege> pSet = resultMap.get(roleName);
+        if (pSet == null) {
+          pSet = new HashSet<TSentryPrivilege>();
+          resultMap.put(roleName, pSet);
+        }
+        pSet.addAll(convertToTSentryPrivileges(current, e.getValue()));
+      }
+    }
+  }
+
+  private Set<TSentryPrivilege> convertToTSentryPrivileges(Authorizable auth, 
AuthPrivilege authPriv) {
+    Set<TSentryPrivilege> retPrivs = new HashSet<TSentryPrivilege>();
+    for (Privilege privToTest : Privilege.values()) {
+      // These Apply only to DB
+      if (Sets.newHashSet(
+          Privilege.CREATE, Privilege.DROP,
+          Privilege.INDEX, Privilege.LOCK).contains(privToTest)
+          && (auth.getAuthType() != AuthType.DB)) {
+        continue;
+      }
+      if (privToTest == Privilege.NONE) {
+        continue;
+      }
+      if (Privilege.includedIn(privToTest, authPriv.privilege)) {
+        TSentryPrivilege tPriv = new TSentryPrivilege(); 
+        tPriv.setAction(
+            (privToTest == Privilege.ALL)
+            && (auth.getAuthType() != AuthType.URI) ? 
+                "*" : privToTest.toString().toLowerCase());
+        tPriv.setPrivilegeScope(auth.getAuthType().toString());
+        if (auth.getAuthType() == AuthType.SERVER) {
+          tPriv.setServerName(auth.getName());
+        } else if (auth.getAuthType() == AuthType.DB) {
+          tPriv.setServerName(auth.getParent().getName());
+          tPriv.setDbName(auth.getName());
+        } else if (auth.getAuthType() == AuthType.URI) {
+          tPriv.setServerName(auth.getParent().getName());
+          tPriv.setURI(auth.getName());
+        } else if (auth.getAuthType() == AuthType.TABLE) {
+          tPriv.setServerName(auth.getParent().getParent().getName());
+          tPriv.setDbName(auth.getParent().getName());
+          tPriv.setTableName(auth.getName());
+        } else if (auth.getAuthType() == AuthType.COLUMN) {
+          
tPriv.setServerName(auth.getParent().getParent().getParent().getName());
+          tPriv.setDbName(auth.getParent().getParent().getName());
+          tPriv.setTableName(auth.getParent().getName());
+          tPriv.setColumnName(auth.getName());
+        }
+        tPriv.setGrantOption(
+            TSentryGrantOption.valueOf(authPriv.getGrantOption().toString()));
+        // Not storing this for the timebeing
+        tPriv.setCreateTime(0);
+        if (privToTest == Privilege.ALL) {
+          // Remove all other privilege objects if ALL
+          retPrivs.clear();
+          retPrivs.add(tPriv);
+          break;
+        }
+        retPrivs.add(tPriv);
+      }
+    }
+    return retPrivs;
+  }
+
+  private void recursiveRevoke(String roleName, Privilege priv,
+      Authorizable authorizable, GrantOption inGrantOption) {
+    AuthPrivilege authPriv = authorizable.getPrivilege(roleName);
+    if (authPriv != null) {
+      boolean doRevoke = true;
+      if (authPriv.getGrantOption() != GrantOption.UNSET) {
+        doRevoke = authPriv.getGrantOption() == inGrantOption;
+        if (inGrantOption == GrantOption.UNSET) {
+          doRevoke = true;
+        }
+      }
+      if (doRevoke) {
+        boolean delPriv = authorizable.delPrivilege(roleName, priv);
+        // Remove from roleToAuth mapping if no privileges
+        if (delPriv) {
+          Set<Authorizable> authSet = roleToAuthorizable.get(roleName);
+          authSet.remove(authorizable);
+        }
+      }
+    }
+    for(Authorizable child : authorizable.getChildren().values()) {
+      recursiveRevoke(roleName, priv, child, inGrantOption);
+    }
+  }
+
+  private Set<String> getRolesToQuery(Set<String> groups,
+      TSentryActiveRoleSet roleSet) {
+    if (roleSet == null) {
+      roleSet = new TSentryActiveRoleSet(true, null);
+    }
+    Set<String> activeRoleNames = StoreUtils.toTrimedLower(roleSet.getRoles());
+    Set<String> roleNamesForGroups = 
StoreUtils.toTrimedLower(getRoleNamesForGroups(groups));
+    Set<String> rolesToQuery = roleSet.isAll() ? roleNamesForGroups : 
Sets.intersection(activeRoleNames, roleNamesForGroups);
+    return rolesToQuery;
+  }
+
+  @Override
+  public CommitContext alterSentryRoleGrantPrivilege(String grantorPrincipal,
+      String roleName, TSentryPrivilege inPriv) throws SentryUserException {
+    if (!doesRoleExists(roleName)) {
+      throw new SentryNoSuchObjectException("Role: " + roleName);
+    }
+    grantOptionCheck(grantorPrincipal, inPriv);
+    Authorizable current = getLeaf(inPriv, true);
+    current.addPrivilege(roleName, Privilege.fromTSentryPrivilege(inPriv));
+    if (inPriv.getGrantOption() != null) {
+      current.getPrivilege(roleName).setGrantOption(
+          GrantOption.valueOf(inPriv.getGrantOption().toString()));
+    }
+    Set<Authorizable> authSet = roleToAuthorizable.get(roleName);
+    authSet.add(current);
+    return new CommitContext(serverId, seqId.getAndIncrement());
+  }
+
+  
+  @Override
+  public CommitContext alterSentryRoleGrantPrivileges(String grantorPrincipal,
+      String roleName, Set<TSentryPrivilege> privileges)
+      throws SentryUserException {
+    CommitContext ctx = null;
+    for (TSentryPrivilege inPriv : privileges) {
+      ctx = alterSentryRoleGrantPrivilege(grantorPrincipal, roleName, inPriv);
+    }
+    return ctx;
+  }
+
+  @Override
+  public CommitContext alterSentryRoleRevokePrivilege(String grantorPrincipal,
+      String roleName, TSentryPrivilege inPriv) throws SentryUserException {
+    if (!doesRoleExists(roleName)) {
+      throw new SentryNoSuchObjectException("Role: " + roleName);
+    }
+    grantOptionCheck(grantorPrincipal, inPriv);
+    Authorizable current = getLeaf(inPriv, false);
+    // NOTE : look how much simpler this is !!
+    recursiveRevoke(roleName, Privilege.fromTSentryPrivilege(inPriv), current,
+        GrantOption.valueOf(inPriv.getGrantOption().toString()));
+    return new CommitContext(serverId, seqId.getAndIncrement());
+  }
+
+  @Override
+  public CommitContext alterSentryRoleRevokePrivileges(String grantorPrincipal,
+      String roleName, Set<TSentryPrivilege> privileges)
+      throws SentryUserException {
+    CommitContext ctx = null;
+    for (TSentryPrivilege inPriv : privileges) {
+      ctx = alterSentryRoleRevokePrivilege(grantorPrincipal, roleName, inPriv);
+    }
+    return ctx;
+  }
+
+  @Override
+  public CommitContext dropSentryRole(String roleName)
+      throws SentryNoSuchObjectException {
+    if (doesRoleExists(roleName)) {
+      Set<Authorizable> authSet = roleToAuthorizable.get(roleName);
+      for (Authorizable authorizable : authSet) {
+        authorizable.delPrivilege(roleName, Privilege.ALL);
+      }
+      roleToAuthorizable.remove(roleName);
+      Set<String> groups = roleToGroups.get(roleName);
+      for (String group : groups) {
+        Set<String> roleSet = groupToRoles.get(group);
+        if (roleSet != null) {
+          roleSet.remove(roleName);
+        }
+      }
+      roleToGroups.remove(roleName);
+      return new CommitContext(serverId, seqId.getAndIncrement());
+    } else {
+      throw new SentryNoSuchObjectException("Role [" + roleName + "] does not 
exist !!");
+    }
+  }
+
+  @Override
+  public CommitContext alterSentryRoleAddGroups(String grantorPrincipal,
+      String roleName, Set<TSentryGroup> inGroups)
+      throws SentryNoSuchObjectException {
+    if (!doesRoleExists(roleName)) {
+      throw new SentryNoSuchObjectException(
+          "Role [" + roleName + "] does not exist !!");
+    }
+    Set<String> groups = roleToGroups.get(roleName);
+    for (TSentryGroup inGroup : inGroups) {
+      groups.add(inGroup.getGroupName());
+      Set<String> rSet = groupToRoles.get(inGroup.getGroupName());
+      if (rSet == null) {
+        rSet = new HashSet<String>();
+        groupToRoles.put(inGroup.getGroupName(), rSet);
+      }
+      rSet.add(roleName);
+    }
+    return new CommitContext(serverId, seqId.getAndIncrement());
+  }
+
+  @Override
+  public CommitContext alterSentryRoleDeleteGroups(String roleName,
+      Set<TSentryGroup> inGroups) throws SentryNoSuchObjectException {
+    if (!doesRoleExists(roleName)) {
+      throw new SentryNoSuchObjectException(
+          "Role [" + roleName + "] does not exist !!");
+    }
+    Set<String> groups = roleToGroups.get(roleName);
+    for (TSentryGroup inGroup : inGroups) {
+      groups.remove(inGroup.getGroupName());
+      Set<String> rSet = groupToRoles.get(inGroup.getGroupName());
+      if (rSet != null) {
+        rSet.remove(roleName);
+      }
+    }
+    return new CommitContext(serverId, seqId.getAndIncrement());
+  }
+
+  @Override
+  public TSentryPrivilegeMap listSentryPrivilegesByAuthorizable(
+      Set<String> groups, TSentryActiveRoleSet activeRoles,
+      TSentryAuthorizable tAuthHierarchy, boolean isAdmin)
+      throws SentryInvalidInputException {
+    Map<String, Set<TSentryPrivilege>> resultPrivilegeMap = Maps.newTreeMap();
+    Set<String> roles = Sets.newHashSet();
+    if (groups != null && !groups.isEmpty()) {
+      roles.addAll(getRolesToQuery(groups, activeRoles));
+    }
+    if (activeRoles != null && !activeRoles.isAll()) {
+      // need to check/convert to lowercase here since this is from user input
+      for (String aRole : activeRoles.getRoles()) {
+        roles.add(aRole.toLowerCase());
+      }
+    }
+    try {
+      resultPrivilegeMap = collectPrivileges(roles, tAuthHierarchy, isAdmin);
+    } catch (SentryUserException e) {
+      // Do this quietly
+//      throw new SentryInvalidInputException(e.getMessage());
+    }
+ 
+    return new TSentryPrivilegeMap(resultPrivilegeMap);
+  }
+
+  @Override
+  public Set<TSentryPrivilege> getAllTSentryPrivilegesByRoleName(
+      String roleName) throws SentryNoSuchObjectException {
+    Set<TSentryPrivilege> resultSet = new HashSet<TSentryPrivilege>();
+    Set<Authorizable> auths = roleToAuthorizable.get(roleName);
+    if (auths != null) {
+      for (Authorizable auth : auths) {
+        resultSet.addAll(
+            convertToTSentryPrivileges(auth, auth.getPrivilege(roleName)));
+      }
+    }
+    return resultSet;
+  }
+
+  @Override
+  public Set<TSentryPrivilege> getTSentryPrivileges(Set<String> roleNames,
+      TSentryAuthorizable authHierarchy) throws SentryInvalidInputException {
+    Set<TSentryPrivilege> resultSet = new HashSet<TSentryPrivilege>();
+    try {
+      Map<String, Set<TSentryPrivilege>> allPrivs =
+          collectPrivileges(roleNames, authHierarchy, false);
+      for (Set<TSentryPrivilege> pivSet : allPrivs.values()) {
+        resultSet.addAll(pivSet);
+      }
+    } catch (SentryUserException e) {
+      throw new SentryInvalidInputException(e.getMessage());
+    }
+    return resultSet;
+  }
+
+  @Override
+  public Set<TSentryRole> getTSentryRolesByGroupName(Set<String> groupNames,
+      boolean checkAllGroups) throws SentryNoSuchObjectException {
+    Set<TSentryRole> resultSet = new HashSet<TSentryRole>();
+    Set<String> roleSet = new HashSet<String>();
+    if ((groupNames == null)||(groupNames.size() == 0)) {
+      roleSet.addAll(roleToGroups.keySet());
+    } else {
+      for (String group : groupNames) {
+        if (group == null) {
+          roleSet.addAll(roleToGroups.keySet());
+          break;
+        }
+        Set<String> rSet = groupToRoles.get(group);
+        if (rSet != null) {
+          for (String role : rSet) {
+            roleSet.add(role);
+          }
+        } else {
+          throw new SentryNoSuchObjectException("Group [" + group + "] does 
not exist !!");
+        }
+      }
+    }
+    for (String role : roleSet) {
+      TSentryRole tRole = new TSentryRole();
+      tRole.setRoleName(role);
+      tRole.setGrantorPrincipal("--");
+      Set<TSentryGroup> tGroups = new HashSet<TSentryGroup>();
+      for (String groupName : roleToGroups.get(role)) {
+        TSentryGroup tSentryGroup = new TSentryGroup();
+        tSentryGroup.setGroupName(groupName);
+        tGroups.add(tSentryGroup);
+      }
+      tRole.setGroups(tGroups);
+      resultSet.add(tRole);
+    }
+    return resultSet;
+  }
+
+  @Override
+  public Set<String> getRoleNamesForGroups(Set<String> groups) {
+    Set<String> roles = new HashSet<String>();
+    for (String group : groups) {
+      Set<String> rs = groupToRoles.get(group);
+      if (rs != null) {
+        roles.addAll(rs);
+      }
+    }
+    return roles;
+  }
+
+  @Override
+  public Set<String> listAllSentryPrivilegesForProvider(Set<String> groups,
+      TSentryActiveRoleSet roleSet) throws SentryInvalidInputException {
+    return listSentryPrivilegesForProvider(groups, roleSet, null);
+  }
+
+  @Override
+  public Set<String> listSentryPrivilegesForProvider(Set<String> groups,
+      TSentryActiveRoleSet roleSet, TSentryAuthorizable authHierarchy)
+      throws SentryInvalidInputException {
+    Set<String> resultSet = new HashSet<String>();
+    TSentryPrivilegeMap privMap =
+        listSentryPrivilegesByAuthorizable(groups, roleSet, authHierarchy, 
false);
+    for (Set<TSentryPrivilege> privSet : privMap.getPrivilegeMap().values()) {
+      for (TSentryPrivilege tPriv : privSet) {
+        String authorizable =
+            StoreUtils.toAuthorizable(tPriv.getServerName(), tPriv.getDbName(),
+            tPriv.getURI(), tPriv.getTableName(),
+            tPriv.getColumnName(), tPriv.getAction());
+        resultSet.add(authorizable);
+      }
+    }
+    return resultSet;
+  }
+
+  @Override
+  public boolean hasAnyServerPrivileges(Set<String> groups,
+      TSentryActiveRoleSet roleSet, String server) {
+    Set<String> rolesToQuery = getRolesToQuery(groups, roleSet);
+    Authorizable serverAuth = rootAuthrizables.get(server);
+    if (serverAuth != null) {
+      // Do breadth first search and return true immediately
+      LinkedList<Authorizable> lst = new LinkedList<Authorizable>();
+      lst.add(serverAuth);
+      while (!lst.isEmpty()) {
+        Authorizable auth = lst.removeFirst();
+        for (String roleName : rolesToQuery) {
+          if (auth.getPrivilege(roleName) != null) {
+            return true;
+          }
+        }
+      }
+    }
+    return false;
+  }
+
+  @Override
+  public String getSentryVersion() throws SentryNoSuchObjectException,
+      SentryAccessDeniedException {
+    return this.schemaVersion;
+  }
+
+  @Override
+  public void setSentryVersion(String newVersion, String verComment)
+      throws SentryNoSuchObjectException, SentryAccessDeniedException {
+    this.schemaVersion = newVersion;
+  }
+
+  @Override
+  public void dropPrivilege(TSentryAuthorizable tAuthorizable)
+      throws SentryNoSuchObjectException, SentryInvalidInputException {
+    LinkedHashMap<AuthType,String> authHierarchy =
+        toAuthorizableHierarchy(tAuthorizable);
+    try {
+      Authorizable node = null;
+      try {
+        node = getLeafCore(false, false, authHierarchy);
+      } catch (Exception e) {
+        node = null;
+      }
+      if (node != null) {
+        if ((node.getChildren().size() == 0)
+            &&(node.getAllPrivileges().size() == 0)
+            &&(node.getParent() != null)) {
+          node.getParent().getChildren().remove(node.getName());
+        }
+      }
+    } catch (Exception e) {
+      // Ignore for the timebeing
+    }
+  }
+
+  @Override
+  public void renamePrivilege(TSentryAuthorizable tAuthorizable,
+      TSentryAuthorizable newTAuthorizable) throws SentryNoSuchObjectException,
+      SentryInvalidInputException {
+    LinkedHashMap<AuthType, String> oldHier = 
toAuthorizableHierarchy(tAuthorizable);
+    LinkedHashMap<AuthType, String> newHier = 
toAuthorizableHierarchy(newTAuthorizable);
+    Iterator<String> iter = newHier.values().iterator();
+    Authorizable parent = null;
+    Authorizable current = null;
+    for (Map.Entry<AuthType, String> e : oldHier.entrySet()) {
+      String newAuthName = iter.next();
+      if (e.getKey() == AuthType.SERVER) {
+        current = rootAuthrizables.get(e.getValue());
+        if (current == null) {
+          throw new SentryNoSuchObjectException(
+              "Invalid authHierarchy [" + oldHier + "]");
+        }
+      } else {
+        // parent cannot be null here
+        if (parent == null) {
+          throw new SentryNoSuchObjectException(
+              "Invalid authHierarchy [" + oldHier + "]");
+        } else {
+          current = parent.getChild(e.getValue());
+          if (current == null) {
+            throw new SentryNoSuchObjectException(
+                "Invalid authHierarchy [" + oldHier + "]");
+          }
+        }
+      }
+      if (!newAuthName.equals(e.getValue())) {
+        if (parent != null) {
+          parent.getChildren().remove(e.getValue());
+          current.setName(newAuthName);
+        }
+      }
+      parent = current;
+    }
+  }
+
+  @Override
+  public Map<String, HashMap<String, String>> retrieveFullPrivilegeImage() {
+    Map<String, HashMap<String, String>> retVal =
+        new HashMap<String, HashMap<String,String>>();
+    for (Authorizable rootA : rootAuthrizables.values()) {
+      // We need jut two levels here (DB and Table)..
+      for (Authorizable db : rootA.getChildren().values()) {
+        HashMap<String, String> pUpdate = new HashMap<String, String>();
+        retVal.put(db.name, pUpdate);
+        fillPrivMap(pUpdate, db);
+        for (Authorizable table : db.getChildren().values()) {
+          pUpdate = new HashMap<String, String>();
+          retVal.put(db.name + "." + table.name, pUpdate);
+          fillPrivMap(pUpdate, table);
+        }
+      }
+    }
+    return retVal;
+  }
+
+  @Override
+  public Map<String, LinkedList<String>> retrieveFullRoleImage() {
+    Map<String, LinkedList<String>> retVal =
+        new HashMap<String, LinkedList<String>>();
+    for (Map.Entry<String, Set<String>> e : roleToGroups.entrySet()) {
+      retVal.put(e.getKey(), new LinkedList<String>(e.getValue()));
+    }
+    return retVal;
+  }
+
+  @Override
+  public long getRoleCount() {
+    return (long)roleToAuthorizable.size();
+  }
+
+  @Override
+  public long getPrivilegeCount() {
+    long count = 0;
+    for (Set<Authorizable> auths : roleToAuthorizable.values()) {
+      count += auths.size();
+    }
+    return count;
+  }
+
+  @Override
+  public long getGroupCount() {
+    return (long)groupToRoles.size();
+  }
+
+  @Override
+  public void stop() {
+    // TODO Auto-generated method stub
+    
+  }
+
+  @Override
+  public TStoreSnapshot toSnapshot() {
+    AtomicInteger counter = new AtomicInteger(0);
+    TStoreSnapshot snapshot = 
+        new TStoreSnapshot(
+            new HashMap<String, TStoreAuthorizable>(),
+            new HashMap<String, Set<String>>(),
+            new HashMap<Integer, TStoreAuthorizable>());
+    Map<String, TStoreAuthorizable> tRootAuths = 
snapshot.getRootAuthorizable();
+    for (Map.Entry<String, Authorizable> e : rootAuthrizables.entrySet()) {
+      TStoreAuthorizable tAuthorizabe =
+          new TStoreAuthorizable(e.getKey(), AuthType.SERVER.toString());
+      tAuthorizabe.setChildren(new HashSet<Integer>());
+      tAuthorizabe.setPrivileges(new HashMap<String, TStorePrivilege>());
+      for (Map.Entry<String, AuthPrivilege> priv : 
e.getValue().getAllPrivileges().entrySet()) {
+        tAuthorizabe.getPrivileges().put(priv.getKey(),
+            new TStorePrivilege(
+                
TSentryGrantOption.valueOf(priv.getValue().grantOption.toString()),
+                priv.getValue().privilege));
+      }
+      snapshot.getObjIds().put(counter.getAndIncrement(), tAuthorizabe);
+      cloneTStoreAuthorizable(
+              e.getValue(), tAuthorizabe, counter, snapshot.getObjIds());
+      tRootAuths.put(e.getKey(), tAuthorizabe);
+    }
+    for (Map.Entry<String, Set<String>> e : roleToGroups.entrySet()) {
+      snapshot.getRoleToGroups().put(e.getKey(), new 
HashSet<String>(e.getValue()));
+    }
+    return snapshot;
+  }
+
+  private void cloneTStoreAuthorizable(Authorizable parent,
+      TStoreAuthorizable tParent, AtomicInteger counter,
+      Map<Integer, TStoreAuthorizable> objIds) {
+    for (Authorizable child : parent.getChildren().values()) {
+      TStoreAuthorizable tChild =
+          new TStoreAuthorizable(child.getName(),
+              child.getAuthType().toString());
+      tChild.setChildren(new HashSet<Integer>());
+      tChild.setPrivileges(new HashMap<String, TStorePrivilege>());
+      for (Map.Entry<String, AuthPrivilege> priv : 
child.getAllPrivileges().entrySet()) {
+        tChild.getPrivileges().put(priv.getKey(),
+            new TStorePrivilege(
+                
TSentryGrantOption.valueOf(priv.getValue().grantOption.toString()),
+                priv.getValue().privilege));
+      }
+      int objId = counter.getAndIncrement();
+      objIds.put(objId, tChild);
+      tParent.addToChildren(objId);
+      cloneTStoreAuthorizable(child, tChild, counter, objIds);
+    }
+  }
+
+  @Override
+  public void fromSnapshot(TStoreSnapshot snapshot) {
+    initializeRolesAndGroups(snapshot);
+    // Should be called only after initializeRolesAndGroups()
+    initializeAuthorizables(snapshot);
+  }
+
+  private void initializeAuthorizables(TStoreSnapshot snapshot) {
+    roleToAuthorizable.clear();
+    for (String role : roleToGroups.keySet()) {
+      roleToAuthorizable.put(role, new HashSet<Authorizable>());
+    }
+    rootAuthrizables.clear();
+    for(Map.Entry<String, TStoreAuthorizable> e : 
snapshot.getRootAuthorizable().entrySet()) {
+      Authorizable auth =
+          new Authorizable(e.getValue().getName(),
+              AuthType.valueOf(e.getValue().getType()), null);
+      setPrivileges(e.getValue(), auth);
+      createChildren(e.getValue(), auth, snapshot.getObjIds());
+    }
+  }
+
+  private void setPrivileges(TStoreAuthorizable tAuth, Authorizable auth) {
+    for (Map.Entry<String, TStorePrivilege> privEntry : 
tAuth.getPrivileges().entrySet()) {
+      auth.setPrivilege(privEntry.getKey(), 
privEntry.getValue().getPrivilege());
+      if (privEntry.getValue().getGrantOption() != null) {
+        auth.getPrivilege(privEntry.getKey()).setGrantOption(
+            
GrantOption.valueOf(privEntry.getValue().getGrantOption().toString()));
+      }
+      Set<Authorizable> authSet = roleToAuthorizable.get(privEntry.getKey());
+      if (authSet == null) {
+        authSet = new HashSet<Authorizable>();
+        roleToAuthorizable.put(privEntry.getKey(), authSet);
+      }
+      authSet.add(auth);
+    }
+  }
+
+  private void createChildren(TStoreAuthorizable tParent, Authorizable parent,
+      Map<Integer, TStoreAuthorizable> objIds) {
+    for (Integer id : tParent.getChildren()) {
+      TStoreAuthorizable tChild = objIds.get(id);
+      Authorizable child =
+          parent.addChild(tChild.getName(), 
AuthType.valueOf(tChild.getType()));
+      setPrivileges(tChild, child);
+      createChildren(tChild, child, objIds);
+    }
+  }
+
+  private void initializeRolesAndGroups(TStoreSnapshot snapshot) {
+    roleToGroups.clear();
+    groupToRoles.clear();
+    for (Map.Entry<String, Set<String>> e : 
snapshot.getRoleToGroups().entrySet()) {
+      for (String groupName : e.getValue()) {
+        Set<String> roleSet = groupToRoles.get(groupName);
+        if (roleSet == null) {
+          roleSet = new HashSet<String>();
+          groupToRoles.put(groupName, roleSet);
+        }
+        roleSet.add(e.getKey());
+      }
+      roleToGroups.put(e.getKey(), new HashSet<String>(e.getValue()));
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/c8c88786/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/LockingSentryStore.java
----------------------------------------------------------------------
diff --git 
a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/LockingSentryStore.java
 
b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/LockingSentryStore.java
new file mode 100644
index 0000000..d343257
--- /dev/null
+++ 
b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/LockingSentryStore.java
@@ -0,0 +1,446 @@
+package org.apache.sentry.provider.db.service.persistent;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.sentry.SentryUserException;
+import org.apache.sentry.provider.db.SentryAccessDeniedException;
+import org.apache.sentry.provider.db.SentryAlreadyExistsException;
+import org.apache.sentry.provider.db.SentryInvalidInputException;
+import org.apache.sentry.provider.db.SentryNoSuchObjectException;
+import org.apache.sentry.provider.db.service.thrift.TSentryActiveRoleSet;
+import org.apache.sentry.provider.db.service.thrift.TSentryAuthorizable;
+import org.apache.sentry.provider.db.service.thrift.TSentryGroup;
+import org.apache.sentry.provider.db.service.thrift.TSentryPrivilege;
+import org.apache.sentry.provider.db.service.thrift.TSentryPrivilegeMap;
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.apache.sentry.provider.db.service.thrift.TSentryRole;
+import org.apache.sentry.provider.db.service.thrift.TStoreSnapshot;
+
+/**
+ * A Decorator SentryStore that delegates all calls to a provided SentryStore
+ * within a LockContext. The LockContext encapsulates the Locking policy. This
+ * is determined by a subclass. The Subclass is responsible for creating the
+ * LockContext before a method is called and after the method, unlock() is
+ * called on the Context.
+ * 
+ * @param <T> A {@link LockContext} which exposes a single unlock() method
+ * a subclass has to implement.
+ */
+public abstract class LockingSentryStore<T extends 
LockingSentryStore.LockContext>
+    implements SentryStore {
+
+  public static interface LockContext {
+    public void unlock();
+  }
+
+  private final SentryStore sentryStore;
+
+  public LockingSentryStore(SentryStore sentryStore) {
+    this.sentryStore = sentryStore;
+  }
+
+  protected abstract T writeLock();
+  protected abstract T readLock();
+
+  
+  @Override
+  public Configuration getConfiguration() {
+    return sentryStore.getConfiguration();
+  }
+
+  @Override
+  public CommitContext createSentryRole(String roleName)
+      throws SentryAlreadyExistsException {
+    T context = writeLock();
+    try {
+      return sentryStore.createSentryRole(roleName);
+    } finally {
+      if (context != null) {
+        context.unlock();
+      }
+    }
+  }
+
+  @Override
+  public CommitContext alterSentryRoleGrantPrivilege(String grantorPrincipal,
+      String roleName, TSentryPrivilege privilege) throws SentryUserException {
+    T context = writeLock();
+    try {
+      return sentryStore.alterSentryRoleGrantPrivilege(
+          grantorPrincipal,roleName, privilege);
+    } finally {
+      if (context != null) {
+        context.unlock();
+      }
+    }
+  }
+
+  @Override
+  public CommitContext alterSentryRoleGrantPrivileges(String grantorPrincipal,
+      String roleName, Set<TSentryPrivilege> privileges)
+      throws SentryUserException {
+    T context = writeLock();
+    try {
+      return sentryStore.alterSentryRoleGrantPrivileges(
+          grantorPrincipal, roleName, privileges);
+    } finally {
+      if (context != null) {
+        context.unlock();
+      }
+    }
+  }
+
+  @Override
+  public CommitContext alterSentryRoleRevokePrivilege(String grantorPrincipal,
+      String roleName, TSentryPrivilege tPrivilege) throws SentryUserException 
{
+    T context = writeLock();
+    try {
+      return sentryStore.alterSentryRoleRevokePrivilege(
+          grantorPrincipal, roleName, tPrivilege);
+    } finally {
+      if (context != null) {
+        context.unlock();
+      }
+    }
+  }
+
+  @Override
+  public CommitContext alterSentryRoleRevokePrivileges(String grantorPrincipal,
+      String roleName, Set<TSentryPrivilege> tPrivileges)
+      throws SentryUserException {
+    T context = writeLock();
+    try {
+      return sentryStore.alterSentryRoleRevokePrivileges(
+          grantorPrincipal, roleName, tPrivileges);
+    } finally {
+      if (context != null) {
+        context.unlock();
+      }
+    }
+  }
+
+  @Override
+  public CommitContext dropSentryRole(String roleName)
+      throws SentryNoSuchObjectException {
+    T context = writeLock();
+    try {
+      return sentryStore.dropSentryRole(roleName);
+    } finally {
+      if (context != null) {
+        context.unlock();
+      }
+    }
+  }
+
+  @Override
+  public CommitContext alterSentryRoleAddGroups(String grantorPrincipal,
+      String roleName, Set<TSentryGroup> groupNames)
+      throws SentryNoSuchObjectException {
+    T context = writeLock();
+    try {
+      return sentryStore.alterSentryRoleAddGroups(
+          grantorPrincipal, roleName, groupNames);
+    } finally {
+      if (context != null) {
+        context.unlock();
+      }
+    }
+  }
+
+  @Override
+  public CommitContext alterSentryRoleDeleteGroups(String roleName,
+      Set<TSentryGroup> groupNames) throws SentryNoSuchObjectException {
+    T context = writeLock();
+    try {
+      return sentryStore.alterSentryRoleDeleteGroups(roleName, groupNames);
+    } finally {
+      if (context != null) {
+        context.unlock();
+      }
+    }
+  }
+
+  @Override
+  public void dropPrivilege(TSentryAuthorizable tAuthorizable)
+      throws SentryNoSuchObjectException, SentryInvalidInputException {
+    T context = writeLock();
+    try {
+      sentryStore.dropPrivilege(tAuthorizable);
+    } finally {
+      if (context != null) {
+        context.unlock();
+      }
+    }
+  }
+
+  @Override
+  public void renamePrivilege(TSentryAuthorizable tAuthorizable,
+      TSentryAuthorizable newTAuthorizable) throws SentryNoSuchObjectException,
+      SentryInvalidInputException {
+    T context = writeLock();
+    try {
+      sentryStore.renamePrivilege(tAuthorizable, newTAuthorizable);
+    } finally {
+      if (context != null) {
+        context.unlock();
+      }
+    }
+  }
+
+  @Override
+  public void setSentryVersion(String newVersion, String verComment)
+      throws SentryNoSuchObjectException, SentryAccessDeniedException {
+    T context = writeLock();
+    try {
+      sentryStore.setSentryVersion(newVersion, verComment);
+    } finally {
+      if (context != null) {
+        context.unlock();
+      }
+    }
+  }
+
+  @Override
+  public TSentryPrivilegeMap listSentryPrivilegesByAuthorizable(
+      Set<String> groups, TSentryActiveRoleSet activeRoles,
+      TSentryAuthorizable authHierarchy, boolean isAdmin)
+      throws SentryInvalidInputException {
+    T context = readLock();
+    try {
+      return sentryStore.listSentryPrivilegesByAuthorizable(groups, 
activeRoles,
+          authHierarchy, isAdmin);
+    } finally {
+      if (context != null) {
+        context.unlock();
+      }
+    }
+  }
+
+  @Override
+  public Set<TSentryPrivilege>
+      getAllTSentryPrivilegesByRoleName(String roleName)
+          throws SentryNoSuchObjectException {
+    T context = readLock();
+    try {
+      return sentryStore.getAllTSentryPrivilegesByRoleName(roleName);
+    } finally {
+      if (context != null) {
+        context.unlock();
+      }
+    }
+  }
+
+  @Override
+  public Set<TSentryPrivilege> getTSentryPrivileges(Set<String> roleNames,
+      TSentryAuthorizable authHierarchy) throws SentryInvalidInputException {
+    T context = readLock();
+    try {
+      return sentryStore.getTSentryPrivileges(roleNames, authHierarchy);
+    } finally {
+      if (context != null) {
+        context.unlock();
+      }
+    }
+  }
+
+  @Override
+  public Set<TSentryRole> getTSentryRolesByGroupName(Set<String> groupNames,
+      boolean checkAllGroups) throws SentryNoSuchObjectException {
+    T context = readLock();
+    try {
+      return sentryStore.getTSentryRolesByGroupName(groupNames, 
checkAllGroups);
+    } finally {
+      if (context != null) {
+        context.unlock();
+      }
+    }
+  }
+
+  @Override
+  public Set<String> getRoleNamesForGroups(Set<String> groups) {
+    T context = readLock();
+    try {
+      return sentryStore.getRoleNamesForGroups(groups);
+    } finally {
+      if (context != null) {
+        context.unlock();
+      }
+    }
+  }
+
+  @Override
+  public Set<String> listAllSentryPrivilegesForProvider(Set<String> groups,
+      TSentryActiveRoleSet roleSet) throws SentryInvalidInputException {
+    T context = readLock();
+    try {
+      return sentryStore.listAllSentryPrivilegesForProvider(groups, roleSet);
+    } finally {
+      if (context != null) {
+        context.unlock();
+      }
+    }
+  }
+
+  @Override
+  public Set<String> listSentryPrivilegesForProvider(Set<String> groups,
+      TSentryActiveRoleSet roleSet, TSentryAuthorizable authHierarchy)
+      throws SentryInvalidInputException {
+    T context = readLock();
+    try {
+      return sentryStore.listSentryPrivilegesForProvider(groups, roleSet,
+          authHierarchy);
+    } finally {
+      if (context != null) {
+        context.unlock();
+      }
+    }
+  }
+
+  @Override
+  public boolean hasAnyServerPrivileges(Set<String> groups,
+      TSentryActiveRoleSet roleSet, String server) {
+    LockContext context = readLock();
+    try {
+      return sentryStore.hasAnyServerPrivileges(groups, roleSet, server);
+    } finally {
+      if (context != null) {
+        context.unlock();
+      }
+    }
+  }
+
+  @Override
+  public String getSentryVersion() throws SentryNoSuchObjectException,
+      SentryAccessDeniedException {
+    T context = readLock();
+    try {
+      return sentryStore.getSentryVersion();
+    } finally {
+      if (context != null) {
+        context.unlock();
+      }
+    }
+  }
+
+  @Override
+  public Map<String, HashMap<String, String>> retrieveFullPrivilegeImage() {
+    T context = readLock();
+    try {
+      return sentryStore.retrieveFullPrivilegeImage();
+    } finally {
+      if (context != null) {
+        context.unlock();
+      }
+    }
+  }
+
+  @Override
+  public Map<String, LinkedList<String>> retrieveFullRoleImage() {
+    T context = readLock();
+    try {
+      return sentryStore.retrieveFullRoleImage();
+    } finally {
+      if (context != null) {
+        context.unlock();
+      }
+    }
+  }
+
+  @Override
+  public Set<String> getGroupsForRole(String roleName) {
+    T context = readLock();
+    try {
+      return sentryStore.getGroupsForRole(roleName);
+    } finally {
+      if (context != null) {
+        context.unlock();
+      }
+    }
+  }
+
+  @Override
+  public long getRoleCount() {
+    T context = readLock();
+    try {
+      return sentryStore.getRoleCount();
+    } finally {
+      if (context != null) {
+        context.unlock();
+      }
+    }
+  }
+
+  @Override
+  public long getPrivilegeCount() {
+    T context = readLock();
+    try {
+      return sentryStore.getPrivilegeCount();
+    } finally {
+      if (context != null) {
+        context.unlock();
+      }
+    }
+  }
+
+  @Override
+  public long getGroupCount() {
+    T context = readLock();
+    try {
+      return sentryStore.getGroupCount();
+    } finally {
+      if (context != null) {
+        context.unlock();
+      }
+    }
+  }
+
+  @Override
+  public void stop() {
+    sentryStore.stop();
+  }
+
+  @Override
+  public TStoreSnapshot toSnapshot() {
+    T context = readLock();
+    try {
+      return sentryStore.toSnapshot();
+    } finally {
+      if (context != null) {
+        context.unlock();
+      }
+    }
+  }
+
+  @Override
+  public void fromSnapshot(TStoreSnapshot snapshot) {
+    T context = writeLock();
+    try {
+      sentryStore.fromSnapshot(snapshot);
+    } finally {
+      if (context != null) {
+        context.unlock();
+      }
+    }
+  }
+}

Reply via email to