blob: 373d15ce2f45512d9755eba711cbef0937363756 [file] [log] [blame]
/*
* Copyright 2005 The Apache Software Foundation.
*
* 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.apache.jdo.impl.fostore;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.HashSet;
import java.util.Iterator;
/**
* Process GetExtent requests.
*
* @author Dave Bristor
*/
// This is server-side code. It does not need to live in the client.
class GetExtentHandler extends RequestHandler {
private GetExtentHandler(Reply reply, int length,
FOStoreServerConnection con) {
super(reply, length, con);
}
public static final HandlerFactory factory =
new HandlerFactory() {
public RequestHandler getHandler(Reply reply, int length,
FOStoreServerConnection con) {
return new GetExtentHandler(reply, length, con);
}};
/**
* The desired extent's class can be specified either by CLID (i.e., the
* class's CLID was already loaded from store to the client) or classname
* and FSUID (in case the CLID wasn't known). In the latter case, look
* up the CLID.
* <br>
* With the CLID, get the set of extents: it will be only one if
* subclasses is false, an aribtrary number otherwise.
* <br>
* Iterate over the extents, writing the items into the reply.
* @see RequestHandler#handleRequest
* @see GetExtentRequest#doRequestBody
*/
RequestFinisher handleRequest()
throws IOException, FOStoreDatabaseException {
FOStoreInput in = con.getInputFromClient();
FOStoreDatabase db = con.getDatabase();
HashSet dbExtents = null;
// true => resulting extent to include subclasses of indicated class.
boolean subclasses;
int maxInstances = in.readInt();
// By CLID or by classname/fsuid?
boolean isCLID = in.readBoolean();
CLID clid = null;
if (isCLID) {
clid = CLID.read(in);
subclasses = in.readBoolean();
} else {
// Find the clid for the given name/fsuid.
String name = in.readUTF();
FOStoreSchemaUID fsuid = FOStoreSchemaUID.read(in);
subclasses = in.readBoolean();
if (logger.isDebugEnabled()) {
logger.debug(
"GetExtentHandler for name=" + name); // NOI18N
}
for (Iterator i = db.getDBInfo().getDBClasses(); i.hasNext();) {
DBClass dbClass = (DBClass)i.next();
if (fsuid.equals(dbClass.getFSUID()) &&
name.equals(dbClass.getName())) {
clid = dbClass.getCLID();
// break because there can be only one match.
break;
}
}
}
// Get the set of CLIDs of extents
if (null != clid) {
dbExtents = getDBExtents(clid, subclasses, db);
}
if (logger.isDebugEnabled()) {
if (null == dbExtents) {
logger.debug("GetExtentHandler.hr: no extents"); // NOI18N
} else {
for (Iterator i = dbExtents.iterator(); i.hasNext();) {
logger.debug(
"GetExtentHandler.hr: extent=" + i.next()); // NOI18N
}
}
}
Status status = null;
int extentSize = 0;
int numInstances = 0;
int numOIDs = 0;
// Write instances into the reply
if (null == dbExtents) {
reply.writeInt(0);
reply.writeInt(0);
reply.writeInt(0);
status = Status.OK;
} else {
// Save space for writing various counts in the reply.
int extentSizePos = reply.beginStash();
int numInstancesPos = reply.beginStash();
int numOIDsPos = reply.beginStash();
for (Iterator i = dbExtents.iterator(); i.hasNext();) {
DBExtent extent = (DBExtent)i.next();
if (null != extent && extent.size() > 0) {
// Fetch some of the instances from the store.
// If we fail to get an object, continue, but set status
// to WARN.
for (Iterator j = extent.iterator(); j.hasNext();) {
OID oid = (OID)j.next();
try {
reply.writeOID(oid);
if (logger.isDebugEnabled()) {
logger.debug(
"GetExtentHandler.hR/2: " + // NOI18N
oid + " " + // NOI18N
Tester.toHex(oid.oid, 16));
}
if (numInstances < maxInstances) {
Block block = (Block)db.get(oid);
if (logger.isTraceEnabled()) {
block.dump();
}
byte data[] = block.getData();
reply.writeInt(data.length);
reply.write(data);
numInstances++;
} else {
numOIDs++;
}
extentSize++;
} catch (FOStoreDatabaseException ex) {
status = Status.WARN;
}
}
}
}
// Write counts.
reply.endStash(extentSize, extentSizePos);
reply.endStash(numInstances, numInstancesPos);
reply.endStash(numOIDs, numOIDsPos);
if (null == status) {
status = Status.OK;
}
}
reply.setStatus(status);
if (logger.isDebugEnabled()) {
logger.debug(
"GetExtentHandler.hR/3: " + // NOI18N
"extentSize=" + extentSize + // NOI18N
", numInstances=" + numInstances + // NOI18N
", numOIDs=" + numOIDs + " " + status); // NOI18N
}
return null;
}
/**
* Get a set of CLIDs of extents for the given clid. The set will have at
* most one element if subclasses is false, or an arbitrary number
* otherwise.
* @param clid The CLID of the class whose extent is wanted.
* @param subclasses If true, then include extents for all subclasses of
* the class corresponding to CLID.
* @param db Database in which to find extents.
* @return Set of extents of clid (and possibly its subclasses).
* @throws FOStoreDatabaseException if a database error occurs.
*/
HashSet getDBExtents(CLID clid, boolean subclasses, FOStoreDatabase db)
throws FOStoreDatabaseException {
HashSet rc = null;
if (logger.isDebugEnabled()) {
logger.debug(
"GetExtentHandler.getExtents: for " + clid); // NOI18N
}
OID oid = db.getDBInfo().getExtentOID(clid);
DBExtent extent = (DBExtent)db.getIfExists(oid);
if (null != extent) {
rc = new HashSet();
rc.add(extent);
}
if (logger.isDebugEnabled()) {
logger.debug(
"GetExtentHandler.getExtents: got " + extent); // NOI18N
}
if (subclasses) {
OID ssOID = DBInfo.getSubclassSetOID(clid);
SubclassSet ss = (SubclassSet)db.getIfExists(ssOID);
if (null != ss) {
for (Iterator i = ss.iterator(); i.hasNext();) {
CLID subCLID = (CLID)i.next();
OID subExtentOID = DBInfo.getExtentOID(subCLID);
DBExtent subExtent =
(DBExtent)db.getIfExists(subExtentOID);
if (null != subExtent) {
if (logger.isDebugEnabled()) {
logger.debug(
"GetExtentHandler.getExtents: "+ // NOI18N
"subclass " + subExtent); // NOI18N
}
if (null == rc) {
rc = new HashSet();
}
rc.add(subExtent);
}
}
}
}
return rc;
}
}