add doc write lock and make imgui use it
This commit is contained in:
@@ -37,3 +37,20 @@ CRDTNotes::Doc* CRDTNotes::addDoc(const CRDTAgent& self_agent, const DocID& id)
|
|||||||
return &doc;
|
return &doc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CRDTNotes::writeLockRelease(const DocID& id) {
|
||||||
|
assert(_doc_write_locks.count(id) > 0);
|
||||||
|
_doc_write_locks.erase(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CRDTNotes::isWriteLocked(const DocID& id) const {
|
||||||
|
return _doc_write_locks.count(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<CRDTNotes::DocWriteLock> CRDTNotes::writeLockAquire(const DocID& id) {
|
||||||
|
if (_doc_write_locks.count(id)) {
|
||||||
|
return std::nullopt; // replace with exception instead?
|
||||||
|
}
|
||||||
|
|
||||||
|
_doc_write_locks.emplace(id);
|
||||||
|
return DocWriteLock{*this, id};
|
||||||
|
}
|
||||||
|
@@ -6,6 +6,8 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
using ID32 = std::array<uint8_t, 32>;
|
using ID32 = std::array<uint8_t, 32>;
|
||||||
|
|
||||||
@@ -37,9 +39,23 @@ class CRDTNotes {
|
|||||||
uint64_t seq{0};
|
uint64_t seq{0};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// RAII lock wrapper
|
||||||
|
struct DocWriteLock {
|
||||||
|
CRDTNotes* notes;
|
||||||
|
DocID id;
|
||||||
|
|
||||||
|
// ctr assumes lock
|
||||||
|
DocWriteLock(CRDTNotes& notes, const DocID& id) : notes(¬es), id(id) {}
|
||||||
|
DocWriteLock(const DocWriteLock&) = delete;
|
||||||
|
DocWriteLock(DocWriteLock&& other) : notes(other.notes), id(other.id) { other.notes = nullptr; }
|
||||||
|
~DocWriteLock(void) { if (notes) { notes->writeLockRelease(id); } }
|
||||||
|
bool operator==(const DocWriteLock& other) const { return id == other.id; }
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// TODO: add metadata to docs
|
// TODO: add metadata to docs
|
||||||
std::unordered_map<DocID, Doc> _docs;
|
std::unordered_map<DocID, Doc> _docs;
|
||||||
|
std::unordered_set<DocID> _doc_write_locks;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// config?
|
// config?
|
||||||
@@ -52,5 +68,16 @@ class CRDTNotes {
|
|||||||
Doc* getDoc(const DocID& id);
|
Doc* getDoc(const DocID& id);
|
||||||
|
|
||||||
Doc* addDoc(const CRDTAgent& self_agent, const DocID& doc);
|
Doc* addDoc(const CRDTAgent& self_agent, const DocID& doc);
|
||||||
|
|
||||||
|
void writeLockRelease(const DocID& id);
|
||||||
|
bool isWriteLocked(const DocID& id) const;
|
||||||
|
std::optional<DocWriteLock> writeLockAquire(const DocID& id);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct std::hash<CRDTNotes::DocWriteLock> {
|
||||||
|
std::uint64_t operator()(const CRDTNotes::DocWriteLock& s) const noexcept {
|
||||||
|
return std::hash<ID32>{}(s.id);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -48,6 +48,12 @@ namespace detail {
|
|||||||
} // detail
|
} // detail
|
||||||
|
|
||||||
|
|
||||||
|
std::unordered_set<CRDTNotes::DocWriteLock>::iterator CRDTNotesImGui::findLock(const CRDTNotes::DocID& doc_id) {
|
||||||
|
auto it = _held_locks.begin();
|
||||||
|
for (; it != _held_locks.end() && it->id != doc_id; it++) {}
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
|
||||||
CRDTNotesImGui::CRDTNotesImGui(CRDTNotes& notes, CRDTNotesSync& notes_sync, ContactStore4I& cs) : _notes(notes), _notes_sync(notes_sync), _cs(cs) {
|
CRDTNotesImGui::CRDTNotesImGui(CRDTNotes& notes, CRDTNotesSync& notes_sync, ContactStore4I& cs) : _notes(notes), _notes_sync(notes_sync), _cs(cs) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,17 +148,36 @@ bool CRDTNotesImGui::renderDoc(const CRDTNotes::DocID& doc_id) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto lock_it = findLock(doc_id);
|
||||||
|
bool self_held = lock_it != _held_locks.end();
|
||||||
|
const bool foreign_held = !self_held && _notes.isWriteLocked(doc_id);
|
||||||
|
|
||||||
auto text = doc->getText();
|
auto text = doc->getText();
|
||||||
if (renderDocText(text)) {
|
ImGui::InputTextMultiline(
|
||||||
|
"##doc",
|
||||||
|
&text,
|
||||||
|
{-1,-1},
|
||||||
|
ImGuiInputTextFlags_AllowTabInput |
|
||||||
|
(foreign_held ? ImGuiInputTextFlags_ReadOnly : ImGuiInputTextFlags_None) |
|
||||||
|
ImGuiInputTextFlags_CallbackAlways
|
||||||
|
//cb,
|
||||||
|
//&text
|
||||||
|
);
|
||||||
|
if (!foreign_held && !self_held && (ImGui::IsItemActive() || ImGui::IsItemEdited())) {
|
||||||
|
// TODO: check
|
||||||
|
_held_locks.emplace(_notes.writeLockAquire(doc_id).value());
|
||||||
|
self_held = true;
|
||||||
|
std::cout << "!!!! imgui lock aquired\n";
|
||||||
|
} else if (!foreign_held && self_held && !(ImGui::IsItemActive() || ImGui::IsItemEdited())) {
|
||||||
|
// release lock
|
||||||
|
_held_locks.erase(lock_it);
|
||||||
|
std::cout << "!!!! imgui lock released\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self_held && ImGui::IsItemEdited()) {
|
||||||
_notes_sync.merge(doc_id, text);
|
_notes_sync.merge(doc_id, text);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CRDTNotesImGui::renderDocText(std::string& text) const {
|
|
||||||
// TODO: replace with text editor (zep) or visualize stuff??
|
|
||||||
return ImGui::InputTextMultiline("##doc", &text, {-1,-1}, ImGuiInputTextFlags_AllowTabInput);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@@ -4,6 +4,7 @@
|
|||||||
#include <solanaceae/contact/fwd.hpp>
|
#include <solanaceae/contact/fwd.hpp>
|
||||||
|
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
class CRDTNotesImGui {
|
class CRDTNotesImGui {
|
||||||
CRDTNotes& _notes;
|
CRDTNotes& _notes;
|
||||||
@@ -13,6 +14,9 @@ class CRDTNotesImGui {
|
|||||||
bool _show_global_list {true};
|
bool _show_global_list {true};
|
||||||
|
|
||||||
std::set<CRDTNotes::DocID> _open_docs;
|
std::set<CRDTNotes::DocID> _open_docs;
|
||||||
|
std::unordered_set<CRDTNotes::DocWriteLock> _held_locks;
|
||||||
|
|
||||||
|
std::unordered_set<CRDTNotes::DocWriteLock>::iterator findLock(const CRDTNotes::DocID& doc_id);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CRDTNotesImGui(CRDTNotes& notes, CRDTNotesSync& notes_sync, ContactStore4I& cs);
|
CRDTNotesImGui(CRDTNotes& notes, CRDTNotesSync& notes_sync, ContactStore4I& cs);
|
||||||
@@ -22,6 +26,5 @@ class CRDTNotesImGui {
|
|||||||
bool renderContactListContactSmall(const Contact4 c, const bool selected) const;
|
bool renderContactListContactSmall(const Contact4 c, const bool selected) const;
|
||||||
|
|
||||||
bool renderDoc(const CRDTNotes::DocID& doc_id);
|
bool renderDoc(const CRDTNotes::DocID& doc_id);
|
||||||
bool renderDocText(std::string& text) const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user