如何在c++中实现分布式映射的API

How to implement an API for a distributed map in c++?

本文关键字:分布式 映射 API 实现 c++      更新时间:2023-10-16

我正在用c++实现一个分布式映射,并寻找一个好的API设计。第一个简单的选择是使它与std::map完全一样。迭代器出现问题。

IMap<std::string,Person>::iterator it;
it =  map.find("sample");
if(it == map.end() ){
    //NULL
}
for(it = map.begin(); it != map.end(); it++){
    //iterate
}

在分布式环境中(至少在我正在实现的环境中),没有映射的开始和结束。无论如何,它都不是有序的,所以返回迭代器看起来不像是一个选项。

第二种选择是通过复制返回值类,如下所示:

Person emptyPerson; 
Person person = map.get("sample");
if(person == emptyPerson){
    //NULL
}

问题是NULL检查看起来很奇怪。您可以先询问它是否可用,然后获取对象,但要求这些操作必须是原子操作。

第三个选项是返回指针:

Person* person = map.get("sample");
if(person == NULL){
    //NULL
}

我不想这样做,因为它很容易出错。用户需要删除我在内部创建的指针。

我正在考虑返回一个包装用户对象的类,比如:

value_reference<std::map, Person>  person = map.get("sample");
if(value_reference.hasValue() ){
    Person p = value_reference;
}

那么你认为最好的方法是什么呢?

你知道有什么好的api类似于需求我的分布式地图吗?

基于您的术语"分布式地图",我做出以下假设:

  • 数据的一个子集在本地可用,对于不是数据集的数据,需要执行一些远程获取
  • 对返回对象的写入不应自动保留在数据存储中。应改为发出明确的更新请求

如果这是真的,那么迭代器不是您想要的,也不需要STL容器模型。C++迭代程序的概念要求您实现预增量(++i)运算符,如果您的数据是无序的并且分布在多个节点上,那么"给我下一个条目"的请求就没有意义了。

如果出于互操作性的原因想要模拟STL容器和迭代器,您可能会创建一个糟糕的拼凑:让映射的end()方法返回一个sentinel迭代器实例,让迭代器的operator++()返回相同的sentinel。实际上,每个迭代器都会指向"映射中的最后一个元素"。我强烈建议不要采取这种方法,除非有必要,而且我认为不会。

听起来您想要的是一个简单的CRUD模型,其中必须明确请求更新。在这种情况下,您的API看起来像:

template <typename TKey, typename TValue>
class IMap<TKey, TValue>
{
public:
    void create(TKey const & key, TValue const & value) = 0;
    std::unique_ptr<TValue> retrieve(TKey const & key) = 0;
    bool update(TKey const & key, TValue const & value) = 0;
    bool remove(TKey const & key) = 0;
};

在检索的情况下,您只需按照建议返回一个空指针。std::unique_ptr<>将确保调用者将删除分配的对象或显式地获得它的所有权

对于"返回指针到新分配的对象"的情况,另一种选择是让调用方传入引用,如果在映射中找到该值,则该方法将返回true。例如,这将允许调用者直接将对象检索到数组槽或其他本地结构中,而不需要中间堆分配。

bool retrieve(TKey const & key, TValue & value) = 0;

使用这种方法看起来像:

Person person;
if (map.retrieve("sample", person)) {
    std::cout << "Found person: " << person << std::endl;
} else {
    std::cout << "Did not find person." << std::endl;
}

您也可以同时提供这两种重载,默认情况下,返回指针的重载可以用另一种实现:

template <typename TKey, typename TValue>
std::unique_ptr<TValue> IMap<TKey, TValue>::retrieve(TKey const & key)
{
    TValue v;
    return std::unique_ptr<TValue>(retrieve(key, v) ? new TValue(v) : nullptr);
}

我认为选项3是最好的。你可以使用C++11中引入的一种标准智能指针类型来模拟它,这样你仍然可以创建一个指针,但用户不必释放它

std::unqiue_ptr<Person> person = map.get("sample");
if(person) {
      person->makeMeASandwitch();
}