/*
* Data Hub Service (DHuS) - For Space data distribution.
* Copyright (C) 2013,2014,2015 GAEL Systems
*
* This file is part of DHuS software sources.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.gael.dhus.datastore.eviction;
import fr.gael.dhus.database.dao.EvictionDao;
import fr.gael.dhus.database.dao.ProductDao;
import fr.gael.dhus.database.object.Eviction;
import fr.gael.dhus.database.object.Product;
import fr.gael.dhus.database.object.config.system.ArchiveConfiguration;
import fr.gael.dhus.datastore.exception.DataStoreException;
import fr.gael.dhus.service.ProductService;
import fr.gael.dhus.system.config.ConfigurationManager;
import java.io.File;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* Manages eviction functions
*
*/
@Service
public class EvictionManager
{
private static final Logger LOGGER = LogManager.getLogger(EvictionManager.class);
@Autowired
private ProductDao productDao;
@Autowired
private EvictionDao evictionDao;
@Autowired
private ConfigurationManager cfgManager;
@Autowired
private ProductService productService;
private EvictionManager(){}
/**
* Computes the path to be evicted. If the incoming path has been
* entered, eviction spaces is managed according to this directory.
* Otherwise it is computed from the archive data path.
*
* @return the path where the eviction is performed.
*/
private String getPath ()
{
ArchiveConfiguration archive = cfgManager.getArchiveConfiguration ();
String path = archive.getIncomingConfiguration ().getPath ();
if (path == null) path = archive.getPath ();
return path;
}
/**
* Computes the date <i>days</i> days ago.
*
* @param days number of days
* @return a date representation of date <i>days</i> ago.
*/
public Date getKeepPeriod (int days)
{
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DAY_OF_YEAR, -days);
LOGGER.info("Eviction Max date : " + cal.getTime());
return cal.getTime();
}
/**
* Computes free space on disk where the eviction works.
*
* @return number of available bytes on disk partition.
*/
public long getFreeSpace ()
{
String path = getPath ();
File fpath = new File(path);
return fpath.getFreeSpace ();
}
/**
* Computes the total space on disk where the eviction works.
*
* @return the total space in byte on disk partition.
*/
public long getTotalSpace ()
{
String path = getPath ();
File fpath = new File(path);
return fpath.getTotalSpace ();
}
/**
* Compute space disk usage on partition where the eviction works.
*
* @return space disk usage in bytes on disk partition.
*/
public long getUsableSpace ()
{
String path = getPath ();
File fpath = new File(path);
return fpath.getUsableSpace ();
}
/**
* Compute percentage of usage space disk of eviction partition.
*
* @return space disk usage in percent on disk partition.
* @see EvictionManager#getUsableSpace()
* @see EvictionManager#getTotalSpace()
*/
public float getSpaceUsagePercentage ()
{
return 100-(((float)getUsableSpace ()/getTotalSpace ())*100.0f);
}
/**
* Check if the limit of disk usage is exceeded
*
* @param eviction eviction system contains the limit of disk usage.
* @return true if disk usage of <i>eviction</i> is exceeded, otherwise false
*/
public boolean canEvictFromArchive (Eviction eviction)
{
if ((getSpaceUsagePercentage() > eviction.getMaxDiskUsage ()))
return true;
return false;
}
/**
* Seeks all products ingested <i>keep_period</i> days ago or more.
*
* @param keep_period number of days.
* @return a iterator of {@link Product}.
*/
public Iterator<Product> getProductsByIngestionDate(int keep_period)
{
return productDao.getProductsByIngestionDate (getKeepPeriod (keep_period));
}
/**
* Seeks the least watched products on the given period.
* @param keep_period the period in day.
* @return a iterator of {@link Product}.
*/
public Iterator<Product> getProductsByLowestAccess (int keep_period)
{
// FIXME never call
return productDao.getProductsLowerAccess (getKeepPeriod (keep_period));
}
/**
* Compute of next evictable products
*/
public void computeNextProducts ()
{
Eviction eviction = evictionDao.getEviction ();
if (eviction == null)
{
LOGGER.warn("No Eviction setting found.");
return;
}
Set<Product>products = eviction.getStrategy ().getProductsToEvict (
eviction);
evictionDao.setProducts (products);
}
/**
* Returns the next evictable products.
* @return a set of {@link Product}.
*/
public Set<Product>getProducts ()
{
return evictionDao.getEviction ().getProducts ();
}
/**
* Performs a eviction of products.
*/
public void doEvict ()
{
Set<Product>products = getProducts ();
evictionDao.setProducts (new HashSet<Product> ());
int evicted = 0;
if (products != null)
{
evicted = products.size ();
doEvict (products);
}
if (evicted == 0)
{
LOGGER.info("No product Evicted.");
}
}
/**
* Evicts <i>products</i> in a new {@link Thread}
*
* @param products set of products to evict.
*/
public void doEvict(Set<Product>products)
{
Thread t = new Thread (new DeleteProductTask (products),
"doEvictionTread");
t.start ();
}
private class DeleteProductTask implements Runnable
{
private Set<Product> products;
public DeleteProductTask (Set<Product> products)
{
this.products = products;
}
@Override
public void run()
{
for (Product product:products)
{
String path = ProductDao.getPathFromProduct (product);
path = path.replaceAll ("file://?", "/");
LOGGER.info("Trying to evict product \"" + path + "\".");
try
{
productService.systemDeleteProduct (product.getId ());
LOGGER.info("Evicted " + product.getIdentifier () + " (" +
product.getSize () + " bytes, " +
product.getDownloadableSize () + " bytes compressed)");
}
catch (DataStoreException e)
{
LOGGER.error("Unable to delete product at path \"" + path +
"\": " + e.getMessage (), e);
}
}
}
}
}