You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ed...@apache.org on 2013/06/20 09:20:03 UTC

[30/50] [abbrv] clean up storage related code, and add lru replacement algorithm for cache storage

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a715eb81/engine/api/src/org/apache/cloudstack/storage/datastore/db/TemplateDataStoreVO.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/storage/datastore/db/TemplateDataStoreVO.java b/engine/api/src/org/apache/cloudstack/storage/datastore/db/TemplateDataStoreVO.java
index 2cee4d1..c6b434d 100755
--- a/engine/api/src/org/apache/cloudstack/storage/datastore/db/TemplateDataStoreVO.java
+++ b/engine/api/src/org/apache/cloudstack/storage/datastore/db/TemplateDataStoreVO.java
@@ -71,7 +71,7 @@ public class TemplateDataStoreVO implements StateObject<ObjectInDataStoreStateMa
     private int downloadPercent;
 
     @Column(name = "size")
-    private long size;
+    private Long size;
 
     @Column(name = "physical_size")
     private long physicalSize;
@@ -112,11 +112,15 @@ public class TemplateDataStoreVO implements StateObject<ObjectInDataStoreStateMa
     @Enumerated(EnumType.STRING)
     ObjectInDataStoreStateMachine.State state;
 
+    @Column(name = "ref_cnt")
+    Long refCnt;
+
     public TemplateDataStoreVO(Long hostId, long templateId) {
         super();
         this.dataStoreId = hostId;
         this.templateId = templateId;
         this.state = ObjectInDataStoreStateMachine.State.Allocated;
+        this.refCnt = 0L;
     }
 
     public TemplateDataStoreVO(Long hostId, long templateId, Date lastUpdated, int downloadPercent,
@@ -131,6 +135,7 @@ public class TemplateDataStoreVO implements StateObject<ObjectInDataStoreStateMa
         this.localDownloadPath = localDownloadPath;
         this.errorString = errorString;
         this.jobId = jobId;
+        this.refCnt = 0L;
         this.installPath = installPath;
         this.setDownloadUrl(downloadUrl);
         switch (downloadState) {
@@ -156,7 +161,7 @@ public class TemplateDataStoreVO implements StateObject<ObjectInDataStoreStateMa
     }
 
     public TemplateDataStoreVO() {
-
+        this.refCnt = 0L;
     }
 
     @Override
@@ -352,4 +357,16 @@ public class TemplateDataStoreVO implements StateObject<ObjectInDataStoreStateMa
         this.dataStoreRole = dataStoreRole;
     }
 
