aternos / rados-ffi
一个使用 FFI 与 librados 的面向对象的 PHP 库
Requires
- ext-ffi: *
Requires (Dev)
- phpunit/phpunit: ^11.0
Suggests
- ext-posix: Resolve error codes to strings
This package is auto-updated.
Last update: 2024-09-08 15:41:59 UTC
README
一个使用 FFI 与 librados 的面向对象的 PHP 库。
要求
- Linux
- PHP 8.1 或更高版本
- php-ffi
- librados
安装
composer require aternos/rados-ffi
为什么不使用 phprados?
phprados 扩展是一个原生 PHP 扩展,提供了对 librados 的绑定。不幸的是,它在过去几年中几乎没有得到维护。虽然它可以编译最新版本的 PHP,但许多包含的 rados 函数 没有按预期工作,并且可能导致崩溃。此外,phprados 只添加了 librados API 的一小部分绑定。
php-rados-ffi 使用 PHP 的 FFI 系统提供了一个现代、面向对象且完整的接口来使用 librados。通过 FFI,PHP 可以直接加载共享库,如 librados,并调用其函数。这允许在不使用原生 PHP 扩展的情况下使用 librados,使其安装更容易,更新更安全。
使用方法
在可以使用库之前,必须加载 librados 共享库。这可以通过调用 Rados 类的 initialize() 方法来完成。
$rados = \Aternos\Rados\Rados::getInstance()->initialize();
预加载
为了预加载 librados,请确保启用 FFI 预加载,并将以下行添加到您的 opcache.preload 文件中
\Aternos\Rados\Rados::getInstance()->preload();
然后可以通过调用 initializePreloaded() 而不是 initialize() 来初始化 Rados。
$rados = \Aternos\Rados\Rados::getInstance()->initializePreloaded();
集群
然后可以使用 Rados 实例来创建一个 Cluster 实例,该实例用于连接到 Ceph 集群。
$cluster = $rados->createCluster(); $cluster->configReadFile('/etc/ceph/ceph.conf'); $cluster->connect();
一旦连接,就可以使用 Cluster 对象执行操作并请求有关集群的信息。例如,可以 ping 监视器、请求集群 ID 或列出存储池。
var_dump($cluster->pingMonitor("mon1")); var_dump($cluster->getClusterFsid()); foreach ($cluster->getPools() as $pool) { echo $pool->getName() . PHP_EOL; }
存储池
Pool 对象包含有关存储池的一般信息,并可用于获取一个 IOContext。
$ioContext = $pool->createIOContext();
IOContext
IOContext 对象用于在存储池上执行操作。例如,可以用来遍历存储池中的对象,或获取特定的对象。
foreach ($ioContext->createObjectIterator() as $entry) { echo $entry->getObject()->getId() . PHP_EOL; } $object = $ioContext->getObject("object1");
RadosObject
RadosObject 代表 Ceph 存储池中的一个对象,可以用来读取和写入数据或修改属性。
// Write full object $object->writeFull("Hello, World"); // Write at offset $object->write("World", 7); //Append to object $object->append("!"); // Read from object echo $object->read(13, 0) . PHP_EOL;
异步操作和完成
许多 IO 操作可以异步执行。异步操作返回一个 ResultCompletion 对象,可以用来跟踪操作的状态并等待其完成。
$completion = $object->writeFullAsync("Hello, World");
要检查完成的状况,可以使用 isComplete() 方法。
if ($completion->isComplete()) { echo "Operation is complete" . PHP_EOL; }
也可以使用 waitForComplete() 方法阻塞,直到操作完成。
$completion->waitForComplete(); $completion->isComplete(); // true
可以通过调用 cancel() 方法取消完成。
$completion->cancel();
可以使用 getResult() 方法获取操作的结果。结果类型取决于执行的操作。
$result = $completion->getResult();
如果操作失败,getResult() 方法将抛出异常。
同样,如果操作尚未完成,也会抛出异常。为了避免这种情况,可以使用 waitAndGetResult() 来阻塞,直到操作完成并获取结果。
$result = $completion->waitAndGetResult();
对象操作
对象操作 允许对对象进行原子操作。可以通过调用 $rados->createWriteOperation() 和 $rados->createReadOperation() 分别创建写和读操作。
$object = $ioContext->getObject("object1"); $operation = $rados->createWriteOperation(); $operation->addTask(new \Aternos\Rados\Operation\Common\Task\AssertExistsTask()); $operation->addTask(new \Aternos\Rados\Operation\Write\Task\AppendTask("Hello, World")); $operation->operate($object);
某些任务,尤其是在读操作中,会返回数据。这些数据可以在操作完成后通过在任务对象上调用 getResult() 来访问。
如果任务失败,getResult() 可能会抛出异常。
$object = $ioContext->getObject("object1"); $object->writeFull("Hello, World"); $operation = $rados->createReadOperation(); $task = new \Aternos\Rados\Operation\Read\Task\ReadTask(0, 12); $operation->addTask($task); $operation->operate($object); echo $task->getResult() . PHP_EOL;
如果操作中的单个任务失败,整个操作将失败。为了避免这种情况,可以向允许失败的任务添加 OperationTaskFlag::FailOK 标志。
$task = new \Aternos\Rados\Operation\Common\Task\CompareExtTask("Hello_", 0); $task->setFlags([\Aternos\Rados\Constants\OperationTaskFlag::FailOK]);
操作也可以通过使用 operateAsync() 方法异步执行。
可用任务
常用
读取
ChecksumTaskExecuteTask(带有输出数据)GetXAttributesTaskOMapGetByKeysTaskOMapGetKeysTaskOMapGetTaskReadTaskStatTask
写入
AppendTaskCreateObjectTaskExecuteTask(不包含输出数据)OMapClearTaskOMapRemoveKeyRangeTaskOMapRemoveKeysTaskOMapSetTaskRemoveTaskRemoveXAttributeTaskSetAllocHintTaskSetXAttributeTaskTruncateTaskWriteFullTaskWriteSameTaskWriteTaskZeroTask
异常和错误处理
如果 Rados 操作失败,它将抛出 RadosException。
可以使用 getCode() 方法获取从 librados 返回的错误代码。
要检查错误是否具有特定的错误代码,可以使用 is() 方法。
try { $cluster->getPool("nonexistent")->createIOContext(); } catch (\Aternos\Rados\Exception\RadosException $e) { if ($e->is(\Aternos\Rados\Generated\Errno::ENOENT)) { echo "Pool does not exist" . PHP_EOL; } }
可用的 Rados 功能
这个库旨在实现完整的 librados API。然而,由于 PHP 的 FFI 系统的限制,有些功能无法实现。
未计划
- 完成时的回调函数
- Watch/Notify
- 日志回调
可以使用 FFI 将 PHP 回调函数传递到 C 函数,但它们只能从主线程安全地调用(或多或少)。由于完成和监视都可以从任何线程调用,因此使用 PHP 回调函数是不可行的。
已实现,但不太支持
一些 librados 功能的文档不够充分,以至于我无法理解它们应该做什么。这些功能在这个库中有绑定,但我不能保证它们按预期工作。目前包括
- 自我管理的快照
- rados_(un)set_pool_full_try
如何避免段错误
该库使用 FFI 来调用 librados 共享库。为了避免由于不正确使用 librados 而导致的崩溃,只能调用标记为 public 且在源代码中未标记为 @internal 的方法和构造函数。
标记为 @internal 的方法不是公共 API 的一部分,不应直接调用。
许可
php-rados-ffi - 使用 FFI 的 Ceph RADOS 的 PHP 库
版权 (C) 2024 Aternos GmbH
这是一款免费软件;您可以在GNU Lesser General Public License版本2.1的条款下重新分发它或修改它,该许可证由自由软件基金会发布。请参阅文件LICENSE。
该库分发时希望它能派上用场,但没有任何保证;甚至没有关于其商业性或针对特定目的适用性的暗示性保证。
本库中的文档注释源自librados的文档注释。该文件include/librados.h是由Ceph的一部分librados.h生成的。Ceph的源代码可在https://github.com/ceph/ceph找到
Ceph - 可扩展的分布式文件系统
版权所有(C) 2004-2012 Sage Weil sage@newdream.net
这是一款免费软件;您可以在GNU Lesser General Public License版本2.1的条款下重新分发它或修改它,该许可证由自由软件基金会发布。请参阅文件LICENSE。