 | 级别: 中级 Vladimir Silva (vladimir_silva@hotmail.com), 软件工程师, Consultant
2007 年 1 月 18 日 Storage Resource Broker(SRB)是由 San Diego Super Computer Center(SDSC)开发的,它是一个为连接网络上的异构数据源提供接口的软件平台。SRB 是一个被设计用来构建数据网格和访问远距离分布的复制数据集的中间件。在本文中,您将学习 SRB 的内幕知识,另外还可以了解 SRB 与流行的开放源码 Jakarta Commons Virtual File System(VFS)进行交互所需要的工具。
SRB 组件和特性
SRB 是为网格环境中的数据管理而设计的一个分布式文件系统,它提供了以下特性:
- 透明复制
- 归档、缓存、数据同步和备份
- 异构存储特性
- 容器和聚合数据移动
- 大量数据的提取
- 第三方操作,例如复制和移动
- 版本控制和分区数据管理
SRB 被划分成 3 个逻辑层:Client(表示层)、Metadata Catalog(MCAT)(逻辑层)和 SRB Agents(数据层)。SRB 的核心是 MCAT。
MCAT
MCAT 是一个记录名称空间以及数据对象与联邦中存储资源的映射的数据库系统。MCAT 可用来确定要在哪里定位给定的数据对象,以及具体的文件属性、元数据、访问控制列表、存储资源信息以及用户数据。
通过查询 MCAT,客户机可以很容易地找到分布数据对象,对数据进行复制、传输或同步,执行复杂查询以及其他功能。MCAT 会存储有关资源、用户、域机器和数据的信息。这些信息通常会在一些称为集合 的逻辑实体中进行分组。
集合和存储资源
集合 非常类似于文件系统中的文件夹或目录。它是一个包含其他集合或数据对象的对象。集合用来将数据组织成用户可以很容易访问和理解的逻辑层次。数据对象和最终物理存储之间的映射是通过资源来实现的。资源有 3 种:
- 物理资源表示数据对象物理存储的位置。例如 UNIX®/Linux® 文件系统、关系数据库(例如 Oracle 或 DB2®)、磁带、FTP 或 Web 服务器。
- 逻辑资源用来对一个或多个物理资源进行分组,这使得它对于数据存储的地点来说是透明的。这样就使透明的数据存储成为了可能。
- 集群资源可以对幕后的集群文件系统进行有效的管理。集群文件系统可以附加零个或多个物理资源。集群资源对于故障恢复情况非常有用,此时集合可以从一个失效服务器传输到另外一个服务器上,条件是它们共享相同的数据。
了解 Jakarta Commons
将 SRB 的强大特性和从 Jakarta 访问各种文件系统的单一 API 结合在一起可以获得什么好处呢?答案非常简单:这样做可以获得从任何地方查询并传输文件的功能。假设这样一种情况:用户具有一些异构的存储资源,例如 FTP、SFTP、SSH、HTTP 和 SRB 服务器。使用 Commons VFS 提供的单一 API,一个组织就可以充分利用自己的资源,而不需要对现有基础设施进行任何修改(或者只需少量进行修改即可)。文件可以在服务器之间透明地进行传输。发现服务可以很容易地被构建以查询用户和文件元数据。所有这些都会带来软件、硬件和开发资源的大量节省,并会最大化组织的投资回报。
Commons VFS-SRB 提供者实现
图 1. VFS-SRB 提供者实现类
实现 VFS-SRB 提供者的第一个步骤是创建一个配置 XML 文件。这个文件会告诉核心 API 有关提供者类名和协议模式的信息。这个文件必须在核心所读取的 Java™ 项目中的 META-INF 文件夹中创建。这非常关键,否则 VFS 就无法识别新的协议模式。SRB 的配置文件如下所示:
清单 1. SRB 配置文件
<providers>
<provider class-name=
"org.apache.commons.vfs.provider
.srb.SrbFileProvider">
<scheme name="srb"/>
</provider>
</providers>
|
有了配置文件,现在应该实现所需要的接口了。要实现的第一个类是文件提供者,其角色是提供有关新文件系统能力的信息,并创建文件系统的一个新实例。
SRB 文件提供者
SrbFileProvider 类的角色是双重的。首先,它提供了有关新文件系统能力的信息,例如:
- 创建、删除或重命名文件。
- 获取文件信息,例如类型、URI 和最近的修改时间。
- 从文件中读取数据,或者将数据写入文件。
- 列出子信息。
其次,它会通过返回一个 SrbFileSystem 类型的新对象来创建一个 SRB 文件系统的实例。
清单 2. SrbFileProvider 类
/**
* A file system provider, which uses direct file access.
*
* @author Vladimir Silva
*/
public class SrbFileProvider
extends AbstractOriginatingFileProvider
{
private Log log = LogFactory.getLog(SrbFileProvider.class);
public final static Collection capabilities =
Collections.unmodifiableCollection
(Arrays.asList(new Capability[]
{
Capability.CREATE,
Capability.DELETE,
Capability.RENAME,
Capability.GET_TYPE,
Capability.GET_LAST_MODIFIED,
Capability.SET_LAST_MODIFIED_FILE,
Capability.SET_LAST_MODIFIED_FOLDER,
Capability.LIST_CHILDREN,
Capability.READ_CONTENT,
Capability.URI,
Capability.WRITE_CONTENT
}));
public SrbFileProvider()
{
super();
setFileNameParser(SrbFileNameParser.getInstance());
}
/**
* Creates the filesystem.
*/
protected FileSystem doCreateFileSystem(final FileName name
, final FileSystemOptions fileSystemOptions)
throws FileSystemException
{
// Create the file system
String Path = name.getPath();
log.debug("Creating file system with name=" + name
+ " URI=" + name.getRootURI());
return
new SrbFileSystem((GenericFileName)name
, Path, fileSystemOptions);
}
public Collection getCapabilities()
{
return capabilities;
}
}
|

 |