+    public Long getRefCnt() {
+        return refCnt;
+    }
+
+    public void incrRefCnt() {
+        this.refCnt++;
+    }
+
+    public void decrRefCnt() {
+        this.refCnt--;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a715eb81/engine/api/src/org/apache/cloudstack/storage/datastore/db/VolumeDataStoreDao.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/storage/datastore/db/VolumeDataStoreDao.java b/engine/api/src/org/apache/cloudstack/storage/datastore/db/VolumeDataStoreDao.java
index 7c89bbf..4152516 100644
--- a/engine/api/src/org/apache/cloudstack/storage/datastore/db/VolumeDataStoreDao.java
+++ b/engine/api/src/org/apache/cloudstack/storage/datastore/db/VolumeDataStoreDao.java
@@ -27,15 +27,15 @@ import com.cloud.utils.fsm.StateDao;
 public interface VolumeDataStoreDao extends GenericDao<VolumeDataStoreVO, Long>,
         StateDao<ObjectInDataStoreStateMachine.State, ObjectInDataStoreStateMachine.Event, DataObjectInStore> {
 
-    public List<VolumeDataStoreVO> listByStoreId(long id);
+    List<VolumeDataStoreVO> listByStoreId(long id);
 
-    public void deletePrimaryRecordsForStore(long id);
+    void deletePrimaryRecordsForStore(long id);
 
-    public VolumeDataStoreVO findByVolume(long volumeId);
+    VolumeDataStoreVO findByVolume(long volumeId);
 
-    public VolumeDataStoreVO findByStoreVolume(long storeId, long volumeId);
+    VolumeDataStoreVO findByStoreVolume(long storeId, long volumeId);
 
-    public VolumeDataStoreVO findByStoreVolume(long storeId, long volumeId, boolean lock);
+    VolumeDataStoreVO findByStoreVolume(long storeId, long volumeId, boolean lock);
 
-    public List<VolumeDataStoreVO> listDestroyed(long storeId);
+    List<VolumeDataStoreVO> listDestroyed(long storeId);
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a715eb81/engine/api/src/org/apache/cloudstack/storage/datastore/db/VolumeDataStoreVO.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/storage/datastore/db/VolumeDataStoreVO.java b/engine/api/src/org/apache/cloudstack/storage/datastore/db/VolumeDataStoreVO.java
index d2e5c25..222447f 100755
--- a/engine/api/src/org/apache/cloudstack/storage/datastore/db/VolumeDataStoreVO.java
+++ b/engine/api/src/org/apache/cloudstack/storage/datastore/db/VolumeDataStoreVO.java
@@ -111,6 +111,9 @@ public class VolumeDataStoreVO implements StateObject<ObjectInDataStoreStateMach
     @Enumerated(EnumType.STRING)
     ObjectInDataStoreStateMachine.State state;
 
+    @Column(name = "ref_cnt")
+    Long refCnt;
+
     public String getInstallPath() {
         return installPath;
     }
@@ -189,6 +192,7 @@ public class VolumeDataStoreVO implements StateObject<ObjectInDataStoreStateMach
         this.dataStoreId = hostId;
         this.volumeId = volumeId;
         this.state = ObjectInDataStoreStateMachine.State.Allocated;
+        this.refCnt = 0L;
     }
 
     public VolumeDataStoreVO(long hostId, long volumeId, Date lastUpdated, int downloadPercent, Status downloadState,
@@ -207,10 +211,11 @@ public class VolumeDataStoreVO implements StateObject<ObjectInDataStoreStateMach
         this.installPath = installPath;
         this.setDownloadUrl(downloadUrl);
         this.checksum = checksum;
+        this.refCnt = 0L;
     }
 
     public VolumeDataStoreVO() {
-
+        this.refCnt = 0L;
     }
 
     public void setLocalDownloadPath(String localPath) {
@@ -328,4 +333,16 @@ public class VolumeDataStoreVO implements StateObject<ObjectInDataStoreStateMach
         return this.state;
     }
 
+    public Long getRefCnt() {
+        return refCnt;
+    }
+
+    public void incrRefCnt() {
+        this.refCnt++;
+    }
+
+    public void decrRefCnt() {
+        this.refCnt--;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a715eb81/engine/api/src/org/apache/cloudstack/storage/image/datastore/ImageStoreInfo.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/storage/image/datastore/ImageStoreInfo.java b/engine/api/src/org/apache/cloudstack/storage/image/datastore/ImageStoreInfo.java
index d51780d..7261a15 100644
--- a/engine/api/src/org/apache/cloudstack/storage/image/datastore/ImageStoreInfo.java
+++ b/engine/api/src/org/apache/cloudstack/storage/image/datastore/ImageStoreInfo.java
@@ -21,7 +21,7 @@ package org.apache.cloudstack.storage.image.datastore;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
 
 public interface ImageStoreInfo extends DataStore {
-    public long getImageStoreId();
+    long getImageStoreId();
 
-    public String getType();
+    String getType();
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a715eb81/engine/api/src/org/apache/cloudstack/storage/to/ImageStoreTO.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/storage/to/ImageStoreTO.java b/engine/api/src/org/apache/cloudstack/storage/to/ImageStoreTO.java
index 45d0e98..0037ea5 100644
--- a/engine/api/src/org/apache/cloudstack/storage/to/ImageStoreTO.java
+++ b/engine/api/src/org/apache/cloudstack/storage/to/ImageStoreTO.java
@@ -46,9 +46,6 @@ public class ImageStoreTO implements DataStoreTO {
         return this.uri;
     }
 
-    /**
-     * @return the providerName
-     */
     public String getProviderName() {
         return providerName;
     }
@@ -73,4 +70,10 @@ public class ImageStoreTO implements DataStoreTO {
     public DataStoreRole getRole() {
         return this.role;
     }
+
+    @Override
+    public String toString() {
+        return new StringBuilder("ImageStoreTO[type=").append(type).append("|provider=").append(providerName)
+                .append("|role=").append(role).append("|uri=").append(uri).append("]").toString();
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a715eb81/engine/api/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java b/engine/api/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java
index 1b4c08f..5e870df 100644
--- a/engine/api/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java
+++ b/engine/api/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java
@@ -94,4 +94,10 @@ public class PrimaryDataStoreTO implements DataStoreTO {
     public void setPort(int port) {
         this.port = port;
     }
+
+    @Override
+    public String toString() {
+        return new StringBuilder("PrimaryDataStoreTO[uuid=").append(uuid).append("|name=").append(name)
+                .append("|id=").append(id).append("|pooltype=").append(poolType).append("]").toString();
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a715eb81/engine/api/src/org/apache/cloudstack/storage/to/SnapshotObjectTO.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/storage/to/SnapshotObjectTO.java b/engine/api/src/org/apache/cloudstack/storage/to/SnapshotObjectTO.java
index fcaa320..1115aec 100644
--- a/engine/api/src/org/apache/cloudstack/storage/to/SnapshotObjectTO.java
+++ b/engine/api/src/org/apache/cloudstack/storage/to/SnapshotObjectTO.java
@@ -117,4 +117,10 @@ public class SnapshotObjectTO implements DataTO {
     public void setHypervisorType(HypervisorType hypervisorType) {
         this.hypervisorType = hypervisorType;
     }
+
+    @Override
+    public String toString() {
+        return new StringBuilder("SnapshotTO[datastore=").append(dataStore).append("|volume=").append(volume).append("|path")
+                .append(path).append("]").toString();
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a715eb81/engine/api/src/org/apache/cloudstack/storage/to/TemplateObjectTO.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/storage/to/TemplateObjectTO.java b/engine/api/src/org/apache/cloudstack/storage/to/TemplateObjectTO.java
index b3dc189..abe59eb 100644
--- a/engine/api/src/org/apache/cloudstack/storage/to/TemplateObjectTO.java
+++ b/engine/api/src/org/apache/cloudstack/storage/to/TemplateObjectTO.java
@@ -190,4 +190,10 @@ public class TemplateObjectTO implements DataTO {
     public void setSize(Long size) {
         this.size = size;
     }
+
+    @Override
+    public String toString() {
+        return new StringBuilder("TemplateTO[id=").append(id).append("|origUrl=").append(origUrl)
+                .append("|name").append(name).append("]").toString();
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a715eb81/engine/api/src/org/apache/cloudstack/storage/to/VolumeObjectTO.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/storage/to/VolumeObjectTO.java b/engine/api/src/org/apache/cloudstack/storage/to/VolumeObjectTO.java
index 6057a74..bc1c061 100644
--- a/engine/api/src/org/apache/cloudstack/storage/to/VolumeObjectTO.java
+++ b/engine/api/src/org/apache/cloudstack/storage/to/VolumeObjectTO.java
@@ -166,4 +166,10 @@ public class VolumeObjectTO implements DataTO {
         this.format = format;
     }
 
+    @Override
+    public String toString() {
+        return new StringBuilder("volumeTO[uuid=").append(uuid).append("|path=").append(path)
+                .append("|datastore=").append(dataStore).append("]").toString();
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a715eb81/engine/storage/cache/src/org/apache/cloudstack/storage/cache/manager/StorageCacheManagerImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/cache/src/org/apache/cloudstack/storage/cache/manager/StorageCacheManagerImpl.java b/engine/storage/cache/src/org/apache/cloudstack/storage/cache/manager/StorageCacheManagerImpl.java
index cb5ea10..4b4e521 100644
--- a/engine/storage/cache/src/org/apache/cloudstack/storage/cache/manager/StorageCacheManagerImpl.java
+++ b/engine/storage/cache/src/org/apache/cloudstack/storage/cache/manager/StorageCacheManagerImpl.java
@@ -18,32 +18,32 @@
  */
 package org.apache.cloudstack.storage.cache.manager;
 
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ExecutionException;
-
-import javax.inject.Inject;
-import javax.naming.ConfigurationException;
-
-import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionService;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
-import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
+import com.cloud.configuration.Config;
+import com.cloud.configuration.dao.ConfigurationDao;
+import com.cloud.storage.DataStoreRole;
+import com.cloud.utils.NumbersUtil;
+import com.cloud.utils.component.Manager;
+import com.cloud.utils.concurrency.NamedThreadFactory;
+import com.cloud.utils.db.GlobalLock;
+import com.cloud.utils.db.SearchCriteria;
+import com.cloud.utils.db.SearchCriteria2;
+import com.cloud.utils.db.SearchCriteriaService;
+import com.cloud.utils.exception.CloudRuntimeException;
+import org.apache.cloudstack.engine.subsystem.api.storage.*;
 import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event;
-import org.apache.cloudstack.engine.subsystem.api.storage.Scope;
-import org.apache.cloudstack.engine.subsystem.api.storage.StorageCacheManager;
 import org.apache.cloudstack.framework.async.AsyncCallFuture;
-import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher;
-import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
-import org.apache.cloudstack.framework.async.AsyncRpcConext;
 import org.apache.cloudstack.storage.cache.allocator.StorageCacheAllocator;
 import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager;
+import org.apache.cloudstack.storage.datastore.db.ImageStoreVO;
 import org.apache.log4j.Logger;
 
-import com.cloud.utils.component.Manager;
-import com.cloud.utils.exception.CloudRuntimeException;
+import javax.inject.Inject;
+import javax.naming.ConfigurationException;
+import java.util.*;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
 
 public class StorageCacheManagerImpl implements StorageCacheManager, Manager {
     private static final Logger s_logger = Logger.getLogger(StorageCacheManagerImpl.class);
@@ -53,6 +53,16 @@ public class StorageCacheManagerImpl implements StorageCacheManager, Manager {
     DataMotionService dataMotionSvr;
     @Inject
     ObjectInDataStoreManager objectInStoreMgr;
+    @Inject
+    DataStoreManager dataStoreManager;
+    @Inject
+    StorageCacheReplacementAlgorithm cacheReplacementAlgorithm;
+    @Inject
+    ConfigurationDao configDao;
+    Boolean cacheReplacementEnabled = Boolean.TRUE;
+    int workers;
+    ScheduledExecutorService executors;
+    int cacheReplaceMentInterval;
 
     @Override
     public DataStore getCacheStorage(Scope scope) {
@@ -65,6 +75,17 @@ public class StorageCacheManagerImpl implements StorageCacheManager, Manager {
         return null;
     }
 
+    protected List<DataStore> getCacheStores() {
+        SearchCriteriaService<ImageStoreVO, ImageStoreVO> sc = SearchCriteria2.create(ImageStoreVO.class);
+        sc.addAnd(sc.getEntity().getRole(), SearchCriteria.Op.EQ, DataStoreRole.ImageCache);
+        List<ImageStoreVO> imageStoreVOs = sc.list();
+        List<DataStore> stores = new ArrayList<DataStore>();
+        for (ImageStoreVO vo : imageStoreVOs) {
+            stores.add(dataStoreManager.getDataStore(vo.getId(), vo.getRole()));
+        }
+        return stores;
+    }
+
     @Override
     public String getName() {
         // TODO Auto-generated method stub
@@ -103,12 +124,59 @@ public class StorageCacheManagerImpl implements StorageCacheManager, Manager {
 
     @Override
     public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
-        // TODO Auto-generated method stub
+        cacheReplacementEnabled = Boolean.parseBoolean(configDao.getValue(Config.StorageCacheReplacementEnabled.key()));
+        cacheReplaceMentInterval = NumbersUtil.parseInt(configDao.getValue(Config.StorageCacheReplacementInterval.key()), 86400);
+        workers = NumbersUtil.parseInt(configDao.getValue(Config.ExpungeWorkers.key()), 10);
+        executors = Executors.newScheduledThreadPool(workers, new NamedThreadFactory("StorageCacheManager-cache-replacement"));
         return true;
     }
 
+    protected class CacheReplacementRunner implements Runnable {
+
+        @Override
+        public void run() {
+            GlobalLock replacementLock = null;
+            try {
+                replacementLock = GlobalLock.getInternLock("storageCacheMgr.replacement");
+                if (replacementLock.lock(3)) {
+                    List<DataStore> stores = getCacheStores();
+                    Collections.shuffle(stores);
+                    DataObject object = null;
+                    DataStore findAStore = null;
+                    for (DataStore store : stores) {
+                        object = cacheReplacementAlgorithm.chooseOneToBeReplaced(store);
+                        findAStore = store;
+                        if (object != null) {
+                              break;
+                        }
+                    }
+
+                    if (object == null) {
+                        return;
+                    }
+
+                    while(object != null) {
+                        object.delete();
+                        object = cacheReplacementAlgorithm.chooseOneToBeReplaced(findAStore);
+                    }
+                }
+            } catch (Exception e) {
+                s_logger.debug("Failed to execute CacheReplacementRunner: " + e.toString());
+            } finally {
+                if (replacementLock != null) {
+                    replacementLock.unlock();
+                }
+            }
+        }
+    }
+
     @Override
     public boolean start() {
+        if (cacheReplacementEnabled) {
+            Random generator = new Random();
+            int initalDelay = generator.nextInt(cacheReplaceMentInterval);
+            executors.scheduleWithFixedDelay(new CacheReplacementRunner(), initalDelay, cacheReplaceMentInterval, TimeUnit.SECONDS);
+        }
         return true;
     }
 
@@ -118,29 +186,17 @@ public class StorageCacheManagerImpl implements StorageCacheManager, Manager {
         return true;
     }
 
-    private class CreateCacheObjectContext<T> extends AsyncRpcConext<T> {
-        final AsyncCallFuture<CopyCommandResult> future;
-
-        /**
-         * @param callback
-         */
-        public CreateCacheObjectContext(AsyncCompletionCallback<T> callback, AsyncCallFuture<CopyCommandResult> future) {
-            super(callback);
-            this.future = future;
-        }
-
-    }
-
     @Override
-    public DataObject createCacheObject(DataObject data, Scope scope) {
-        DataStore cacheStore = this.getCacheStorage(scope);
-        DataObjectInStore obj = objectInStoreMgr.findObject(data, cacheStore);
+    public DataObject createCacheObject(DataObject data, DataStore store) {
+        DataObjectInStore obj = objectInStoreMgr.findObject(data, store);
         if (obj != null && obj.getState() == ObjectInDataStoreStateMachine.State.Ready) {
             s_logger.debug("there is already one in the cache store");
-            return objectInStoreMgr.get(data, cacheStore);
+            DataObject dataObj = objectInStoreMgr.get(data, store);
+            dataObj.incRefCount();
+            return dataObj;
         }
 
-        DataObject objOnCacheStore = cacheStore.create(data);
+        DataObject objOnCacheStore = store.create(data);
 
         AsyncCallFuture<CopyCommandResult> future = new AsyncCallFuture<CopyCommandResult>();
         CopyCommandResult result = null;
@@ -154,6 +210,7 @@ public class StorageCacheManagerImpl implements StorageCacheManager, Manager {
                 objOnCacheStore.processEvent(Event.OperationFailed);
             } else {
                 objOnCacheStore.processEvent(Event.OperationSuccessed, result.getAnswer());
+                objOnCacheStore.incRefCount();
                 return objOnCacheStore;
             }
         } catch (InterruptedException e) {
@@ -167,28 +224,31 @@ public class StorageCacheManagerImpl implements StorageCacheManager, Manager {
                 objOnCacheStore.processEvent(Event.OperationFailed);
             }
         }
-
         return null;
     }
 
     @Override
+    public DataObject createCacheObject(DataObject data, Scope scope) {
+        DataStore cacheStore = this.getCacheStorage(scope);
+        return this.createCacheObject(data, cacheStore);
+    }
+
+    @Override
     public DataObject getCacheObject(DataObject data, Scope scope) {
         DataStore cacheStore = this.getCacheStorage(scope);
         DataObject objOnCacheStore = cacheStore.create(data);
-
+        objOnCacheStore.incRefCount();
         return objOnCacheStore;
     }
 
-    protected Void createCacheObjectCallBack(
-            AsyncCallbackDispatcher<StorageCacheManagerImpl, CopyCommandResult> callback,
-            CreateCacheObjectContext<CopyCommandResult> context) {
-        AsyncCallFuture<CopyCommandResult> future = context.future;
-        future.complete(callback.getResult());
-        return null;
+    @Override
+    public boolean releaseCacheObject(DataObject data) {
+        data.decRefCount();
+        return true;
     }
 
     @Override
     public boolean deleteCacheObject(DataObject data) {
-        return objectInStoreMgr.delete(data);
+        return data.getDataStore().delete(data);
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a715eb81/engine/storage/cache/src/org/apache/cloudstack/storage/cache/manager/StorageCacheReplacementAlgorithm.java
----------------------------------------------------------------------
diff --git a/engine/storage/cache/src/org/apache/cloudstack/storage/cache/manager/StorageCacheReplacementAlgorithm.java b/engine/storage/cache/src/org/apache/cloudstack/storage/cache/manager/StorageCacheReplacementAlgorithm.java
new file mode 100644
index 0000000..f7a23fe
--- /dev/null
+++ b/engine/storage/cache/src/org/apache/cloudstack/storage/cache/manager/StorageCacheReplacementAlgorithm.java
@@ -0,0 +1,26 @@
+/*
+ * 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.cloudstack.storage.cache.manager;
+
+import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
+import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
+
+public interface StorageCacheReplacementAlgorithm {
+    DataObject chooseOneToBeReplaced(DataStore store);
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a715eb81/engine/storage/cache/src/org/apache/cloudstack/storage/cache/manager/StorageCacheReplacementAlgorithmLRU.java
----------------------------------------------------------------------
diff --git a/engine/storage/cache/src/org/apache/cloudstack/storage/cache/manager/StorageCacheReplacementAlgorithmLRU.java b/engine/storage/cache/src/org/apache/cloudstack/storage/cache/manager/StorageCacheReplacementAlgorithmLRU.java
new file mode 100644
index 0000000..440bf53
--- /dev/null
+++ b/engine/storage/cache/src/org/apache/cloudstack/storage/cache/manager/StorageCacheReplacementAlgorithmLRU.java
@@ -0,0 +1,106 @@
+/*
+ * 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.cloudstack.storage.cache.manager;
+import com.cloud.configuration.Config;
+import com.cloud.configuration.dao.ConfigurationDao;
+import com.cloud.utils.DateUtil;
+import com.cloud.utils.NumbersUtil;
+import com.cloud.utils.db.SearchCriteria;
+import com.cloud.utils.db.SearchCriteria2;
+import com.cloud.utils.db.SearchCriteriaService;
+import org.apache.cloudstack.engine.subsystem.api.storage.*;
+import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO;
+import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
+import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreVO;
+import org.apache.commons.lang.math.NumberUtils;
+
+import java.util.Calendar;
+import java.util.Date;
+import javax.annotation.PostConstruct;
+import javax.inject.Inject;
+
+
+
+public class StorageCacheReplacementAlgorithmLRU implements StorageCacheReplacementAlgorithm {
+    @Inject
+    ConfigurationDao configDao;
+    @Inject
+    TemplateDataFactory templateFactory;
+    @Inject
+    VolumeDataFactory volumeFactory;
+    @Inject
+    SnapshotDataFactory snapshotFactory;
+
+    Integer unusedTimeInterval;
+
+    public StorageCacheReplacementAlgorithmLRU() {
+
+    }
+
+    @PostConstruct
+    public void initialize() {
+        unusedTimeInterval = NumbersUtil.parseInt(configDao.getValue(Config.StorageCacheReplacementLRUTimeInterval.key()), 30);
+    }
+
+    public void setUnusedTimeInterval(Integer interval) {
+        unusedTimeInterval = interval;
+    }
+
+    @Override
+    public DataObject chooseOneToBeReplaced(DataStore store) {
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(DateUtil.now());
+        cal.add(Calendar.DAY_OF_MONTH, -unusedTimeInterval.intValue());
+        Date bef = cal.getTime();
+
+        SearchCriteriaService<TemplateDataStoreVO, TemplateDataStoreVO> sc = SearchCriteria2.create(TemplateDataStoreVO.class);
+        sc.addAnd(sc.getEntity().getLastUpdated(), SearchCriteria.Op.LT, bef);
+        sc.addAnd(sc.getEntity().getState(), SearchCriteria.Op.EQ, ObjectInDataStoreStateMachine.State.Ready);
+        sc.addAnd(sc.getEntity().getDataStoreId(), SearchCriteria.Op.EQ, store.getId());
+        sc.addAnd(sc.getEntity().getDataStoreRole(), SearchCriteria.Op.EQ, store.getRole());
+        sc.addAnd(sc.getEntity().getRefCnt(), SearchCriteria.Op.EQ, 0);
+        TemplateDataStoreVO template = sc.find();
+        if (template != null) {
+            return templateFactory.getTemplate(template.getTemplateId(), store);
+        }
+
+        SearchCriteriaService<VolumeDataStoreVO, VolumeDataStoreVO> volSc = SearchCriteria2.create(VolumeDataStoreVO.class);
+        volSc.addAnd(volSc.getEntity().getLastUpdated(), SearchCriteria.Op.LT, bef);
+        volSc.addAnd(volSc.getEntity().getState(), SearchCriteria.Op.EQ, ObjectInDataStoreStateMachine.State.Ready);
+        volSc.addAnd(volSc.getEntity().getDataStoreId(), SearchCriteria.Op.EQ, store.getId());
+        volSc.addAnd(volSc.getEntity().getRefCnt(), SearchCriteria.Op.EQ, 0);
+        VolumeDataStoreVO volume = volSc.find();
+        if (volume != null) {
+            return volumeFactory.getVolume(volume.getVolumeId(), store);
+        }
+
+        SearchCriteriaService<SnapshotDataStoreVO, SnapshotDataStoreVO> snapshotSc = SearchCriteria2.create(SnapshotDataStoreVO.class);
+        snapshotSc.addAnd(snapshotSc.getEntity().getLastUpdated(), SearchCriteria.Op.LT, bef);
+        snapshotSc.addAnd(snapshotSc.getEntity().getState(), SearchCriteria.Op.EQ, ObjectInDataStoreStateMachine.State.Ready);
+        snapshotSc.addAnd(snapshotSc.getEntity().getDataStoreId(), SearchCriteria.Op.EQ, store.getId());
+        snapshotSc.addAnd(snapshotSc.getEntity().getRole(), SearchCriteria.Op.EQ, store.getRole());
+        snapshotSc.addAnd(snapshotSc.getEntity().getRefCnt(), SearchCriteria.Op.EQ, 0);
+        SnapshotDataStoreVO snapshot = snapshotSc.find();
+        if (snapshot != null) {
+            return snapshotFactory.getSnapshot(snapshot.getSnapshotId(), store);
+        }
+
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a715eb81/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
----------------------------------------------------------------------
diff --git a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java b/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
index a01d2d3..631de6a 100644
--- a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
+++ b/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
@@ -172,10 +172,11 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
                 EndPoint ep = selector.select(srcData, destData);
                 answer = ep.sendMessage(cmd);
             }
-            // clean up cache entry in case of failure
-            if (answer == null || !answer.getResult()) {
-                if (cacheData != null) {
+            if (cacheData != null) {
+                if (answer == null || !answer.getResult()) {
                     cacheMgr.deleteCacheObject(cacheData);
+                } else {
+                    cacheMgr.releaseCacheObject(cacheData);
                 }
             }
             return answer;
@@ -191,8 +192,9 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
 
     protected DataObject cacheSnapshotChain(SnapshotInfo snapshot) {
         DataObject leafData = null;
+        DataStore store = cacheMgr.getCacheStorage(snapshot.getDataStore().getScope());
         while (snapshot != null) {
-            DataObject cacheData = cacheMgr.createCacheObject(snapshot, snapshot.getDataStore().getScope());
+            DataObject cacheData = cacheMgr.createCacheObject(snapshot, store);
             if (leafData == null) {
                 leafData = cacheData;
             }
@@ -202,7 +204,10 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
     }
 
     protected void deleteSnapshotCacheChain(SnapshotInfo snapshot) {
-
+       while (snapshot != null) {
+           cacheMgr.deleteCacheObject(snapshot);
+           snapshot = snapshot.getParent();
+       }
     }
 
     protected Answer copyVolumeFromSnapshot(DataObject snapObj, DataObject volObj) {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a715eb81/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/DataMotionDriver.java
----------------------------------------------------------------------
diff --git a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/DataMotionDriver.java b/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/DataMotionDriver.java
deleted file mode 100644
index 3a59b21..0000000
--- a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/DataMotionDriver.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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.cloudstack.storage.motion;
-
-import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
-
-public interface DataMotionDriver {
-    public void copy(DataObject srcObj, DataObject destObj);
-}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a715eb81/engine/storage/image/src/org/apache/cloudstack/storage/image/ImageOrchestrator.java
----------------------------------------------------------------------
diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/ImageOrchestrator.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/ImageOrchestrator.java
deleted file mode 100644
index e4141f3..0000000
--- a/engine/storage/image/src/org/apache/cloudstack/storage/image/ImageOrchestrator.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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.cloudstack.storage.image;
-
-public interface ImageOrchestrator {
-    void registerTemplate(long templateId);
-
-    void registerSnapshot(long snapshotId);
-
-    void registerVolume(long volumeId);
-
-    void registerIso(long isoId);
-}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a715eb81/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java
index c06756e..96c35f3 100644
--- a/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java
+++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java
@@ -576,8 +576,6 @@ public class TemplateServiceImpl implements TemplateService {
             if (result.isFailed()) {
                 res.setResult(result.getResult());
                 destTemplate.processEvent(Event.OperationFailed);
-                // remove entry from template_store_ref
-                destTemplate.getDataStore().delete(destTemplate);
             } else {
                 destTemplate.processEvent(Event.OperationSuccessed, result.getAnswer());
             }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a715eb81/engine/storage/image/src/org/apache/cloudstack/storage/image/downloader/ImageDownloader.java
----------------------------------------------------------------------
diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/downloader/ImageDownloader.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/downloader/ImageDownloader.java
deleted file mode 100644
index af572d4..0000000
--- a/engine/storage/image/src/org/apache/cloudstack/storage/image/downloader/ImageDownloader.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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.cloudstack.storage.image.downloader;
-
-import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo;
-
-public interface ImageDownloader {
-    public void downloadImage(TemplateInfo template);
-}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a715eb81/engine/storage/image/src/org/apache/cloudstack/storage/image/manager/ImageStoreProviderManagerImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/manager/ImageStoreProviderManagerImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/manager/ImageStoreProviderManagerImpl.java
index 73c960f..64ef78f 100644
--- a/engine/storage/image/src/org/apache/cloudstack/storage/image/manager/ImageStoreProviderManagerImpl.java
+++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/manager/ImageStoreProviderManagerImpl.java
@@ -66,7 +66,6 @@ public class ImageStoreProviderManagerImpl implements ImageStoreProviderManager
         ImageStoreProvider provider = (ImageStoreProvider) providerManager.getDataStoreProvider(providerName);
         ImageStoreEntity imgStore = ImageStoreImpl
                 .getDataStore(dataStore, driverMaps.get(provider.getName()), provider);
-        // TODO Auto-generated method stub
         return imgStore;
     }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a715eb81/engine/storage/image/src/org/apache/cloudstack/storage/image/store/ImageStoreImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/ImageStoreImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/ImageStoreImpl.java
index a3da304..6d8e8e5 100644
--- a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/ImageStoreImpl.java
+++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/ImageStoreImpl.java
@@ -24,6 +24,7 @@ import java.util.concurrent.ExecutionException;
 
 import javax.inject.Inject;
 
+import com.cloud.capacity.dao.CapacityDao;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver;
 import org.apache.cloudstack.engine.subsystem.api.storage.ImageStoreProvider;
@@ -52,10 +53,11 @@ public class ImageStoreImpl implements ImageStoreEntity {
     VMTemplateDao imageDao;
     @Inject
     private ObjectInDataStoreManager objectInStoreMgr;
+    @Inject
+    private CapacityDao capacityDao;
     protected ImageStoreDriver driver;
     protected ImageStoreVO imageDataStoreVO;
     protected ImageStoreProvider provider;
-    boolean needDownloadToCacheStorage = false;
 
     public ImageStoreImpl() {
         super();
@@ -77,13 +79,11 @@ public class ImageStoreImpl implements ImageStoreEntity {
 
     @Override
     public Set<TemplateInfo> listTemplates() {
-        // TODO Auto-generated method stub
         return null;
     }
 
     @Override
     public DataStoreDriver getDriver() {
-        // TODO Auto-generated method stub
         return this.driver;
     }
 
@@ -94,7 +94,6 @@ public class ImageStoreImpl implements ImageStoreEntity {
 
     @Override
     public long getId() {
-        // TODO Auto-generated method stub
         return this.imageDataStoreVO.getId();
     }
 
@@ -110,19 +109,16 @@ public class ImageStoreImpl implements ImageStoreEntity {
 
     @Override
     public TemplateInfo getTemplate(long templateId) {
-        // TODO Auto-generated method stub
         return null;
     }
 
     @Override
     public VolumeInfo getVolume(long volumeId) {
-        // TODO Auto-generated method stub
         return null;
     }
 
     @Override
     public SnapshotInfo getSnapshot(long snapshotId) {
-        // TODO Auto-generated method stub
         return null;
     }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a715eb81/engine/storage/image/src/org/apache/cloudstack/storage/image/store/TemplateObject.java
----------------------------------------------------------------------
diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/TemplateObject.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/TemplateObject.java
index 72a8849..5ab52de 100644
--- a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/TemplateObject.java
+++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/TemplateObject.java
@@ -259,6 +259,48 @@ public class TemplateObject implements TemplateInfo {
     }
 
     @Override
+    public void incRefCount() {
+        if (this.dataStore == null) {
+            return;
+        }
+
+        if (this.dataStore.getRole() == DataStoreRole.Image ||
+                this.dataStore.getRole() == DataStoreRole.ImageCache) {
+            TemplateDataStoreVO store = templateStoreDao.findById(this.dataStore.getId());
+            store.incrRefCnt();
+            store.setLastUpdated(new Date());
+            templateStoreDao.update(store.getId(), store);
+        }
+    }
+
+    @Override
+    public void decRefCount() {
+        if (this.dataStore == null) {
+            return;
+        }
+        if (this.dataStore.getRole() == DataStoreRole.Image ||
+                this.dataStore.getRole() == DataStoreRole.ImageCache) {
+            TemplateDataStoreVO store = templateStoreDao.findById(this.dataStore.getId());
+            store.decrRefCnt();
+            store.setLastUpdated(new Date());
+            templateStoreDao.update(store.getId(), store);
+        }
+    }
+
+    @Override
+    public Long getRefCount() {
+        if (this.dataStore == null) {
+            return null;
+        }
+        if (this.dataStore.getRole() == DataStoreRole.Image ||
+                this.dataStore.getRole() == DataStoreRole.ImageCache) {
+            TemplateDataStoreVO store = templateStoreDao.findById(this.dataStore.getId());
+            return store.getRefCnt();
+        }
+        return null;
+    }
+
+    @Override
     public DataTO getTO() {
         DataTO to = null;
         if (this.dataStore == null) {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a715eb81/engine/storage/integration-test/test/org/apache/cloudstack/storage/allocator/StorageAllocatorTest.java
----------------------------------------------------------------------
diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/allocator/StorageAllocatorTest.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/allocator/StorageAllocatorTest.java
index 3d300de..40d9d41 100644
--- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/allocator/StorageAllocatorTest.java
+++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/allocator/StorageAllocatorTest.java
@@ -128,7 +128,7 @@ public class StorageAllocatorTest {
         storage.setClusterId(clusterId);
         storage.setStatus(StoragePoolStatus.Up);
         storage.setScope(ScopeType.CLUSTER);
-        storage.setAvailableBytes(1000);
+        storage.setUsedBytes(1000);
         storage.setCapacityBytes(20000);
         storage.setHostAddress(UUID.randomUUID().toString());
         storage.setPath(UUID.randomUUID().toString());
@@ -170,7 +170,7 @@ public class StorageAllocatorTest {
             storage.setClusterId(clusterId);
             storage.setStatus(StoragePoolStatus.Up);
             storage.setScope(ScopeType.CLUSTER);
-            storage.setAvailableBytes(1000);
+            storage.setUsedBytes(1000);
             storage.setCapacityBytes(20000);
             storage.setHostAddress(UUID.randomUUID().toString());
             storage.setPath(UUID.randomUUID().toString());

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a715eb81/engine/storage/integration-test/test/org/apache/cloudstack/storage/cache/manager/StorageCacheReplacementAlgorithmLRUTest.java
----------------------------------------------------------------------
diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/cache/manager/StorageCacheReplacementAlgorithmLRUTest.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/cache/manager/StorageCacheReplacementAlgorithmLRUTest.java
new file mode 100644
index 0000000..7d40ea7
--- /dev/null
+++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/cache/manager/StorageCacheReplacementAlgorithmLRUTest.java
@@ -0,0 +1,226 @@
+/*
+ * 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.cloudstack.storage.cache.manager;
+
+import com.cloud.storage.DataStoreRole;
+import com.cloud.storage.Storage;
+import com.cloud.storage.VMTemplateVO;
+import com.cloud.storage.dao.VMTemplateDao;
+import com.cloud.utils.DateUtil;
+import com.cloud.utils.component.ComponentContext;
+import junit.framework.Assert;
+import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
+import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
+import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider;
+import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
+import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
+import org.apache.cloudstack.storage.datastore.db.ImageStoreVO;
+import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
+import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import javax.inject.Inject;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.UUID;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(locations = "classpath:/storageContext.xml")
+public class StorageCacheReplacementAlgorithmLRUTest {
+    @Inject
+    VMTemplateDao templateDao;
+    @Inject
+    ImageStoreDao imageStoreDao;
+    @Inject
+    TemplateDataStoreDao templateDataStoreDao;
+    @Inject
+    StorageCacheReplacementAlgorithmLRU cacheReplacementAlgorithm;
+    @Inject
+    DataStoreManager dataStoreManager;
+    @Before
+    public void setup() throws Exception {
+        ComponentContext.initComponentsLifeCycle();
+    }
+    @Test
+    public void testSelectObject() {
+        cacheReplacementAlgorithm.setUnusedTimeInterval(1);
+        try {
+            VMTemplateVO template = new VMTemplateVO();
+            template.setTemplateType(Storage.TemplateType.USER);
+            template.setUrl(UUID.randomUUID().toString());
+            template.setUniqueName(UUID.randomUUID().toString());
+            template.setName(UUID.randomUUID().toString());
+            template.setPublicTemplate(true);
+            template.setFeatured(true);
+            template.setRequiresHvm(true);
+            template.setBits(64);
+            template.setFormat(Storage.ImageFormat.VHD);
+            template.setEnablePassword(true);
+            template.setEnableSshKey(true);
+            template.setGuestOSId(1);
+            template.setBootable(true);
+            template.setPrepopulate(true);
+            template.setCrossZones(true);
+            template.setExtractable(true);
+            template = templateDao.persist(template);
+
+            VMTemplateVO template2 = new VMTemplateVO();
+            template2.setTemplateType(Storage.TemplateType.USER);
+            template2.setUrl(UUID.randomUUID().toString());
+            template2.setUniqueName(UUID.randomUUID().toString());
+            template2.setName(UUID.randomUUID().toString());
+            template2.setPublicTemplate(true);
+            template2.setFeatured(true);
+            template2.setRequiresHvm(true);
+            template2.setBits(64);
+            template2.setFormat(Storage.ImageFormat.VHD);
+            template2.setEnablePassword(true);
+            template2.setEnableSshKey(true);
+            template2.setGuestOSId(1);
+            template2.setBootable(true);
+            template2.setPrepopulate(true);
+            template2.setCrossZones(true);
+            template2.setExtractable(true);
+            template2 = templateDao.persist(template2);
+
+            ImageStoreVO imageStoreVO = new ImageStoreVO();
+            imageStoreVO.setRole(DataStoreRole.ImageCache);
+            imageStoreVO.setName(UUID.randomUUID().toString());
+            imageStoreVO.setProviderName(DataStoreProvider.NFS_IMAGE);
+            imageStoreVO.setProtocol("nfs");
+            imageStoreVO.setUrl(UUID.randomUUID().toString());
+            imageStoreVO = imageStoreDao.persist(imageStoreVO);
+
+            Calendar cal = Calendar.getInstance();
+            cal.setTime(DateUtil.now());
+            cal.add(Calendar.DAY_OF_MONTH, -2);
+            Date date = cal.getTime();
+
+            TemplateDataStoreVO templateStoreVO1 = new TemplateDataStoreVO();
+            templateStoreVO1.setLastUpdated(date);
+            templateStoreVO1.setDataStoreRole(DataStoreRole.ImageCache);
+            templateStoreVO1.setDataStoreId(imageStoreVO.getId());
+            templateStoreVO1.setState(ObjectInDataStoreStateMachine.State.Ready);
+            templateStoreVO1.setCopy(true);
+            templateStoreVO1.setTemplateId(template.getId());
+            templateDataStoreDao.persist(templateStoreVO1);
+
+            TemplateDataStoreVO templateStoreVO2 = new TemplateDataStoreVO();
+            templateStoreVO2.setLastUpdated(date);
+            templateStoreVO2.setDataStoreRole(DataStoreRole.ImageCache);
+            templateStoreVO2.setDataStoreId(imageStoreVO.getId());
+            templateStoreVO2.setState(ObjectInDataStoreStateMachine.State.Ready);
+            templateStoreVO2.setCopy(true);
+            templateStoreVO2.setTemplateId(template2.getId());
+            templateDataStoreDao.persist(templateStoreVO2);
+
+            DataStore store = dataStoreManager.getDataStore(imageStoreVO.getId(), DataStoreRole.ImageCache);
+            Assert.assertNotNull(cacheReplacementAlgorithm.chooseOneToBeReplaced(store));
+
+        } catch (Exception e) {
+           Assert.fail();
+        }
+    }
+
+
+    @Test
+    public void testSelectObjectFailed() {
+        cacheReplacementAlgorithm.setUnusedTimeInterval(1);
+        try {
+            VMTemplateVO template = new VMTemplateVO();
+            template.setTemplateType(Storage.TemplateType.USER);
+            template.setUrl(UUID.randomUUID().toString());
+            template.setUniqueName(UUID.randomUUID().toString());
+            template.setName(UUID.randomUUID().toString());
+            template.setPublicTemplate(true);
+            template.setFeatured(true);
+            template.setRequiresHvm(true);
+            template.setBits(64);
+            template.setFormat(Storage.ImageFormat.VHD);
+            template.setEnablePassword(true);
+            template.setEnableSshKey(true);
+            template.setGuestOSId(1);
+            template.setBootable(true);
+            template.setPrepopulate(true);
+            template.setCrossZones(true);
+            template.setExtractable(true);
+            template = templateDao.persist(template);
+
+            VMTemplateVO template2 = new VMTemplateVO();
+            template2.setTemplateType(Storage.TemplateType.USER);
+            template2.setUrl(UUID.randomUUID().toString());
+            template2.setUniqueName(UUID.randomUUID().toString());
+            template2.setName(UUID.randomUUID().toString());
+            template2.setPublicTemplate(true);
+            template2.setFeatured(true);
+            template2.setRequiresHvm(true);
+            template2.setBits(64);
+            template2.setFormat(Storage.ImageFormat.VHD);
+            template2.setEnablePassword(true);
+            template2.setEnableSshKey(true);
+            template2.setGuestOSId(1);
+            template2.setBootable(true);
+            template2.setPrepopulate(true);
+            template2.setCrossZones(true);
+            template2.setExtractable(true);
+            template2 = templateDao.persist(template2);
+
+            ImageStoreVO imageStoreVO = new ImageStoreVO();
+            imageStoreVO.setRole(DataStoreRole.ImageCache);
+            imageStoreVO.setName(UUID.randomUUID().toString());
+            imageStoreVO.setProviderName(DataStoreProvider.NFS_IMAGE);
+            imageStoreVO.setProtocol("nfs");
+            imageStoreVO.setUrl(UUID.randomUUID().toString());
+            imageStoreVO = imageStoreDao.persist(imageStoreVO);
+
+
+            Date date = DateUtil.now();
+
+            TemplateDataStoreVO templateStoreVO1 = new TemplateDataStoreVO();
+            templateStoreVO1.setLastUpdated(date);
+            templateStoreVO1.setDataStoreRole(DataStoreRole.ImageCache);
+            templateStoreVO1.setDataStoreId(imageStoreVO.getId());
+            templateStoreVO1.setState(ObjectInDataStoreStateMachine.State.Ready);
+            templateStoreVO1.setCopy(true);
+            templateStoreVO1.setTemplateId(template.getId());
+            templateDataStoreDao.persist(templateStoreVO1);
+
+            TemplateDataStoreVO templateStoreVO2 = new TemplateDataStoreVO();
+            templateStoreVO2.setLastUpdated(date);
+            templateStoreVO2.setDataStoreRole(DataStoreRole.ImageCache);
+            templateStoreVO2.setDataStoreId(imageStoreVO.getId());
+            templateStoreVO2.setState(ObjectInDataStoreStateMachine.State.Ready);
+            templateStoreVO2.setCopy(true);
+            templateStoreVO2.setTemplateId(template2.getId());
+            templateDataStoreDao.persist(templateStoreVO2);
+
+            DataStore store = dataStoreManager.getDataStore(imageStoreVO.getId(), DataStoreRole.ImageCache);
+            Assert.assertNull(cacheReplacementAlgorithm.chooseOneToBeReplaced(store));
+
+        } catch (Exception e) {
+            Assert.fail();
+        }
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a715eb81/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/SnapshotTest.java
----------------------------------------------------------------------
diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/SnapshotTest.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/SnapshotTest.java
index 8210dfe..2579a38 100644
--- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/SnapshotTest.java
+++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/SnapshotTest.java
@@ -26,6 +26,8 @@ import java.util.concurrent.ExecutionException;
 
 import javax.inject.Inject;
 
+import junit.framework.Assert;
+
 import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
@@ -43,6 +45,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.TemplateService;
 import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
 import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
 import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService;
+import org.apache.cloudstack.engine.subsystem.api.storage.TemplateService.TemplateApiResult;
 import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService.VolumeApiResult;
 import org.apache.cloudstack.framework.async.AsyncCallFuture;
 import org.apache.cloudstack.storage.LocalHostEndpoint;
@@ -351,7 +354,7 @@ public class SnapshotTest extends CloudStackTestNGBase {
         return volume;
     }
 
-    public VolumeInfo createCopyBaseImage() {
+    public VolumeInfo createCopyBaseImage() throws InterruptedException, ExecutionException {
         DataStore primaryStore = createPrimaryDataStore();
         primaryStoreId = primaryStore.getId();
         primaryStore = this.dataStoreMgr.getPrimaryDataStore(primaryStoreId);
@@ -361,45 +364,13 @@ public class SnapshotTest extends CloudStackTestNGBase {
                 this.primaryStoreId, this.templateFactory.getTemplate(this.image.getId(), DataStoreRole.Image));
 
         VolumeApiResult result;
-        try {
-            result = future.get();
-            return result.getVolume();
-        } catch (InterruptedException e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
-        } catch (ExecutionException e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
-        }
-        return null;
+        result = future.get();
+        Assert.assertTrue(result.isSuccess());
+        return result.getVolume();
+        
     }
 
-    @Test
-    public void createSnapshot() {
-        VolumeInfo vol = createCopyBaseImage();
-        SnapshotVO snapshotVO = createSnapshotInDb(vol);
-        SnapshotInfo snapshot = this.snapshotFactory.getSnapshot(snapshotVO.getId(), vol.getDataStore());
-        SnapshotInfo newSnapshot = null;
-        for (SnapshotStrategy strategy : this.snapshotStrategies) {
-            if (strategy.canHandle(snapshot)) {
-                newSnapshot = strategy.takeSnapshot(snapshot);
-            }
-        }
-        AssertJUnit.assertNotNull(newSnapshot);
-
-        LocalHostEndpoint ep = new MockLocalHostEndPoint();
-        ep.setResource(new MockLocalNfsSecondaryStorageResource());
-        Mockito.when(epSelector.select(Matchers.any(DataStore.class))).thenReturn(ep);
-
-        // delete snapshot
-        for (SnapshotStrategy strategy : this.snapshotStrategies) {
-            if (strategy.canHandle(snapshot)) {
-                strategy.deleteSnapshot(newSnapshot.getId());
-            }
-        }
-
-        Mockito.when(epSelector.select(Matchers.any(DataStore.class))).thenReturn(remoteEp);
-    }
+   
 
     private VMTemplateVO createTemplateInDb() {
         VMTemplateVO image = new VMTemplateVO();
@@ -424,7 +395,7 @@ public class SnapshotTest extends CloudStackTestNGBase {
     }
 
     @Test
-    public void createVolumeFromSnapshot() {
+    public void createVolumeFromSnapshot() throws InterruptedException, ExecutionException {
         VolumeInfo vol = createCopyBaseImage();
         SnapshotVO snapshotVO = createSnapshotInDb(vol);
         SnapshotInfo snapshot = this.snapshotFactory.getSnapshot(snapshotVO.getId(), vol.getDataStore());
@@ -440,11 +411,13 @@ public class SnapshotTest extends CloudStackTestNGBase {
 
         VolumeVO volVO = createVolume(vol.getTemplateId(), vol.getPoolId());
         VolumeInfo newVol = this.volFactory.getVolume(volVO.getId());
-        this.volumeService.createVolumeFromSnapshot(newVol, newVol.getDataStore(), snapshot);
+        AsyncCallFuture<VolumeApiResult> volFuture = this.volumeService.createVolumeFromSnapshot(newVol, newVol.getDataStore(), snapshot);
+        VolumeApiResult apiResult = volFuture.get();
+        Assert.assertTrue(apiResult.isSuccess());
     }
 
     @Test
-    public void deleteSnapshot() {
+    public void deleteSnapshot() throws InterruptedException, ExecutionException {
         VolumeInfo vol = createCopyBaseImage();
         SnapshotVO snapshotVO = createSnapshotInDb(vol);
         SnapshotInfo snapshot = this.snapshotFactory.getSnapshot(snapshotVO.getId(), vol.getDataStore());
@@ -466,7 +439,7 @@ public class SnapshotTest extends CloudStackTestNGBase {
     }
 
     @Test
-    public void createTemplateFromSnapshot() {
+    public void createTemplateFromSnapshot() throws InterruptedException, ExecutionException {
         VolumeInfo vol = createCopyBaseImage();
         SnapshotVO snapshotVO = createSnapshotInDb(vol);
         SnapshotInfo snapshot = this.snapshotFactory.getSnapshot(snapshotVO.getId(), vol.getDataStore());
@@ -482,10 +455,46 @@ public class SnapshotTest extends CloudStackTestNGBase {
         LocalHostEndpoint ep = new LocalHostEndpoint();
         ep.setResource(new MockLocalNfsSecondaryStorageResource());
         Mockito.when(epSelector.select(Matchers.any(DataObject.class), Matchers.any(DataObject.class))).thenReturn(ep);
-        VMTemplateVO templateVO = createTemplateInDb();
-        TemplateInfo tmpl = this.templateFactory.getTemplate(templateVO.getId(), DataStoreRole.Image);
-        DataStore imageStore = this.dataStoreMgr.getImageStore(this.dcId);
-        this.imageService.createTemplateFromSnapshotAsync(snapshot, tmpl, imageStore);
+
+        try {
+            VMTemplateVO templateVO = createTemplateInDb();
+            TemplateInfo tmpl = this.templateFactory.getTemplate(templateVO.getId(), DataStoreRole.Image);
+            DataStore imageStore = this.dataStoreMgr.getImageStore(this.dcId);
+            AsyncCallFuture<TemplateApiResult> templateFuture = this.imageService.createTemplateFromSnapshotAsync(snapshot, tmpl, imageStore);
+            TemplateApiResult apiResult = templateFuture.get();
+            Assert.assertTrue(apiResult.isSuccess());
+        } finally {
+            Mockito.when(epSelector.select(Matchers.any(DataObject.class), Matchers.any(DataObject.class))).thenReturn(remoteEp);
+        }
+    }
+    
+    @Test
+    public void createSnapshot() throws InterruptedException, ExecutionException {
+        VolumeInfo vol = createCopyBaseImage();
+        SnapshotVO snapshotVO = createSnapshotInDb(vol);
+        SnapshotInfo snapshot = this.snapshotFactory.getSnapshot(snapshotVO.getId(), vol.getDataStore());
+        SnapshotInfo newSnapshot = null;
+        for (SnapshotStrategy strategy : this.snapshotStrategies) {
+            if (strategy.canHandle(snapshot)) {
+                newSnapshot = strategy.takeSnapshot(snapshot);
+            }
+        }
+        AssertJUnit.assertNotNull(newSnapshot);
+
+        LocalHostEndpoint ep = new MockLocalHostEndPoint();
+        ep.setResource(new MockLocalNfsSecondaryStorageResource());
+        Mockito.when(epSelector.select(Matchers.any(DataStore.class))).thenReturn(ep);
+
+        try {
+            for (SnapshotStrategy strategy : this.snapshotStrategies) {
+                if (strategy.canHandle(snapshot)) {
+                    boolean res = strategy.deleteSnapshot(newSnapshot.getId());
+                    Assert.assertTrue(res);
+                }
+            }
+        } finally {
+            Mockito.when(epSelector.select(Matchers.any(DataStore.class))).thenReturn(remoteEp);
+        }
     }
 
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a715eb81/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/VolumeTest.java
----------------------------------------------------------------------
diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/VolumeTest.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/VolumeTest.java
index ef5c4ca..70fdb1b 100644
--- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/VolumeTest.java
+++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/VolumeTest.java
@@ -26,6 +26,8 @@ import java.util.concurrent.ExecutionException;
 
 import javax.inject.Inject;
 
+import junit.framework.Assert;
+
 import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
@@ -39,6 +41,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.TemplateService;
 import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
 import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
 import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService;
+import org.apache.cloudstack.engine.subsystem.api.storage.TemplateService.TemplateApiResult;
 import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService.VolumeApiResult;
 import org.apache.cloudstack.framework.async.AsyncCallFuture;
 import org.apache.cloudstack.storage.RemoteHostEndPoint;
@@ -237,6 +240,7 @@ public class VolumeTest extends CloudStackTestNGBase {
         TemplateObjectTO to = new TemplateObjectTO();
         to.setPath(this.getImageInstallPath());
         to.setFormat(ImageFormat.VHD);
+        to.setSize(100L);
         CopyCmdAnswer answer = new CopyCmdAnswer(to);
         templateOnStore.processEvent(Event.CreateOnlyRequested);
         templateOnStore.processEvent(Event.OperationSuccessed, answer);
@@ -335,57 +339,52 @@ public class VolumeTest extends CloudStackTestNGBase {
             AssertJUnit.assertTrue(result.isSuccess());
 
             VolumeInfo newVol = result.getVolume();
-            this.volumeService.destroyVolume(newVol.getId());
+            boolean res = this.volumeService.destroyVolume(newVol.getId());
+            Assert.assertTrue(res);
             VolumeInfo vol = this.volFactory.getVolume(volume.getId());
-            this.volumeService.expungeVolumeAsync(vol);
+            future = this.volumeService.expungeVolumeAsync(vol);
+            result = future.get();
+            Assert.assertTrue(result.isSuccess());
         } catch (InterruptedException e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
+            Assert.fail(e.toString());
         } catch (ExecutionException e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
+            Assert.fail(e.toString());
         } catch (ConcurrentOperationException e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
+            Assert.fail(e.toString());
         }
     }
 
     @Test
-    public void testCreateDataDisk() {
+    public void testCreateDataDisk() throws InterruptedException, ExecutionException {
         DataStore primaryStore = createPrimaryDataStore();
         primaryStoreId = primaryStore.getId();
         primaryStore = this.dataStoreMgr.getPrimaryDataStore(primaryStoreId);
         VolumeVO volume = createVolume(null, primaryStore.getId());
         VolumeInfo volInfo = this.volFactory.getVolume(volume.getId());
-        this.volumeService.createVolumeAsync(volInfo, primaryStore);
+        AsyncCallFuture<VolumeApiResult> future = this.volumeService.createVolumeAsync(volInfo, primaryStore);
+        VolumeApiResult result = future.get();
+        Assert.assertTrue(result.isSuccess());
     }
 
     @Test
-    public void testDeleteDisk() {
+    public void testDeleteDisk() throws InterruptedException, ExecutionException, ConcurrentOperationException {
         DataStore primaryStore = createPrimaryDataStore();
         primaryStoreId = primaryStore.getId();
         primaryStore = this.dataStoreMgr.getPrimaryDataStore(primaryStoreId);
         VolumeVO volume = createVolume(null, primaryStore.getId());
         VolumeInfo volInfo = this.volFactory.getVolume(volume.getId());
         AsyncCallFuture<VolumeApiResult> future = this.volumeService.createVolumeAsync(volInfo, primaryStore);
-        try {
-            VolumeApiResult result = future.get();
-            VolumeInfo vol = result.getVolume();
 
-            this.volumeService.destroyVolume(volInfo.getId());
-            volInfo = this.volFactory.getVolume(vol.getId());
-            this.volumeService.expungeVolumeAsync(volInfo);
-        } catch (InterruptedException e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
-        } catch (ExecutionException e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
-        } catch (ConcurrentOperationException e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
-        }
+        VolumeApiResult result = future.get();
+        Assert.assertTrue(result.isSuccess());
+        VolumeInfo vol = result.getVolume();
 
+        boolean res = this.volumeService.destroyVolume(volInfo.getId());
+        Assert.assertTrue(res);
+        volInfo = this.volFactory.getVolume(vol.getId());
+        future = this.volumeService.expungeVolumeAsync(volInfo);
+        result = future.get();
+        Assert.assertTrue(result.isSuccess());
     }
 
     private VMTemplateVO createTemplateInDb() {
@@ -411,30 +410,24 @@ public class VolumeTest extends CloudStackTestNGBase {
     }
 
     @Test
-    public void testCreateTemplateFromVolume() {
+    public void testCreateTemplateFromVolume() throws InterruptedException, ExecutionException {
         DataStore primaryStore = createPrimaryDataStore();
         primaryStoreId = primaryStore.getId();
         primaryStore = this.dataStoreMgr.getPrimaryDataStore(primaryStoreId);
         VolumeVO volume = createVolume(null, primaryStore.getId());
         VolumeInfo volInfo = this.volFactory.getVolume(volume.getId());
         AsyncCallFuture<VolumeApiResult> future = this.volumeService.createVolumeAsync(volInfo, primaryStore);
-        try {
-            VolumeApiResult result = future.get();
 
-            AssertJUnit.assertTrue(result.isSuccess());
-            volInfo = result.getVolume();
-            VMTemplateVO templateVO = createTemplateInDb();
-            TemplateInfo tmpl = this.templateFactory.getTemplate(templateVO.getId(), DataStoreRole.Image);
-            DataStore imageStore = this.dataStoreMgr.getImageStore(this.dcId);
+        VolumeApiResult result = future.get();
 
-            this.imageService.createTemplateFromVolumeAsync(volInfo, tmpl, imageStore);
-        } catch (InterruptedException e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
-        } catch (ExecutionException e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
-        }
+        AssertJUnit.assertTrue(result.isSuccess());
+        volInfo = result.getVolume();
+        VMTemplateVO templateVO = createTemplateInDb();
+        TemplateInfo tmpl = this.templateFactory.getTemplate(templateVO.getId(), DataStoreRole.Image);
+        DataStore imageStore = this.dataStoreMgr.getImageStore(this.dcId);
 
+        AsyncCallFuture<TemplateApiResult> templateResult = this.imageService.createTemplateFromVolumeAsync(volInfo, tmpl, imageStore);
+        TemplateApiResult templateApiResult = templateResult.get();
+        Assert.assertTrue(templateApiResult.isSuccess());
     }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a715eb81/engine/storage/integration-test/test/resource/storageContext.xml
----------------------------------------------------------------------
diff --git a/engine/storage/integration-test/test/resource/storageContext.xml b/engine/storage/integration-test/test/resource/storageContext.xml
index cc8e3bf..9f4f102 100644
--- a/engine/storage/integration-test/test/resource/storageContext.xml
+++ b/engine/storage/integration-test/test/resource/storageContext.xml
@@ -43,9 +43,7 @@
   <bean id="objectInDataStoreDaoImpl" class="org.apache.cloudstack.storage.db.ObjectInDataStoreDaoImpl" />
   <bean id="primaryDataStoreDaoImpl" class="org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDaoImpl" />
   <bean id="primaryDataStoreDetailsDaoImpl" class="org.apache.cloudstack.storage.volume.db.PrimaryDataStoreDetailsDaoImpl" />
-  <bean id="snapshotDao2Impl" class="org.apache.cloudstack.storage.snapshot.db.SnapshotDao2Impl" />
   <bean id="templatePrimaryDataStoreDaoImpl" class="org.apache.cloudstack.storage.volume.db.TemplatePrimaryDataStoreDaoImpl" />
-  <bean id="volumeDao2Impl" class="org.apache.cloudstack.storage.volume.db.VolumeDao2Impl" />
   <bean id="LocalStoragePoolAllocator" class="org.apache.cloudstack.storage.allocator.LocalStoragePoolAllocator"/>
   <bean id="clusterScopeStoragePoolAllocator" class="org.apache.cloudstack.storage.allocator.ClusterScopeStoragePoolAllocator" />
   <bean id="zoneWideStoragePoolAllocator" class="org.apache.cloudstack.storage.allocator.ZoneWideStoragePoolAllocator" />
@@ -76,7 +74,6 @@
   <bean id="snapshotDataFactoryImpl" class="org.apache.cloudstack.storage.snapshot.SnapshotDataFactoryImpl" />
   <bean id="snapshotServiceImpl" class="org.apache.cloudstack.storage.snapshot.SnapshotServiceImpl" />
   <bean id="snapshotStateMachineManagerImpl" class="org.apache.cloudstack.storage.snapshot.SnapshotStateMachineManagerImpl" />
-  <bean id="templateInstallStrategyImpl" class="org.apache.cloudstack.storage.volume.TemplateInstallStrategyImpl" />
   <bean id="unknown" class="org.apache.cloudstack.storage.image.format.Unknown" />
   <bean id="VHD" class="org.apache.cloudstack.storage.image.format.VHD" />
   <bean id="volumeDataFactoryImpl" class="org.apache.cloudstack.storage.volume.VolumeDataFactoryImpl" />
@@ -88,4 +85,6 @@
   <bean id="BAREMETAL" class="org.apache.cloudstack.storage.image.format.BAREMETAL" />
   <bean id="storagePoolAutomationImpl" class="com.cloud.storage.StoragePoolAutomationImpl" />
   <bean id="AccountGuestVlanMapDaoImpl" class="com.cloud.network.dao.AccountGuestVlanMapDaoImpl" />
+  <bean id="StorageCacheReplacementAlgorithm" class="org.apache.cloudstack.storage.cache.manager.StorageCacheReplacementAlgorithmLRU" />
+  <bean id="ServiceOfferingDetailsDao" class="com.cloud.service.dao.ServiceOfferingDetailsDaoImpl" />
 </beans>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a715eb81/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java
----------------------------------------------------------------------
diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java
index bd14573..0310488 100644
--- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java
+++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java
@@ -22,6 +22,7 @@ import java.util.Date;
 
 import javax.inject.Inject;
 
+import com.cloud.storage.DataStoreRole;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
 import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
 import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory;
@@ -273,6 +274,47 @@ public class SnapshotObject implements SnapshotInfo {
         this.processEvent(event);
     }
 
+    public void incRefCount() {
+        if (this.store == null) {
+            return;
+        }
+
+        if (this.store.getRole() == DataStoreRole.Image ||
+                this.store.getRole() == DataStoreRole.ImageCache) {
+            SnapshotDataStoreVO store = snapshotStoreDao.findById(this.store.getId());
+            store.incrRefCnt();
+            store.setLastUpdated(new Date());
+            snapshotStoreDao.update(store.getId(), store);
+        }
+    }
+
+    @Override
+    public void decRefCount() {
+        if (this.store == null) {
+            return;
+        }
+        if (this.store.getRole() == DataStoreRole.Image ||
+                this.store.getRole() == DataStoreRole.ImageCache) {
+            SnapshotDataStoreVO store = snapshotStoreDao.findById(this.store.getId());
+            store.decrRefCnt();
+            store.setLastUpdated(new Date());
+            snapshotStoreDao.update(store.getId(), store);
+        }
+    }
+
+    @Override
+    public Long getRefCount() {
+        if (this.store == null) {
+            return null;
+        }
+        if (this.store.getRole() == DataStoreRole.Image ||
+                this.store.getRole() == DataStoreRole.ImageCache) {
+            SnapshotDataStoreVO store = snapshotStoreDao.findById(this.store.getId());
+            return store.getRefCnt();
+        }
+        return null;
+    }
+
     @Override
     public ObjectInDataStoreStateMachine.State getStatus() {
         return this.objectInStoreMgr.findObject(this, store).getObjectInStoreState();
@@ -280,8 +322,6 @@ public class SnapshotObject implements SnapshotInfo {
 
     @Override
     public void addPayload(Object data) {
-        // TODO Auto-generated method stub
-
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a715eb81/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java
index ed53811..631d220 100644
--- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java
+++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java
@@ -17,23 +17,19 @@
 
 package org.apache.cloudstack.storage.snapshot;
 
-import java.util.concurrent.ExecutionException;
-
-import javax.inject.Inject;
-
-import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
-import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionService;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
-import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
+import com.cloud.dc.dao.ClusterDao;
+import com.cloud.storage.DataStoreRole;
+import com.cloud.storage.Snapshot;
+import com.cloud.storage.VolumeManager;
+import com.cloud.storage.dao.SnapshotDao;
+import com.cloud.storage.dao.VolumeDao;
+import com.cloud.storage.snapshot.SnapshotManager;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.utils.fsm.NoTransitionException;
+import com.cloud.vm.dao.UserVmDao;
+import com.cloud.vm.snapshot.dao.VMSnapshotDao;
+import org.apache.cloudstack.engine.subsystem.api.storage.*;
 import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event;
-import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver;
-import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory;
-import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
-import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotResult;
-import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotService;
-import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
 import org.apache.cloudstack.framework.async.AsyncCallFuture;
 import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher;
 import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
@@ -47,19 +43,8 @@ import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO;
 import org.apache.log4j.Logger;
 import org.springframework.stereotype.Component;
 
-import com.cloud.dc.dao.ClusterDao;
-import com.cloud.storage.DataStoreRole;
-import com.cloud.storage.Snapshot;
-import com.cloud.storage.SnapshotVO;
-import com.cloud.storage.VolumeManager;
-import com.cloud.storage.dao.SnapshotDao;
-import com.cloud.storage.dao.VolumeDao;
-import com.cloud.storage.snapshot.SnapshotManager;
-import com.cloud.utils.db.DB;
-import com.cloud.utils.exception.CloudRuntimeException;
-import com.cloud.utils.fsm.NoTransitionException;
-import com.cloud.vm.dao.UserVmDao;
-import com.cloud.vm.snapshot.dao.VMSnapshotDao;
+import javax.inject.Inject;
+import java.util.concurrent.ExecutionException;
 
 @Component
 public class SnapshotServiceImpl implements SnapshotService {
@@ -391,7 +376,6 @@ public class SnapshotServiceImpl implements SnapshotService {
 
     @Override
     public boolean revertSnapshot(SnapshotInfo snapshot) {
-        // TODO Auto-generated method stub
         return false;
     }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a715eb81/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStateMachineManager.java
----------------------------------------------------------------------
diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStateMachineManager.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStateMachineManager.java
index f07db7e..2ad4ae7 100644
--- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStateMachineManager.java
+++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStateMachineManager.java
@@ -22,5 +22,5 @@ import com.cloud.storage.SnapshotVO;
 import com.cloud.utils.fsm.NoTransitionException;
 
 public interface SnapshotStateMachineManager {
-    public void processEvent(SnapshotVO snapshot, Event event) throws NoTransitionException;
+    void processEvent(SnapshotVO snapshot, Event event) throws NoTransitionException;
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a715eb81/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java
----------------------------------------------------------------------
diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java
index 0c3f31c..92af8c2 100644
--- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java
+++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java
@@ -194,7 +194,6 @@ public class XenserverSnapshotStrategy extends SnapshotStrategyBase {
     @Override
     public SnapshotInfo takeSnapshot(SnapshotInfo snapshot) {
         snapshot = snapshotSvr.takeSnapshot(snapshot).getSnashot();
-        // TODO: add async
         return this.backupSnapshot(snapshot);
     }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a715eb81/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/db/SnapshotDao2.java
----------------------------------------------------------------------
diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/db/SnapshotDao2.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/db/SnapshotDao2.java
deleted file mode 100644
index d531ede..0000000
--- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/db/SnapshotDao2.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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.cloudstack.storage.snapshot.db;
-
-import com.cloud.utils.db.GenericDao;
-
-public interface SnapshotDao2 extends GenericDao<SnapshotVO, Long> {
-
-}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a715eb81/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/db/SnapshotDao2Impl.java
----------------------------------------------------------------------
diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/db/SnapshotDao2Impl.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/db/SnapshotDao2Impl.java
deleted file mode 100644
index 74cec5e..0000000
--- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/db/SnapshotDao2Impl.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * 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.cloudstack.storage.snapshot.db;
-
-import org.springframework.stereotype.Component;
-
-import com.cloud.utils.db.GenericDaoBase;
-
-@Component
-public class SnapshotDao2Impl extends GenericDaoBase<SnapshotVO, Long> implements SnapshotDao2 {
-
-}