From 6f1eb4bf441f4a8c310cd105ac0544325576ba82 Mon Sep 17 00:00:00 2001 From: anthony Date: Thu, 2 Dec 2010 19:19:46 -0800 Subject: [PATCH] bug 7144: return snapshotId with jobid 1. manual and recursive snapshot use the same command 2. upgrade from 2.2 beta1 to beta need to execute schema-22beta1to22beta2.sql and data-22beta1to22beta2.sql 3. upgrade from 2.1GA to 2.2GA need to execute schema-21to22.sql and data-21to22.sql status 7144: resolved fixed --- .../cloud/api/commands/CreateSnapshotCmd.java | 22 ++- .../commands/CreateSnapshotInternalCmd.java | 131 ------------------ .../storage/snapshot/SnapshotService.java | 11 +- .../agent/api/DeleteSnapshotsDirCommand.java | 6 +- core/src/com/cloud/storage/SnapshotVO.java | 8 +- .../com/cloud/storage/dao/SnapshotDao.java | 1 + .../cloud/storage/dao/SnapshotDaoImpl.java | 54 +++++--- .../storage/snapshot/SnapshotManager.java | 7 +- .../storage/snapshot/SnapshotManagerImpl.java | 91 ++++++++---- .../snapshot/SnapshotSchedulerImpl.java | 4 +- setup/db/create-schema.sql | 3 +- setup/db/data-21to22.sql | 2 + setup/db/data-22beta1to22beta2.sql | 2 + setup/db/schema-21to22.sql | 3 +- setup/db/schema-22beta1to22beta2.sql | 1 + 15 files changed, 141 insertions(+), 205 deletions(-) delete mode 100644 api/src/com/cloud/api/commands/CreateSnapshotInternalCmd.java create mode 100644 setup/db/data-22beta1to22beta2.sql create mode 100644 setup/db/schema-22beta1to22beta2.sql diff --git a/api/src/com/cloud/api/commands/CreateSnapshotCmd.java b/api/src/com/cloud/api/commands/CreateSnapshotCmd.java index 94fddf93d17..5e54db27421 100644 --- a/api/src/com/cloud/api/commands/CreateSnapshotCmd.java +++ b/api/src/com/cloud/api/commands/CreateSnapshotCmd.java @@ -21,11 +21,12 @@ package com.cloud.api.commands; import org.apache.log4j.Logger; import com.cloud.api.ApiConstants; -import com.cloud.api.BaseAsyncCmd; +import com.cloud.api.BaseAsyncCreateCmd; import com.cloud.api.BaseCmd; import com.cloud.api.Implementation; import com.cloud.api.Parameter; import com.cloud.api.ServerApiException; +import com.cloud.api.BaseCmd.CommandType; import com.cloud.api.response.SnapshotResponse; import com.cloud.async.AsyncJob; import com.cloud.event.EventTypes; @@ -35,7 +36,7 @@ import com.cloud.storage.Volume; import com.cloud.user.Account; @Implementation(description="Creates an instant snapshot of a volume.", responseObject=SnapshotResponse.class) -public class CreateSnapshotCmd extends BaseAsyncCmd { +public class CreateSnapshotCmd extends BaseAsyncCreateCmd { public static final Logger s_logger = Logger.getLogger(CreateSnapshotCmd.class.getName()); private static final String s_name = "createsnapshotresponse"; @@ -52,6 +53,9 @@ public class CreateSnapshotCmd extends BaseAsyncCmd { @Parameter(name=ApiConstants.VOLUME_ID, type=CommandType.LONG, required=true, description="The ID of the disk volume") private Long volumeId; + @Parameter(name=ApiConstants.POLICY_ID, type=CommandType.LONG, description="polocy id of the snapshot, if this is null, then use MANUAL_POLICY.") + private Long policyId; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -67,6 +71,14 @@ public class CreateSnapshotCmd extends BaseAsyncCmd { public Long getVolumeId() { return volumeId; } + + public Long getPolicyId() { + if( policyId != null) { + return policyId; + } else { + return Snapshot.MANUAL_POLICY_ID; + } + } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// @@ -106,6 +118,12 @@ public class CreateSnapshotCmd extends BaseAsyncCmd { return AsyncJob.Type.Snapshot; } + @Override + public void callCreate(){ + long id = _snapshotMgr.getNextInSequence(this); + this.setId(id); + } + @Override public void execute(){ try { diff --git a/api/src/com/cloud/api/commands/CreateSnapshotInternalCmd.java b/api/src/com/cloud/api/commands/CreateSnapshotInternalCmd.java deleted file mode 100644 index ff43ecd4966..00000000000 --- a/api/src/com/cloud/api/commands/CreateSnapshotInternalCmd.java +++ /dev/null @@ -1,131 +0,0 @@ -/** - * Copyright (C) 2010 Cloud.com, Inc. All rights reserved. - * - * This software is licensed under the GNU General Public License v3 or later. - * - * It is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or any later version. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -package com.cloud.api.commands; - -import org.apache.log4j.Logger; - -import com.cloud.api.ApiConstants; -import com.cloud.api.BaseAsyncCmd; -import com.cloud.api.BaseCmd; -import com.cloud.api.Implementation; -import com.cloud.api.Parameter; -import com.cloud.api.ServerApiException; -import com.cloud.api.response.SnapshotResponse; -import com.cloud.domain.Domain; -import com.cloud.event.EventTypes; -import com.cloud.exception.ResourceAllocationException; -import com.cloud.storage.Snapshot; -import com.cloud.storage.Snapshot.Type; -import com.cloud.storage.Volume; -import com.cloud.user.Account; - -@Implementation(description="Creates an instant snapshot of a volume.", responseObject=SnapshotResponse.class) -public class CreateSnapshotInternalCmd extends BaseAsyncCmd { - public static final Logger s_logger = Logger.getLogger(CreateSnapshotInternalCmd.class.getName()); - private static final String s_name = "createsnapshotresponse"; - - ///////////////////////////////////////////////////// - //////////////// API parameters ///////////////////// - ///////////////////////////////////////////////////// - - @Parameter(name=ApiConstants.POLICY_ID, type=CommandType.LONG) - private Long policyId; - - @Parameter(name=ApiConstants.VOLUME_ID, type=CommandType.LONG, required=true) - private Long volumeId; - - ///////////////////////////////////////////////////// - /////////////////// Accessors /////////////////////// - ///////////////////////////////////////////////////// - - public Long getPolicyId() { - return policyId; - } - - public Long getVolumeId() { - return volumeId; - } - - ///////////////////////////////////////////////////// - /////////////// API Implementation/////////////////// - ///////////////////////////////////////////////////// - - @Override - public String getName() { - return s_name; - } - - public static String getResultObjectName() { - return "snapshot"; - } - - @Override - public long getAccountId() { - Volume volume = _entityMgr.findById(Volume.class, getVolumeId()); - if (volume != null) { - return volume.getAccountId(); - } - - // bad id given, parent this command to SYSTEM so ERROR events are tracked - return Account.ACCOUNT_ID_SYSTEM; - } - - @Override - public String getEventType() { - return EventTypes.EVENT_SNAPSHOT_CREATE; - } - - @Override - public String getEventDescription() { - return "creating snapshot for volume: " + getVolumeId(); - } - - @Override - public void execute(){ - try { - Snapshot snapshot = _snapshotMgr.createSnapshotInternal(this); - if (snapshot != null) { - SnapshotResponse response = new SnapshotResponse(); - response.setId(snapshot.getId()); - - Account account = _entityMgr.findById(Account.class, snapshot.getAccountId()); - if (account != null) { - response.setAccountName(account.getAccountName()); - response.setDomainId(account.getDomainId()); - response.setDomainName(_entityMgr.findById(Domain.class, account.getDomainId()).getName()); - } - - Volume volume = _entityMgr.findById(Volume.class, snapshot.getVolumeId()); - String snapshotTypeStr = Type.values()[snapshot.getSnapshotType()].name(); - response.setSnapshotType(snapshotTypeStr); - response.setVolumeId(snapshot.getVolumeId()); - response.setVolumeName(volume.getName()); - response.setVolumeType(volume.getVolumeType().toString()); - response.setCreated(snapshot.getCreated()); - response.setName(snapshot.getName()); - response.setObjectName("snapshot"); - response.setResponseName(getName()); - this.setResponseObject(response); - } else { - throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Failed to create snapshot"); - } - } catch (ResourceAllocationException ex) { - throw new ServerApiException(BaseCmd.RESOURCE_ALLOCATION_ERROR, ex.getMessage()); - } - } -} diff --git a/api/src/com/cloud/storage/snapshot/SnapshotService.java b/api/src/com/cloud/storage/snapshot/SnapshotService.java index dcf51fc4602..004da20bff9 100644 --- a/api/src/com/cloud/storage/snapshot/SnapshotService.java +++ b/api/src/com/cloud/storage/snapshot/SnapshotService.java @@ -20,7 +20,6 @@ package com.cloud.storage.snapshot; import java.util.List; import com.cloud.api.commands.CreateSnapshotCmd; -import com.cloud.api.commands.CreateSnapshotInternalCmd; import com.cloud.api.commands.CreateSnapshotPolicyCmd; import com.cloud.api.commands.DeleteSnapshotCmd; import com.cloud.api.commands.DeleteSnapshotPoliciesCmd; @@ -40,14 +39,6 @@ public interface SnapshotService { */ Snapshot createSnapshot(CreateSnapshotCmd cmd) throws InvalidParameterValueException, ResourceAllocationException; - /** - * An internal method for creating recurring snapshots. The command is not exposed through the API but is used to hook into the async framework. - * @param cmd the command specifying volumeId and policyId - * @return the created snapshot - * @throws ResourceAllocationException - */ - Snapshot createSnapshotInternal(CreateSnapshotInternalCmd cmd) throws ResourceAllocationException; - /** * List all snapshots of a disk volume. Optionally lists snapshots created by specified interval * @param cmd the command containing the search criteria (order by, limit, etc.) @@ -87,5 +78,7 @@ public interface SnapshotService { List listPoliciesforVolume(ListSnapshotPoliciesCmd cmd); boolean deleteSnapshotPolicies(DeleteSnapshotPoliciesCmd cmd); + + long getNextInSequence(CreateSnapshotCmd cmd); } diff --git a/core/src/com/cloud/agent/api/DeleteSnapshotsDirCommand.java b/core/src/com/cloud/agent/api/DeleteSnapshotsDirCommand.java index 2073019e61e..c9694d35c43 100644 --- a/core/src/com/cloud/agent/api/DeleteSnapshotsDirCommand.java +++ b/core/src/com/cloud/agent/api/DeleteSnapshotsDirCommand.java @@ -57,10 +57,10 @@ public class DeleteSnapshotsDirCommand extends SnapshotCommand { Long dcId, Long accountId, Long volumeId, - String snapshotUUID, - String snapshotName) + String volumePath) { - super(primaryStoragePoolNameLabel, secondaryStoragePoolURL, snapshotUUID, snapshotName, dcId, accountId, volumeId); + super(primaryStoragePoolNameLabel, secondaryStoragePoolURL, null, null, dcId, accountId, volumeId); + this.setVolumePath(volumePath); } } \ No newline at end of file diff --git a/core/src/com/cloud/storage/SnapshotVO.java b/core/src/com/cloud/storage/SnapshotVO.java index 20c68d18957..4b4c3b4dbac 100644 --- a/core/src/com/cloud/storage/SnapshotVO.java +++ b/core/src/com/cloud/storage/SnapshotVO.java @@ -29,6 +29,7 @@ import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; +import javax.persistence.TableGenerator; import com.cloud.utils.db.GenericDao; import com.google.gson.annotations.Expose; @@ -38,8 +39,8 @@ import com.google.gson.annotations.Expose; public class SnapshotVO implements Snapshot { @Id - @GeneratedValue(strategy=GenerationType.IDENTITY) - @Column(name="id") + @TableGenerator(name="snapshots_sq", table="sequence", pkColumnName="name", valueColumnName="value", pkColumnValue="snapshots_seq", allocationSize=1) + @Column(name="id", updatable=false, nullable = false) Long id; @Column(name="account_id") @@ -81,7 +82,8 @@ public class SnapshotVO implements Snapshot { public SnapshotVO() { } - public SnapshotVO(long accountId, long volumeId, String path, String name, short snapshotType, String typeDescription) { + public SnapshotVO(long id, long accountId, long volumeId, String path, String name, short snapshotType, String typeDescription) { + this.id = id; this.accountId = accountId; this.volumeId = volumeId; this.path = path; diff --git a/server/src/com/cloud/storage/dao/SnapshotDao.java b/server/src/com/cloud/storage/dao/SnapshotDao.java index 4391add9a82..fcd6d6dd064 100644 --- a/server/src/com/cloud/storage/dao/SnapshotDao.java +++ b/server/src/com/cloud/storage/dao/SnapshotDao.java @@ -31,5 +31,6 @@ public interface SnapshotDao extends GenericDao { SnapshotVO findNextSnapshot(long parentSnapId); long getLastSnapshot(long volumeId, long snapId); List listByVolumeIdType(long volumeId, String type); + List listByVolumeIdIncludingRemoved(long volumeId); } diff --git a/server/src/com/cloud/storage/dao/SnapshotDaoImpl.java b/server/src/com/cloud/storage/dao/SnapshotDaoImpl.java index d50f5fc43ec..fe7f44dc68b 100644 --- a/server/src/com/cloud/storage/dao/SnapshotDaoImpl.java +++ b/server/src/com/cloud/storage/dao/SnapshotDaoImpl.java @@ -18,25 +18,29 @@ package com.cloud.storage.dao; +import java.sql.PreparedStatement; +import java.sql.ResultSet; import java.util.List; import javax.ejb.Local; -import com.cloud.storage.Snapshot; +import org.apache.log4j.Logger; + import com.cloud.storage.SnapshotVO; import com.cloud.utils.db.Filter; import com.cloud.utils.db.GenericDaoBase; -import com.cloud.utils.db.GenericSearchBuilder; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.Transaction; @Local (value={SnapshotDao.class}) public class SnapshotDaoImpl extends GenericDaoBase implements SnapshotDao { + public static final Logger s_logger = Logger.getLogger(SnapshotDaoImpl.class.getName()); + private static final String GET_LAST_SNAPSHOT = "SELECT id FROM snapshots where volume_id = ? AND id != ? ORDER BY created DESC"; private final SearchBuilder VolumeIdSearch; private final SearchBuilder VolumeIdTypeSearch; private final SearchBuilder ParentIdSearch; - private final GenericSearchBuilder lastSnapSearch; @Override public SnapshotVO findNextSnapshot(long snapshotId) { @@ -62,6 +66,12 @@ public class SnapshotDaoImpl extends GenericDaoBase implements return listBy(sc, filter); } + @Override + public List listByVolumeIdIncludingRemoved(long volumeId) { + SearchCriteria sc = VolumeIdSearch.create(); + sc.setParameters("volumeId", volumeId); + return listIncludingRemovedBy(sc, null); + } public List listByVolumeIdType(Filter filter, long volumeId, String type ) { SearchCriteria sc = VolumeIdTypeSearch.create(); @@ -83,24 +93,28 @@ public class SnapshotDaoImpl extends GenericDaoBase implements ParentIdSearch = createSearchBuilder(); ParentIdSearch.and("prevSnapshotId", ParentIdSearch.entity().getPrevSnapshotId(), SearchCriteria.Op.EQ); ParentIdSearch.done(); - - lastSnapSearch = createSearchBuilder(Long.class); - lastSnapSearch.select(null, SearchCriteria.Func.MAX, lastSnapSearch.entity().getId()); - lastSnapSearch.and("volumeId", lastSnapSearch.entity().getVolumeId(), SearchCriteria.Op.EQ); - lastSnapSearch.and("snapId", lastSnapSearch.entity().getId(), SearchCriteria.Op.NEQ); - lastSnapSearch.done(); + + } + + @Override + public long getLastSnapshot(long volumeId, long snapId) { + Transaction txn = Transaction.currentTxn(); + PreparedStatement pstmt = null; + String sql = GET_LAST_SNAPSHOT; + try { + pstmt = txn.prepareAutoCloseStatement(sql); + pstmt.setLong(1, volumeId); + pstmt.setLong(2, snapId); + ResultSet rs = pstmt.executeQuery(); + if (rs.next()) { + return rs.getLong(1); + } + } catch (Exception ex) { + s_logger.error("error getting last snapshot", ex); + } + return 0; } - @Override - public long getLastSnapshot(long volumeId, long snapId) { - SearchCriteria sc = lastSnapSearch.create(); - sc.setParameters("volumeId", volumeId); - sc.setParameters("snapId", snapId); - List prevSnapshots = searchIncludingRemoved(sc, null); - if(prevSnapshots != null && prevSnapshots.size() > 0 && prevSnapshots.get(0) != null) { - return prevSnapshots.get(0); - } - return 0; - } + } diff --git a/server/src/com/cloud/storage/snapshot/SnapshotManager.java b/server/src/com/cloud/storage/snapshot/SnapshotManager.java index 24eb041c038..02e5e573e60 100755 --- a/server/src/com/cloud/storage/snapshot/SnapshotManager.java +++ b/server/src/com/cloud/storage/snapshot/SnapshotManager.java @@ -19,9 +19,6 @@ package com.cloud.storage.snapshot; import java.util.List; -import com.cloud.api.commands.ListSnapshotsCmd; -import com.cloud.exception.InvalidParameterValueException; -import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.ResourceAllocationException; import com.cloud.storage.SnapshotPolicyVO; import com.cloud.storage.SnapshotVO; @@ -46,7 +43,7 @@ public interface SnapshotManager { * @param cmd the API command wrapping the parameters for creating the snapshot (mainly volumeId) * @return the Snapshot that was created */ - SnapshotVO createSnapshotImpl(Long volumeId, Long policyId, Long startEventId) throws ResourceAllocationException; + SnapshotVO createSnapshotImpl(Long volumeId, Long policyId, Long startEventId, Long snapshotId) throws ResourceAllocationException; /** * After successfully creating a snapshot of a volume, copy the snapshot to the secondary storage for @@ -130,5 +127,5 @@ public interface SnapshotManager { * @param cmd the API command wrapping the parameters for creating the snapshot (mainly volumeId) * @return the Snapshot that was created */ - SnapshotVO createSnapshotOnPrimary(VolumeVO volume, Long polocyId) throws ResourceAllocationException; + SnapshotVO createSnapshotOnPrimary(VolumeVO volume, Long polocyId, Long snapshotId) throws ResourceAllocationException; } diff --git a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java index 77ebdfdf437..f53174ec99b 100755 --- a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java +++ b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java @@ -18,6 +18,8 @@ package com.cloud.storage.snapshot; +import java.sql.PreparedStatement; +import java.sql.ResultSet; import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -41,7 +43,6 @@ import com.cloud.agent.api.ManageSnapshotCommand; import com.cloud.api.BaseCmd; import com.cloud.api.ServerApiException; import com.cloud.api.commands.CreateSnapshotCmd; -import com.cloud.api.commands.CreateSnapshotInternalCmd; import com.cloud.api.commands.CreateSnapshotPolicyCmd; import com.cloud.api.commands.DeleteSnapshotCmd; import com.cloud.api.commands.DeleteSnapshotPoliciesCmd; @@ -62,6 +63,7 @@ import com.cloud.event.dao.EventDao; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.UsageServerException; import com.cloud.host.dao.DetailsDao; import com.cloud.host.dao.HostDao; import com.cloud.storage.Snapshot; @@ -110,6 +112,8 @@ import com.cloud.vm.dao.UserVmDao; @Local(value={SnapshotManager.class, SnapshotService.class}) public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Manager { private static final Logger s_logger = Logger.getLogger(SnapshotManagerImpl.class); + private static final String GET_LAST_ID = "SELECT id FROM cloud.snapshots ORDER BY id DESC LIMIT 1"; + private static final String UPDATE_SNAPSHOT_SEQ = "UPDATE cloud.sequence SET value=? WHERE name='snapshots_seq'"; @Inject protected HostDao _hostDao; @Inject protected UserVmDao _vmDao; @@ -193,7 +197,7 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma } @Override - public SnapshotVO createSnapshotOnPrimary(VolumeVO volume, Long policyId) throws ResourceAllocationException { + public SnapshotVO createSnapshotOnPrimary(VolumeVO volume, Long policyId, Long snapshotId) throws ResourceAllocationException { SnapshotVO createdSnapshot = null; Long volumeId = volume.getId(); if (volume.getStatus() != AsyncInstanceCreateStatus.Created) { @@ -227,7 +231,7 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma // Create the Snapshot object and save it so we can return it to the // user Type snapshotType = SnapshotVO.getSnapshotType(policyId); - SnapshotVO snapshotVO = new SnapshotVO(volume.getAccountId(), volume.getId(), null, snapshotName, + SnapshotVO snapshotVO = new SnapshotVO(snapshotId, volume.getAccountId(), volume.getId(), null, snapshotName, (short) snapshotType.ordinal(), snapshotType.name()); snapshotVO = _snapshotDao.persist(snapshotVO); id = snapshotVO.getId(); @@ -321,7 +325,7 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma } @Override @DB - public SnapshotVO createSnapshotImpl(Long volumeId, Long policyId, Long startEventId) throws ResourceAllocationException { + public SnapshotVO createSnapshotImpl(Long volumeId, Long policyId, Long snapshotId, Long startEventId) throws ResourceAllocationException { VolumeVO volume = _volsDao.acquireInLockTable(volumeId, 10); if( volume == null ) { volume = _volsDao.findById(volumeId); @@ -333,9 +337,8 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma } SnapshotVO snapshot = null; boolean backedUp = false; - Long snapshotId = null; try { - snapshot = createSnapshotOnPrimary(volume, policyId); + snapshot = createSnapshotOnPrimary(volume, policyId, snapshotId); if (snapshot != null && snapshot.getStatus() == Snapshot.Status.CreatedOnPrimary ) { snapshotId = snapshot.getId(); backedUp = backupSnapshotToSecondaryStorage(snapshot, startEventId); @@ -356,19 +359,12 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma @Override public SnapshotVO createSnapshot(CreateSnapshotCmd cmd) throws ResourceAllocationException { - Long volumeId = cmd.getVolumeId(); - Long policyId = Snapshot.MANUAL_POLICY_ID ; - Long startEventId = cmd.getStartEventId(); - return createSnapshotImpl(volumeId, policyId, startEventId); - } - - @Override - public SnapshotVO createSnapshotInternal(CreateSnapshotInternalCmd cmd) throws ResourceAllocationException { Long volumeId = cmd.getVolumeId(); Long policyId = cmd.getPolicyId(); + Long snapshotId = cmd.getId(); Long startEventId = cmd.getStartEventId(); - return createSnapshotImpl(volumeId, policyId, startEventId); - } + return createSnapshotImpl(volumeId, policyId, snapshotId, startEventId); + } private SnapshotVO updateDBOnCreate(Long id, String snapshotPath, long preSnapshotId) { SnapshotVO createdSnapshot = _snapshotDao.findByIdIncludingRemoved(id); @@ -887,20 +883,11 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma Long dcId = volume.getDataCenterId(); String secondaryStoragePoolURL = _storageMgr.getSecondaryStorageURL(dcId); String primaryStoragePoolNameLabel = _storageMgr.getPrimaryStorageNameLabel(volume); - long mostRecentSnapshotId = _snapshotDao.getLastSnapshot(volumeId, -1L); - if (mostRecentSnapshotId == 0L) { + if (_snapshotDao.listByVolumeIdIncludingRemoved(volumeId).isEmpty() ) { // This volume doesn't have any snapshots. Nothing do delete. continue; } - SnapshotVO mostRecentSnapshot = _snapshotDao.findByIdIncludingRemoved(mostRecentSnapshotId); - if (mostRecentSnapshot == null) { - // Huh. The code should never reach here. - s_logger.error("Volume Id's mostRecentSnapshot with id: " + mostRecentSnapshotId + " turns out to be null"); - } - // even if mostRecentSnapshot.removed() != null, we still have to explicitly remove it from the primary storage. - // Then deleting the volume VDI will GC the base copy and nothing will be left on primary storage. - String mostRecentSnapshotUuid = mostRecentSnapshot.getPath(); - DeleteSnapshotsDirCommand cmd = new DeleteSnapshotsDirCommand(primaryStoragePoolNameLabel, secondaryStoragePoolURL, dcId, accountId, volumeId, mostRecentSnapshotUuid, mostRecentSnapshot.getName()); + DeleteSnapshotsDirCommand cmd = new DeleteSnapshotsDirCommand(primaryStoragePoolNameLabel, secondaryStoragePoolURL, dcId, accountId, volumeId, volume.getPath()); String basicErrMsg = "Failed to destroy snapshotsDir for: " + volume.getId() + " under account: " + accountId; Answer answer = null; Long poolId = volume.getPoolId(); @@ -1161,6 +1148,45 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma return _snapshotPolicyDao.findOneByVolume(volumeId); } + @Override + public long getNextInSequence(CreateSnapshotCmd cmd) { + return _snapshotDao.getNextInSequence(Long.class, "id"); + } + + private Long _getLastId() { + Transaction txn = Transaction.open(Transaction.CLOUD_DB); + PreparedStatement pstmt = null; + String sql = GET_LAST_ID; + try { + pstmt = txn.prepareAutoCloseStatement(sql); + ResultSet rs = pstmt.executeQuery(); + if (rs.next()) { + return Long.valueOf(rs.getLong(1)); + } + } catch (Exception ex) { + s_logger.error("error getting last id", ex); + } + return null; + } + + private void _updateSnapshotSeq(Long seq) { + Transaction txn = Transaction.open(Transaction.CLOUD_DB); + try { + txn.start(); + String sql = UPDATE_SNAPSHOT_SEQ; + PreparedStatement pstmt = null; + pstmt = txn.prepareAutoCloseStatement(sql); + pstmt.setLong(1, seq.longValue()); + pstmt.execute(); + txn.commit(); + } catch (Exception ex) { + txn.rollback(); + String msg = "error seting snapshots_seq to " + seq; + s_logger.error(msg, ex); + throw new CloudRuntimeException(msg, ex); + } + } + @Override public boolean configure(String name, Map params) throws ConfigurationException { _name = name; @@ -1179,7 +1205,15 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma _deltaSnapshotMax = NumbersUtil.parseInt(configDao.getValue("snapshot.delta.max"), DELTAMAX); _totalRetries = NumbersUtil.parseInt(configDao.getValue("total.retries"), 4); _pauseInterval = 2*NumbersUtil.parseInt(configDao.getValue("ping.interval"), 60); - + + Long lastId = _getLastId(); + if ( lastId == null ) { + String msg = "Can not get last id of snapshots"; + s_logger.error(msg); + throw new CloudRuntimeException(msg); + } + s_logger.info("Set shapshot sequence to " + (lastId + 1)); + _updateSnapshotSeq( lastId + 1 ); s_logger.info("Snapshot Manager is configured."); return true; @@ -1249,4 +1283,5 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma return success; } + } diff --git a/server/src/com/cloud/storage/snapshot/SnapshotSchedulerImpl.java b/server/src/com/cloud/storage/snapshot/SnapshotSchedulerImpl.java index be91e3ea66d..d6f7bf7410d 100644 --- a/server/src/com/cloud/storage/snapshot/SnapshotSchedulerImpl.java +++ b/server/src/com/cloud/storage/snapshot/SnapshotSchedulerImpl.java @@ -30,7 +30,7 @@ import javax.persistence.EntityExistsException; import org.apache.log4j.Logger; -import com.cloud.api.commands.CreateSnapshotInternalCmd; +import com.cloud.api.commands.CreateSnapshotCmd; import com.cloud.async.AsyncJobManager; import com.cloud.async.AsyncJobResult; import com.cloud.async.AsyncJobVO; @@ -228,7 +228,7 @@ public class SnapshotSchedulerImpl implements SnapshotScheduler { // 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(CreateSnapshotInternalCmd.class.getName()); + job.setCmd(CreateSnapshotCmd.class.getName()); job.setCmdInfo(GsonHelper.getBuilder().create().toJson(params)); long jobId = _asyncMgr.submitAsyncJob(job); diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql index 551f34d441d..1742d7c66b6 100755 --- a/setup/db/create-schema.sql +++ b/setup/db/create-schema.sql @@ -277,6 +277,7 @@ INSERT INTO `cloud`.`sequence` (name, value) VALUES ('private_mac_address_seq', INSERT INTO `cloud`.`sequence` (name, value) VALUES ('storage_pool_seq', 200); INSERT INTO `cloud`.`sequence` (name, value) VALUES ('volume_seq', 1); INSERT INTO `cloud`.`sequence` (name, value) VALUES ('networks_seq', 1); +INSERT INTO `cloud`.`sequence` (name, value) VALUES ('snapshots_seq', 1); CREATE TABLE `cloud`.`volumes` ( `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'Primary Key', @@ -315,7 +316,7 @@ CREATE TABLE `cloud`.`volumes` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `cloud`.`snapshots` ( - `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'Primary Key', + `id` bigint unsigned UNIQUE NOT NULL 'Primary Key', `account_id` bigint unsigned NOT NULL COMMENT 'owner. foreign key to account table', `volume_id` bigint unsigned NOT NULL COMMENT 'volume it belongs to. foreign key to volume table', `status` varchar(32) COMMENT 'snapshot creation status', diff --git a/setup/db/data-21to22.sql b/setup/db/data-21to22.sql index a13fa0a9946..7fcc35e36a8 100644 --- a/setup/db/data-21to22.sql +++ b/setup/db/data-21to22.sql @@ -15,5 +15,7 @@ UPDATE vm_template set unique_name='routing_old' where id=1; INSERT INTO vm_template (id, unique_name, name, public, created, type, hvm, bits, account_id, url, checksum, enable_password, display_text, format, guest_os_id, featured, cross_zones) VALUES (10, 'routing', 'SystemVM Template', 0, now(), 'ext3', 0, 64, 1, 'http://download.cloud.com/releases/2.2/systemvm.vhd.bz2', 'bcc7f290f4c27ab4d0fe95d1012829ea', 0, 'SystemVM Template', 'VHD', 15, 0, 1); Update configuration set name='storage.max.volume.size' where name='max.volume.size.mb'; +INSERT INTO sequence (name, value) + VALUES ('snapshots_seq', '1') COMMIT; diff --git a/setup/db/data-22beta1to22beta2.sql b/setup/db/data-22beta1to22beta2.sql new file mode 100644 index 00000000000..f52a94b3651 --- /dev/null +++ b/setup/db/data-22beta1to22beta2.sql @@ -0,0 +1,2 @@ +INSERT INTO sequence (name, value) + VALUES ('snapshots_seq', '1') diff --git a/setup/db/schema-21to22.sql b/setup/db/schema-21to22.sql index ebfb3a35d3e..3e3d8f0ea5c 100644 --- a/setup/db/schema-21to22.sql +++ b/setup/db/schema-21to22.sql @@ -3,5 +3,6 @@ SET foreign_key_checks = 0; -- -- Schema upgrade from 2.1 to 2.2 -- -ALTER TABLE `cloud`.`template_host_ref` ADD COLUMN `physical_size` bigint unsigned NOT NULL DEFAULT 0; +ALTER TABLE `cloud`.`template_host_ref` ADD COLUMN `physical_size` bigint unsigned NOT NULL DEFAULT 0 +ALTER TABLE `cloud`.`snapshots` MODIFY COLUMN `id` bigint unsigned UNIQUE NOT NULL ALTER TABLE `vm_instance` DROP COLUMN `group` diff --git a/setup/db/schema-22beta1to22beta2.sql b/setup/db/schema-22beta1to22beta2.sql new file mode 100644 index 00000000000..efb631a2deb --- /dev/null +++ b/setup/db/schema-22beta1to22beta2.sql @@ -0,0 +1 @@ +ALTER TABLE `cloud`.`snapshots` MODIFY COLUMN `id` bigint unsigned UNIQUE NOT NULL