|
SRB 文件系统
SRB 登录信息是由两个环境文件控制的:.MdasEnv 和 .MdasAuth。它们都保存在用户根目录下面的 .srb 目录中。文件 .MdasEnv 包含了用户的姓名、根集合、域、SRB 主机、端口和认证模式等信息。.MdasEnv 的语法请参阅清单 3 所示。文件 .MdasAuth 包含了一行代表用户密码的内容。
清单 3. MCAT/Agent 环境文件 $HOME/.srb/.MadsEnv
# SRB MCAT log in parameters
# The password resides in $HOME/.srb/.MdasAuth
# User's Collection (home directory name)
mdasCollectionName '/nccZone/home/srbAdmin.NCC'
# Location of the hhome directory
mdasCollectionHome '/nccZone/home/srbAdmin.NCC'
# SRB domain
mdasDomainName 'NCC'
mdasDomainHome 'NCC'
# User name
srbUser 'srbAdmin'
# Meta data catalog MCAT Host
srbHost 'ebony.rtpnc.epa.gov'
# Default port
#srbPort '5544'
# Default storage resource (machine) name
defaultResource 'nccResc'
# Authorization Schemes
# SRB supports Grid Security Infrastructure authentication!
# However the server must be
# recompiled with the GSI libraries
#AUTH_SCHEME 'PASSWD_AUTH'
#AUTH_SCHEME 'GSI_AUTH'
AUTH_SCHEME 'ENCRYPT1'
|
采用 Java 编程语言的 SRB 访问由 Real Grids On Networks(JARGON)的 Java API 提供。JARGON 是从头设计的,目的是为了使对网格的编程能够尽可能简单。它的功能包括透明复制、归档、缓存异构存储、聚合数据移动、影子对象等。使用 JARGON 连接 SRB 也非常简单。
清单 4. 使用 JARGON 连接 SRB
edu.sdsc.grid.io.GeneralFileSystem
srbFileSystem = FileFactory.newFileSystem(
new SRBAccount(host // SRB host
, port // SRB port (5544)
, user // User
, pwd // Pwd
, home // User's home dir
, domain // SRB domain
, defRes // SRB default resource (machine)
, mcatZone)); // MCAT Zone (for federations)
|
这段代码会创建一个 SRB 连接,它可以用来执行所有的文件系统操作或元数据查询操作。更加简单的方法是让 API 通过简单地调用下面的方法从配置文件 $HOME/.srb/.MdasEnv 和 $HOME/.srb/.MdasAuth 中读取帐号信息:
srbFileSystem = FileFactory.newFileSystem( new SRBAccount());
|
清单 5 给出了 SRB 文件系统提供者的 Commons VFS 实现。
清单 5. SrbFileSystem 类
/**
* A local file system.
*
* @author Vladimir Silva
*/
public class SrbFileSystem extends AbstractFileSystem
implements FileSystem
{
private Log log = LogFactory.getLog(SrbFileSystem.class);
private final GeneralFileSystem srbFileSystem;
private Map attribs = new HashMap();
public static final String HOME_DIRECTORY = "HOME_DIRECTORY";
/**
* Constructor
* @param rootName Path to the root folder
* @param rootFile
* @param opts FS options
* @throws FileSystemException
*/
public SrbFileSystem(final GenericFileName rootName,
final String rootFile,
final FileSystemOptions opts) throws
FileSystemException {
super(rootName, null, opts);
String host = rootName.getHostName();
int port = rootName.getPort();
String user = rootName.getUserName();
String pwd = rootName.getPassword();
try {
// Load some stuff from ~/.srb/MdasEnv user info file
SRBAccount srbAccount = new SRBAccount();
String domain;
// SRB user names are composed by [USER-NAME].[DOMAIN]
if (user.indexOf(".") != -1) {
domain = user.substring(user.indexOf(".") + 1);
user = user.substring(0, user.indexOf("."));
} else {
domain = srbAccount.getDomainName();
}
String home = srbAccount.getHomeDirectory();
String mcatZone = srbAccount.getMcatZone();
String defRes = srbAccount.getDefaultStorageResource();
// Create SRB connection, mot of the data comes from
// $HOME/.srb/MdasEnv
srbFileSystem = FileFactory.newFileSystem(
new SRBAccount(host // SRB host
, port // SRB port (5599)
, user // User
, pwd // Pwd
, home // User's home dir
, domain // SRB domain
, defRes, // SRB default resource (machine)
mcatZone)); // MCAT Zone (for federations)
// save SRB home dir
attribs.put(HOME_DIRECTORY, home);
log.debug("Constructor: Created new SRB FileSystem " +
srbFileSystem + " with home=" +
attribs.get(HOME_DIRECTORY));
} catch (Exception e) {
throw new FileSystemException(e.getMessage(), e);
}
}
/**
* Creates a file object.
*/
protected FileObject createFile(final FileName name)
throws FileSystemException {
// Create the file
String fileName = name.getPath();
log.debug("Creating new file="
+ fileName + " Name=" + name
+ " Parent=" + name.getParent());
return new SrbFileObject(this, name);
}
/**
* Returns the capabilities of this file system.
*/
protected void addCapabilities(final Collection caps) {
caps.addAll(DefaultLocalFileProvider.capabilities);
}
protected GeneralFileSystem getSRBFileSystem() {
return srbFileSystem;
}
public Object getAttribute(final String attrName)
throws FileSystemException {
return attribs.get(attrName);
}
}
|

 |

