aternos/rados-ffi

一个使用 FFI 与 librados 的面向对象的 PHP 库

v1.1.2 2024-04-08 14:53 UTC

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() 方法异步执行。

可用任务

常用
读取
写入

异常和错误处理

如果 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。