Interacting with an XRootD deployment

Recall that an XRootD deployment consists of a tree of instances of wrench::xrootd::Node, with some of these nodes being supervisors nodes and others being storage nodes. The following operations are supported by a supervisor node (and are accomplished by the supervisor interacting with the nodes that are in the subtree of which it is the root):

  • Synchronously reading a file (rarely used by an execution controller but included for completeness); and

  • Semi-Synchronously deleting a file (execution waits for supervisor to acknowledge delete request, but does not wait for the full XRootD subtree to be purged)

In addition, all storage nodes in an XRootD tree support all operations that an instance of Simple Storage Service does (which must be invoked directory on that node).

All interactions above are done by calling member functions of the wrench::StorageService class. Some of these member functions take an optional wrench::FileRegistryService argument, in which case they will also update entries in a file registry service (e.g., removing an entry when a file is deleted).

The following operations:

  • Writing to a file; and

  • Creating a file

are intentionally only implemented for storage nodes and not supervisor nodes (i.e., subtrees), due to the ambiguity of which storage node in the subtree rooted at the supervisor should storage the newly created data.

Several interactions with an XRootD Deployment are done simply by calling virtual methods of the wrench::StorageService class, but it is also possible to call directly methods of these Simple Storage Service class for XRootD storage nodes. This is because, in the XRootD distributed file systems, some notions (such as the location of a file) are different than in a non-distributed file system. For instance:

std::shared_ptr<wrench::XRootD::Deployment> deployment;
std::shared_ptr<wrench::DataFile> some_file;

[...]

// Read a file from one specific storage node
deployment->getRootSupervisor()->getChild(0)->readFile(some_file);

// Delete a file from the whole subtree, which may
// delete the file at multiple storage nodes
deployment->getRootSupervisor()->deleteFile(some_file);

Note that file deletion from an XRootD (sub)tree will not return an error even if the file does not exist. This is because the delete operation is only semi-synchronous and XRootD does not propagate “file not found” errors up the tree. Similarly, the only indication that a file read operation has failed is a network timeout while searching.

Note that reading and writing files is something an execution controller typically does not do directly. Instead, jobs created by the execution controller contain actions/tasks that read and write files as they execute. A XRootD supervisor node can then be passed to these tasks/actions exactly as one would pass a Simple Storage Service instance. For instance:

// Create a job
auto job = job_manager->createCompoundJob("some_job");
// Add a file read action that will read from an XRootD supervisor node
auto action = job->addFileReadAction("file_read", some_file, deployment->getRootSupervisor());

See the execution controller implementation in examples/action-api/XRootD/Controller.cpp for a more complete example.