|
SRB-VFS 文件对象
SrbFileObject 是所有文件操作执行的地方,包括:
- 将文件对象附加到资源上(
doAttach)。
- 创建、删除、重命名子文件夹或文件(
doCreateFolder、doDelete、doRename)。
- 获取文件信息:名字、大小、属性等。
- 处理读写的 IO 流。
清单 6 给出了 SrbFileObject 类。
清单 6. SrbFileObject 类
/**
* A file object implementation which uses direct file access.
*
* @author Vladmir Silva
*/
public class SrbFileObject
extends AbstractFileObject implements FileObject {
private Log log = LogFactory.getLog(SrbFileObject.class);
// SRB file object
private GeneralFile file;
// File info: Name, size, last modified
private FileName fileName;
private String filePath;
private MetaDataRecordList attribs;
// SRB Attributes
private Map fileAttributes = new HashMap();
// File Object children
private Map children = new TreeMap();
// used to parse SRB date: yyyy-MM-dd-HH.mm.ss
Calendar calendar = Calendar.getInstance();
/**
* For items which matched the query, met the conditions above,
* the following values will be returned.
*/
final String[] selectFieldNames = {
SRBMetaDataSet.FILE_NAME,
SRBMetaDataSet.FILE_COMMENTS,
SRBMetaDataSet.FILE_TYPE_NAME,
SRBMetaDataSet.SIZE,
SRBMetaDataSet.USER_NAME,
SRBMetaDataSet.FILE_LAST_ACCESS_TIMESTAMP,
SRBMetaDataSet.RESOURCE_NAME,
SRBMetaDataSet.
DEFINABLE_METADATA_FOR_FILES
};
MetaDataSelect selects[] =
MetaDataSet.newSelection(selectFieldNames);
/**
* Creates a non-root file.
*/
protected SrbFileObject(final SrbFileSystem fileSystem,
final FileName name)
throws FileSystemException {
super(name, fileSystem);
this.fileName = name;
this.filePath = UriParser.decode(name.getPath());
log.debug("Constructor for file path "
+ filePath + " file name=" + name);
}
/**
* Returns the local file that this file object represents.
*/
protected GeneralFile getGeneralFile() {
return file;
}
/*
* Get an SRB Attribute value from a query record
*/
private Object getSrbAttribute(MetaDataRecordList record, String key)
{
return record.getValue(record.getFieldIndex(key));
}
/**
* Set custom SRB attributes for a given File object
* @param f
* @param results
*/
synchronized private void setMetaAttributes(SrbFileObject f,
MetaDataRecordList results)
{
// Size and last mod date must be setup
for (int i = 0; i < selectFieldNames.length; i++) {
final Object value = getSrbAttribute
(results, selectFieldNames[i]);
if (value != null && value.toString().length() > 0)
{
f.fileAttributes.put(selectFieldNames[i], value);
}
}
}
/**
* Load File info from the SRB server
*/
private void statSelf() {
SrbFileSystem fs = (SrbFileSystem) getFileSystem();
file = FileFactory.newFile(fs.getSRBFileSystem(), filePath);
if (file.isDirectory()) {
injectType(FileType.FOLDER);
} else {
injectType(FileType.FILE);
}
if (!file.exists()) {
log.debug(file + " not found in server");
injectType(FileType.IMAGINARY);
return;
}
try {
/**
* The metadata records list for each file
* (directory, or other value
* the query selected for) is stored in this array.
*/
MetaDataRecordList[] results = file.query(selects);
// Extract size & date stamp from results
if (results != null) {
// Set custom Attributes
this.attribs = results[0];
setMetaAttributes(this, results[0]);
log.debug("File info for " + filePath
+ " meta data:" + fileAttributes);
}
} catch (Exception e) {
log.error(e);
}
}
/**
* Attaches this file object to its file resource.
*/
protected void doAttach() throws Exception {
// check parent
SrbFileObject parent = (SrbFileObject) getParent();
if (parent != null && parent.children != null) {
final SrbFileObject self =
(SrbFileObject) parent.children.get(
fileName.getBaseName());
if (self != null) {
log.debug("Found self " + self.getGeneralFile()
+ " in parent " + parent);
file = self.getGeneralFile();
}
}
if (file == null) {
log.debug("Loading info for file " + filePath + " from SRB");
statSelf();
}
}
/**
* Determines the type of the file, returns null if the file does not
* exist.
*/
protected FileType doGetType() throws Exception {
throw new IllegalStateException("this should not happen");
}
/**
* Load subfolder for this file object
* @param srbFileSystem
* @param file
* @throws Exception
*/
private void getSubFolders(SRBFileSystem srbFileSystem, GeneralFile file)
throws Exception
{
SRBFileSystem srbFileSysem = (SRBFileSystem) ((SrbFileSystem)
getFileSystem()).getSRBFileSystem();
MetaDataCondition conditions[] = new MetaDataCondition[1];
MetaDataSelect selects[] =
{MetaDataSet.newSelection(SRBMetaDataSet.
DIRECTORY_NAME)};
String path = (file.isDirectory()) ? file.getAbsolutePath() :
file.getParent();
conditions[0] = MetaDataSet.newCondition(
SRBMetaDataSet.PARENT_DIRECTORY_NAME,
MetaDataCondition.EQUAL, path);
MetaDataRecordList[] results =
srbFileSystem.query(conditions, selects);
if (results != null) {
for (int i = 0; i < results.length; i++) {
final String absPath = (String) getSrbAttribute(results[i],
SRBMetaDataSet.DIRECTORY_NAME);
final String dirName = absPath.substring(
absPath.lastIndexOf("/") + 1);
SrbFileObject fo = (SrbFileObject) getFileSystem()
.resolveFile(getFileSystem().getFileSystemManager()
.resolveName(getName(),
UriParser.encode(dirName),
NameScope.CHILD));
fo.attribs = results[i];
fo.file = FileFactory.newFile(srbFileSysem, absPath);
fo.injectType(FileType.FOLDER);
log.debug("Folder [" + i + "]=" + dirName + " abs path " +
absPath + " parent=" + filePath);
children.put(dirName, fo);
}
}
}
/**
* Get children information
*/
private void statChildren() throws FileSystemException {
SRBFileSystem srbFileSysem = (SRBFileSystem) ((SrbFileSystem)
getFileSystem()).getSRBFileSystem();
try {
// 2 queries are required: 1 for files, other for folders
MetaDataRecordList[] results = file.query(selects);
if (results != null) {
//children = new TreeMap();
for (int i = 0; i < results.length; i++) {
// File Name
final String name = (String) getSrbAttribute(results[i],
SRBMetaDataSet.FILE_NAME);
// File Size
final long size = Long.parseLong((String) getSrbAttribute(
results[i], SRBMetaDataSet.SIZE));
// time stamp
final String sDate = (String) getSrbAttribute(results[i],
SRBMetaDataSet.FILE_LAST_ACCESS_TIMESTAMP);
// type
final String type = (String) getSrbAttribute(results[i],
SRBMetaDataSet.FILE_TYPE_NAME);
calendar.setTime(
new SimpleDateFormat("yyyy-MM-dd-HH.mm.ss").
parse(sDate));
final long lastModified =
calendar.getTimeInMillis();
// Add child
SrbFileObject fo = (SrbFileObject) getFileSystem().
resolveFile(getFileSystem().
getFileSystemManager().resolveName(
getName(),
UriParser.encode(name),
NameScope.CHILD));
fo.attribs = results[i];
fo.file = FileFactory.newFile(srbFileSysem
, filePath + "/" + name);
fo.injectType(FileType.FILE);
setMetaAttributes(fo, results[i]);
log.debug("File[" + i + "]="
+ name + " Size=" + size
+ " Last Mod:" + lastModified + " Type:" + type);
children.put(name, fo);
}
}
// query folders
getSubFolders(srbFileSysem, file);
} catch (Exception e) {
throw new FileSystemException (
"vfs.provider.srb/get-children.error",file);
}
}
/**
* Returns the children of the file.
*/
protected String[] doListChildren() throws Exception {
// use doListChildrenResolved for performance
return null;
}
/**
* Lists the children of this file.
*/
protected FileObject[] doListChildrenResolved() throws Exception {
// List the contents of the folder
statChildren();
return (SrbFileObject[]) children.values().toArray(
new SrbFileObject[children.size()]);
}
/**
* Deletes this file, and all children.
*/
protected void doDelete() throws Exception {
if (!file.delete()) {
throw new FileSystemException(
"vfs.provider.local/delete-file.error", file);
}
}
/**
* rename this file
*/
protected void doRename(FileObject newfile) throws Exception {
if (!file.renameTo(((SrbFileObject) newfile).getGeneralFile())) {
throw new FileSystemException(
"vfs.provider.local/rename-file.error",
new String[] {file.toString(),newfile.toString()});
}
}
/**
* Creates this folder.
*/
protected void doCreateFolder() throws Exception {
if (!file.mkdirs()) {
throw new FileSystemException(
"vfs.provider.local/create-folder.error", file);
}
}
/**
* Determines if this file can be written to.
*/
protected boolean doIsWriteable() throws FileSystemException {
return file.canWrite();
}
/**
* Determines if this file is hidden.
*/
protected boolean doIsHidden() {
return file.isHidden();
}
/**
* Determines if this file can be read.
*/
protected boolean doIsReadable() throws FileSystemException {
return file.canRead();
}
/**
* Gets the last modified time of this file.
*/
protected long doGetLastModifiedTime() throws FileSystemException {
if (attribs == null) {
log.error(
"Assertion failed - NULL meta data record list for file:"
+ file);
return -1;
}
try {
// SRB dirs don't have a time stamp
String sDate = (String) getSrbAttribute(attribs,
SRBMetaDataSet.FILE_LAST_ACCESS_TIMESTAMP);
// parse SRB date: yyyy-MM-dd-HH.mm.ss
calendar.setTime(
new SimpleDateFormat("yyyy-MM-dd-HH.mm.ss").parse(sDate));
return calendar.getTimeInMillis();
} catch (Exception e) {
throw new FileSystemException(e.getMessage(), e);
}
}
/**
* Sets the last modified time of this file.
*/
protected void doSetLastModifiedTime(final long modtime) throws
FileSystemException {
file.setLastModified(modtime);
}
/**
* Creates an input stream to read the content from.
*/
protected InputStream doGetInputStream() throws Exception {
return new SRBFileInputStream((SRBFile) file);
}
/**
* Creates an output stream to write the file content to.
*/
protected OutputStream doGetOutputStream(boolean bAppend)
throws Exception {
return new SRBFileOutputStream((SRBFile) file);
}
/**
* Returns the size of the file content (in bytes).
*/
protected long doGetContentSize() throws Exception {
//return getSize(); // fileSize;
if (attribs == null) {
log.error(
"Assertion failed - NULL meta data record list for file:"
+ file);
return -1;
}
return Long.parseLong((String) getSrbAttribute(attribs,
SRBMetaDataSet.SIZE));
}
/**
* Returns the attributes of this file.
*
* This implementation always returns an empty map.
*/
protected Map doGetAttributes() throws Exception {
return fileAttributes;
}
/**
* Called when the type or content of this file changes.
*/
protected void onChange() throws Exception {
log.debug("file=" + file);
statSelf();
}
}
|

 |

