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()
方法异步执行。
可用任务
常用
读取
ChecksumTask
ExecuteTask
(带有输出数据)GetXAttributesTask
OMapGetByKeysTask
OMapGetKeysTask
OMapGetTask
ReadTask
StatTask
写入
AppendTask
CreateObjectTask
ExecuteTask
(不包含输出数据)OMapClearTask
OMapRemoveKeyRangeTask
OMapRemoveKeysTask
OMapSetTask
RemoveTask
RemoveXAttributeTask
SetAllocHintTask
SetXAttributeTask
TruncateTask
WriteFullTask
WriteSameTask
WriteTask
ZeroTask
异常和错误处理
如果 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。