/*
* Copyright 1999-2008 University of Chicago
*
* Licensed 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.globus.workspace.persistence;
import java.io.IOException;
import java.sql.Blob;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;
import javax.sql.DataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.globus.workspace.Lager;
import org.globus.workspace.WorkspaceConstants;
import org.globus.workspace.async.AsyncRequest;
import org.globus.workspace.creation.IdempotentInstance;
import org.globus.workspace.creation.IdempotentReservation;
import org.globus.workspace.creation.defaults.IdempotentInstanceImpl;
import org.globus.workspace.creation.defaults.IdempotentReservationImpl;
import org.globus.workspace.network.Association;
import org.globus.workspace.network.AssociationEntry;
import org.globus.workspace.persistence.impls.*;
import org.globus.workspace.async.backfill.Backfill;
import org.globus.workspace.scheduler.defaults.ResourcepoolEntry;
import org.globus.workspace.service.CoschedResource;
import org.globus.workspace.service.GroupResource;
import org.globus.workspace.service.InstanceResource;
import org.globus.workspace.service.binding.vm.FileCopyNeed;
import org.globus.workspace.service.binding.vm.VirtualMachine;
import org.globus.workspace.service.binding.vm.VirtualMachinePartition;
import org.nimbustools.api._repr._SpotPriceEntry;
import org.nimbustools.api.repr.CannotTranslateException;
import org.nimbustools.api.repr.ReprFactory;
import org.nimbustools.api.repr.SpotPriceEntry;
import org.nimbustools.api.services.rm.DoesNotExistException;
import org.nimbustools.api.services.rm.ManageException;
public class PersistenceAdapterImpl implements WorkspaceConstants,
PersistenceAdapterConstants,
PersistenceAdapter {
// -------------------------------------------------------------------------
// STATIC VARIABLES
// -------------------------------------------------------------------------
private static final Log logger =
LogFactory.getLog(PersistenceAdapterImpl.class.getName());
private static final int[] EMPTY_INT_ARRAY = new int[0];
// -------------------------------------------------------------------------
// INSTANCE VARIABLES
// -------------------------------------------------------------------------
private final Lager lager;
private final DataSource dataSource;
private final boolean dbTrace;
private final ReprFactory repr;
// caches, todo: ehcache
private Hashtable associations;
// -------------------------------------------------------------------------
// CONSTRUCTOR
// -------------------------------------------------------------------------
public PersistenceAdapterImpl(DataSource dataSourceImpl,
Lager lagerImpl,
DBLoader loader,
ReprFactory reprImpl) throws Exception {
if (dataSourceImpl == null) {
throw new IllegalArgumentException("dataSource may not be null");
}
this.dataSource = dataSourceImpl;
if (lagerImpl == null) {
throw new IllegalArgumentException("lager may not be null");
}
this.lager = lagerImpl;
this.dbTrace = lagerImpl.dbLog;
if (reprImpl == null) {
throw new IllegalArgumentException("reprImpl may not be null");
}
this.repr = reprImpl;
if (loader == null) {
throw new IllegalArgumentException("loader may not be null");
}
if (!loader.isLoaded()) {
throw new Exception("DBLoader reporting not loaded (?)");
}
try {
this.prepareStatements();
} catch (SQLException sql) {
throw new Exception("Problem preparing DB statements: ", sql);
}
}
// -------------------------------------------------------------------------
// SETUP
// -------------------------------------------------------------------------
/**
* This moves significant prepared statement setup times to service
* initialization instead of the first time they're used.
*
* Documentation states that PreparedStatement caches are per pool
* connection but testing indicates with Derby (in embedded mode),
* this is OK using one connection.
*
* @throws SQLException problem
*/
private void prepareStatements() throws SQLException {
if (this.dbTrace) {
logger.debug("prepareStatements()");
}
long mstart = 0;
if (this.lager.perfLog) {
mstart = System.currentTimeMillis();
}
//String[] ins =
// PersistenceAdapterConstants.INSENSITIVE_PREPARED_STATEMENTS;
final String[] pstmts = PREPARED_STATEMENTS;
Connection c = null;
PreparedStatement pstmt = null;
try {
c = getConnection();
//for (int i = 0; i < ins.length; i++) {
// pstmt = c.prepareStatement(ins[i],
// ResultSet.TYPE_SCROLL_INSENSITIVE,
// ResultSet.CONCUR_UPDATABLE);
// pstmt.close();
//}
for (int i = 0; i < pstmts.length; i++) {
pstmt = c.prepareStatement(pstmts[i]);
pstmt.close();
}
pstmt = null;
} catch(SQLException e) {
logger.error("",e);
throw e;
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
if (this.lager.perfLog) {
final long mstop = System.currentTimeMillis();
logger.debug("_perf: prepareStatements() took " +
Long.toString(mstop - mstart) + " ms");
}
}
}
/* ********* */
/* DB access */
/* ********* */
public void setState(int id, int state, Throwable t)
throws WorkspaceDatabaseException{
if (this.dbTrace) {
logger.trace("setState(): " + Lager.id(id) + ", state = " + state);
}
final byte[] faultBytes;
try {
faultBytes = ErrorUtil.toByteArray(t);
} catch (IOException e) {
throw new WorkspaceDatabaseException(e);
}
Connection c = null;
PreparedStatement pstmt = null;
try {
c = getConnection();
pstmt = c.prepareStatement(SQL_SET_STATE);
pstmt.setInt(1,state);
if (faultBytes != null) {
pstmt.setObject(2, faultBytes, Types.BLOB);
} else {
pstmt.setNull(2, Types.BLOB);
}
pstmt.setInt(3,id);
final int updated = pstmt.executeUpdate();
if (this.dbTrace) {
logger.trace(Lager.id(id) + ": updated " + updated + " rows");
}
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
public void setTargetState(int id, int targetState)
throws WorkspaceDatabaseException{
if (this.dbTrace) {
logger.trace("setTargetState(): " + Lager.id(id) +
", targetState = " + targetState);
}
Connection c = null;
PreparedStatement pstmt = null;
try {
c = getConnection();
pstmt = c.prepareStatement(SQL_SET_TARGET_STATE);
pstmt.setInt(1,targetState);
pstmt.setInt(2,id);
final int updated = pstmt.executeUpdate();
if (this.dbTrace) {
logger.trace(Lager.id(id) + ": updated " + updated + " rows");
}
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
public void setOpsEnabled(int id, boolean enabled)
throws WorkspaceDatabaseException{
if (this.dbTrace) {
logger.trace("setOpsEnabled(): " + Lager.id(id) +
", enabled = " + enabled);
}
Connection c = null;
PreparedStatement pstmt = null;
try {
c = getConnection();
pstmt = c.prepareStatement(SQL_SET_OPS_ENABLED);
if (enabled) {
pstmt.setInt(1, 1);
} else {
pstmt.setInt(1, 0);
}
pstmt.setInt(2,id);
final int updated = pstmt.executeUpdate();
if (this.dbTrace) {
logger.trace(Lager.id(id) + ": updated " + updated + " rows");
}
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
public void setNetwork(int id, String network)
throws WorkspaceDatabaseException{
if (this.dbTrace) {
logger.trace("setNetwork(): " + Lager.id(id) +
", network = " + network);
}
Connection c = null;
PreparedStatement pstmt = null;
try {
c = getConnection();
pstmt = c.prepareStatement(SQL_SET_NETWORKING);
if (network != null) {
pstmt.setString(1, network);
} else {
pstmt.setNull(1, Types.VARCHAR);
}
pstmt.setInt(2,id);
final int updated = pstmt.executeUpdate();
if (this.dbTrace) {
logger.trace(Lager.id(id) + ": updated " + updated + " rows");
}
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
public void setVMMaccessOK(int resourceID, boolean accessOK)
throws WorkspaceDatabaseException {
if (this.dbTrace) {
logger.trace("setVMMaccessOK(): " + Lager.id(resourceID)
+ ", OK? " + accessOK);
}
Connection c = null;
PreparedStatement pstmt = null;
try {
c = getConnection();
pstmt = c.prepareStatement(SQL_SET_VMM_ACCESS_OK);
if (accessOK) {
pstmt.setInt(1, 1);
} else {
pstmt.setInt(1, 0);
}
pstmt.setInt(2, resourceID);
final int updated = pstmt.executeUpdate();
if (this.dbTrace) {
logger.trace(Lager.id(resourceID) + ": updated " +
updated + " rows");
}
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
public void setHostname(int id, String hostname)
throws WorkspaceDatabaseException{
if (this.dbTrace) {
logger.trace("setHostname(): " + Lager.id(id) +
", hostname = " + hostname);
}
Connection c = null;
PreparedStatement pstmt = null;
try {
c = getConnection();
pstmt = c.prepareStatement(SQL_SET_HOSTNAME);
if (hostname != null) {
pstmt.setString(1, hostname);
} else {
pstmt.setNull(1, Types.VARCHAR);
}
pstmt.setInt(2,id);
final int updated = pstmt.executeUpdate();
if (this.dbTrace) {
logger.trace(Lager.id(id) + ": updated " + updated + " rows");
}
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
public void setRootUnpropTarget(int id, String path)
throws WorkspaceDatabaseException {
if (this.dbTrace) {
logger.trace("setRootUnpropTarget(): " + Lager.id(id) +
", path = " + path);
}
Connection c = null;
PreparedStatement pstmt = null;
try {
c = getConnection();
// we need two SQL statements because unprop is known to be needed
// if setting path, but unknown if clearing it
if (path == null) {
pstmt = c.prepareStatement(SQL_UNSET_ROOT_UNPROP_TARGET);
pstmt.setNull(1, Types.VARCHAR);
pstmt.setInt(2,id);
} else {
pstmt = c.prepareStatement(SQL_SET_ROOT_UNPROP_TARGET);
pstmt.setString(1, path);
pstmt.setInt(2,id);
}
final int updated = pstmt.executeUpdate();
if (this.dbTrace) {
logger.trace(Lager.id(id) + ": updated " + updated + " rows");
}
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
public void addCustomizationNeed(int id, FileCopyNeed need)
throws WorkspaceDatabaseException {
if (this.dbTrace) {
logger.trace("addFileCopyNeed(): " + Lager.id(id));
}
if (need == null) {
throw new IllegalArgumentException("need may not be null");
}
Connection c = null;
PreparedStatement pstmt = null;
try {
c = getConnection();
pstmt = c.prepareStatement(SQL_INSERT_FILE_COPY);
pstmt.setInt(1, id);
pstmt.setString(2, need.sourcePath);
pstmt.setString(3, need.destPath);
if (need.onImage()) {
pstmt.setInt(4, 1);
} else {
pstmt.setInt(4, 0);
}
final int updated = pstmt.executeUpdate();
if (this.dbTrace) {
logger.trace(Lager.id(id) + ": updated " + updated + " rows");
}
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
public void setFileCopyOnImage(int id, FileCopyNeed need)
throws WorkspaceDatabaseException {
if (this.dbTrace) {
logger.trace("setFileCopyOnImage(): " + Lager.id(id) +
", on image = " + need.onImage());
}
Connection c = null;
PreparedStatement pstmt = null;
try {
c = getConnection();
pstmt = c.prepareStatement(SQL_SET_FILE_COPY_ON_IMAGE);
if (need.onImage()) {
pstmt.setInt(1, 1);
} else {
pstmt.setInt(1, 0);
}
pstmt.setInt(2, id);
pstmt.setString(3, need.sourcePath);
pstmt.setString(4, need.destPath);
final int updated = pstmt.executeUpdate();
if (this.dbTrace) {
logger.trace(Lager.id(id) + ": updated " + updated + " rows");
}
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
public void setStartTime(int id, Calendar startTime)
throws WorkspaceDatabaseException {
if (this.dbTrace) {
logger.trace("setStartTime(): " + Lager.id(id) +
", startTime = " + startTime);
}
Connection c = null;
PreparedStatement pstmt = null;
try {
c = getConnection();
pstmt = c.prepareStatement(SQL_SET_STARTTIME);
if (startTime != null) {
pstmt.setObject(1,
new Long(startTime.getTimeInMillis()));
} else {
pstmt.setInt(1, 0);
}
pstmt.setInt(2,id);
final int updated = pstmt.executeUpdate();
if (this.dbTrace) {
logger.trace(Lager.id(id) + ": updated " + updated + " rows");
}
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
public void setTerminationTime(int id, Calendar termTime)
throws WorkspaceDatabaseException {
if (this.dbTrace) {
logger.trace("setTerminationTime(): " + Lager.id(id) +
", startTime = " + termTime);
}
Connection c = null;
PreparedStatement pstmt = null;
try {
c = getConnection();
pstmt = c.prepareStatement(SQL_SET_TERMTIME);
if (termTime != null) {
pstmt.setObject(1,
new Long(termTime.getTimeInMillis()));
} else {
pstmt.setInt(1, 0);
}
pstmt.setInt(2,id);
final int updated = pstmt.executeUpdate();
if (this.dbTrace) {
logger.trace(Lager.id(id) + ": updated " + updated + " rows");
}
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
public void remove(int id, InstanceResource resource)
throws WorkspaceDatabaseException {
if (this.dbTrace) {
logger.trace("remove(): " + Lager.id(id)
+ ", resource = " + resource);
}
if (id < 0) {
throw new WorkspaceDatabaseException("id is less than zero");
}
Connection c = null;
PreparedStatement pstmt = null;
PreparedStatement[] pstmts = null;
try {
c = getConnection();
c.setAutoCommit(false);
pstmt = c.prepareStatement(SQL_DELETE_RESOURCE);
pstmt.setInt(1, id);
int numMod = pstmt.executeUpdate();
if (this.dbTrace) {
logger.trace(Lager.id(id) + " resources: removed "
+ numMod + " rows");
}
if (resource.getVM() != null) {
pstmts = VirtualMachinePersistenceUtil.
getRemoveVM(resource.getVM(), id, c);
}
if (pstmts != null) {
for (int i = 0; i < pstmts.length; i++) {
numMod = pstmts[i].executeUpdate();
if (this.dbTrace) {
logger.trace(Lager.id(id) + " vm record: removed "
+ numMod + " rows");
}
}
}
c.commit();
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
if (pstmts != null) {
for (int i = 0; i < pstmts.length; i++) {
pstmts[i].close();
}
}
if (c != null) {
c.setAutoCommit(true);
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
public void removeGroup(String id)
throws WorkspaceDatabaseException {
if (this.dbTrace) {
logger.trace("removeGroup(): " + Lager.groupid(id));
}
this.removeGroupOrEnsemble(id);
}
public void removeEnsemble(String id)
throws WorkspaceDatabaseException {
if (this.dbTrace) {
logger.trace("removeEnsemble(): " + Lager.ensembleid(id));
}
this.removeGroupOrEnsemble(id);
}
private void removeGroupOrEnsemble(String id)
throws WorkspaceDatabaseException {
Connection c = null;
PreparedStatement pstmt = null;
try {
c = getConnection();
pstmt = c.prepareStatement(SQL_DELETE_GROUP_RESOURCE);
pstmt.setString(1, id);
final int removed = pstmt.executeUpdate();
if (this.dbTrace) {
logger.trace(Lager.groupid(id) + " groupresources: removed "
+ removed + " rows");
}
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
public int[] findActiveWorkspacesIDs() throws WorkspaceDatabaseException {
if (this.dbTrace) {
logger.trace("findActiveWorkspacesIDs()");
}
Connection c = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
c = getConnection();
pstmt = c.prepareStatement(SQL_SELECT_RESOURCES);
rs = pstmt.executeQuery();
final ArrayList results = new ArrayList();
if (rs == null || !rs.next()) {
return null;
} else {
do {
final Integer id = new Integer(rs.getInt(1));
results.add(id);
if (this.dbTrace) {
logger.trace("found id: " + id);
}
} while (rs.next());
}
// can't use toArray without converting to Integer[]
final int[] ret = new int[results.size()];
for (int i = 0; i < ret.length; i++) {
ret[i] = ((Number) results.get(i)).intValue();
}
return ret;
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (rs != null) {
rs.close();
}
if (pstmt != null) {
pstmt.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
public boolean isActiveWorkspaceID(int id)
throws WorkspaceDatabaseException {
if (this.dbTrace) {
logger.trace("isActiveWorkspaceID(), id = " + id);
}
Connection c = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
c = getConnection();
pstmt = c.prepareStatement(SQL_LOAD_RESOURCE_NAME);
pstmt.setInt(1, id);
rs = pstmt.executeQuery();
if (rs == null || !rs.next()) {
logger.debug("No workspace with id " + id);
return false;
} else {
final String name = rs.getString(1);
if (this.dbTrace) {
logger.trace("found id " + id + ", name = " + name);
}
return true;
}
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (rs != null) {
rs.close();
}
if (pstmt != null) {
pstmt.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
public int[] findVMsInGroup(String groupID)
throws WorkspaceDatabaseException {
if (groupID == null) {
throw new WorkspaceDatabaseException("groupID is null");
}
return this.findVMsInGroupOrEnsemble(groupID,
SQL_SELECT_ALL_VMS_IN_GROUP);
}
public int[] findVMsInEnsemble(String ensembleID)
throws WorkspaceDatabaseException {
if (ensembleID == null) {
throw new WorkspaceDatabaseException("ensembleID is null");
}
return this.findVMsInGroupOrEnsemble(ensembleID,
SQL_SELECT_ALL_VMS_IN_ENSEMBLE);
}
private int[] findVMsInGroupOrEnsemble(String ID,
String pstmtString)
throws WorkspaceDatabaseException {
Connection c = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
c = getConnection();
pstmt = c.prepareStatement(pstmtString);
pstmt.setString(1, ID);
rs = pstmt.executeQuery();
if (rs == null || !rs.next()) {
logger.debug("no VM ensemble/group found with ID = " + ID);
return EMPTY_INT_ARRAY;
}
final ArrayList vmidsList = new ArrayList(64);
do {
vmidsList.add(new Integer(rs.getInt(1)));
} while (rs.next());
// can't use toArray without converting to Integer[]
final int[] ret = new int[vmidsList.size()];
for (int i = 0; i < ret.length; i++) {
ret[i] = ((Number)vmidsList.get(i)).intValue();
}
return ret;
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (rs != null) {
rs.close();
}
if (pstmt != null) {
pstmt.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
public int[] findVMsByOwner(String ownerID)
throws WorkspaceDatabaseException {
if (ownerID == null) {
throw new WorkspaceDatabaseException("ownerID is missing");
}
Connection c = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
c = getConnection();
pstmt = c.prepareStatement(SQL_SELECT_ALL_VMS_BY_OWNER);
pstmt.setString(1, ownerID);
rs = pstmt.executeQuery();
if (rs == null || !rs.next()) {
logger.debug("no VMs found with ID = " + ownerID);
return EMPTY_INT_ARRAY;
}
final ArrayList vmidsList = new ArrayList(64);
do {
vmidsList.add(new Integer(rs.getInt(1)));
} while (rs.next());
// can't use toArray without converting to Integer[]
final int[] ret = new int[vmidsList.size()];
for (int i = 0; i < ret.length; i++) {
ret[i] = ((Number)vmidsList.get(i)).intValue();
}
return ret;
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (rs != null) {
rs.close();
}
if (pstmt != null) {
pstmt.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
public void add(InstanceResource resource)
throws WorkspaceDatabaseException {
if (resource == null) {
throw new WorkspaceDatabaseException("resource is null");
}
final int id = resource.getID();
if (id < 0) {
throw new WorkspaceDatabaseException("id is less than zero");
}
if (this.dbTrace) {
logger.trace("add(): " + Lager.id(id) +
", WorkspaceResource = " + resource);
}
final byte[] faultBytes;
try {
faultBytes = ErrorUtil.toByteArray(resource.getStateThrowable());
} catch (IOException e) {
throw new WorkspaceDatabaseException(e);
}
Connection c = null;
PreparedStatement pstmt = null;
PreparedStatement[] pstmts = null;
try {
c = getConnection();
c.setAutoCommit(false);
pstmt = c.prepareStatement(SQL_INSERT_RESOURCE);
pstmt.setInt(1, id);
pstmt.setString(2,resource.getName());
pstmt.setInt(3, resource.getState());
pstmt.setInt(4, resource.getTargetState());
if (resource.getTerminationTime() != null) {
pstmt.setObject(5,
new Long(resource.getTerminationTime().getTimeInMillis()));
} else {
pstmt.setInt(5, 0);
}
if (resource.isOpsEnabled()) {
pstmt.setInt(6, 1);
} else {
pstmt.setInt(6, 0);
}
if (resource.getCreatorID() != null) {
pstmt.setString(7, resource.getCreatorID());
} else {
pstmt.setNull(7, Types.VARCHAR);
}
if (resource.getStartTime() != null) {
pstmt.setObject(8,
new Long(resource.getStartTime().getTimeInMillis()));
} else {
pstmt.setInt(8, 0);
}
if (resource.isVMMaccessOK()) {
pstmt.setInt(9, 1);
} else {
pstmt.setInt(9, 0);
}
if (resource.getEnsembleId() != null) {
pstmt.setString(10, resource.getEnsembleId());
} else {
pstmt.setNull(10, Types.VARCHAR);
}
if (resource.getGroupId() != null) {
pstmt.setString(11, resource.getGroupId());
} else {
pstmt.setNull(11, Types.VARCHAR);
}
pstmt.setInt(12, resource.getGroupSize());
if (resource.isLastInGroup()) {
pstmt.setInt(13, 1);
} else {
pstmt.setInt(13, 0);
}
pstmt.setInt(14, resource.getLaunchIndex());
if (faultBytes != null) {
pstmt.setObject(15, faultBytes, Types.BLOB);
} else {
pstmt.setNull(15, Types.BLOB);
}
pstmt.setString(16, resource.getClientToken());
pstmt.setDouble(17, resource.getChargeRatio());
if (this.dbTrace) {
logger.trace("creating WorkspaceResource db " +
"entry for " + Lager.id(id));
}
pstmt.executeUpdate();
if (resource instanceof VMPersistence) {
pstmts = VirtualMachinePersistenceUtil.
getInsertVM(resource, id, c);
if (this.dbTrace) {
logger.trace("creating VirtualMachine db " +
"entry for " + Lager.id(id) + ": " +
pstmts.length + " inserts");
}
for (int i = 0; i < pstmts.length; i++) {
pstmts[i].executeUpdate();
}
}
c.commit();
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} catch (ManageException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
if (pstmts != null) {
for (int i = 0; i < pstmts.length; i++) {
pstmts[i].close();
}
}
if (c != null) {
c.setAutoCommit(true);
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
public void addGroup(GroupResource resource)
throws WorkspaceDatabaseException {
if (resource == null) {
throw new IllegalArgumentException("resource is null");
}
final String id = resource.getID();
if (this.dbTrace) {
logger.trace("addGroup(): " + Lager.groupid(id));
}
this.addGroupOrEnsemble(id, resource.getCreatorID());
}
public void addEnsemble(CoschedResource resource)
throws WorkspaceDatabaseException {
if (resource == null) {
throw new IllegalArgumentException("resource is null");
}
final String id = resource.getID();
if (this.dbTrace) {
logger.trace("addEnsemble(): " + Lager.ensembleid(id));
}
this.addGroupOrEnsemble(id, resource.getCreatorID());
}
private void addGroupOrEnsemble(String id, String creatorDN)
throws WorkspaceDatabaseException {
if (id == null) {
throw new IllegalArgumentException("id is null");
}
Connection c = null;
PreparedStatement pstmt = null;
try {
c = getConnection();
pstmt = c.prepareStatement(SQL_INSERT_GROUP_RESOURCE);
pstmt.setString(1, id);
if (creatorDN != null) {
pstmt.setString(2, creatorDN);
} else {
pstmt.setNull(2, Types.VARCHAR);
}
pstmt.executeUpdate();
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
/**
* @param id id
* @param resource resource
* @throws DoesNotExistException
* @throws WorkspaceDatabaseException
*/
public void load(int id, InstanceResource resource)
throws DoesNotExistException, WorkspaceDatabaseException {
if (this.dbTrace) {
logger.trace("load(): " + Lager.id(id) +
", WorkspaceResource = " + resource);
}
if (id < 0) {
throw new DoesNotExistException("id is less than zero");
}
Connection c = null;
PreparedStatement pstmt = null;
PreparedStatement[] pstmts = null;
ResultSet rs = null;
try {
c = getConnection();
pstmt = c.prepareStatement(SQL_LOAD_RESOURCE);
pstmt.setInt(1, id);
rs = pstmt.executeQuery();
if (rs == null || !rs.next()) {
final String err = "resource with id = " + id + " not found";
logger.debug(err);
throw new DoesNotExistException(err);
} else {
final String name = rs.getString(1);
resource.setName(name);
final int state = rs.getInt(2);
final int targetState = rs.getInt(3);
resource.setInitialTargetState(targetState);
final long t = rs.getLong(4);
if (t == 0) {
resource.setTerminationTime(null);
} else {
final Calendar term = Calendar.getInstance();
term.setTimeInMillis(t);
resource.setTerminationTime(term);
}
final boolean opsEnabled = rs.getBoolean(5);
resource.setInitialOpsEnabled(opsEnabled);
final String dn = rs.getString(6);
resource.setCreatorID(dn);
final long s = rs.getLong(7);
if (s == 0) {
resource.setStartTime(null);
} else {
final Calendar start = Calendar.getInstance();
start.setTimeInMillis(s);
resource.setStartTime(start);
}
final boolean vmmAccessOK = rs.getBoolean(8);
resource.setInitialVMMaccessOK(vmmAccessOK);
final String ensembleid = rs.getString(9);
resource.setEnsembleId(ensembleid);
final String groupid = rs.getString(10);
resource.setGroupId(groupid);
final int groupsize = rs.getInt(11);
resource.setGroupSize(groupsize);
final boolean isLastInGroup = rs.getBoolean(12);
resource.setLastInGroup(isLastInGroup);
final int launchIndex = rs.getInt(13);
resource.setLaunchIndex(launchIndex);
final Blob errBlob = rs.getBlob(14);
if (errBlob != null) {
// getBytes requires int, cast from long
final int length = (int)errBlob.length();
final Throwable err =
ErrorUtil.getThrowable(errBlob.getBytes(1,length));
resource.setInitialState(state, err);
} else {
resource.setInitialState(state, null);
}
final String clientToken = rs.getString(15);
resource.setClientToken(clientToken);
final double chargeRatio = rs.getDouble(16);
resource.setChargeRatio(chargeRatio);
if (this.dbTrace) {
logger.trace("found " + Lager.id(id) +
": name = " + name +
", state = " + state +
", targetState = " + targetState +
", termination time = " + t +
", opsEnabled = " + opsEnabled +
", creator ID = " + dn +
", start time = " + s +
", vmmAccessOK = " + vmmAccessOK +
", ensembleid = " + ensembleid +
", groupid = " + groupid +
", groupsize = " + groupsize +
", isLastInGroup = " + isLastInGroup +
", launchIndex = " + launchIndex +
", clientToken = " + clientToken +
", chargeRatio = " + chargeRatio +
", error present = " + (errBlob != null));
}
rs.close();
if (resource instanceof VMPersistence) {
if (this.dbTrace) {
logger.trace(Lager.id(id) + ": load virtual machine");
}
pstmts = VirtualMachinePersistenceUtil.getVMQuery(id, c);
rs = pstmts[0].executeQuery();
if (rs == null || !rs.next()) {
logger.error("resource with id=" + id + " not found");
throw new DoesNotExistException();
}
final VirtualMachine vm =
VirtualMachinePersistenceUtil.newVM(id, rs);
if (this.dbTrace) {
logger.trace(Lager.id(id) +
", created vm:\n" + vm.toString());
}
rs.close();
rs = pstmts[1].executeQuery();
if (rs == null || !rs.next()) {
logger.debug("resource with id=" + id + " has no" +
" deployment information");
} else {
VirtualMachinePersistenceUtil.addDeployment(vm, rs);
if (this.dbTrace) {
logger.trace("added deployment info to vm object");
}
rs.close();
}
rs = pstmts[2].executeQuery();
if (rs == null || !rs.next()) {
logger.warn("resource with id=" + id + " has no" +
" partitions");
} else {
final ArrayList partitions = new ArrayList(8);
do {
partitions.add(VirtualMachinePersistenceUtil.
getPartition(rs));
} while (rs.next());
final VirtualMachinePartition[] parts =
(VirtualMachinePartition[]) partitions.toArray(
new VirtualMachinePartition[partitions.size()]);
vm.setPartitions(parts);
}
rs = pstmts[3].executeQuery();
if (rs == null || !rs.next()) {
if (this.lager.dbLog) {
logger.debug("resource with id=" + id + " has no" +
" customization needs");
}
} else {
do {
vm.addFileCopyNeed(
VirtualMachinePersistenceUtil.getNeed(rs));
} while (rs.next());
}
((VMPersistence)resource).setWorkspace(vm);
}
}
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} catch(DoesNotExistException e) {
throw e;
} catch (IOException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} catch (ClassNotFoundException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
if (pstmts != null) {
for (int i = 0; i < pstmts.length; i++) {
pstmts[i].close();
}
}
if (rs != null) {
rs.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
public VirtualMachine loadVM(int id, Connection c) throws SQLException, DoesNotExistException, WorkspaceDatabaseException {
if (this.dbTrace) {
logger.trace(Lager.id(id) + ": load virtual machine");
}
PreparedStatement[] pstmts = VirtualMachinePersistenceUtil.getVMQuery(id, c);
ResultSet rs = pstmts[0].executeQuery();
if (rs == null || !rs.next()) {
logger.error("resource with id=" + id + " not found");
throw new DoesNotExistException();
}
final VirtualMachine vm =
VirtualMachinePersistenceUtil.newVM(id, rs);
if (this.dbTrace) {
logger.trace(Lager.id(id) +
", created vm:\n" + vm.toString());
}
rs.close();
rs = pstmts[1].executeQuery();
if (rs == null || !rs.next()) {
logger.debug("resource with id=" + id + " has no" +
" deployment information");
} else {
VirtualMachinePersistenceUtil.addDeployment(vm, rs);
if (this.dbTrace) {
logger.trace("added deployment info to vm object");
}
rs.close();
}
rs = pstmts[2].executeQuery();
if (rs == null || !rs.next()) {
logger.warn("resource with id=" + id + " has no" +
" partitions");
} else {
final ArrayList partitions = new ArrayList(8);
do {
partitions.add(VirtualMachinePersistenceUtil.
getPartition(rs));
} while (rs.next());
final VirtualMachinePartition[] parts =
(VirtualMachinePartition[]) partitions.toArray(
new VirtualMachinePartition[partitions.size()]);
vm.setPartitions(parts);
}
rs = pstmts[3].executeQuery();
if (rs == null || !rs.next()) {
if (this.lager.dbLog) {
logger.debug("resource with id=" + id + " has no" +
" customization needs");
}
} else {
do {
vm.addFileCopyNeed(
VirtualMachinePersistenceUtil.getNeed(rs));
} while (rs.next());
}
return vm;
}
public void loadGroup(String id, GroupResource resource)
throws DoesNotExistException, WorkspaceDatabaseException {
if (this.dbTrace) {
logger.trace("loadGroup(): " + Lager.groupid(id) +
", WorkspaceGroupResource = " + resource);
}
final String callerID = this.loadGroupOrEnsemble(id);
resource.setCreatorID(callerID);
resource.setID(id);
if (this.dbTrace) {
logger.trace("found " + Lager.groupid(id) +
", creator ID = " + callerID);
}
}
public void loadEnsemble(String id, CoschedResource resource)
throws DoesNotExistException, WorkspaceDatabaseException {
if (this.dbTrace) {
logger.trace("loadEnsemble(): " + Lager.ensembleid(id) +
", WorkspaceEnsembleResource = " + resource);
}
final String creatorID = this.loadGroupOrEnsemble(id);
if (creatorID != null) {
resource.setCreatorID(creatorID);
}
resource.setID(id);
if (this.dbTrace) {
logger.trace("found " + Lager.ensembleid(id) +
", creator ID = " + creatorID);
}
}
private String loadGroupOrEnsemble(String id)
throws DoesNotExistException, WorkspaceDatabaseException {
if (id == null) {
throw new DoesNotExistException("id is null");
}
Connection c = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
c = getConnection();
pstmt = c.prepareStatement(SQL_LOAD_GROUP_RESOURCE);
pstmt.setString(1, id);
rs = pstmt.executeQuery();
if (rs == null || !rs.next()) {
final String err = "resource with id = " + id + " not found";
logger.error(err);
throw new DoesNotExistException(err);
} else {
// could be null
return rs.getString(1);
}
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (rs != null) {
rs.close();
}
if (pstmt != null) {
pstmt.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
/**
* This is only called at factory initialization and not a priority
* to switch to using PreparedStatements
*
* @param assocs all associations (potentially merged with previous)
* @throws WorkspaceDatabaseException
*/
public void replaceAssocations(Hashtable assocs)
throws WorkspaceDatabaseException {
if (this.dbTrace) {
logger.trace("replaceAssocations()");
}
final String[] inserts =
AssociationPersistenceUtil.insertAllAssociationsSQL(assocs);
if (inserts == null || inserts.length == 0) {
logger.debug("no networks to persist");
this.associations = null;
return;
}
Connection c = null;
Statement st = null;
PreparedStatement pstmt = null;
PreparedStatement pstmt2 = null;
try {
c = getConnection();
c.setAutoCommit(false);
// first delete all current rows
pstmt = c.prepareStatement(SQL_DELETE_ALL_ASSOCIATIONS);
final int removedNum = pstmt.executeUpdate();
if (this.dbTrace) {
logger.trace("removed " + removedNum +
" entries from associations table");
}
pstmt2 = c.prepareStatement(SQL_DELETE_ALL_ASSOCIATION_ENTRIES);
final int removedEntries = pstmt2.executeUpdate();
if (this.dbTrace) {
logger.trace("removed " + removedEntries + " entries from " +
"association entries table");
}
st = c.createStatement();
for (int i = 0; i < inserts.length; i++) {
if (this.dbTrace) {
logger.trace("executing insert: '" + inserts[i] + "'");
}
st.executeUpdate(inserts[i]);
}
c.commit();
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
if (pstmt2 != null) {
pstmt2.close();
}
if (st != null) {
st.close();
}
if (c != null) {
c.setAutoCommit(true);
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
this.associations = assocs;
}
/**
* For now, only in-use flag is replaceable.
* @param name name
* @param entry assoc entry
*/
public void replaceAssociationEntry(String name, AssociationEntry entry)
throws WorkspaceDatabaseException {
if (this.dbTrace) {
logger.trace("replaceAssociationEntry()");
}
Connection c = null;
PreparedStatement pstmt = null;
try {
c = getConnection();
pstmt = AssociationPersistenceUtil.updateEntryInUse(name,entry,c);
pstmt.executeUpdate();
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
public Hashtable currentAssociations()
throws WorkspaceDatabaseException {
return currentAssociations(true);
}
public synchronized Hashtable currentAssociations(boolean cachedIsFine)
throws WorkspaceDatabaseException {
if (this.dbTrace) {
logger.trace("currentAssociations()");
}
if (cachedIsFine) {
if (this.associations != null) {
return this.associations;
}
}
Connection c = null;
PreparedStatement pstmt = null;
PreparedStatement pstmt2 = null;
ResultSet rs = null;
ResultSet rs2 = null;
try {
c = getConnection();
pstmt = c.prepareStatement(SQL_SELECT_ALL_ASSOCIATIONS);
rs = pstmt.executeQuery();
if (rs == null || !rs.next()) {
if (lager.traceLog) {
logger.debug("no previous networks (associations)");
}
return new Hashtable();
}
Hashtable assocs = new Hashtable();
do {
// rs was next'd above already
String name = rs.getString(1);
String dns = rs.getString(2);
long fileTime = rs.getLong(3);
Association assoc = new Association(dns);
assoc.setFileTime(fileTime);
pstmt2 = c.prepareStatement(SQL_SELECT_ASSOCIATION);
pstmt2.setString(1, name);
rs2 = pstmt2.executeQuery();
ArrayList entries = new ArrayList();
while (rs2.next()) {
AssociationEntry entry =
new AssociationEntry(rs2.getString(2),
rs2.getString(3),
rs2.getString(4),
rs2.getString(5),
rs2.getString(6),
rs2.getString(7));
entry.setInUse(rs2.getBoolean(8));
// Encoding that MAC is explicit in the MAC field itself.
// better to introduce a new field to schema?
String mac = entry.getMac();
if (mac.startsWith(AssociationPersistenceUtil.EXPLICIT_MAC_PREFIX)) {
mac = mac.substring(AssociationPersistenceUtil.EXPLICIT_MAC_PREFIX.length());
entry.setMac(mac);
entry.setExplicitMac(true);
}
entries.add(entry);
}
assoc.setEntries(entries);
assocs.put(name,assoc);
if (this.dbTrace) {
logger.trace("found previously stored network '" +
name + "':\n" + assoc);
}
pstmt2.close();
rs2.close();
} while (rs.next());
rs = null;
rs2 = null;
pstmt = null;
pstmt2 = null;
this.associations = assocs;
return assocs;
} catch(SQLException e) {
this.associations = null;
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
if (pstmt2 != null) {
pstmt2.close();
}
if (rs != null) {
rs.close();
}
if (rs2 != null) {
rs2.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
this.associations = null;
logger.error("SQLException in finally cleanup", sql);
}
}
}
public void updateResourcepoolEntryAvailableMemory(String hostname,
int newAvailMemory,
int preemptibleMemory)
throws WorkspaceDatabaseException {
if (this.dbTrace) {
logger.trace("updateResourcepoolEntryAvailableMemory()");
}
if (hostname == null) {
throw new IllegalArgumentException("hostname may not be null");
}
if (newAvailMemory < 0) {
throw new IllegalArgumentException("newAvailMemory must be non-negative");
}
if (preemptibleMemory < 0) {
throw new IllegalArgumentException("preemptibleMemory must be non-negative");
}
Connection c = null;
PreparedStatement pstmt = null;
try {
c = getConnection();
pstmt =
c.prepareStatement(SQL_UPDATE_RESOURCE_POOL_ENTRY_MEMORY);
pstmt.setInt(1, newAvailMemory);
pstmt.setInt(2, preemptibleMemory);
pstmt.setString(3, hostname);
final int updated = pstmt.executeUpdate();
if (updated != 1) {
throw new WorkspaceDatabaseException("expected row update");
}
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
public boolean updateResourcepoolEntry(String hostname,
String pool,
String networks,
Integer memoryMax,
Integer memoryAvail,
Boolean active)
throws WorkspaceDatabaseException {
if (this.dbTrace) {
logger.trace("updateResourcepoolEntry()");
}
if (hostname == null) {
throw new IllegalArgumentException("hostname may not be null");
}
final StringBuilder sb = new StringBuilder();
final List<Object> params = new ArrayList<Object>(5);
if (pool != null) {
appendUpdatePair(sb, "resourcepool");
params.add(pool);
}
if (networks != null) {
appendUpdatePair(sb, "associations");
params.add(networks);
}
if (memoryMax != null) {
appendUpdatePair(sb, "maximum_memory");
params.add(memoryMax);
}
if (memoryAvail != null) {
appendUpdatePair(sb, "available_memory");
params.add(memoryAvail);
}
if (active != null) {
appendUpdatePair(sb, "active");
params.add(active);
}
if (params.isEmpty()) {
throw new IllegalArgumentException(
"at least one updated field must be specified");
}
Connection c = null;
PreparedStatement pstmt = null;
try {
c = getConnection();
final String q = String.format(
SQL_UPDATE_RESOURCE_POOL_ENTRY_SKELETAL, sb.toString());
if (this.dbTrace) {
logger.trace("resourcepool_entry update query: "+ q);
}
pstmt = c.prepareStatement(q);
int paramIndex = 1;
for (Object p : params) {
pstmt.setObject(paramIndex, p);
paramIndex++;
}
// add on the hostname param
pstmt.setString(paramIndex, hostname);
final int updated = pstmt.executeUpdate();
return updated >= 1;
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
private void appendUpdatePair(StringBuilder stringBuilder, String columnName) {
if (stringBuilder.length() != 0) {
stringBuilder.append(",");
}
stringBuilder.append(columnName).append("=?");
}
// one can only use result of this safely during service initialization
public int memoryUsedOnPoolnode(String poolnode)
throws WorkspaceDatabaseException {
if (this.dbTrace) {
logger.trace("memoryUsedOnPoolnode(): poolnode = " + poolnode);
}
Connection c = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
c = getConnection();
pstmt = c.prepareStatement(SQL_JOIN_SELECT_RESOURCE_POOL_MEMORY);
pstmt.setString(1, poolnode);
rs = pstmt.executeQuery();
if (rs == null) {
if (this.dbTrace) {
logger.trace("memoryUsedOnPoolnode(): null result so " +
"total is 0 MB");
}
return 0;
}
int total = 0;
while (rs.next()) {
int memory = rs.getInt(1);
total += memory;
if (this.dbTrace) {
logger.trace("memoryUsedOnPoolnode(): found " + memory +
" MB for one VM, new total is " + total);
}
}
if (this.dbTrace) {
logger.trace("memoryUsedOnPoolnode(): final total = " + total);
}
return total;
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (rs != null) {
rs.close();
}
if (pstmt != null) {
pstmt.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
public List<ResourcepoolEntry> currentResourcepoolEntries()
throws WorkspaceDatabaseException {
Connection c = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
c = getConnection();
pstmt = c.prepareStatement(SQL_SELECT_ALL_RESOURCE_POOL_ENTRIES);
rs = pstmt.executeQuery();
if (rs == null || !rs.next()) {
return Collections.emptyList();
}
List<ResourcepoolEntry> list = new ArrayList<ResourcepoolEntry>();
do {
final ResourcepoolEntry entry = new ResourcepoolEntry(rs.getString(1),
rs.getString(2),
rs.getInt(4),
rs.getInt(5),
rs.getInt(7),
rs.getString(3),
rs.getBoolean(6));
list.add(entry);
} while (rs.next());
return list;
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
if (rs != null) {
rs.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
public ResourcepoolEntry getResourcepoolEntry(String hostname)
throws WorkspaceDatabaseException {
Connection c = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
c = getConnection();
pstmt = c.prepareStatement(SQL_SELECT_RESOURCE_POOL_ENTRY);
pstmt.setString(1, hostname);
rs = pstmt.executeQuery();
if (rs == null || !rs.next()) {
return null;
}
return new ResourcepoolEntry(rs.getString(1),
rs.getString(2),
rs.getInt(4),
rs.getInt(5),
rs.getInt(7),
rs.getString(3),
rs.getBoolean(6));
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
if (rs != null) {
rs.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
public void addResourcepoolEntry(ResourcepoolEntry entry)
throws WorkspaceDatabaseException {
if (entry == null) {
throw new IllegalArgumentException("entry may not be null");
}
if (this.dbTrace) {
logger.trace("addResourcepoolEntry(): hostname = " + entry.getHostname());
}
Connection c = null;
PreparedStatement pstmt = null;
try {
c = getConnection();
pstmt = c.prepareStatement(SQL_INSERT_RESOURCE_POOL_ENTRY);
pstmt.setString(1, entry.getResourcePool());
pstmt.setString(2, entry.getHostname());
pstmt.setString(3, entry.getSupportedAssociations());
pstmt.setInt(4, entry.getMemMax());
pstmt.setInt(5, entry.getMemCurrent());
pstmt.setInt(6, entry.isActive() ? 1 : 0);
final int updated = pstmt.executeUpdate();
if (this.dbTrace) {
logger.trace("Inserted " + updated + " row(s)");
}
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
public boolean removeResourcepoolEntry(String hostname)
throws WorkspaceDatabaseException {
if (hostname == null) {
throw new IllegalArgumentException("hostname may not be null");
}
if (this.dbTrace) {
logger.trace("removeResourcepoolEntry(): hostname = " + hostname);
}
Connection c = null;
PreparedStatement pstmt = null;
try {
c = getConnection();
pstmt = c.prepareStatement(SQL_DELETE_RESOURCE_POOL_ENTRY);
pstmt.setString(1, hostname);
final int updated = pstmt.executeUpdate();
if (this.dbTrace) {
logger.trace("Deleted " + updated + " row(s)");
}
return updated > 0;
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
private Connection getConnection() throws SQLException {
return this.dataSource.getConnection();
}
private static void returnConnection(Connection connection) {
if(connection != null) {
try {
connection.close();
} catch(SQLException e) {
logger.error("",e);
}
}
}
/* ******************************************************************** */
// TEMPORARY: for propagation implementation
public void updateCursorPosition(long filepos)
throws WorkspaceDatabaseException {
final String SQL_UPDATE_CURSOR_POSITION =
"UPDATE notification_position SET position=? WHERE 1=1";
Connection c = null;
PreparedStatement pstmt = null;
try {
c = getConnection();
pstmt = c.prepareStatement(SQL_UPDATE_CURSOR_POSITION);
pstmt.setLong(1, filepos);
pstmt.executeUpdate();
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
public long currentCursorPosition() throws WorkspaceDatabaseException {
final String SQL_INSERT_CURSOR_POSITION =
"INSERT INTO notification_position VALUES(0)";
final String SQL_SELECT_CURSOR_POSITION =
"SELECT position FROM notification_position";
Connection c = null;
PreparedStatement pstmt = null;
PreparedStatement pstmt2 = null;
ResultSet rs = null;
try {
c = getConnection();
pstmt = c.prepareStatement(SQL_SELECT_CURSOR_POSITION);
rs = pstmt.executeQuery();
if (rs == null || !rs.next()) {
pstmt2 = c.prepareStatement(SQL_INSERT_CURSOR_POSITION);
pstmt2.executeUpdate();
return 0;
}
return rs.getLong(1);
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (rs != null) {
rs.close();
}
if (pstmt != null) {
pstmt.close();
}
if (pstmt2 != null) {
pstmt2.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
public void updatePropagationCounter(int n)
throws WorkspaceDatabaseException {
if (this.dbTrace) {
logger.trace("updatePropagationCounter()");
}
final String SQL_SET_PROP_COUNTER =
"UPDATE counter SET pending=? WHERE id=1";
this.updateCounter(n, SQL_SET_PROP_COUNTER);
}
private void updateCounter(int n, String prepd)
throws WorkspaceDatabaseException {
Connection c = null;
PreparedStatement pstmt = null;
try {
c = getConnection();
pstmt = c.prepareStatement(prepd);
pstmt.setInt(1, n);
pstmt.executeUpdate();
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
public int readPropagationCounter() throws WorkspaceDatabaseException {
if (this.dbTrace) {
logger.trace("readPropagationCounter()");
}
final String SQL_SELECT_PROP_COUNTER =
"SELECT pending FROM counter where id=1";
return this.readCounter(1, SQL_SELECT_PROP_COUNTER);
}
private int readCounter(int n, String prepd)
throws WorkspaceDatabaseException {
final String SQL_INSERT_COUNTER = "INSERT INTO counter VALUES(?,?)";
Connection c = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
c = getConnection();
pstmt = c.prepareStatement(prepd);
rs = pstmt.executeQuery();
if (rs == null || !rs.next()) {
pstmt.close();
pstmt = c.prepareStatement(SQL_INSERT_COUNTER);
pstmt.setInt(1, n);
pstmt.setInt(2, 0);
pstmt.executeUpdate();
return 0;
} else {
return rs.getInt(1);
}
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (rs != null) {
rs.close();
}
if (pstmt != null) {
pstmt.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
public boolean isInfeasibleRequest(int requestedMem)
throws WorkspaceDatabaseException{
Connection c = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
c = getConnection();
pstmt = c.prepareStatement(SQL_SELECT_INFEASIBLE_MEMORY);
pstmt.setInt(1, requestedMem);
rs = pstmt.executeQuery();
if (rs == null || !rs.next()) {
throw new WorkspaceDatabaseException("Should always have a result");
} else {
int numPossibleVmms = rs.getInt(1);
if (numPossibleVmms > 0) {
return false;
} else {
return true;
}
}
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
if (rs != null) {
rs.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
public List<ResourcepoolEntry> getAvailableEntriesSortedByFreeMemoryPercentage(int requestedMem, String resourcePool)
throws WorkspaceDatabaseException{
Connection c = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
ArrayList<ResourcepoolEntry> entries = new ArrayList<ResourcepoolEntry>();
try {
c = getConnection();
if (resourcePool != null && resourcePool.length() > 0) {
pstmt = c.prepareStatement(SQL_SELECT_AVAILABLE_ENTRIES_BY_POOL);
pstmt.setInt(1, requestedMem);
pstmt.setString(2, resourcePool);
}
else {
pstmt = c.prepareStatement(SQL_SELECT_AVAILABLE_ENTRIES);
pstmt.setInt(1, requestedMem);
}
rs = pstmt.executeQuery();
if (rs == null || !rs.next()) {
if (lager.traceLog) {
logger.debug("no available resource pool entries");
}
} else do {
// rs was next'd above already
String name = rs.getString(1);
String hostname = rs.getString(2);
String assocs = rs.getString(3);
if (hostname == null) {
logger.error("hostname cannot be null for resource pool entry");
continue;
}
if (assocs == null) {
logger.error("assocs cannot be null for resource pool entry");
continue;
}
ResourcepoolEntry entry =
new ResourcepoolEntry(name,
hostname,
rs.getInt(4),
rs.getInt(5),
rs.getInt(7),
assocs,
rs.getBoolean(6));
entries.add(entry);
} while (rs.next());
return entries;
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
if (rs != null) {
rs.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
public String[] getResourcePools() throws WorkspaceDatabaseException{
Connection c = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
ArrayList<String> entries = new ArrayList<String>();
try {
c = getConnection();
pstmt = c.prepareStatement(SQL_SELECT_ALL_RESOURCE_POOLS);
rs = pstmt.executeQuery();
if (rs == null || !rs.next()) {
if (lager.traceLog) {
logger.debug("no available resource pool entries");
}
} else do {
// rs was next'd above already
String name = rs.getString(1);
entries.add(name);
} while (rs.next());
String[] zones = new String[entries.size()];
entries.toArray(zones);
return zones;
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
if (rs != null) {
rs.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
private synchronized Integer getTotalMemory(String sql) throws WorkspaceDatabaseException {
Connection c = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
c = getConnection();
pstmt = c.prepareStatement(sql);
rs = pstmt.executeQuery();
if (rs == null) {
if (this.dbTrace) {
logger.trace("getTotalMemory(): null result so " +
"total is 0 MB");
}
return 0;
}
Integer total = 0;
if(rs.next()){
total = rs.getInt(1);
}
return total;
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (rs != null) {
rs.close();
}
if (pstmt != null) {
pstmt.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException e) {
logger.error("SQLException in finally cleanup", e);
}
}
}
public Integer getTotalAvailableMemory(Integer multipleOf) throws WorkspaceDatabaseException {
if (this.dbTrace) {
logger.trace("getTotalAvailableMemory(" + multipleOf + ")");
}
Integer total = 0;
Connection c = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
c = getConnection();
pstmt = c.prepareStatement(SQL_SELECT_MULTIPLE_OF_AVAILABLE_MEMORY);
pstmt.setInt(1, multipleOf);
rs = pstmt.executeQuery();
if (rs == null) {
if (this.dbTrace) {
logger.trace("getTotalMemory(): null result so " +
"total is 0 MB");
}
return 0;
}
if(rs.next()){
total = rs.getInt(1);
}
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (rs != null) {
rs.close();
}
if (pstmt != null) {
pstmt.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException e) {
logger.error("SQLException in finally cleanup", e);
}
}
if (this.dbTrace) {
logger.trace("getTotalAvailableMemory(" + multipleOf + "): total available memory = " + total);
}
return total;
}
public Integer getTotalAvailableMemory() throws WorkspaceDatabaseException {
if (this.dbTrace) {
logger.trace("getTotalAvailableMemory()");
}
Integer total = getTotalMemory(SQL_SELECT_TOTAL_AVAILABLE_MEMORY);
if (this.dbTrace) {
logger.trace("getTotalAvailableMemory(): total max memory = " + total);
}
return total;
}
public Integer getTotalMaxMemory() throws WorkspaceDatabaseException {
if (this.dbTrace) {
logger.trace("getTotalMaxMemory()");
}
Integer total = getTotalMemory(SQL_SELECT_TOTAL_MAX_MEMORY);
if (this.dbTrace) {
logger.trace("getTotalMaxMemory(): total max memory = " + total);
}
return total;
}
public Integer getTotalPreemptableMemory() throws WorkspaceDatabaseException {
if (this.dbTrace) {
logger.trace("getTotalPreemptableMemory()");
}
Integer total = getTotalMemory(SQL_SELECT_TOTAL_PREEMPTABLE_MEMORY);
if (this.dbTrace) {
logger.trace("getTotalPreemptableMemory(): total pre-emptable memory = " + total);
}
return total;
}
public Integer getUsedNonPreemptableMemory() throws WorkspaceDatabaseException {
if (this.dbTrace) {
logger.trace("getUsedNonPreemptableMemory()");
}
Integer total = getTotalMemory(SQL_SELECT_USED_NON_PREEMPTABLE_MEMORY);
if (this.dbTrace) {
logger.trace("getUsedNonPreemptableMemory(): used non pre-emptable memory = " + total);
}
return total;
}
public void addSpotPriceHistory(Calendar timeStamp, Double newPrice) throws WorkspaceDatabaseException{
if (this.dbTrace) {
logger.trace("addSpotPriceHistory(): timeStamp = " + timeStamp + ", spot price = " + newPrice);
}
Connection c = null;
PreparedStatement pstmt = null;
try {
c = getConnection();
pstmt = c.prepareStatement(SQL_INSERT_SPOT_PRICE);
if (timeStamp != null) {
pstmt.setLong(1,
new Long(timeStamp.getTimeInMillis()));
} else {
pstmt.setInt(1, 0);
}
pstmt.setDouble(2, newPrice);
final int updated = pstmt.executeUpdate();
if (this.dbTrace) {
logger.trace("addSpotPriceHistory(): updated " + updated + " rows");
}
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
public List<SpotPriceEntry> getSpotPriceHistory(Calendar startDate,
Calendar endDate) throws WorkspaceDatabaseException {
if (this.dbTrace) {
logger.trace("getSpotPriceHistory() startDate: " + startDate == null? null : startDate.getTime()
+ ". endDate: " + endDate == null? null : endDate.getTime());
}
Connection c = null;
Statement st = null;
ResultSet rs = null;
try {
c = getConnection();
st = c.createStatement();
String statement = SQL_SELECT_SPOT_PRICE;
if(startDate != null || endDate != null){
statement += " WHERE ";
if(startDate != null){
statement += "tstamp >= " + startDate.getTimeInMillis();
if(endDate != null){
statement += " AND";
}
}
if(endDate != null){
statement += " tstamp <= " + endDate.getTimeInMillis();
}
}
rs = st.executeQuery(statement);
if (rs == null || !rs.next()) {
if (lager.traceLog) {
logger.debug("no previous spot price history");
}
return new LinkedList<SpotPriceEntry>();
}
List<SpotPriceEntry> result = new LinkedList<SpotPriceEntry>();
do {
// rs was next'd above already
Long timeMillis = rs.getLong(1);
Double spotPrice = rs.getDouble(2);
_SpotPriceEntry spotPriceEntry = repr._newSpotPriceEntry();
Calendar timeStamp = Calendar.getInstance();
timeStamp.setTimeInMillis(timeMillis);
spotPriceEntry.setTimeStamp(timeStamp);
spotPriceEntry.setSpotPrice(spotPrice);
result.add(spotPriceEntry);
if (this.dbTrace) {
logger.trace("found spot price entry: '" +
timeStamp + " : " + spotPrice + "'");
}
} while (rs.next());
return result;
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (st != null) {
st.close();
}
if (rs != null) {
rs.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
public Double getLastSpotPrice() throws WorkspaceDatabaseException {
if (this.dbTrace) {
logger.trace("getLastSpotPrice()");
}
Connection c = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
c = getConnection();
pstmt = c.prepareStatement(SQL_SELECT_LAST_SPOT_PRICE);
rs = pstmt.executeQuery();
if (rs == null || !rs.next()) {
if (lager.traceLog) {
logger.debug("no previous spot price");
}
return null;
}
double result = rs.getDouble(1);
if(rs.next()){
logger.warn("Wrong behavior: multiple spot prices from last time stamp.");
}
return result;
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
if (rs != null) {
rs.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
public Backfill getStoredBackfill() throws WorkspaceDatabaseException {
if (this.dbTrace) {
logger.trace("getStoredBackfill()");
}
Connection c = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
c = getConnection();
pstmt = c.prepareStatement(SQL_SELECT_BACKFILL);
rs = pstmt.executeQuery();
if (rs == null || !rs.next()) {
if (lager.traceLog) {
logger.debug("no previous backfill");
}
return null;
}
Backfill bf = new Backfill(null, null, null, null);
bf.setBackfillEnabled(rs.getBoolean(1));
bf.setMaxInstances(rs.getInt(2));
bf.setDiskImage(rs.getString(3));
bf.setSiteCapacity(rs.getInt(4));
bf.setRepoUser(rs.getString(5));
return bf;
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
if (rs != null) {
rs.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
public synchronized void setBackfill(Backfill bf) throws WorkspaceDatabaseException {
if (bf == null) {
throw new IllegalArgumentException("backfill may not be null");
}
if (this.dbTrace) {
logger.trace("setBackfill()");
}
Connection c = null;
PreparedStatement pstmt = null;
try {
c = getConnection();
// Need to determine whether to use insert or update
Backfill previous = this.getStoredBackfill();
if (previous == null) {
pstmt = c.prepareStatement(SQL_INSERT_BACKFILL);
} else {
pstmt = c.prepareStatement(SQL_UPDATE_BACKFILL);
}
pstmt.setInt(1, bf.isBackfillEnabled() ? 1 : 0);
pstmt.setInt(2, bf.getMaxInstances());
pstmt.setString(3, bf.getDiskImage());
pstmt.setInt(4, bf.getSiteCapacity());
pstmt.setString(5, bf.getRepoUser());
pstmt.setInt(6, bf.getInstanceMem());
final int updated = pstmt.executeUpdate();
if (this.dbTrace) {
logger.trace("Updated/inserted backfill");
}
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
/**
* Retrieves idempotency reservation
*
* @param creatorId initiating client user
* @param clientToken client-provided idempotency token
* @return stored reservation, or null of not found
* @throws WorkspaceDatabaseException
* DB error
*/
public IdempotentReservation getIdempotentReservation(String creatorId, String clientToken)
throws WorkspaceDatabaseException {
if (creatorId == null) {
throw new IllegalArgumentException("creatorId may not be null");
}
if (clientToken == null) {
throw new IllegalArgumentException("clientToken may not be null");
}
if (this.dbTrace) {
logger.trace("getIdempotentReservation()");
}
Connection c = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
c = getConnection();
pstmt = c.prepareStatement(SQL_SELECT_IDEMPOTENT_CREATION);
pstmt.setString(1, creatorId);
pstmt.setString(2, clientToken);
rs = pstmt.executeQuery();
if (rs == null || !rs.next()) {
if (lager.traceLog) {
logger.debug("no existing idempotency reservation");
}
return null;
}
ArrayList<IdempotentInstance> instances = new ArrayList<IdempotentInstance>();
// rs was next'd above already
final String groupId = rs.getString(2);
do {
final int vmId = rs.getInt(1);
final String name = rs.getString(3);
final int launchIndex = rs.getInt(4);
instances.add(new IdempotentInstanceImpl(vmId, name, launchIndex));
} while(rs.next());
return new IdempotentReservationImpl(creatorId, clientToken, groupId, instances);
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
if (rs != null) {
rs.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
/**
* Stores idempotency reservation
*
* @param reservation the reservation to store
* @throws WorkspaceDatabaseException
* DB error
*/
public void addIdempotentReservation(IdempotentReservation reservation)
throws WorkspaceDatabaseException {
if (this.dbTrace) {
logger.trace("addIdempotentReservation()");
}
Connection c = null;
PreparedStatement[] pstmts = null;
try {
c = getConnection();
c.setAutoCommit(false);
pstmts = IdempotencyPersistenceUtil.getInsertReservation(reservation, c);
for (PreparedStatement pstmt : pstmts) {
pstmt.executeUpdate();
}
c.commit();
if (this.dbTrace) {
logger.trace("Inserted idempotency reservation");
}
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (pstmts != null) {
for (PreparedStatement pstmt : pstmts) {
pstmt.close();
}
}
if (c != null) {
c.setAutoCommit(true);
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
/**
* Removes existing idempotency reservation
*
* @param creatorId initiating client user
* @param clientToken client-provided idempotency token
* @throws WorkspaceDatabaseException
* DB error
*/
public void removeIdempotentReservation(String creatorId, String clientToken)
throws WorkspaceDatabaseException {
if (creatorId == null) {
throw new IllegalArgumentException("creatorId may not be null");
}
if (clientToken == null) {
throw new IllegalArgumentException("clientToken may not be null");
}
if (this.dbTrace) {
logger.trace("removeIdempotentReservation()");
}
Connection c = null;
PreparedStatement pstmt = null;
try {
c = getConnection();
pstmt = c.prepareStatement(SQL_DELETE_IDEMPOTENT_CREATION);
pstmt.setString(1, creatorId);
pstmt.setString(2, clientToken);
pstmt.executeUpdate();
} catch(SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
public void addAsyncRequest(AsyncRequest asyncRequest)
throws WorkspaceDatabaseException {
if (asyncRequest == null) {
throw new IllegalArgumentException("asyncRequest may not be null");
}
Connection c = null;
PreparedStatement pstmt = null;
PreparedStatement[] pstmts = null;
try {
c = getConnection();
AsyncRequest oldAsyncRequest = getAsyncRequest(asyncRequest.getId());
if (oldAsyncRequest != null) {
logger.debug("Updating old request " + oldAsyncRequest.getId());
// We will later need to persist modified versions of our persisted VMs,
// so we need to remove all of our earlier copies
pstmts = AsyncRequestMapPersistenceUtil.getRemoveAsyncBindings(oldAsyncRequest, c);
for (PreparedStatement p : pstmts) {
p.executeUpdate();
}
AsyncRequestMapPersistenceUtil.removeAllocatedVMs(oldAsyncRequest, c);
AsyncRequestMapPersistenceUtil.removeFinishedVMs(oldAsyncRequest, c);
AsyncRequestMapPersistenceUtil.removeToBePreempted(oldAsyncRequest, c);
pstmt = AsyncRequestMapPersistenceUtil.getUpdateAsyncRequest(asyncRequest, this.repr, c);
pstmt.executeUpdate();
c.commit();
}
else {
logger.debug("Persisting request: " + asyncRequest.getId());
pstmt = AsyncRequestMapPersistenceUtil.getInsertAsyncRequest(asyncRequest, this.repr, c);
pstmt.executeUpdate();
}
AsyncRequestMapPersistenceUtil.putAllocatedVMs(asyncRequest, c);
AsyncRequestMapPersistenceUtil.putFinishedVMs(asyncRequest, c);
AsyncRequestMapPersistenceUtil.putToBePreempted(asyncRequest, c);
AsyncRequestMapPersistenceUtil.putAsyncRequestBindings(asyncRequest, c);
c.commit();
} catch (SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} catch (ManageException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
if (pstmts != null) {
for (PreparedStatement p : pstmts) {
p.close();
}
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
}
public AsyncRequest getAsyncRequest(String id)
throws WorkspaceDatabaseException {
if (id == null) {
throw new IllegalArgumentException("id may not be null");
}
AsyncRequest asyncRequest = null;
Connection c = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
c = getConnection();
pstmt = AsyncRequestMapPersistenceUtil.getAsyncRequest(id, c);
rs = pstmt.executeQuery();
if (rs == null || !rs.next()) {
logger.debug("No Asyncrequest with ID " + id);
return null;
}
asyncRequest = AsyncRequestMapPersistenceUtil.rsToAsyncRequest(rs, this.repr, c);
VirtualMachine[] bindings = AsyncRequestMapPersistenceUtil.getAsyncVMs(asyncRequest.getId(), c);
asyncRequest.setBindings(bindings);
AsyncRequestMapPersistenceUtil.addAllocatedVMs(asyncRequest, c);
AsyncRequestMapPersistenceUtil.addFinishedVMs(asyncRequest, c);
AsyncRequestMapPersistenceUtil.addToBePreempted(asyncRequest, c);
} catch (SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} catch (CannotTranslateException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
return asyncRequest;
}
public ArrayList<AsyncRequest> getAllAsyncRequests()
throws WorkspaceDatabaseException {
ArrayList<AsyncRequest> asyncRequests = new ArrayList<AsyncRequest>();
Connection c = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
c = getConnection();
pstmt = AsyncRequestMapPersistenceUtil.getAllAsyncRequests(c);
rs = pstmt.executeQuery();
if (rs == null || !rs.next()) {
return asyncRequests;
}
do {
String id = rs.getString("id");
AsyncRequest asyncRequest = this.getAsyncRequest(id);
asyncRequests.add(asyncRequest);
} while(rs.next());
} catch (SQLException e) {
logger.error("",e);
throw new WorkspaceDatabaseException(e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
if (c != null) {
returnConnection(c);
}
} catch (SQLException sql) {
logger.error("SQLException in finally cleanup", sql);
}
}
return asyncRequests;
}
}