|
结束语
SRB 是一个为连接网络上的异构数据源提供接口的软件平台。SRB 是为构建数据网格和访问远距离分布的复制数据集而设计的。本文的主要目的是介绍 Jakarta Commons VFS 和 SRB 间的一个软件接口。
下载 | 描述 | 名字 | 大小 | 下载方法 |
|---|
| 示例脚本 | gr-jvfssrb.zip | 3MB | HTTP |
|---|
参考资料 学习
获得产品和技术
-
使用 IBM 试用版软件 构建您的下一个开放源码开发项目,这些软件可以从 developerWorks 上直接下载。
讨论
关于作者  | |  | Vladimir Silva 出生在厄瓜多尔的基多,在这里他获得了 Polytechnic Institute of the Army 的工程师学位。然后他又在 Middle Tennessee State University 获得了计算机科学的硕士学位。毕业后,他加入了 IBM Web-Ahead 技术智囊团,在这里他以一名软件工程师的身份参加了很多项目,例如 IBM 内部网格和 IBM Grid Toolbox。他还为 developerWorks 发表了很多与网格有关的技术文章,他在服务器端安全性方面的一些工作(数字证书)已经集成到了最新的 Globus Toolkit(GT4)版本中。他是 Grid Computing for Developers 一书的作者。他的其他兴趣包括神经网络和人工智能。他还拥有包括 OCP、MCSD 和 MCP 在内的众多 IT 证书。 |
对本文的评价
|  |