Skip to content

Commit

Permalink
feat(FAM): added FamMap (WIP)
Browse files Browse the repository at this point in the history
  • Loading branch information
mcakircali committed Oct 30, 2024
1 parent b35baf0 commit a6b564d
Show file tree
Hide file tree
Showing 26 changed files with 820 additions and 96 deletions.
5 changes: 4 additions & 1 deletion src/eckit/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,10 @@ io/fam/FamList.cc
io/fam/FamList.h
io/fam/FamListIterator.cc
io/fam/FamListIterator.h
io/fam/FamMap.cc
io/fam/FamMap.h
io/fam/FamMapIterator.cc
io/fam/FamMapIterator.h
io/fam/FamName.cc
io/fam/FamName.h
io/fam/FamObject.cc
Expand Down Expand Up @@ -1009,4 +1013,3 @@ endif()
if( eckit_HAVE_ECKIT_GEO )
add_subdirectory( geo )
endif()

1 change: 1 addition & 0 deletions src/eckit/io/fam/FamHandle.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#include "eckit/config/LibEcKit.h"
#include "eckit/exception/Exceptions.h"
#include "eckit/io/fam/FamObject.h"
#include "eckit/log/Log.h"

namespace eckit {
Expand Down
2 changes: 0 additions & 2 deletions src/eckit/io/fam/FamHandle.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@

namespace eckit {

class FamObject;

//----------------------------------------------------------------------------------------------------------------------

class FamHandle: public DataHandle {
Expand Down
47 changes: 47 additions & 0 deletions src/eckit/io/fam/FamHashTable.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* (C) Copyright 1996- ECMWF.
*
* This software is licensed under the terms of the Apache Licence Version 2.0
* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
* In applying this licence, ECMWF does not waive the privileges and immunities
* granted to it by virtue of its status as an intergovernmental organisation nor
* does it submit to any jurisdiction.
*/

/*
* This software was developed as part of the Horizon Europe programme funded project OpenCUBE
* (Grant agreement: 101092984) horizon-opencube.eu
*/

#include "eckit/io/fam/FamHashTable.h"

#include "detail/FamHashNode.h"
#include "eckit/io/fam/FamObject.h"
#include "eckit/io/fam/FamObjectName.h"
#include "eckit/io/fam/FamRegionName.h"

// #include "detail/FamSessionDetail.h"
// #include "eckit/exception/Exceptions.h"

namespace eckit {

//----------------------------------------------------------------------------------------------------------------------

FamHashTable::FamHashTable(const FamRegionName& regionName, const std::string& tableName):
region_ {regionName.lookup()},
begin_ {initSentinel(tableName + "-hash-begin", sizeof(FamDescriptor))},
count_ {initSentinel(tableName + "-hash-count", sizeof(size_type))} { }

auto FamHashTable::initSentinel(const std::string& name, const fam::size_t size) const -> FamObject {
try {
return region_.allocateObject(size, name);
} catch (const AlreadyExists&) {
auto object = region_.lookupObject(name);
ASSERT(object.size() == size);
return object;
}
}

//----------------------------------------------------------------------------------------------------------------------

} // namespace eckit
108 changes: 108 additions & 0 deletions src/eckit/io/fam/FamHashTable.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/*
* (C) Copyright 1996- ECMWF.
*
* This software is licensed under the terms of the Apache Licence Version 2.0
* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
* In applying this licence, ECMWF does not waive the privileges and immunities
* granted to it by virtue of its status as an intergovernmental organisation nor
* does it submit to any jurisdiction.
*/

/*
* This software was developed as part of the Horizon Europe programme funded project OpenCUBE
* (Grant agreement: 101092984) horizon-opencube.eu
*/

/// @file FamHashTable.h
/// @author Metin Cakircali
/// @date Jul 2024

#pragma once

#include "eckit/io/fam/FamObject.h"
#include "eckit/io/fam/FamRegion.h"
// #include "eckit/io/fam/FamRegionName.h"
// #include "eckit/io/fam/FamVector.h"
#include "eckit/io/fam/FamMapIterator.h"
#include "eckit/types/FixedString.h"

#include <array>
#include <string>

namespace eckit {

class FamList;
// class FamRegion;
class FamRegionName;

//----------------------------------------------------------------------------------------------------------------------
// FAM HASHER

/// @brief Hash functor. Override this to make a specialized hasher
template<typename key_type>
struct FamHash {
auto operator()(const key_type& key) const noexcept -> std::size_t {
return std::hash<std::string> {}(key.asString());
/// @note example for a 3-level key
// const auto l1 = std::hash<std::string> {}(key.firstLevel);
// const auto l2 = std::hash<std::string> {}(key.secondLevel);
// const auto l3 = std::hash<std::string> {}(key.thirdLevel);
// return l1 ^ (l2 ^ (l3 << 1));
}
};

//----------------------------------------------------------------------------------------------------------------------

/// @todo template: initial table size, key size, (also equal and/or hasher ?)

/// @brief data structure is array of lists: FamVector< FamList >
// unsigned int index = key % table->size;

class FamHashTable {
static constexpr auto keySize = 32; // template?

static constexpr auto capacity = 1024;

public: // types
using key_type = FixedString<keySize>;
using hash_type = FamHash<key_type>;
/// @todo char array ?
using value_type = char;
// using key_equal = key_equal;
using size_type = fam::size_t;
using difference_type = size_type;

// using mapped_type = mapped_type;
// using allocator_type = allocator_type;
// using pointer = pointer;
// using const_pointer = const_pointer;

using reference = value_type&;
using const_reference = const value_type&;

using iterator = FamMapIterator;
using const_iterator = const FamMapIterator;

// using local_iterator = local_iterator;
// using const_local_iterator = const_local_iterator;

using node_type = FamList;

public: // methods
FamHashTable(const FamRegionName& regionName, const std::string& tableName);

private: // methods
auto initSentinel(const std::string& name, fam::size_t size) const -> FamObject;

private: // members
FamRegion region_;

FamObject begin_;
FamObject count_;

std::array<node_type, capacity> table_;
};

//----------------------------------------------------------------------------------------------------------------------

} // namespace eckit
99 changes: 70 additions & 29 deletions src/eckit/io/fam/FamList.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

#include "eckit/io/fam/FamList.h"

#include "detail/FamNode.h"
#include "detail/FamListNode.h"
#include "eckit/exception/Exceptions.h"
#include "eckit/io/fam/FamObject.h"
#include "eckit/io/fam/FamRegion.h"
Expand All @@ -28,35 +28,58 @@ namespace eckit {

//----------------------------------------------------------------------------------------------------------------------

namespace {

auto initSentinel(const FamRegion& region, const std::string& objectName, const fam::size_t objectSize) -> FamObject {
try {
return region.allocateObject(objectSize, objectName);
} catch (const AlreadyExists&) {
auto object = region.lookupObject(objectName);
ASSERT(object.size() == objectSize);
return object;
}
}

} // namespace

//----------------------------------------------------------------------------------------------------------------------

FamList::FamList(const FamRegion& region, const Descriptor& desc):
region_ {region},
head_ {region_.proxyObject(desc.head)},
tail_ {region_.proxyObject(desc.tail)},
size_ {region_.proxyObject(desc.size)} {
ASSERT(region.index() == desc.region);
}

FamList::FamList(const FamRegion& region, const std::string& listName):
region_ {region}, head_ {initSentinel(listName + "-head", sizeof(FamNode))},
tail_ {initSentinel(listName + "-tail", sizeof(FamNode))},
size_ {initSentinel(listName + "-size", sizeof(fam::size_t))} {
region_ {region},
head_ {initSentinel(region_, listName + "-list-head", sizeof(FamListNode))},
tail_ {initSentinel(region_, listName + "-list-tail", sizeof(FamListNode))},
size_ {initSentinel(region_, listName + "-list-size", sizeof(size_type))} {
// set head's next to tail's prev
if (FamNode::getNextOffset(head_) == 0) { head_.put(tail_.descriptor(), offsetof(FamNode, next)); }
if (FamListNode::getNextOffset(head_) == 0) { head_.put(tail_.descriptor(), offsetof(FamListNode, next)); }
// set tail's prev to head's next
if (FamNode::getPrevOffset(tail_) == 0) { tail_.put(head_.descriptor(), offsetof(FamNode, prev)); }
if (FamListNode::getPrevOffset(tail_) == 0) { tail_.put(head_.descriptor(), offsetof(FamListNode, prev)); }
}

FamList::FamList(const FamRegionName& name): FamList(name.lookup(), name.path().objectName) { }

FamList::~FamList() = default;

auto FamList::initSentinel(const std::string& name, const fam::size_t size) const -> FamObject {
try {
return region_.allocateObject(size, name);
} catch (const AlreadyExists&) { return region_.lookupObject(name); }
auto FamList::descriptor() const -> Descriptor {
return {region_.index(), head_.offset(), tail_.offset(), size_.offset()};
}

//----------------------------------------------------------------------------------------------------------------------
// iterators

auto FamList::begin() const -> iterator {
return {region_.proxyObject(FamNode::getNextOffset(head_))};
return {region_.proxyObject(FamListNode::getNextOffset(head_))};
}

auto FamList::cbegin() const -> const_iterator {
return {region_.proxyObject(FamNode::getNextOffset(head_))};
return {region_.proxyObject(FamListNode::getNextOffset(head_))};
}

auto FamList::end() const -> iterator {
Expand All @@ -81,31 +104,49 @@ auto FamList::back() const -> Buffer {
//----------------------------------------------------------------------------------------------------------------------
// modifiers

void FamList::push_front(const void* /* data */, const fam::size_t /* length */) {
NOTIMP;
void FamList::push_front(const void* data, const size_type length) {
// allocate an object
auto newObject = region_.allocateObject(sizeof(FamListNode) + length);

// set new object's previous to head
newObject.put(head_.descriptor(), offsetof(FamListNode, prev));

// set head's next to new object
const auto prevOffset = head_.swap(offsetof(FamListNode, next.offset), newObject.offset());
const auto oldObject = region_.proxyObject(prevOffset);

// set old object's prev to new object
oldObject.put(newObject.descriptor(), offsetof(FamListNode, prev));
// set new object's next to old object
newObject.put(oldObject.descriptor(), offsetof(FamListNode, next));

// finally put the data
newObject.put(length, offsetof(FamListNode, length));
newObject.put(data, sizeof(FamListNode), length);

// increment size
size_.add(0, 1UL);
}

void FamList::push_back(const void* data, const fam::size_t length) {
void FamList::push_back(const void* data, const size_type length) {
// allocate an object
auto newObject = region_.allocateObject(sizeof(FamNode) + length);
auto newObject = region_.allocateObject(sizeof(FamListNode) + length);

// set new object's next to tail
newObject.put(tail_.descriptor(), offsetof(FamNode, next));
newObject.put(tail_.descriptor(), offsetof(FamListNode, next));

// set tail's prev to new object
const auto prevOffset = tail_.swap(offsetof(FamNode, prev.offset), newObject.offset());

const auto oldObject = region_.proxyObject(prevOffset);
const auto prevOffset = tail_.swap(offsetof(FamListNode, prev.offset), newObject.offset());
const auto oldObject = region_.proxyObject(prevOffset);

// set old object's next to new object
oldObject.put(newObject.descriptor(), offsetof(FamNode, next));

oldObject.put(newObject.descriptor(), offsetof(FamListNode, next));
// set new object's prev to old object
newObject.put(oldObject.descriptor(), offsetof(FamNode, prev));
newObject.put(oldObject.descriptor(), offsetof(FamListNode, prev));

// finally the data
newObject.put(length, offsetof(FamNode, length));
newObject.put(data, sizeof(FamNode), length);
// finally put the data
newObject.put(length, offsetof(FamListNode, length));
newObject.put(data, sizeof(FamListNode), length);

// increment size
size_.add(0, 1UL);
Expand All @@ -122,12 +163,12 @@ void FamList::pop_back() {
//----------------------------------------------------------------------------------------------------------------------
// capacity

auto FamList::size() const -> fam::size_t {
return size_.get<fam::size_t>(0);
auto FamList::size() const -> size_type {
return size_.get<size_type>();
}

auto FamList::empty() const -> bool {
return (FamNode::getNextOffset(head_) == tail_.offset());
return (FamListNode::getNextOffset(head_) == tail_.offset());
}

//----------------------------------------------------------------------------------------------------------------------
Expand Down
Loading

0 comments on commit a6b564d

Please sign in to comment.