@Override
    public void run() {
      try {
        List<VolumeVO> volumes = _volsDao.listAll();
        Map<Long, List<VolumeCommand>> commandsByPool = new HashMap<Long, List<VolumeCommand>>();

        for (VolumeVO volume : volumes) {
          List<VolumeCommand> commands = commandsByPool.get(volume.getPoolId());
          if (commands == null) {
            commands = new ArrayList<VolumeCommand>();
            commandsByPool.put(volume.getPoolId(), commands);
          }
          VolumeCommand vCommand = new VolumeCommand();
          vCommand.volumeId = volume.getId();
          vCommand.command = new GetFileStatsCommand(volume);
          commands.add(vCommand);
        }
        ConcurrentHashMap<Long, VolumeStats> volumeStats =
            new ConcurrentHashMap<Long, VolumeStats>();
        for (Iterator<Long> iter = commandsByPool.keySet().iterator(); iter.hasNext(); ) {
          Long poolId = iter.next();
          List<VolumeCommand> commandsList = commandsByPool.get(poolId);

          long[] volumeIdArray = new long[commandsList.size()];
          Commands commands = new Commands(OnError.Continue);
          for (int i = 0; i < commandsList.size(); i++) {
            VolumeCommand vCommand = commandsList.get(i);
            volumeIdArray[i] = vCommand.volumeId;
            commands.addCommand(vCommand.command);
          }

          List<StoragePoolHostVO> poolhosts = _storagePoolHostDao.listByPoolId(poolId);
          for (StoragePoolHostVO poolhost : poolhosts) {
            Answer[] answers = _agentMgr.send(poolhost.getHostId(), commands);
            if (answers != null) {
              long totalBytes = 0L;
              for (int i = 0; i < answers.length; i++) {
                if (answers[i].getResult()) {
                  VolumeStats vStats = (VolumeStats) answers[i];
                  volumeStats.put(volumeIdArray[i], vStats);
                  totalBytes += vStats.getBytesUsed();
                }
              }
              break;
            }
          }
        }

        // We replace the existing volumeStats so that it does not grow with no bounds
        _volumeStats = volumeStats;
      } catch (AgentUnavailableException e) {
        s_logger.debug(e.getMessage());
      } catch (Throwable t) {
        s_logger.error("Error trying to retrieve volume stats", t);
      }
    }
  @Override
  public String reserveVirtualMachine(
      VMEntityVO vmEntityVO, String plannerToUse, DeploymentPlan planToDeploy, ExcludeList exclude)
      throws InsufficientCapacityException, ResourceUnavailableException {

    // call planner and get the deployDestination.
    // load vm instance and offerings and call virtualMachineManagerImpl
    // FIXME: profile should work on VirtualMachineEntity
    VMInstanceVO vm = _vmDao.findByUuid(vmEntityVO.getUuid());
    VirtualMachineProfileImpl<VMInstanceVO> vmProfile =
        new VirtualMachineProfileImpl<VMInstanceVO>(vm);
    DataCenterDeployment plan =
        new DataCenterDeployment(
            vm.getDataCenterId(), vm.getPodIdToDeployIn(), null, null, null, null);
    if (planToDeploy != null && planToDeploy.getDataCenterId() != 0) {
      plan =
          new DataCenterDeployment(
              planToDeploy.getDataCenterId(),
              planToDeploy.getPodId(),
              planToDeploy.getClusterId(),
              planToDeploy.getHostId(),
              planToDeploy.getPoolId(),
              planToDeploy.getPhysicalNetworkId());
    }

    List<VolumeVO> vols = _volsDao.findReadyRootVolumesByInstance(vm.getId());
    if (!vols.isEmpty()) {
      VolumeVO vol = vols.get(0);
      StoragePoolVO pool = _storagePoolDao.findById(vol.getPoolId());
      if (!pool.isInMaintenance()) {
        long rootVolDcId = pool.getDataCenterId();
        Long rootVolPodId = pool.getPodId();
        Long rootVolClusterId = pool.getClusterId();
        if (planToDeploy != null && planToDeploy.getDataCenterId() != 0) {
          Long clusterIdSpecified = planToDeploy.getClusterId();
          if (clusterIdSpecified != null && rootVolClusterId != null) {
            if (rootVolClusterId.longValue() != clusterIdSpecified.longValue()) {
              // cannot satisfy the plan passed in to the
              // planner
              throw new ResourceUnavailableException(
                  "Root volume is ready in different cluster, Deployment plan provided cannot be satisfied, unable to create a deployment for "
                      + vm,
                  Cluster.class,
                  clusterIdSpecified);
            }
          }
          plan =
              new DataCenterDeployment(
                  planToDeploy.getDataCenterId(),
                  planToDeploy.getPodId(),
                  planToDeploy.getClusterId(),
                  planToDeploy.getHostId(),
                  vol.getPoolId(),
                  null,
                  null);
        } else {
          plan =
              new DataCenterDeployment(
                  rootVolDcId, rootVolPodId, rootVolClusterId, null, vol.getPoolId(), null, null);
        }
      }
    }

    DeploymentPlanner planner = ComponentContext.getComponent(plannerToUse);
    DeployDestination dest = null;

    if (planner.canHandle(vmProfile, plan, exclude)) {
      dest = planner.plan(vmProfile, plan, exclude);
    }

    if (dest != null) {
      // save destination with VMEntityVO
      VMReservationVO vmReservation =
          new VMReservationVO(
              vm.getId(),
              dest.getDataCenter().getId(),
              dest.getPod().getId(),
              dest.getCluster().getId(),
              dest.getHost().getId());
      Map<Long, Long> volumeReservationMap = new HashMap<Long, Long>();
      for (Volume vo : dest.getStorageForDisks().keySet()) {
        volumeReservationMap.put(vo.getId(), dest.getStorageForDisks().get(vo).getId());
      }
      vmReservation.setVolumeReservation(volumeReservationMap);

      vmEntityVO.setVmReservation(vmReservation);
      _vmEntityDao.persist(vmEntityVO);

      return vmReservation.getUuid();
    } else {
      throw new InsufficientServerCapacityException(
          "Unable to create a deployment for " + vmProfile,
          DataCenter.class,
          plan.getDataCenterId());
    }
  }
  @DB
  protected void scheduleSnapshots() {
    String displayTime = DateUtil.displayDateInTimezone(DateUtil.GMT_TIMEZONE, _currentTimestamp);
    s_logger.debug("Snapshot scheduler.poll is being called at " + displayTime);

    List<SnapshotScheduleVO> snapshotsToBeExecuted =
        _snapshotScheduleDao.getSchedulesToExecute(_currentTimestamp);
    s_logger.debug(
        "Got " + snapshotsToBeExecuted.size() + " snapshots to be executed at " + displayTime);

    // This is done for recurring snapshots, which are executed by the system automatically
    // Hence set user id to that of system
    long userId = 1;

    for (SnapshotScheduleVO snapshotToBeExecuted : snapshotsToBeExecuted) {
      long policyId = snapshotToBeExecuted.getPolicyId();
      long volumeId = snapshotToBeExecuted.getVolumeId();
      VolumeVO volume = _volsDao.findById(volumeId);
      if (volume.getPoolId() == null) {
        // this volume is not attached
        continue;
      }
      if (_snapshotPolicyDao.findById(policyId) == null) {
        _snapshotScheduleDao.remove(snapshotToBeExecuted.getId());
      }
      if (s_logger.isDebugEnabled()) {
        Date scheduledTimestamp = snapshotToBeExecuted.getScheduledTimestamp();
        displayTime = DateUtil.displayDateInTimezone(DateUtil.GMT_TIMEZONE, scheduledTimestamp);
        s_logger.debug(
            "Scheduling 1 snapshot for volume "
                + volumeId
                + " for schedule id: "
                + snapshotToBeExecuted.getId()
                + " at "
                + displayTime);
      }
      long snapshotScheId = snapshotToBeExecuted.getId();
      SnapshotScheduleVO tmpSnapshotScheduleVO = null;
      try {
        tmpSnapshotScheduleVO = _snapshotScheduleDao.acquireInLockTable(snapshotScheId);

        Long eventId =
            EventUtils.saveScheduledEvent(
                User.UID_SYSTEM,
                Account.ACCOUNT_ID_SYSTEM,
                EventTypes.EVENT_SNAPSHOT_CREATE,
                "creating snapshot for volume Id:" + volumeId,
                0);

        Map<String, String> params = new HashMap<String, String>();
        params.put("volumeid", "" + volumeId);
        params.put("policyid", "" + policyId);
        params.put("ctxUserId", "1");
        params.put("ctxAccountId", "1");
        params.put("ctxStartEventId", String.valueOf(eventId));

        CreateSnapshotCmd cmd = new CreateSnapshotCmd();
        ApiDispatcher.getInstance().dispatchCreateCmd(cmd, params);
        params.put("id", "" + cmd.getEntityId());
        params.put("ctxStartEventId", "1");

        AsyncJobVO job = new AsyncJobVO();
        job.setUserId(userId);
        // Just have SYSTEM own the job for now.  Users won't be able to see this job, but
        // it's an internal job so probably not a huge deal.
        job.setAccountId(1L);
        job.setCmd(CreateSnapshotCmd.class.getName());
        job.setInstanceId(cmd.getEntityId());
        job.setCmdInfo(GsonHelper.getBuilder().create().toJson(params));

        long jobId = _asyncMgr.submitAsyncJob(job);

        tmpSnapshotScheduleVO.setAsyncJobId(jobId);
        _snapshotScheduleDao.update(snapshotScheId, tmpSnapshotScheduleVO);
      } finally {
        if (tmpSnapshotScheduleVO != null) {
          _snapshotScheduleDao.releaseFromLockTable(snapshotScheId);
        }
      }
    }
  }