Sahina Bose has uploaded a new change for review. Change subject: gluster: Fixing NPE in sync for empty cluster ......................................................................
gluster: Fixing NPE in sync for empty cluster When cluster is empty, invokeAll returns null as an empty task list is given. Fixed code to skip this case. Change-Id: I7e94a11f7550b7cf5d95b44edb7a8d30bf896db8 Signed-off-by: Sahina Bose <sab...@redhat.com> --- M backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/gluster/GlusterHookSyncJob.java M backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/gluster/GlusterHookSyncJobTest.java 2 files changed, 174 insertions(+), 160 deletions(-) git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/40/14740/1 diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/gluster/GlusterHookSyncJob.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/gluster/GlusterHookSyncJob.java index ab1d990..72bee20 100644 --- a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/gluster/GlusterHookSyncJob.java +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/gluster/GlusterHookSyncJob.java @@ -42,7 +42,7 @@ log.debug("Refreshing hooks list"); List<VDSGroup> clusters = getClusterDao().getAll(); - for (VDSGroup cluster : clusters) { + for (VDSGroup cluster : clusters) { if (!supportsGlusterHookFeature(cluster)) { continue; @@ -50,6 +50,10 @@ log.debugFormat("Syncing hooks for cluster {0}", cluster.getname()); List<VDS> upServers = getClusterUtils().getAllUpServers(cluster.getId()); + + if (upServers == null || upServers.isEmpty()) { + continue; + } List<Callable<Pair<VDS, VDSReturnValue>>> taskList = new ArrayList<Callable<Pair<VDS, VDSReturnValue>>>(); for (final VDS upServer : upServers) { @@ -70,173 +74,177 @@ private void addOrUpdateHooks(Guid clusterId, List<Pair<VDS, VDSReturnValue>> pairResults ) { - List<GlusterHookEntity> existingHooks = getHooksDao().getByClusterId(clusterId); + try { + List<GlusterHookEntity> existingHooks = getHooksDao().getByClusterId(clusterId); - Map<String, GlusterHookEntity> existingHookMap = new HashMap<String,GlusterHookEntity>(); - Map<Guid, Set<VDS>> existingHookServersMap = new HashMap<Guid,Set<VDS>>(); - Map<String, Integer> existingHookConflictMap = new HashMap<String, Integer>(); - for (final GlusterHookEntity hook: existingHooks) { - existingHookServersMap.put(hook.getId(),new HashSet<VDS>()); - existingHookConflictMap.put(hook.getHookKey(), hook.getConflictStatus()); - //initialize hook conflict status as this is to be computed again - hook.setConflictStatus(0); - existingHookMap.put(hook.getHookKey(), hook); - } - - Set<String> fetchedHookKeyList = new HashSet<String>(); - Map<String, GlusterHookEntity> newHookMap = new HashMap<String,GlusterHookEntity>(); - List<GlusterServerHook> newServerHooks = new ArrayList<GlusterServerHook>(); - List<GlusterServerHook> updatedServerHooks = new ArrayList<GlusterServerHook>(); - List<GlusterServerHook> deletedServerHooks = new ArrayList<GlusterServerHook>(); - Set<VDS> upServers = new HashSet<VDS>(); - - - for (Pair<VDS, VDSReturnValue> pairResult : pairResults) { - VDS server = pairResult.getFirst(); - upServers.add(server); - - if (!pairResult.getSecond().getSucceeded()) { - log.infoFormat("Failed to get list of hooks from server {0} with error {1} ", server, - pairResult.getSecond().getVdsError().getMessage()); - logUtil.logServerMessage(server, AuditLogType.GLUSTER_HOOK_LIST_FAILED); - continue; + Map<String, GlusterHookEntity> existingHookMap = new HashMap<String,GlusterHookEntity>(); + Map<Guid, Set<VDS>> existingHookServersMap = new HashMap<Guid,Set<VDS>>(); + Map<String, Integer> existingHookConflictMap = new HashMap<String, Integer>(); + for (final GlusterHookEntity hook: existingHooks) { + existingHookServersMap.put(hook.getId(),new HashSet<VDS>()); + existingHookConflictMap.put(hook.getHookKey(), hook.getConflictStatus()); + //initialize hook conflict status as this is to be computed again + hook.setConflictStatus(0); + existingHookMap.put(hook.getHookKey(), hook); } - @SuppressWarnings("unchecked") - List<GlusterHookEntity> fetchedHooks = (List<GlusterHookEntity>) pairResult.getSecond().getReturnValue(); - - for (GlusterHookEntity fetchedHook : fetchedHooks) { - String key= fetchedHook.getHookKey(); - fetchedHookKeyList.add(key); - - GlusterHookEntity existingHook = existingHookMap.get(key); - - if (existingHook != null) { - updateHookServerMap(existingHookServersMap, existingHook.getId(), server); - - GlusterServerHook serverHook = getHooksDao().getGlusterServerHook(existingHook.getId(), server.getId()); - - Integer conflictStatus = getConflictStatus(existingHook, fetchedHook); - //aggregate conflicts across hooks - existingHook.setConflictStatus(conflictStatus | existingHookMap.get(key).getConflictStatus()); + Set<String> fetchedHookKeyList = new HashSet<String>(); + Map<String, GlusterHookEntity> newHookMap = new HashMap<String,GlusterHookEntity>(); + List<GlusterServerHook> newServerHooks = new ArrayList<GlusterServerHook>(); + List<GlusterServerHook> updatedServerHooks = new ArrayList<GlusterServerHook>(); + List<GlusterServerHook> deletedServerHooks = new ArrayList<GlusterServerHook>(); + Set<VDS> upServers = new HashSet<VDS>(); - if (conflictStatus==0) { - //there is no conflict in server hook and engine's copy of hook - //so remove from server hooks table if exists - if (serverHook != null) - { - deletedServerHooks.add(serverHook); - } - } else { - //there is a conflict. we need to either add or update entry in server hook - if (serverHook == null) - { - newServerHooks.add(buildServerHook(server.getId(), existingHook.getId(), fetchedHook)); + for (Pair<VDS, VDSReturnValue> pairResult : pairResults) { + VDS server = pairResult.getFirst(); + upServers.add(server); + + if (!pairResult.getSecond().getSucceeded()) { + log.infoFormat("Failed to get list of hooks from server {0} with error {1} ", server, + pairResult.getSecond().getVdsError().getMessage()); + logUtil.logServerMessage(server, AuditLogType.GLUSTER_HOOK_LIST_FAILED); + continue; + } + + @SuppressWarnings("unchecked") + List<GlusterHookEntity> fetchedHooks = (List<GlusterHookEntity>) pairResult.getSecond().getReturnValue(); + + for (GlusterHookEntity fetchedHook : fetchedHooks) { + String key= fetchedHook.getHookKey(); + fetchedHookKeyList.add(key); + + GlusterHookEntity existingHook = existingHookMap.get(key); + + if (existingHook != null) { + updateHookServerMap(existingHookServersMap, existingHook.getId(), server); + + GlusterServerHook serverHook = getHooksDao().getGlusterServerHook(existingHook.getId(), server.getId()); + + Integer conflictStatus = getConflictStatus(existingHook, fetchedHook); + //aggregate conflicts across hooks + existingHook.setConflictStatus(conflictStatus | existingHookMap.get(key).getConflictStatus()); + + + if (conflictStatus==0) { + //there is no conflict in server hook and engine's copy of hook + //so remove from server hooks table if exists + if (serverHook != null) + { + deletedServerHooks.add(serverHook); + } } else { - if (!(serverHook.getChecksum().equals(fetchedHook.getChecksum()) && serverHook.getContentType().equals(fetchedHook.getContentType()) - && serverHook.getStatus().equals(fetchedHook.getStatus()))) { - log.infoFormat("Updating existing server hook {0} in server {1} ", key, server); - serverHook.setChecksum(fetchedHook.getChecksum()); - serverHook.setContentType(fetchedHook.getContentType()); - serverHook.setStatus(fetchedHook.getStatus()); - updatedServerHooks.add(serverHook); + //there is a conflict. we need to either add or update entry in server hook + if (serverHook == null) + { + newServerHooks.add(buildServerHook(server.getId(), existingHook.getId(), fetchedHook)); + } else { + if (!(serverHook.getChecksum().equals(fetchedHook.getChecksum()) && serverHook.getContentType().equals(fetchedHook.getContentType()) + && serverHook.getStatus().equals(fetchedHook.getStatus()))) { + log.infoFormat("Updating existing server hook {0} in server {1} ", key, server); + serverHook.setChecksum(fetchedHook.getChecksum()); + serverHook.setContentType(fetchedHook.getContentType()); + serverHook.setStatus(fetchedHook.getStatus()); + updatedServerHooks.add(serverHook); + } } } - } - } else { - GlusterHookEntity newHook = newHookMap.get(key); - if (newHook == null) { - newHook = fetchedHook; - newHook.setClusterId(clusterId); - newHook.setId(Guid.NewGuid()); - log.infoFormat("Detected new hook {0} in server {1}, adding to engine hooks", key,server); - logMessage(clusterId, key, AuditLogType.GLUSTER_HOOK_ADDED); - //for new hook we need to fetch content as well -TBD: in another patch - existingHookServersMap.put(newHook.getId(),new HashSet<VDS>()); + } else { + GlusterHookEntity newHook = newHookMap.get(key); + if (newHook == null) { + newHook = fetchedHook; + newHook.setClusterId(clusterId); + newHook.setId(Guid.NewGuid()); + log.infoFormat("Detected new hook {0} in server {1}, adding to engine hooks", key,server); + logMessage(clusterId, key, AuditLogType.GLUSTER_HOOK_ADDED); + //for new hook we need to fetch content as well -TBD: in another patch + existingHookServersMap.put(newHook.getId(),new HashSet<VDS>()); + } + Integer conflictStatus = getConflictStatus(newHook, fetchedHook); + if (conflictStatus > 0) { + newHook.getServerHooks().add(buildServerHook(server.getId(), newHook.getId(), fetchedHook)); + } + newHook.setConflictStatus(newHook.getConflictStatus() | conflictStatus); + newHookMap.put(key, newHook); + updateHookServerMap(existingHookServersMap, newHook.getId(), server); } - Integer conflictStatus = getConflictStatus(newHook, fetchedHook); - if (conflictStatus > 0) { - newHook.getServerHooks().add(buildServerHook(server.getId(), newHook.getId(), fetchedHook)); - } - newHook.setConflictStatus(newHook.getConflictStatus() | conflictStatus); - newHookMap.put(key, newHook); - updateHookServerMap(existingHookServersMap, newHook.getId(), server); } } - } - //Save new hooks - for (GlusterHookEntity hook: newHookMap.values()) { - getHooksDao().save(hook); - } - - //Add new server hooks - for (GlusterServerHook serverHook: newServerHooks) { - getHooksDao().saveGlusterServerHook(serverHook); - } - - //Update existing server hooks - for (GlusterServerHook serverHook: updatedServerHooks) { - getHooksDao().updateGlusterServerHook(serverHook); - } - - //Add missing conflicts for hooks that are missing on any one of the servers - for (Guid hookId: existingHookServersMap.keySet()) { - if (existingHookServersMap.get(hookId).size() == upServers.size()) { - //hook is present in all of the servers. Nothing to do - continue; + //Save new hooks + for (GlusterHookEntity hook: newHookMap.values()) { + getHooksDao().save(hook); } - //Get servers on which the hooks are missing. - Set<VDS> hookMissingServers = new HashSet<VDS>(upServers); - hookMissingServers.removeAll(existingHookServersMap.get(hookId)); - for (VDS missingServer : hookMissingServers) { - GlusterServerHook missingServerHook = new GlusterServerHook(); - missingServerHook.setHookId(hookId); - missingServerHook.setServerId(missingServer.getId()); - missingServerHook.setStatus(GlusterHookStatus.MISSING); - getHooksDao().saveOrUpdateGlusterServerHook(missingServerHook); - } - //get the hook from database, as we don't have the hookkey for it - GlusterHookEntity hookEntity = getHooksDao().getById(hookId); - if (existingHookMap.get(hookEntity.getHookKey()) != null) { - //if it was an already existing hook, get the hook with - //updated conflict values from map - hookEntity = existingHookMap.get(hookEntity.getHookKey()); - } - hookEntity.addMissingConflict(); - existingHookMap.put(hookEntity.getHookKey(), hookEntity); - } + //Add new server hooks + for (GlusterServerHook serverHook: newServerHooks) { + getHooksDao().saveGlusterServerHook(serverHook); + } - //Update conflict status for existing hooks - for (GlusterHookEntity hook: existingHookMap.values()) { - // Check if aggregated conflict status is different from existing hook - Integer oldConflictStatus = existingHookConflictMap.get(hook.getHookKey()); - if (!(hook.getConflictStatus().equals(oldConflictStatus))) { - log.debugFormat("Conflict change detected for hook {0} in cluster {1} ", hook.getHookKey(),clusterId); - logMessage(clusterId,hook.getHookKey(), AuditLogType.GLUSTER_HOOK_CONFLICT_DETECTED); + //Update existing server hooks + for (GlusterServerHook serverHook: updatedServerHooks) { + getHooksDao().updateGlusterServerHook(serverHook); + } + + //Add missing conflicts for hooks that are missing on any one of the servers + for (Guid hookId: existingHookServersMap.keySet()) { + if (existingHookServersMap.get(hookId).size() == upServers.size()) { + //hook is present in all of the servers. Nothing to do + continue; + } + //Get servers on which the hooks are missing. + Set<VDS> hookMissingServers = new HashSet<VDS>(upServers); + hookMissingServers.removeAll(existingHookServersMap.get(hookId)); + + for (VDS missingServer : hookMissingServers) { + GlusterServerHook missingServerHook = new GlusterServerHook(); + missingServerHook.setHookId(hookId); + missingServerHook.setServerId(missingServer.getId()); + missingServerHook.setStatus(GlusterHookStatus.MISSING); + getHooksDao().saveOrUpdateGlusterServerHook(missingServerHook); + } + //get the hook from database, as we don't have the hookkey for it + GlusterHookEntity hookEntity = getHooksDao().getById(hookId); + if (existingHookMap.get(hookEntity.getHookKey()) != null) { + //if it was an already existing hook, get the hook with + //updated conflict values from map + hookEntity = existingHookMap.get(hookEntity.getHookKey()); + } + hookEntity.addMissingConflict(); + existingHookMap.put(hookEntity.getHookKey(), hookEntity); + } + + //Update conflict status for existing hooks + for (GlusterHookEntity hook: existingHookMap.values()) { + // Check if aggregated conflict status is different from existing hook + Integer oldConflictStatus = existingHookConflictMap.get(hook.getHookKey()); + if (!(hook.getConflictStatus().equals(oldConflictStatus))) { + log.debugFormat("Conflict change detected for hook {0} in cluster {1} ", hook.getHookKey(),clusterId); + logMessage(clusterId,hook.getHookKey(), AuditLogType.GLUSTER_HOOK_CONFLICT_DETECTED); + getHooksDao().updateGlusterHookConflictStatus(hook.getId(), hook.getConflictStatus()); + } + } + + //Update missing conflicts for hooks found only in db and not on any of the servers + Set<String> hooksOnlyInDB = new HashSet<String>(existingHookMap.keySet()); + hooksOnlyInDB.removeAll(fetchedHookKeyList); + + for (String key: hooksOnlyInDB) { + GlusterHookEntity hook = existingHookMap.get(key); + hook.addMissingConflict(); + logMessage(hook.getClusterId(),hook.getHookKey(),AuditLogType.GLUSTER_HOOK_CONFLICT_DETECTED); getHooksDao().updateGlusterHookConflictStatus(hook.getId(), hook.getConflictStatus()); } - } - - //Update missing conflicts for hooks found only in db and not on any of the servers - Set<String> hooksOnlyInDB = new HashSet<String>(existingHookMap.keySet()); - hooksOnlyInDB.removeAll(fetchedHookKeyList); - - for (String key: hooksOnlyInDB) { - GlusterHookEntity hook = existingHookMap.get(key); - hook.addMissingConflict(); - logMessage(hook.getClusterId(),hook.getHookKey(),AuditLogType.GLUSTER_HOOK_CONFLICT_DETECTED); - getHooksDao().updateGlusterHookConflictStatus(hook.getId(), hook.getConflictStatus()); + } catch (Exception e) { + log.error("Exception in sync", e); } } private void updateHookServerMap(Map<Guid, Set<VDS>> existingHookServersMap, - Guid hookId, - VDS server) { + Guid hookId, + VDS server) { Set<VDS> hookServers = existingHookServersMap.get(hookId); hookServers.add(server); existingHookServersMap.put(hookId, hookServers); @@ -244,8 +252,8 @@ @SuppressWarnings("serial") private void logMessage(Guid clusterId, final String hookName,AuditLogType logType) { - logUtil.logAuditMessage(clusterId,null,null,logType,new HashMap<String,String>(){ - {put("hookName",hookName);}}); + logUtil.logAuditMessage(clusterId,null,null,logType,new HashMap<String,String>(){ + {put("hookName",hookName);}}); } private int getConflictStatus(GlusterHookEntity hook, GlusterHookEntity fetchedHook) { diff --git a/backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/gluster/GlusterHookSyncJobTest.java b/backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/gluster/GlusterHookSyncJobTest.java index caa7c08..3354793 100644 --- a/backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/gluster/GlusterHookSyncJobTest.java +++ b/backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/gluster/GlusterHookSyncJobTest.java @@ -53,7 +53,8 @@ private static final Guid[] SERVER_GUIDS = {new Guid("11111111-1111-1111-1111-111111111111"), new Guid("22222222-2222-2222-2222-222222222222"), new Guid("33333333-3333-3333-3333-333333333333")}; - private static final Guid[] CLUSTER_GUIDS = {new Guid("CC111111-1111-1111-1111-111111111111")}; + private static final Guid[] CLUSTER_GUIDS = {new Guid("CC111111-1111-1111-1111-111111111111"), + new Guid("CC222222-2222-2222-2222-222222222222")}; private static final Guid[] EXISTING_HOOK_IDS = {new Guid("AAAAAAAA-1111-1111-1111-111111111111"), new Guid("AAAAAAAA-2222-2222-2222-222222222222"), @@ -90,9 +91,12 @@ doReturn(clusterDao).when(hookSyncJob).getClusterDao(); doReturn(hooksDao).when(hookSyncJob).getHooksDao(); - doReturn(Collections.singletonList(createCluster())).when(clusterDao).getAll(); - } + List<VDSGroup> clusters = new ArrayList<VDSGroup>(); + clusters.add(createCluster(0)); + clusters.add(createCluster(1)); + doReturn(clusters).when(clusterDao).getAll(); + } private void initMocks() { @@ -100,7 +104,8 @@ logUtil = Mockito.spy(GlusterAuditLogUtil.getInstance()); hookSyncJob.setLogUtil(logUtil); doReturn(clusterUtils).when(hookSyncJob).getClusterUtils(); - doReturn(getServers()).when(clusterUtils).getAllUpServers(any(Guid.class)); + doReturn(getServers()).when(clusterUtils).getAllUpServers(CLUSTER_GUIDS[0]); + doReturn(Collections.EMPTY_LIST).when(clusterUtils).getAllUpServers(CLUSTER_GUIDS[1]); doNothing().when(logUtil).logAuditMessage(any(Guid.class), any(GlusterVolumeEntity.class), any(VDS.class), @@ -187,9 +192,9 @@ return new VDS(vdsStatic, vdsDynamic, new VdsStatistics()); } - private VDSGroup createCluster() { + private VDSGroup createCluster(int index) { VDSGroup cluster = new VDSGroup(); - cluster.setId(CLUSTER_GUIDS[0]); + cluster.setId(CLUSTER_GUIDS[index]); cluster.setname("cluster"); cluster.setGlusterService(true); cluster.setVirtService(false); @@ -211,7 +216,7 @@ Mockito.verify(hooksDao, times(0)).save(any(GlusterHookEntity.class)); Mockito.verify(hooksDao, times(0)).saveOrUpdateGlusterServerHook(any(GlusterServerHook.class)); Mockito.verify(hooksDao, times(0)).updateGlusterHookConflictStatus(any(Guid.class),any(Integer.class)); - } + } @Test public void syncHooksWhenHookMissinginDB() { @@ -227,7 +232,7 @@ Mockito.verify(hooksDao, times(2)).save(any(GlusterHookEntity.class)); Mockito.verify(hooksDao, times(0)).saveOrUpdateGlusterServerHook(any(GlusterServerHook.class)); Mockito.verify(hooksDao, times(0)).updateGlusterHookConflictStatus(any(Guid.class),any(Integer.class)); - } + } @Test public void syncHooksWhenHookMissingInAllServers() { @@ -238,13 +243,13 @@ argThat(vdsServer1())); doReturn(getHooksListVDSReturnVal(2)).when(hookSyncJob).runVdsCommand(eq(VDSCommandType.GlusterHooksList), argThat(vdsServer2())); - doReturn(getHook(2,true)).when(hooksDao).getById(EXISTING_HOOK_IDS[2]); + doReturn(getHook(2,true)).when(hooksDao).getById(EXISTING_HOOK_IDS[2]); hookSyncJob.refreshHooks(); Mockito.verify(hooksDao, times(0)).save(any(GlusterHookEntity.class)); Mockito.verify(hooksDao, times(2)).saveOrUpdateGlusterServerHook(any(GlusterServerHook.class)); Mockito.verify(hooksDao, times(2)).updateGlusterHookConflictStatus(any(Guid.class),any(Integer.class)); - } + } @Test public void syncHooksWhenHookMissingInOneServer() { @@ -261,7 +266,7 @@ Mockito.verify(hooksDao, times(0)).save(any(GlusterHookEntity.class)); Mockito.verify(hooksDao, times(1)).saveOrUpdateGlusterServerHook(any(GlusterServerHook.class)); Mockito.verify(hooksDao, times(1)).updateGlusterHookConflictStatus(any(Guid.class),any(Integer.class)); - } + } @Test public void syncHooksWhenHookContentConflictInOneServer() { @@ -279,7 +284,7 @@ Mockito.verify(hooksDao, times(0)).save(any(GlusterHookEntity.class)); Mockito.verify(hooksDao, times(1)).saveGlusterServerHook(any(GlusterServerHook.class)); Mockito.verify(hooksDao, times(1)).updateGlusterHookConflictStatus(EXISTING_HOOK_IDS[1],GlusterHookConflictFlags.CONTENT_CONFLICT.getValue()); - } + } @Test public void syncHooksWhenHookMissingAndContentConflict() { @@ -301,5 +306,6 @@ Mockito.verify(hooksDao, times(1)).updateGlusterHookConflictStatus(EXISTING_HOOK_IDS[1],GlusterHookConflictFlags.CONTENT_CONFLICT.getValue()); Mockito.verify(hooksDao, times(1)).updateGlusterHookConflictStatus(EXISTING_HOOK_IDS[2],GlusterHookConflictFlags.MISSING_HOOK.getValue()); - } + } + } -- To view, visit http://gerrit.ovirt.org/14740 To unsubscribe, visit http://gerrit.ovirt.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I7e94a11f7550b7cf5d95b44edb7a8d30bf896db8 Gerrit-PatchSet: 1 Gerrit-Project: ovirt-engine Gerrit-Branch: master Gerrit-Owner: Sahina Bose <sab...@redhat.com> _______________________________________________ Engine-patches mailing list Engine-patches@ovirt.org http://lists.ovirt.org/mailman/listinfo/engine-patches