/**
* Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
*
* This software is licensed under the GNU General Public License v3 or later.
*
* It is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.cloud.storage.preallocatedlun.dao;
import java.math.BigDecimal;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import javax.ejb.Local;
import javax.naming.ConfigurationException;
import org.apache.log4j.Logger;
import com.cloud.storage.preallocatedlun.PreallocatedLunDetailVO;
import com.cloud.storage.preallocatedlun.PreallocatedLunVO;
import com.cloud.utils.component.ComponentLocator;
import com.cloud.utils.db.DB;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.db.SearchCriteria.Func;
import com.cloud.utils.exception.CloudRuntimeException;
@Local(value=PreallocatedLunDao.class) @DB(txn=false)
public class PreallocatedLunDaoImpl extends GenericDaoBase<PreallocatedLunVO, Long> implements PreallocatedLunDao {
private static final Logger s_logger = Logger.getLogger(PreallocatedLunDaoImpl.class);
final PreallocatedLunDetailsDao _detailsDao = ComponentLocator.inject(PreallocatedLunDetailsDaoImpl.class);
private final SearchBuilder<PreallocatedLunVO> TakeSearch;
private final SearchBuilder<PreallocatedLunVO> ReleaseSearch;
private final SearchBuilder<PreallocatedLunDetailVO> DetailsSearch;
private final SearchBuilder<PreallocatedLunVO> TotalSizeSearch;
private final SearchBuilder<PreallocatedLunVO> UsedSizeSearch;
private final SearchBuilder<PreallocatedLunVO> DeleteSearch;
private final String TakeSqlPrefix = "SELECT ext_lun_alloc.* FROM ext_lun_alloc LEFT JOIN ext_lun_details ON ext_lun_details.ext_lun_id = ext_lun_alloc.id WHERE (ext_lun_alloc.target_iqn=?) AND (ext_lun_alloc.size>=?) AND (ext_lun_alloc.size<=?) AND ";
private final String TakeSqlSuffix = " ext_lun_alloc.taken IS NULL GROUP BY ext_lun_details.ext_lun_id HAVING COUNT(ext_lun_details.tag) >= ? LIMIT 1 FOR UPDATE";
protected PreallocatedLunDaoImpl() {
TakeSearch = createSearchBuilder();
TakeSearch.and("taken", TakeSearch.entity().getTaken(), SearchCriteria.Op.NULL);
TakeSearch.done();
ReleaseSearch = createSearchBuilder();
ReleaseSearch.and("lun", ReleaseSearch.entity().getLun(), SearchCriteria.Op.EQ);
ReleaseSearch.and("target", ReleaseSearch.entity().getTargetIqn(), SearchCriteria.Op.EQ);
ReleaseSearch.and("taken", ReleaseSearch.entity().getTaken(), SearchCriteria.Op.NNULL);
ReleaseSearch.and("instanceId", ReleaseSearch.entity().getVolumeId(), SearchCriteria.Op.EQ);
ReleaseSearch.done();
DetailsSearch = _detailsDao.createSearchBuilder();
SearchBuilder<PreallocatedLunVO> targetSearch = createSearchBuilder();
targetSearch.and("targetiqn", targetSearch.entity().getTargetIqn(), SearchCriteria.Op.EQ);
DetailsSearch.join("target", targetSearch, targetSearch.entity().getId(), DetailsSearch.entity().getLunId());
DetailsSearch.select(Func.DISTINCT, DetailsSearch.entity().getTag());
DetailsSearch.done();
targetSearch.done();
TotalSizeSearch = createSearchBuilder();
TotalSizeSearch.and("target", TotalSizeSearch.entity().getTargetIqn(), SearchCriteria.Op.EQ);
TotalSizeSearch.select(Func.SUM, TotalSizeSearch.entity().getSize());
TotalSizeSearch.done();
UsedSizeSearch = createSearchBuilder();
UsedSizeSearch.and("target", UsedSizeSearch.entity().getTargetIqn(), SearchCriteria.Op.EQ);
UsedSizeSearch.and("taken", UsedSizeSearch.entity().getTaken(), SearchCriteria.Op.NNULL);
UsedSizeSearch.select(Func.SUM, UsedSizeSearch.entity().getSize());
UsedSizeSearch.done();
DeleteSearch = createSearchBuilder();
DeleteSearch.and("id", DeleteSearch.entity().getId(), SearchCriteria.Op.EQ);
DeleteSearch.and("taken", DeleteSearch.entity().getTaken(), SearchCriteria.Op.NULL);
DeleteSearch.done();
}
@Override
public boolean delete(long id) {
SearchCriteria sc = DeleteSearch.create();
sc.setParameters("id", id);
return delete(sc) > 0;
}
@Override
public boolean release(String targetIqn, int lunId, long instanceId) {
SearchCriteria sc = ReleaseSearch.create();
sc.setParameters("lun", lunId);
sc.setParameters("target", targetIqn);
sc.setParameters("instanceId", instanceId);
PreallocatedLunVO vo = createForUpdate();
vo.setTaken(null);
vo.setVolumeId(null);
return update(vo, sc) > 0;
}
@Override @DB
public PreallocatedLunVO take(long volumeId, String targetIqn, long size1, long size2, String... tags) {
StringBuilder sql = new StringBuilder(TakeSqlPrefix);
if (tags.length > 0) {
sql.append("(");
for (String tag : tags) {
sql.append("ext_lun_details.tag=?").append(" OR ");
}
sql.delete(sql.length() - 4, sql.length());
sql.append(") AND ");
}
sql.append(TakeSqlSuffix);
try {
Transaction txn = Transaction.currentTxn();
txn.start();
PreparedStatement pstmt = txn.prepareAutoCloseStatement(sql.toString());
int i = 1;
pstmt.setString(i++, targetIqn);
pstmt.setLong(i++, size1);
pstmt.setLong(i++, size2);
for (String tag : tags) {
pstmt.setString(i++, tag);
}
pstmt.setInt(i++, tags.length);
ResultSet rs = pstmt.executeQuery();
s_logger.debug("Statement is " + pstmt.toString());
if (!rs.next()) {
return null;
}
PreallocatedLunVO lun = toEntityBean(rs, false);
lun.setTaken(new Date());
lun.setVolumeId(volumeId);
update(lun.getId(), lun);
txn.commit();
return lun;
} catch (SQLException e) {
throw new CloudRuntimeException("Unable to execute " + sql.toString(), e);
}
}
@Override @DB
public List<PreallocatedLunVO> listDistinctTargets(long dataCenterId) {
String DistinctTargetSearchSql = "SELECT * FROM ext_lun_alloc where data_center_id = ? GROUP BY target_iqn";
Transaction txn = Transaction.currentTxn();
try {
PreparedStatement ps = txn.prepareAutoCloseStatement(DistinctTargetSearchSql);
ps.setLong(1, dataCenterId);
ResultSet rs = ps.executeQuery();
List<PreallocatedLunVO> lst = new ArrayList<PreallocatedLunVO>();
while (rs.next()) {
lst.add(toEntityBean(rs, false));
}
return lst;
} catch (SQLException e) {
throw new CloudRuntimeException("Unable to execute " + DistinctTargetSearchSql, e);
}
}
@Override
public long getTotalSize(String targetIqn) {
SearchCriteria sc = TotalSizeSearch.create();
sc.setParameters("target", targetIqn);
List<Object[]> results = searchAll(sc, null);
if (results.size() == 0 || results.get(0)[0] == null) {
return 0;
}
return ((BigDecimal)(results.get(0)[0])).longValue();
}
@Override
public long getUsedSize(String targetIqn) {
SearchCriteria sc = UsedSizeSearch.create();
sc.setParameters("target", targetIqn);
List<Object[]> results = searchAll(sc, null);
if (results.size() == 0 || results.get(0)[0] == null) {
return 0;
}
return ((BigDecimal)(results.get(0)[0])).longValue();
}
@Override
public List<String> findDistinctTagsForTarget(String targetIqn) {
SearchCriteria sc = DetailsSearch.create();
sc.setJoinParameters("target", "targetiqn", targetIqn);
List<Object[]> results = _detailsDao.searchAll(sc);
List<String> tags = new ArrayList<String>(results.size());
for (Object[] result : results) {
tags.add((String)result[0]);
}
return tags;
}
@Override @DB
public PreallocatedLunVO persist(PreallocatedLunVO lun, String[] tags) {
Transaction txn = Transaction.currentTxn();
txn.start();
lun = persist(lun);
for (String tag : tags) {
PreallocatedLunDetailVO detail = new PreallocatedLunDetailVO(lun.getId(), tag);
_detailsDao.persist(detail);
}
txn.commit();
return lun;
}
@Override
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
super.configure(name, params);
_detailsDao.configure(name, params);
return true;
}
}