org.firebirdsql.management.FBMaintenanceManager Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jaybird Show documentation
Show all versions of jaybird Show documentation
JDBC Driver for the Firebird RDBMS
/*
* Firebird Open Source J2EE Connector - JDBC Driver
*
* Copyright (C) All Rights Reserved.
*
* This file was created by members of the firebird development team.
* All individual contributions remain the Copyright (C) of those
* individuals. Contributors to this file are either listed here or
* can be obtained from a CVS history command.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* - Neither the name of the firebird development team nor the names
* of its contributors may be used to endorse or promote products
* derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
package org.firebirdsql.management;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.sql.SQLException;
import java.util.StringTokenizer;
import org.firebirdsql.gds.ISCConstants;
import org.firebirdsql.gds.ServiceRequestBuffer;
import org.firebirdsql.gds.impl.GDSType;
/**
* The FBMaintenanceManager
class is responsible for replicating
* the functionality provided by the gfix
command-line tool.
* Among the responsibilities of this class are:
*
* - Database shutdown
*
- Changing database mode to read-only or read-write
*
- Enabling or disabling forced writes in the database
*
- Changing the dialect of the database
*
- Setting the cache size at database-level
*
- Mending databases and making minor repairs
*
- Sweeping databases
*
- Activating and killing shadow files
*
- Displaying, committing, or recovering limbo transactions
*
*
* @author Gabriel Reid
*/
public class FBMaintenanceManager extends FBServiceManager
implements MaintenanceManager {
/**
* Create a new instance of FBMaintenanceManager
based on
* the default GDSType.
*/
public FBMaintenanceManager()
{
super();
}
/**
* Create a new instance of FBMaintenanceManager
based on
* a given GDSType.
*
* @param gdsType type must be PURE_JAVA, EMBEDDED, or NATIVE
*/
public FBMaintenanceManager(String gdsType)
{
super(gdsType);
}
/**
* Create a new instance of FBMaintenanceManager
based on
* a given GDSType.
*
* @param gdsType The GDS implementation type to use
*/
public FBMaintenanceManager(GDSType gdsType){
super(gdsType);
}
/**
* Set the database to have read-write or read-only access.
*
* @param mode Must be either ACCESS_MODE_READ_WRITE
* or ACCESS_MODE_READ_ONLY
* @throws SQLException if a database access error occurs
*/
public void setDatabaseAccessMode(int mode) throws SQLException {
if (mode != ACCESS_MODE_READ_WRITE && mode != ACCESS_MODE_READ_ONLY){
throw new IllegalArgumentException("mode must be one of "
+ "ACCESS_MODE_READ_WRITE or ACCESS_MODE_READ_ONLY");
}
ServiceRequestBuffer srb = createDefaultPropertiesSRB();
srb.addArgument(ISCConstants.isc_spb_prp_access_mode, (byte)mode);
executeServicesOperation(srb);
}
/**
* Set the database's dialect.
*
* @param dialect The database dialect, must be either 1 or 3
* @throws SQLException if a database access error occurs
*/
public void setDatabaseDialect(int dialect) throws SQLException {
if (dialect != 1 && dialect != 3){
throw new IllegalArgumentException("dialect must be either "
+ "1 or 3");
}
ServiceRequestBuffer srb = createDefaultPropertiesSRB();
srb.addArgument(ISCConstants.isc_spb_prp_set_sql_dialect, dialect);
executeServicesOperation(srb);
}
/**
* Set the default page-buffer count to be cached in the database. The
* Firebird default is 2048.
*
* @param pageCount The number of pages to be cached, must be positive
* @throws SQLException If the given page count cannot be set, or a
* database access error occurs
*/
public void setDefaultCacheBuffer(int pageCount) throws SQLException {
if (pageCount < 1){
throw new IllegalArgumentException("page count must be positive");
}
ServiceRequestBuffer srb = createDefaultPropertiesSRB();
srb.addArgument(ISCConstants.isc_spb_prp_page_buffers, pageCount);
executeServicesOperation(srb);
}
/**
* Enable or disable forced (synchronous) writes in the database.
* Note, it is considered to be a very bad idea to use buffered
* writing on Windows platforms.
*
* @param forced If true
, forced writes will be used in the
* database, otherwise buffered writes will be used.
* @throws SQLException if a database access error occurs
*/
public void setForcedWrites(boolean forced) throws SQLException {
ServiceRequestBuffer srb = createDefaultPropertiesSRB();
srb.addArgument(ISCConstants.isc_spb_prp_write_mode,
(byte) (forced ? ISCConstants.isc_spb_prp_wm_sync
: ISCConstants.isc_spb_prp_wm_async));
executeServicesOperation(srb);
}
/**
* Set the page fill strategy for when inserting records.
* pageFill
can be one of:
*
* PAGE_FILL_FULL
Fully fill database pages
* PAGE_FILL_RESERVE
Reserve 20% of page space for
* later record deltas
*
*
* @param pageFill The page-filling strategy, either
* PAGE_FILL_FULL
or PAGE_FILL_RESERVE
* @throws SQLException if a database access error occurs
*/
public void setPageFill(int pageFill) throws Exception {
if (pageFill != PAGE_FILL_FULL && pageFill != PAGE_FILL_RESERVE){
throw new IllegalArgumentException( "Page fill must be either "
+ "PAGE_FILL_FULL or PAGE_FILL_RESERVE");
}
ServiceRequestBuffer srb = createDefaultPropertiesSRB();
srb.addArgument(ISCConstants.isc_spb_prp_reserve_space,
(byte)pageFill);
executeServicesOperation(srb);
}
//----------- Database Shutdown -------------------
/**
* Shutdown the current database.
* Shutdown can be done in three modes:
*
* SHUTDOWN_ATTACH
- No new non-owner connections
* will be allowed to the database during the shutdown, and shutdown
* is cancelled if there are still processes connected at the end
* of the timeout.
*
* SHUTDOWN_TRANSACTIONAL
- No new transactions can
* be started during the timeout period, and shutdown is cancelled
* if there are still active transactions at the end of the timeout.
*
* SHUTDOWN_FORCE
- Forcefully shuts down the
* database at the end of the timeout.
*
*
* @param shutdownMode One of SHUTDOWN_ATTACH
,
* SHUTDOWN_TRANSACTIONAL
,
* or SHUTDOWN_FORCE
.
* @param timeout The maximum amount of time allocated for the operation,
* in seconds
* @throws SQLException if the requested operation cannot be completed
* within the given timeout, or a database access error occurs
*/
public void shutdownDatabase(int shutdownMode, int timeout)
throws SQLException {
if (shutdownMode != SHUTDOWN_ATTACH
&& shutdownMode != SHUTDOWN_TRANSACTIONAL
&& shutdownMode != SHUTDOWN_FORCE){
throw new IllegalArgumentException("Shutdown mode must be "
+ "one of: SHUTDOWN_ATTACH, SHUTDOWN_TRANSACTIONAL, "
+ "SHUTDOWN_FORCE");
}
if (timeout < 0){
throw new IllegalArgumentException(
"Timeout must be >= 0");
}
ServiceRequestBuffer srb = createDefaultPropertiesSRB();
srb.addArgument(shutdownMode, timeout);
executeServicesOperation(srb);
}
/**
* Bring a shutdown database online.
*
* @throws SQLException if a database access error occurs
*/
public void bringDatabaseOnline() throws SQLException {
executePropertiesOperation(ISCConstants.isc_spb_prp_db_online);
}
//-------------- Database Repair ----------------------
/**
* Mark corrupt records in the database as unavailable.
* This operation ensures that the corrupt records are skipped (for
* example, during a subsequent backup). This method is the equivalent
* of gfix -mend
.
*
* @throws SQLException if a database access error occurs
*/
public void markCorruptRecords() throws SQLException {
executeRepairOperation(ISCConstants.isc_spb_rpr_mend_db);
}
/**
* Locate and release database pages that are allocated but unassigned
* to any data structures. This method also reports corrupt structures.
*
* @throws SQLException if a database access error occurs
*/
public void validateDatabase() throws SQLException {
executeRepairOperation(ISCConstants.isc_spb_rpr_validate_db);
}
/**
* Locate and release database pages that are allocated but unassigned
* to any data structures. This method also reports corrupt structures.
* The value supplied for options
must be one of the
* following:
*
* - 0 - Simple validation
*
VALIDATE_READ_ONLY
- read-only validation,
* no repair
* VALIDATE_FULL
- full validation and repair
*
*
* The value for options
can additionally be combined in
* a bitmask with VALIDATE_IGNORE_CHECKSUM
to ignore
* checksums while performing validation.
*
* @param options Either 0, VALIDATE_READ_ONLY
, or
* VALIDATE_FULL
* @throws SQLException if a database access error occurs
*/
public void validateDatabase(int options) throws SQLException {
if (options < 0
|| options != 0 && options != VALIDATE_IGNORE_CHECKSUM
&& (options & ~VALIDATE_IGNORE_CHECKSUM) != VALIDATE_READ_ONLY
&& (options & ~VALIDATE_IGNORE_CHECKSUM) != VALIDATE_FULL
&& (options |
(VALIDATE_READ_ONLY | VALIDATE_IGNORE_CHECKSUM)) != options
&& (options |
(VALIDATE_FULL | VALIDATE_IGNORE_CHECKSUM)) != options) {
throw new IllegalArgumentException("options must be either 0, "
+ "VALIDATE_READ_ONLY, or VALIDATE_FULL, optionally "
+ "combined with VALIDATE_IGNORE_CHECKSUM");
}
ServiceRequestBuffer srb = createRepairSRB(
options | ISCConstants.isc_spb_rpr_validate_db);
executeServicesOperation(srb);
}
//----------- Sweeping -------------------------
/**
* Set the database automatic sweep interval to a given number of
* transactions. The Firebird default value is 20,000. If
* transactions
is 0, automatic sweeping is disabled.
*
* @param transactions The interval of transactions between automatic
* sweeps of the database. Can be set to 0, which disables
* automatic sweeping of the database.
* @throws SQLException if a database access error occurs
*/
public void setSweepThreshold(int transactions) throws SQLException {
if (transactions < 0){
throw new IllegalArgumentException("transactions must be >= 0");
}
ServiceRequestBuffer srb = createDefaultPropertiesSRB();
srb.addArgument(ISCConstants.isc_spb_prp_sweep_interval, transactions);
executeServicesOperation(srb);
}
/**
* Perform an immediate sweep of the database.
*
* @throws SQLException if a database access error occurs
*/
public void sweepDatabase() throws SQLException {
executeRepairOperation(ISCConstants.isc_spb_rpr_sweep_db);
}
//----------- Shadow Files ------------------------------------
/**
* Activate a database shadow file to be used as the actual database.
* This method is the equivalent of gfix -activate
.
*
* @throws SQLException if a database access error occurs
*/
public void activateShadowFile() throws SQLException {
executePropertiesOperation(ISCConstants.isc_spb_prp_activate);
}
/**
* Remove references to unavailable shadow files. This method is the
* equivalent of gfix -kill
.
*
* @throws SQLException if a database access error occurs
*/
public void killUnavailableShadows() throws SQLException {
executeRepairOperation(ISCConstants.isc_spb_rpr_kill_shadows);
}
//----------- Transaction Management ----------------------------
/**
* Retrieve the ID of each limbo transaction. The output of this method
* is written to the logger.
*
* @throws SQLException if a database access error occurs
*/
public void listLimboTransactions() throws SQLException {
OutputStream saveOut = getLogger();
try {
ByteArrayOutputStream out = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(saveOut);
setLogger(out);
executeRepairOperation(ISCConstants.isc_spb_rpr_list_limbo_trans);
byte output[] = out.toByteArray();
int trId = 0, shift = 0;
for (int i = 0; i < output.length; i++){
if (output[i] == ISCConstants.isc_spb_single_tra_id){
trId = 0;
shift = 0;
} else if (output[i] == 0 && shift != -1){
ps.print(trId + "\n");
shift = -1;
} else if (shift != -1) {
trId += ((output[i] & 0xff) << shift);
shift += 8;
}
}
} finally {
setLogger(saveOut);
}
}
public int[] getLimboTransactions() throws SQLException
{
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
setLogger(byteOut);
listLimboTransactions();
StringTokenizer limboTransactions = new StringTokenizer(byteOut.toString(),"\n");
int[] trans = new int[limboTransactions.countTokens()];
int count = 0;
while(limboTransactions.hasMoreTokens())
trans[count++] = Integer.parseInt(limboTransactions.nextToken().trim());
return trans;
}
/**
* Commit a limbo transaction based on its ID.
*
* @param transactionId The ID of the limbo transaction to be committed
* @throws SQLException if a database access error occurs or the
* given transaction ID is not valid
*/
public void commitTransaction(int transactionId) throws SQLException {
ServiceRequestBuffer srb = createDefaultRepairSRB();
srb.addArgument(ISCConstants.isc_spb_rpr_commit_trans, transactionId);
executeServicesOperation(srb);
}
/**
* Rollback a limbo transaction based on its ID.
*
* @param transactionId The ID of the limbo transaction to be rolled back
* @throws SQLException if a database access error occurs or the
* given transaction ID is not valid
*/
public void rollbackTransaction(int transactionId) throws SQLException {
ServiceRequestBuffer srb = createDefaultRepairSRB();
srb.addArgument(
ISCConstants.isc_spb_rpr_rollback_trans,
transactionId);
executeServicesOperation(srb);
}
//----------- Private imlementation methods --------------------
/**
* Execute a isc_spb_rpr_* (repair) services operation.
*
* @param operation The identifier for the operation to be executed
* @throws SQLException if a database access error occurs
*/
private void executeRepairOperation(int operation) throws SQLException {
ServiceRequestBuffer srb = createRepairSRB(operation);
executeServicesOperation(srb);
}
/**
* Execute a isc_spb_prp_* (properties) services operation.
*
* @param operation The identifier for the operation to be executed
* @throws SQLException if a database access error occurs
*/
private void executePropertiesOperation(int operation)
throws SQLException {
ServiceRequestBuffer srb = createPropertiesSRB(operation);
executeServicesOperation(srb);
}
/**
* Get a mostly empty properties-operation buffer that can be filled in as
* needed. The buffer created by this method cannot have the options
* bitmask set on it.
*/
private ServiceRequestBuffer createDefaultPropertiesSRB(){
return createPropertiesSRB(0);
}
/**
* Get a mostly empty repair-operation buffer that can be filled in as
* needed. The buffer created by this method cannot have the options
* bitmask set on it.
*/
private ServiceRequestBuffer createDefaultRepairSRB(){
return createRepairSRB(0);
}
/**
* Get a mostly-empty properties-operation request buffer that can be
* filled as needed.
*
* @param options The options bitmask for the request buffer
*/
private ServiceRequestBuffer createPropertiesSRB(int options){
return createRequestBuffer(
ISCConstants.isc_action_svc_properties,
options);
}
/**
* Get a mostly-empty repair-operation request buffer that can be
* filled as needed.
*
* @param options The options bitmask for the request buffer
*/
private ServiceRequestBuffer createRepairSRB(int options){
return createRequestBuffer(ISCConstants.isc_action_svc_repair, options);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy