diff --git a/python_tests/test_find.py b/python_tests/test_find.py index 42308bbf..5ca8291c 100644 --- a/python_tests/test_find.py +++ b/python_tests/test_find.py @@ -4,6 +4,7 @@ from .conftest import DB0_DIR, DATA_PX import itertools from datetime import datetime +import operator @db0.memo() @@ -354,4 +355,24 @@ def test_find_with_scope_defined(db0_fixture): # use scoped find to find instances from different prefixes assert [x.value for x in db0.find(MemoScopedClass, "tag1", prefix = px_name)] == [123] assert [x.value for x in db0.find(MemoScopedClass, "tag1", prefix = other_px_name)] == [456] - \ No newline at end of file + + +def test_find_extract_multiple_indices(db0_no_autocommit, memo_tags): + # pick elements by specific indexes + result = db0.find("tag1")[3, 6, 7] + assert type(result) is tuple + assert len(result) == 3 + + +def test_find_extract_duplicate_indices(db0_no_autocommit, memo_tags): + # pick elements by specific indexes + result = db0.find("tag1")[3, 6, 7, 3, 6] + assert result[0] is result[3] + assert result[1] is result[4] + + +def test_find_extract_invalid_indices(db0_no_autocommit, memo_tags): + query = db0.find("tag1") + assert len(query) == 10 + with pytest.raises(IndexError): + _ = db0.find("tag1")[3, 6, 7, 3, 10] diff --git a/python_tests/test_memo_no_cache.py b/python_tests/test_memo_no_cache.py index 9fd60ccb..91312ccc 100644 --- a/python_tests/test_memo_no_cache.py +++ b/python_tests/test_memo_no_cache.py @@ -1,8 +1,9 @@ from random import random import pytest import dbzero as db0 -from .memo_test_types import MemoTestClass, TriColor, MemoAnyAttrs +from .memo_test_types import MemoTestClass from dataclasses import dataclass +from .conftest import DB0_DIR import random import string import gc @@ -17,8 +18,10 @@ def rand_string(max_len): @dataclass class MemoNoCacheClass: data: str - + value: int = 0 + def __init__(self): + self.value = random.randint(0, 1000000) self.data = rand_string(12 << 10) @@ -61,4 +64,54 @@ def test_excluding_no_cache_instances_from_dbzero_cache(db0_fixture): final_cache_size = db0.get_cache_stats()["size"] # make sure cache utilization is low assert abs(final_cache_size - initial_cache_size) < (300 << 10) - \ No newline at end of file + + +def test_fetching_no_cache_objects(db0_fixture): + px_name = db0.get_current_prefix().name + buf = db0.list() + uuid_list = [] + for _ in range(100): + obj = MemoNoCacheClass() + buf.append(obj) + uuid_list.append(db0.uuid(obj)) + + db0.close() + db0.init(DB0_DIR) + db0.open(px_name, "r") + + # now fetch objects by uuid + initial_cache_size = db0.get_cache_stats()["size"] + total_len = 0 + for id in uuid_list: + # NOTE: must fetch with type, otherwise no_cache flag may not be honored + obj = db0.fetch(MemoNoCacheClass, id) + # this forces data retrieval + total_len += len(obj.data) + + final_cache_size = db0.get_cache_stats()["size"] + # make sure cache utilization is low + assert abs(final_cache_size - initial_cache_size) < (300 << 10) + + +def test_find_no_cache_objects(db0_fixture): + px_name = db0.get_current_prefix().name + buf = db0.list() + for _ in range(100): + obj = MemoNoCacheClass() + buf.append(obj) + + db0.close() + db0.init(DB0_DIR) + db0.open(px_name, "r") + + # now retrieve objects using db0.find + initial_cache_size = db0.get_cache_stats()["size"] + total_len = 0 + for obj in db0.find(MemoNoCacheClass): + # this forces data retrieval (but not caching) + total_len += len(obj.data) + + assert total_len > 0 + final_cache_size = db0.get_cache_stats()["size"] + # make sure cache utilization is low + assert abs(final_cache_size - initial_cache_size) < (300 << 10) diff --git a/src/dbzero/bindings/python/PyAPI.cpp b/src/dbzero/bindings/python/PyAPI.cpp index 170493ec..1f0d67bc 100644 --- a/src/dbzero/bindings/python/PyAPI.cpp +++ b/src/dbzero/bindings/python/PyAPI.cpp @@ -75,7 +75,7 @@ namespace db0::python PY_API_FUNC return runSafe(tryGetCacheStats); } - + PyObject *tryGetLangCacheStats() { auto lang_cache = PyToolkit::getPyWorkspace().getWorkspace().getLangCache(); @@ -144,7 +144,7 @@ namespace db0::python return NULL; } - PY_API_FUNC + PY_API_FUNC return runSafe(tryFetch, py_id, reinterpret_cast(py_type), prefix_name).steal(); } diff --git a/src/dbzero/bindings/python/PyInternalAPI.cpp b/src/dbzero/bindings/python/PyInternalAPI.cpp index 5ee3cc5b..cde42726 100644 --- a/src/dbzero/bindings/python/PyInternalAPI.cpp +++ b/src/dbzero/bindings/python/PyInternalAPI.cpp @@ -170,27 +170,32 @@ namespace db0::python using ClassFactory = db0::object_model::ClassFactory; using Class = db0::object_model::Class; - // validate pre-storage class first + // Validate pre-storage class first if (py_expected_type && !checkObjectIdType(object_id, py_expected_type)) { THROWF(db0::InputException) << "Object ID type mismatch"; } auto storage_class = object_id.m_storage_class; auto addr = object_id.m_address; - if (storage_class == db0::object_model::StorageClass::OBJECT_REF) { + if (storage_class == db0::object_model::StorageClass::OBJECT_REF) { auto &class_factory = db0::object_model::getClassFactory(*fixture); - auto result = PyToolkit::unloadObject(fixture, addr, class_factory, nullptr, addr.getInstanceId()); - auto &memo = reinterpret_cast(result.get())->ext(); - // validate type if requested (no validation for MemoBase) - if (py_expected_type && !PyToolkit::getTypeManager().isMemoBase(py_expected_type)) { + if (py_expected_type && !PyToolkit::getTypeManager().isMemoBase(py_expected_type)) { // in other cases the type must match the actual object type - auto expected_class = class_factory.getExistingType(py_expected_type); + auto expected_class = class_factory.getExistingType(py_expected_type); + // honor class-specific access flags (e.g. type-level no_cache) + auto result = PyToolkit::unloadObject(fixture, addr, class_factory, nullptr, addr.getInstanceId(), + expected_class->getInstanceFlags() + ); + auto &memo = reinterpret_cast(result.get())->ext(); if (memo.getType() != *expected_class) { THROWF(db0::InputException) << "Object type mismatch"; } + return result; + } else { + // unload without type validation + return PyToolkit::unloadObject(fixture, addr, class_factory, nullptr, addr.getInstanceId()); } - return result; } else if (storage_class == db0::object_model::StorageClass::DB0_CLASS) { auto &class_factory = db0::object_model::getClassFactory(*fixture); auto class_ptr = class_factory.getTypeByAddr(addr).m_class; diff --git a/src/dbzero/bindings/python/PyInternalAPI.hpp b/src/dbzero/bindings/python/PyInternalAPI.hpp index b338ec84..ddebb5a1 100644 --- a/src/dbzero/bindings/python/PyInternalAPI.hpp +++ b/src/dbzero/bindings/python/PyInternalAPI.hpp @@ -117,6 +117,9 @@ namespace db0::python } catch (const db0::ClassNotFoundException &e) { PyErr_SetString(PyToolkit::getTypeManager().getClassNotFoundError(), e.what()); return returnError(); + } catch (const db0::IndexException &e) { + PyErr_SetString(PyExc_IndexError, e.what()); + return returnError(); } #if ENABLE_DEBUG_EXCEPTIONS catch (const db0::AbstractException &e) { diff --git a/src/dbzero/bindings/python/PyTagsAPI.cpp b/src/dbzero/bindings/python/PyTagsAPI.cpp index 6f00ba94..d7c290c1 100644 --- a/src/dbzero/bindings/python/PyTagsAPI.cpp +++ b/src/dbzero/bindings/python/PyTagsAPI.cpp @@ -58,19 +58,8 @@ namespace db0::python return { std::move(result.first), std::move(query_observers) }; } - PyObject *trySplitBy(PyObject *args, PyObject *kwargs) + PyObject *trySplitBy(PyObject *py_tags, PyObject *py_query, bool exclusive) { - // extract 2 object arguments - PyObject *py_tags = nullptr; - PyObject *py_query = nullptr; - int exclusive = true; - // tags, query, exclusive (bool) - static const char *kwlist[] = {"tags", "query", "exclusive", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|p", const_cast(kwlist), &py_tags, &py_query, &exclusive)) { - PyErr_SetString(PyExc_TypeError, "Invalid argument type"); - return NULL; - } - if (!PyObjectIterable_Check(py_query)) { THROWF(db0::InputException) << "Invalid argument type"; } @@ -84,9 +73,19 @@ namespace db0::python PyObject *PyAPI_splitBy(PyObject *, PyObject *args, PyObject *kwargs) { + // extract 2 object arguments + PyObject *py_tags = nullptr; + PyObject *py_query = nullptr; + int exclusive = true; + // tags, query, exclusive (bool) + static const char *kwlist[] = {"tags", "query", "exclusive", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|p", const_cast(kwlist), &py_tags, &py_query, &exclusive)) { + return NULL; + } + PY_API_FUNC - return runSafe(trySplitBy, args, kwargs); - } + return runSafe(trySplitBy, py_tags, py_query, exclusive); + } PyObject *trySelectModCandidates(const ObjectIterable &iterable, StateNumType from_state, std::optional to_state) diff --git a/src/dbzero/bindings/python/PyTagsAPI.hpp b/src/dbzero/bindings/python/PyTagsAPI.hpp index 357a43b5..2d1b80ac 100644 --- a/src/dbzero/bindings/python/PyTagsAPI.hpp +++ b/src/dbzero/bindings/python/PyTagsAPI.hpp @@ -43,7 +43,7 @@ namespace db0::python const char *prefix_name = nullptr); PyObject *PyAPI_splitBy(PyObject *, PyObject *args, PyObject *kwargs); - + PyObject *PyAPI_selectModCandidates(PyObject *, PyObject *args, PyObject *kwargs); PyObject *PyAPI_splitBySnapshots(PyObject *, PyObject *const *args, Py_ssize_t nargs); diff --git a/src/dbzero/bindings/python/PyToolkit.cpp b/src/dbzero/bindings/python/PyToolkit.cpp index ae728407..3acb14e7 100644 --- a/src/dbzero/bindings/python/PyToolkit.cpp +++ b/src/dbzero/bindings/python/PyToolkit.cpp @@ -91,10 +91,10 @@ namespace db0::python } PyToolkit::ObjectSharedPtr PyToolkit::unloadObject(db0::swine_ptr &fixture, Address address, - TypeObjectPtr lang_class, std::uint16_t instance_id) + TypeObjectPtr lang_class, std::uint16_t instance_id, AccessFlags access_mode) { auto &class_factory = fixture->get(); - return unloadObject(fixture, address, class_factory, lang_class, instance_id); + return unloadObject(fixture, address, class_factory, lang_class, instance_id, access_mode); } bool PyToolkit::isExistingObject(db0::swine_ptr &fixture, Address address, std::uint16_t instance_id) @@ -124,8 +124,9 @@ namespace db0::python return db0::object_model::Object::checkUnload(fixture, address, instance_id, true); } - PyToolkit::ObjectSharedPtr PyToolkit::tryUnloadObject(db0::swine_ptr &fixture, Address address, - const ClassFactory &class_factory, TypeObjectPtr lang_type_ptr, std::uint16_t instance_id) + PyToolkit::ObjectSharedPtr PyToolkit::tryUnloadObject( + db0::swine_ptr &fixture, Address address, const ClassFactory &class_factory, + TypeObjectPtr lang_type_ptr, std::uint16_t instance_id, AccessFlags access_mode) { // try unloading from cache first auto &lang_cache = fixture->getLangCache(); @@ -148,7 +149,9 @@ namespace db0::python } // Unload from backend otherwise - auto stem = db0::object_model::Object::tryUnloadStem(fixture, address, instance_id); + auto stem = db0::object_model::Object::tryUnloadStem( + fixture, address, instance_id, access_mode + ); if (!stem) { // object not found return {}; @@ -180,17 +183,19 @@ namespace db0::python } PyToolkit::ObjectSharedPtr PyToolkit::unloadObject(db0::swine_ptr &fixture, Address address, - const ClassFactory &class_factory, TypeObjectPtr lang_type_ptr, std::uint16_t instance_id) + const ClassFactory &class_factory, TypeObjectPtr lang_type_ptr, std::uint16_t instance_id, AccessFlags access_mode) { - auto result = tryUnloadObject(fixture, address, class_factory, lang_type_ptr, instance_id); + auto result = tryUnloadObject( + fixture, address, class_factory, lang_type_ptr, instance_id, access_mode + ); if (!result) { THROWF(db0::InputException) << "Invalid UUID or object has been deleted"; } return result; } - + PyToolkit::ObjectSharedPtr PyToolkit::unloadObject(db0::swine_ptr &fixture, Address address, - std::shared_ptr type, TypeObjectPtr lang_class) + std::shared_ptr type, TypeObjectPtr lang_class, AccessFlags access_mode) { assert(lang_class); // try unloading from cache first @@ -204,7 +209,7 @@ namespace db0::python // NOTE: lang_class may be of a base type (e.g. MemoBase) auto *memo_ptr = MemoObjectStub_new(lang_class); // unload with type hint - memo_ptr->unload(fixture, address, type, Object::with_type_hint{}); + memo_ptr->unload(fixture, address, type, Object::with_type_hint{}, access_mode); // NOTE: Py_OWN only possible with a proper object obj_ptr = Py_OWN((PyObject*)memo_ptr); if (!memo_ptr->ext().isNoCache()) { @@ -233,7 +238,8 @@ namespace db0::python return unloadExpiredRef(fixture, weak_ref.getAddress(), weak_ref->m_fixture_uuid, weak_ref->m_address); } - PyToolkit::ObjectSharedPtr PyToolkit::unloadList(db0::swine_ptr fixture, Address address, std::uint16_t) + PyToolkit::ObjectSharedPtr PyToolkit::unloadList(db0::swine_ptr fixture, Address address, + std::uint16_t, AccessFlags access_mode) { using List = db0::object_model::List; @@ -247,13 +253,16 @@ namespace db0::python auto list_object = ListDefaultObject_new(); // retrieve actual dbzero instance - list_object->unload(fixture, address); + list_object->unload(fixture, address, access_mode); // add list object to cache - lang_cache.add(address, list_object.get()); + if (!list_object->ext().isNoCache()) { + lang_cache.add(address, list_object.get()); + } return shared_py_cast(std::move(list_object)); } - PyToolkit::ObjectSharedPtr PyToolkit::unloadByteArray(db0::swine_ptr fixture, Address address) + PyToolkit::ObjectSharedPtr PyToolkit::unloadByteArray(db0::swine_ptr fixture, + Address address, AccessFlags access_mode) { // try pulling from cache first auto &lang_cache = fixture->getLangCache(); @@ -265,13 +274,16 @@ namespace db0::python auto byte_array_object = ByteArrayDefaultObject_new(); // retrieve actual dbzero instance - byte_array_object->unload(fixture, address); + byte_array_object->unload(fixture, address, access_mode); // add byte_array object to cache - lang_cache.add(address, byte_array_object.get()); + if (!byte_array_object->ext().isNoCache()) { + lang_cache.add(address, byte_array_object.get()); + } return shared_py_cast(std::move(byte_array_object)); } - PyToolkit::ObjectSharedPtr PyToolkit::unloadIndex(db0::swine_ptr fixture, Address address, std::uint16_t) + PyToolkit::ObjectSharedPtr PyToolkit::unloadIndex(db0::swine_ptr fixture, + Address address, std::uint16_t, AccessFlags access_mode) { // try pulling from cache first auto &lang_cache = fixture->getLangCache(); @@ -283,14 +295,17 @@ namespace db0::python auto index_object = IndexDefaultObject_new(); // retrieve actual dbzero instance - index_object->unload(fixture, address); + index_object->unload(fixture, address, access_mode); // add list object to cache - lang_cache.add(address, index_object.get()); + if (!index_object->ext().isNoCache()) { + lang_cache.add(address, index_object.get()); + } return shared_py_cast(std::move(index_object)); } - PyToolkit::ObjectSharedPtr PyToolkit::unloadSet(db0::swine_ptr fixture, Address address, std::uint16_t) + PyToolkit::ObjectSharedPtr PyToolkit::unloadSet(db0::swine_ptr fixture, + Address address, std::uint16_t, AccessFlags access_mode) { // try pulling from cache first auto &lang_cache = fixture->getLangCache(); @@ -302,14 +317,17 @@ namespace db0::python auto set_object = SetDefaultObject_new(); // retrieve actual dbzero instance - set_object->unload(fixture, address); + set_object->unload(fixture, address, access_mode); // add list object to cache - lang_cache.add(address, set_object.get()); + if (!set_object->ext().isNoCache()) { + lang_cache.add(address, set_object.get()); + } return shared_py_cast(std::move(set_object)); } - PyToolkit::ObjectSharedPtr PyToolkit::unloadDict(db0::swine_ptr fixture, Address address, std::uint16_t) + PyToolkit::ObjectSharedPtr PyToolkit::unloadDict(db0::swine_ptr fixture, + Address address, std::uint16_t, AccessFlags access_mode) { // try pulling from cache first auto &lang_cache = fixture->getLangCache(); @@ -321,14 +339,17 @@ namespace db0::python auto dict_object = DictDefaultObject_new(); // retrieve actual dbzero instance - dict_object->unload(fixture, address); + dict_object->unload(fixture, address, access_mode); // add list object to cache - lang_cache.add(address, *dict_object); + if (!dict_object->ext().isNoCache()) { + lang_cache.add(address, *dict_object); + } return shared_py_cast(std::move(dict_object)); } - PyToolkit::ObjectSharedPtr PyToolkit::unloadTuple(db0::swine_ptr fixture, Address address, std::uint16_t) + PyToolkit::ObjectSharedPtr PyToolkit::unloadTuple(db0::swine_ptr fixture, + Address address, std::uint16_t, AccessFlags access_mode) { // try pulling from cache first auto &lang_cache = fixture->getLangCache(); @@ -340,13 +361,15 @@ namespace db0::python auto tuple_object = TupleDefaultObject_new(); // retrieve actual dbzero instance - tuple_object->unload(fixture, address); + tuple_object->unload(fixture, address, access_mode); // add list object to cache - lang_cache.add(address, *tuple_object); + if (!tuple_object->ext().isNoCache()) { + lang_cache.add(address, *tuple_object); + } return shared_py_cast(std::move(tuple_object)); } - + PyToolkit::ObjectSharedPtr PyToolkit::deserializeObjectIterable(db0::swine_ptr fixture, std::vector::const_iterator &iter, std::vector::const_iterator end) diff --git a/src/dbzero/bindings/python/PyToolkit.hpp b/src/dbzero/bindings/python/PyToolkit.hpp index 644a6b0e..72cf99bb 100644 --- a/src/dbzero/bindings/python/PyToolkit.hpp +++ b/src/dbzero/bindings/python/PyToolkit.hpp @@ -99,11 +99,11 @@ namespace db0::python // Unload with type resolution // optionally may use specific lang class (e.g. MemoBase) static ObjectSharedPtr unloadObject(db0::swine_ptr &, Address, const ClassFactory &, - TypeObjectPtr lang_class = nullptr, std::uint16_t instance_id = 0); + TypeObjectPtr lang_class = nullptr, std::uint16_t instance_id = 0, AccessFlags = {}); static ObjectSharedPtr tryUnloadObject(db0::swine_ptr &, Address, const ClassFactory &, - TypeObjectPtr lang_class = nullptr, std::uint16_t instance_id = 0); + TypeObjectPtr lang_class = nullptr, std::uint16_t instance_id = 0, AccessFlags = {}); static ObjectSharedPtr unloadObject(db0::swine_ptr &, Address, TypeObjectPtr lang_class = nullptr, - std::uint16_t instance_id = 0); + std::uint16_t instance_id = 0, AccessFlags = {}); static bool isExistingObject(db0::swine_ptr &, Address, std::uint16_t instance_id = 0); @@ -121,15 +121,15 @@ namespace db0::python // Unload with known type & lang class // note that lang_class may be a base of the actual type (e.g. MemoBase) static ObjectSharedPtr unloadObject(db0::swine_ptr &, Address address, - std::shared_ptr, TypeObjectPtr lang_class); + std::shared_ptr, TypeObjectPtr lang_class, AccessFlags = {}); - static ObjectSharedPtr unloadList(db0::swine_ptr, Address, std::uint16_t instance_id = 0); - static ObjectSharedPtr unloadIndex(db0::swine_ptr, Address, std::uint16_t instance_id = 0); - static ObjectSharedPtr unloadSet(db0::swine_ptr, Address, std::uint16_t instance_id = 0); - static ObjectSharedPtr unloadDict(db0::swine_ptr, Address, std::uint16_t instance_id = 0); - static ObjectSharedPtr unloadTuple(db0::swine_ptr, Address, std::uint16_t instance_id = 0); + static ObjectSharedPtr unloadList(db0::swine_ptr, Address, std::uint16_t instance_id = 0, AccessFlags = {}); + static ObjectSharedPtr unloadIndex(db0::swine_ptr, Address, std::uint16_t instance_id = 0, AccessFlags = {}); + static ObjectSharedPtr unloadSet(db0::swine_ptr, Address, std::uint16_t instance_id = 0, AccessFlags = {}); + static ObjectSharedPtr unloadDict(db0::swine_ptr, Address, std::uint16_t instance_id = 0, AccessFlags = {}); + static ObjectSharedPtr unloadTuple(db0::swine_ptr, Address, std::uint16_t instance_id = 0, AccessFlags = {}); // Unload dbzero block instance - static ObjectSharedPtr unloadBlock(db0::swine_ptr, Address, std::uint16_t instance_id = 0); + static ObjectSharedPtr unloadBlock(db0::swine_ptr, Address, std::uint16_t instance_id = 0, AccessFlags = {}); // Unload from serialized bytes static ObjectSharedPtr deserializeObjectIterable(db0::swine_ptr, std::vector::const_iterator &iter, @@ -139,7 +139,7 @@ namespace db0::python static ObjectSharedPtr deserializeEnumValueRepr(db0::swine_ptr, std::vector::const_iterator &iter, std::vector::const_iterator end); - static ObjectSharedPtr unloadByteArray(db0::swine_ptr, Address); + static ObjectSharedPtr unloadByteArray(db0::swine_ptr, Address, AccessFlags = {}); // Creates a new Python instance of EnumValue static ObjectSharedPtr makeEnumValue(const EnumValue &); diff --git a/src/dbzero/bindings/python/PyTypeManager.cpp b/src/dbzero/bindings/python/PyTypeManager.cpp index b21a7318..703828cc 100644 --- a/src/dbzero/bindings/python/PyTypeManager.cpp +++ b/src/dbzero/bindings/python/PyTypeManager.cpp @@ -108,7 +108,7 @@ namespace db0::python } m_py_bad_prefix_error.steal(); m_py_class_not_found_error.steal(); - m_py_reference_error.steal(); + m_py_reference_error.steal(); } } @@ -487,7 +487,7 @@ namespace db0::python PyTypeManager::ObjectPtr PyTypeManager::getReferenceError() const { return m_py_reference_error.get(); } - + std::shared_ptr PyTypeManager::extractConstClass(ObjectPtr py_class) const { if (!PyClassObject_Check(py_class)) { diff --git a/src/dbzero/bindings/python/PyTypeManager.hpp b/src/dbzero/bindings/python/PyTypeManager.hpp index a2b5a7cf..ba8473c8 100644 --- a/src/dbzero/bindings/python/PyTypeManager.hpp +++ b/src/dbzero/bindings/python/PyTypeManager.hpp @@ -124,7 +124,7 @@ namespace db0::python ObjectPtr getBadPrefixError() const; ObjectPtr getClassNotFoundError() const; - ObjectPtr getReferenceError() const; + ObjectPtr getReferenceError() const; /** * Called with each new memo type @@ -186,7 +186,7 @@ namespace db0::python // error associated with missing / invalid type accessed (e.g. missing import) mutable ObjectSharedPtr m_py_class_not_found_error; // invalid reference error - e.g. UUID or weak proxy expired - mutable ObjectSharedPtr m_py_reference_error; + mutable ObjectSharedPtr m_py_reference_error; // identified reference to a MemoBase type TypeObjectPtr m_memo_base_type = nullptr; std::unordered_set m_dbzero_type_ids; diff --git a/src/dbzero/bindings/python/dbzero.cpp b/src/dbzero/bindings/python/dbzero.cpp index 1bd22f4f..410b2377 100644 --- a/src/dbzero/bindings/python/dbzero.cpp +++ b/src/dbzero/bindings/python/dbzero.cpp @@ -67,7 +67,7 @@ static PyMethodDef dbzero_methods[] = {"serialize", (PyCFunction)&py::PyAPI_serialize, METH_FASTCALL, "Serialize dbzero serializable instance"}, {"deserialize", (PyCFunction)&py::PyAPI_deserialize, METH_FASTCALL, "Serialize dbzero serializable instance"}, {"is_enum_value", (PyCFunction)&py::PyAPI_isEnumValue, METH_FASTCALL, "Check if parameter represents a dbzero enum value"}, - {"split_by", (PyCFunction)&py::PyAPI_splitBy, METH_VARARGS | METH_KEYWORDS, "Split query iterator by a given criteria"}, + {"split_by", (PyCFunction)&py::PyAPI_splitBy, METH_VARARGS | METH_KEYWORDS, "Split query iterator by a given criteria"}, {"filter", (PyCFunction)&py::filter, METH_VARARGS | METH_KEYWORDS, "Filter with a Python callable"}, {"set_prefix", (PyCFunction)&py::PyAPI_setPrefix, METH_VARARGS | METH_KEYWORDS, "Allows dynamically specifying object's prefix during initialization"}, {"get_slab_metrics", (PyCFunction)&py::getSlabMetrics, METH_NOARGS, "Retrieve slab metrics of the current prefix"}, diff --git a/src/dbzero/bindings/python/iter/PyObjectIterable.cpp b/src/dbzero/bindings/python/iter/PyObjectIterable.cpp index e69ff4a6..91a2e88f 100644 --- a/src/dbzero/bindings/python/iter/PyObjectIterable.cpp +++ b/src/dbzero/bindings/python/iter/PyObjectIterable.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include namespace db0::python @@ -127,33 +128,66 @@ namespace db0::python } } - PyObject *tryPyObjectIterable_GetItemSlice(PyObjectIterable *py_iterable, PyObject *py_slice) + std::vector unpackTuple(PyObject *py_tuple) + { + if (!PyTuple_Check(py_tuple)) { + THROWF(db0::InputException) << "Expected a tuple of indexes"; + } + Py_ssize_t num_items = PyTuple_Size(py_tuple); + std::vector result; + result.reserve(num_items); + for (Py_ssize_t i = 0; i < num_items; ++i) { + PyObject *py_item = PyTuple_GetItem(py_tuple, i); + if (!PyLong_Check(py_item)) { + THROWF(db0::InputException) << "Expected integer indexes in the tuple"; + } + result.push_back(PyLong_AsUnsignedLongLong(py_item)); + } + return result; + } + + PyObject *tryPyObjectIterable_GetItemSlice(PyObjectIterable *py_iterable, PyObject *py_key) { using SliceDef = db0::object_model::SliceDef; - Py_ssize_t start, stop, step; - auto size_func = [&](std::optional &size) { - if (!size) { - size = py_iterable->ext().getSize(); + using ObjectSharedPtr = PyToolkit::ObjectSharedPtr; + + if (PyTuple_Check(py_key)) { + // itemgetter's key (item indexes) + auto indices = unpackTuple(py_key); + auto py_result = Py_OWN(PyTuple_New(indices.size())); + db0::object_model::getItemsByIndices(py_iterable->ext(), indices, + [&](unsigned int ord, ObjectSharedPtr obj_ptr) { + PySafeTuple_SetItem(*py_result, ord, obj_ptr); + }); + return py_result.steal(); + } else if (PySlice_Check(py_key)) { + Py_ssize_t start, stop, step; + auto size_func = [&](std::optional &size) { + if (!size) { + size = py_iterable->ext().getSize(); + } + return *size; + }; + + PySlice_GetUnboundIndices(py_key, size_func, start, stop, step); + std::size_t _stop = (stop == PY_SSIZE_T_MAX) ? SliceDef::MAX_STOP() : (std::size_t)stop; + auto slice_def = SliceDef { (std::size_t)start, _stop, (int)step }; + // the default slice just returns itself + if (slice_def.isDefault()) { + Py_INCREF(py_iterable); + return py_iterable; + } + + if (py_iterable->ext().isSliced()) { + THROWF(db0::InputException) << "Cannot slice an already sliced iterable (Operation not supported)"; } - return *size; - }; - - PySlice_GetUnboundIndices(py_slice, size_func, start, stop, step); - std::size_t _stop = (stop == PY_SSIZE_T_MAX) ? SliceDef::MAX_STOP() : (std::size_t)stop; - auto slice_def = SliceDef { (std::size_t)start, _stop, (int)step }; - // the default slice just returns itself - if (slice_def.isDefault()) { - Py_INCREF(py_iterable); - return py_iterable; - } - if (py_iterable->ext().isSliced()) { - THROWF(db0::InputException) << "Cannot slice an already sliced iterable (Operation not supported)"; - } - - auto py_result = PyObjectIterableDefault_new(); - py_result->makeNew(py_iterable->ext(), slice_def); - return py_result.steal(); + auto py_result = PyObjectIterableDefault_new(); + py_result->makeNew(py_iterable->ext(), slice_def); + return py_result.steal(); + } + THROWF(db0::InputException) + << "Invalid subscript type for ObjectIterable: " << Py_TYPE(py_key)->tp_name << THROWF_END; } PyObject *PyAPI_PyObjectIterable_GetItemSlice(PyObjectIterable *py_iterable, PyObject *py_elem) @@ -180,7 +214,7 @@ namespace db0::python static PyMethodDef PyObjectIterable_methods[] = { {"compare", (PyCFunction)PyAPI_PyObjectIterable_compare, METH_FASTCALL, "Compare two iterables"}, - {"signature", (PyCFunction)PyAPI_PyObjectIterable_signature, METH_NOARGS, "Get the signature of the query"}, + {"signature", (PyCFunction)PyAPI_PyObjectIterable_signature, METH_NOARGS, "Get the signature of the query"}, {NULL} }; diff --git a/src/dbzero/core/exception/Exceptions.cpp b/src/dbzero/core/exception/Exceptions.cpp index c587e645..9f5b33ec 100644 --- a/src/dbzero/core/exception/Exceptions.cpp +++ b/src/dbzero/core/exception/Exceptions.cpp @@ -58,5 +58,10 @@ namespace db0 : CriticalException(exception_id) { } + + IndexException::IndexException() + : CriticalException(exception_id) + { + } } \ No newline at end of file diff --git a/src/dbzero/core/exception/Exceptions.hpp b/src/dbzero/core/exception/Exceptions.hpp index 37e17f22..250f5c43 100644 --- a/src/dbzero/core/exception/Exceptions.hpp +++ b/src/dbzero/core/exception/Exceptions.hpp @@ -92,6 +92,14 @@ namespace db0 ClassNotFoundException(); }; + + class IndexException: public CriticalException + { + public: + static constexpr int exception_id = EXCEPTION_ID_PREFIX::BASIC | 0x0e; + + IndexException(); + }; class AccessTypeException: public CriticalException { diff --git a/src/dbzero/core/vspace/v_ptr.cpp b/src/dbzero/core/vspace/v_ptr.cpp index 82932b37..4e184ccc 100644 --- a/src/dbzero/core/vspace/v_ptr.cpp +++ b/src/dbzero/core/vspace/v_ptr.cpp @@ -12,13 +12,19 @@ namespace db0 assertFlags(); assert(!(m_resource_flags.load() & RESOURCE_LOCK)); } - + vtypeless::vtypeless(const vtypeless &other) : m_memspace_ptr(other.m_memspace_ptr) { *this = other; } + vtypeless::vtypeless(vtypeless &&other) + : m_memspace_ptr(other.m_memspace_ptr) + { + *this = std::move(other); + } + vtypeless::vtypeless(Memspace &memspace, Address address, MemLock &&mem_lock, std::uint16_t resource_flags, FlagSet access_mode) : m_address(address) diff --git a/src/dbzero/core/vspace/v_ptr.hpp b/src/dbzero/core/vspace/v_ptr.hpp index 756e0b50..5d5d87ab 100644 --- a/src/dbzero/core/vspace/v_ptr.hpp +++ b/src/dbzero/core/vspace/v_ptr.hpp @@ -68,6 +68,7 @@ namespace db0 FlagSet); vtypeless(const vtypeless& other); + vtypeless(vtypeless&&); /** * @param access_mode additional flags / modes to use diff --git a/src/dbzero/object_model/bytes/ByteArray.cpp b/src/dbzero/object_model/bytes/ByteArray.cpp index d7b43324..897450fd 100644 --- a/src/dbzero/object_model/bytes/ByteArray.cpp +++ b/src/dbzero/object_model/bytes/ByteArray.cpp @@ -8,19 +8,19 @@ namespace db0::object_model GC0_Define(ByteArray) - ByteArray::ByteArray(db0::swine_ptr &fixture, std::byte *bytes, std::size_t size) - : super_t(fixture) + ByteArray::ByteArray(db0::swine_ptr &fixture, std::byte *bytes, std::size_t size, AccessFlags access_mode) + : super_t(fixture, access_mode) { for (auto *bytes_ptr = bytes, *end = bytes + size; bytes_ptr != end; ++bytes_ptr) { v_bvector::push_back(*bytes_ptr); } } - ByteArray::ByteArray(db0::swine_ptr &fixture, Address address) - : super_t(super_t::tag_from_address(), fixture, address) + ByteArray::ByteArray(db0::swine_ptr &fixture, Address address, AccessFlags access_mode) + : super_t(super_t::tag_from_address(), fixture, address, access_mode) { } - + ByteArray::ByteArray(tag_no_gc, db0::swine_ptr &fixture, const ByteArray &byte_array) : super_t(tag_no_gc(), fixture, byte_array) { @@ -38,9 +38,11 @@ namespace db0::object_model THROWF(db0::InputException) << "Index out of range: " << i; } auto fixture = this->getFixture(); - return unloadMember(fixture, StorageClass::INT64, (long)(*this)[i]); + return unloadMember( + fixture, StorageClass::INT64, (long)(*this)[i], 0, this->getMemberFlags() + ); } - + std::byte ByteArray::getByte(std::size_t i) const { return (*this)[i]; } diff --git a/src/dbzero/object_model/bytes/ByteArray.hpp b/src/dbzero/object_model/bytes/ByteArray.hpp index 0e2186cc..69c99a22 100644 --- a/src/dbzero/object_model/bytes/ByteArray.hpp +++ b/src/dbzero/object_model/bytes/ByteArray.hpp @@ -29,9 +29,9 @@ namespace db0::object_model // as null placeholder ByteArray() = default; - ByteArray(db0::swine_ptr &, std::byte *, std::size_t); + ByteArray(db0::swine_ptr &, std::byte *, std::size_t, AccessFlags = {}); ByteArray(tag_no_gc, db0::swine_ptr &, const ByteArray &); - ByteArray(db0::swine_ptr &, Address); + ByteArray(db0::swine_ptr &, Address, AccessFlags = {}); ~ByteArray(); ObjectSharedPtr getItem(std::size_t i) const; diff --git a/src/dbzero/object_model/class/Class.hpp b/src/dbzero/object_model/class/Class.hpp index 2adfb4ef..c8ddad71 100644 --- a/src/dbzero/object_model/class/Class.hpp +++ b/src/dbzero/object_model/class/Class.hpp @@ -253,6 +253,11 @@ DB0_PACKED_END return m_no_cache; } + // Get instance flags to be applied to objects of this class + inline AccessFlags getInstanceFlags() const { + return m_no_cache ? AccessFlags { AccessOptions::no_cache } : AccessFlags {}; + } + protected: friend class ClassFactory; friend ClassPtr; diff --git a/src/dbzero/object_model/dict/Dict.cpp b/src/dbzero/object_model/dict/Dict.cpp index 5b4392c9..311e90be 100644 --- a/src/dbzero/object_model/dict/Dict.cpp +++ b/src/dbzero/object_model/dict/Dict.cpp @@ -120,7 +120,7 @@ namespace db0::object_model auto it_join = bindex.beginJoin(1); while (!it_join.is_end()) { auto [storage_class, value] = (*it_join).m_first; - auto member = unloadMember(*fixture, storage_class, value); + auto member = unloadMember(*fixture, storage_class, value, 0, member_flags); if (LangToolkit::compare(key, member.get())) { bindex.erase(*it_join); unrefMember(*fixture, storage_class, value); @@ -150,10 +150,14 @@ namespace db0::object_model auto it = bindex.beginJoin(1); while (!it.is_end()) { auto [storage_class, value] = (*it).m_first; - auto member = unloadMember(fixture, storage_class, value); + auto member = unloadMember( + fixture, storage_class, value, 0, this->getMemberFlags() + ); if (LangToolkit::compare(key_value, member.get())) { auto [storage_class, value] = (*it).m_second; - return unloadMember(fixture, storage_class, value); + return unloadMember( + fixture, storage_class, value, 0, this->getMemberFlags() + ); } ++it; } @@ -171,7 +175,7 @@ namespace db0::object_model auto it = bindex.beginJoin(1); while (!it.is_end()) { auto [storage_class, value] = (*it).m_first; - auto member = unloadMember(fixture, storage_class, value); + auto member = unloadMember(fixture, storage_class, value, 0, this->getMemberFlags()); if (LangToolkit::compare(key_value, member.get())) { // a matching key was found return true; @@ -200,7 +204,7 @@ namespace db0::object_model auto [storage_class, value] = (*it).m_second; auto fixture = this->getFixture(); - auto member = unloadMember(fixture, storage_class, value); + auto member = unloadMember(fixture, storage_class, value, 0, this->getMemberFlags()); unrefMember(fixture, key_storage_class, key_value); unrefMember(fixture, storage_class, value); diff --git a/src/dbzero/object_model/dict/DictIterator.cpp b/src/dbzero/object_model/dict/DictIterator.cpp index ddb6d826..e13ac1fe 100644 --- a/src/dbzero/object_model/dict/DictIterator.cpp +++ b/src/dbzero/object_model/dict/DictIterator.cpp @@ -13,7 +13,7 @@ namespace db0::object_model DictIterator::DictIterator( Dict::const_iterator iterator, const Dict * ptr, ObjectPtr lang_dict, IteratorType type) : BaseIterator(iterator, ptr, lang_dict) - , m_type(type) + , m_type(type) { setJoinIterator(); } @@ -51,8 +51,8 @@ namespace db0::object_model iterNext(); return { - unloadMember(fixture, key), - unloadMember(fixture, value) + unloadMember(fixture, key, 0, m_member_flags), + unloadMember(fixture, value, 0, m_member_flags) }; } @@ -61,15 +61,15 @@ namespace db0::object_model auto value = (*m_join_iterator).m_second; iterNext(); auto fixture = m_collection->getFixture(); - return unloadMember(fixture, value); + return unloadMember(fixture, value, 0, m_member_flags); } - DictIterator::ObjectSharedPtr DictIterator::nextKey() + DictIterator::ObjectSharedPtr DictIterator::nextKey() { auto key = (*m_join_iterator).m_first; iterNext(); auto fixture = m_collection->getFixture(); - return unloadMember(fixture, key); + return unloadMember(fixture, key, 0, m_member_flags); } DictIterator::ObjectSharedPtr DictIterator::next() diff --git a/src/dbzero/object_model/index/Index.cpp b/src/dbzero/object_model/index/Index.cpp index 6487cb07..f2a6f5c9 100644 --- a/src/dbzero/object_model/index/Index.cpp +++ b/src/dbzero/object_model/index/Index.cpp @@ -18,16 +18,16 @@ namespace db0::object_model { } - Index::Index(db0::swine_ptr &fixture) - : super_t(fixture, IndexType::RangeTree, IndexDataType::Auto) + Index::Index(db0::swine_ptr &fixture, AccessFlags access_mode) + : super_t(fixture, IndexType::RangeTree, IndexDataType::Auto, access_mode) , m_builder(*this) // NOTE: register the mutation handler for supporting "locked" sections , m_mutation_log(fixture->addMutationHandler()) { } - - Index::Index(db0::swine_ptr &fixture, Address address) - : super_t(super_t::tag_from_address(), fixture, address) + + Index::Index(db0::swine_ptr &fixture, Address address, AccessFlags access_mode) + : super_t(super_t::tag_from_address(), fixture, address, access_mode) , m_builder(*this) , m_mutation_log(fixture->addMutationHandler()) { diff --git a/src/dbzero/object_model/index/Index.hpp b/src/dbzero/object_model/index/Index.hpp index e574466b..b158991b 100644 --- a/src/dbzero/object_model/index/Index.hpp +++ b/src/dbzero/object_model/index/Index.hpp @@ -37,11 +37,11 @@ namespace db0::object_model // null instance constructor Index(); - Index(db0::swine_ptr &); - Index(db0::swine_ptr &, Address); + Index(db0::swine_ptr &, AccessFlags = {}); + Index(db0::swine_ptr &, Address, AccessFlags = {}); Index(const Index &) = delete; ~Index(); - + std::size_t size() const; void add(ObjectPtr key, ObjectPtr value); void remove(ObjectPtr key, ObjectPtr value); diff --git a/src/dbzero/object_model/iterators/BaseIterator.hpp b/src/dbzero/object_model/iterators/BaseIterator.hpp index 14046db5..4e8dce8f 100644 --- a/src/dbzero/object_model/iterators/BaseIterator.hpp +++ b/src/dbzero/object_model/iterators/BaseIterator.hpp @@ -27,6 +27,7 @@ namespace db0::object_model : m_iterator(iterator) , m_collection(ptr) , m_lang_collection_shared_ptr(lang_collection_ptr) + , m_member_flags(ptr->getMemberFlags()) { } @@ -47,6 +48,8 @@ namespace db0::object_model const CollectionT *m_collection; // reference to persist collections' related language specific object ObjectSharedPtr m_lang_collection_shared_ptr; + // member access flags (e.g. no_cache) + const AccessFlags m_member_flags; }; } \ No newline at end of file diff --git a/src/dbzero/object_model/list/List.cpp b/src/dbzero/object_model/list/List.cpp index 1ad099f5..06764cad 100644 --- a/src/dbzero/object_model/list/List.cpp +++ b/src/dbzero/object_model/list/List.cpp @@ -68,11 +68,11 @@ namespace db0::object_model List::ObjectSharedPtr List::getItem(std::size_t i) const { if (i >= size()) { - THROWF(db0::InputException) << "Index out of range: " << i; + THROWF(db0::IndexException) << "Index out of range: " << i; } auto [storage_class, value] = (*this)[i]; auto fixture = this->getFixture(); - return unloadMember(fixture, storage_class, value); + return unloadMember(fixture, storage_class, value, 0, this->getMemberFlags()); } List::ObjectSharedPtr List::pop(FixtureLock &fixture, std::size_t i) @@ -81,10 +81,10 @@ namespace db0::object_model THROWF(db0::InputException) << "Cannot pop from empty container "; } if (i >= size()) { - THROWF(db0::InputException) << "Index out of range: " << i; + THROWF(db0::IndexException) << "Index out of range: " << i; } auto [storage_class, value] = (*this)[i]; - auto member = unloadMember(*fixture, storage_class, value); + auto member = unloadMember(*fixture, storage_class, value, 0, this->getMemberFlags()); this->swapAndPop(fixture, {i}); restoreIterators(); return member; @@ -93,7 +93,7 @@ namespace db0::object_model void List::setItem(FixtureLock &fixture, std::size_t i, ObjectPtr lang_value) { if (i >= size()) { - THROWF(db0::InputException) << "Index out of range: " << i; + THROWF(db0::IndexException) << "Index out of range: " << i; } // recognize type ID from language specific object @@ -122,8 +122,8 @@ namespace db0::object_model auto fixture = this->getFixture(); for (auto &elem: (*this)) { auto [elem_storage_class, elem_value] = elem; - if (unloadMember(fixture, elem_storage_class, elem_value) == lang_value) { - count += 1; + if (unloadMember(fixture, elem_storage_class, elem_value, 0, this->getMemberFlags()) == lang_value) { + ++count; } } return count; @@ -135,7 +135,7 @@ namespace db0::object_model auto fixture = this->getFixture(); for (auto &elem: (*this)) { auto [elem_storage_class, elem_value] = elem; - if (unloadMember(fixture, elem_storage_class, elem_value) == lang_value) { + if (unloadMember(fixture, elem_storage_class, elem_value, 0, this->getMemberFlags()) == lang_value) { return index; } ++index; @@ -143,7 +143,7 @@ namespace db0::object_model THROWF(db0::InputException) << "Item is not in a list "; return -1; } - + bool List::operator==(const List &list) const { if (size() != list.size()) { diff --git a/src/dbzero/object_model/list/ListIterator.cpp b/src/dbzero/object_model/list/ListIterator.cpp index 8eb6e479..e4fb2e6a 100644 --- a/src/dbzero/object_model/list/ListIterator.cpp +++ b/src/dbzero/object_model/list/ListIterator.cpp @@ -16,7 +16,7 @@ namespace db0::object_model auto [storage_class, value] = *m_iterator; ++m_iterator; ++m_index; - return unloadMember(fixture, storage_class, value); + return unloadMember(fixture, storage_class, value, 0, m_member_flags); } void ListIterator::restore() diff --git a/src/dbzero/object_model/object/Object.cpp b/src/dbzero/object_model/object/Object.cpp index 9e813634..59025bd9 100644 --- a/src/dbzero/object_model/object/Object.cpp +++ b/src/dbzero/object_model/object/Object.cpp @@ -134,21 +134,21 @@ namespace db0::object_model , m_type(type) { } - - Object::Object(db0::swine_ptr &fixture, Address address) - : super_t(super_t::tag_from_address(), fixture, address) + + Object::Object(db0::swine_ptr &fixture, Address address, AccessFlags access_mode) + : super_t(super_t::tag_from_address(), fixture, address, access_mode) { } Object::Object(db0::swine_ptr &fixture, ObjectStem &&stem, std::shared_ptr type) : super_t(super_t::tag_from_stem(), fixture, std::move(stem)) - , m_type(type) + , m_type(type) { assert(hasValidClassRef()); } - Object::Object(db0::swine_ptr &fixture, Address address, std::shared_ptr type_hint, with_type_hint) - : Object(fixture, address) + Object::Object(db0::swine_ptr &fixture, Address address, std::shared_ptr type_hint, with_type_hint, AccessFlags access_mode) + : Object(fixture, address, access_mode) { assert(*fixture == *type_hint->getFixture()); setTypeWithHint(type_hint); @@ -158,7 +158,7 @@ namespace db0::object_model : Object(fixture, std::move(stem), getTypeWithHint(*fixture, stem->getClassRef(), type_hint)) { } - + Object::~Object() { // unregister needs to be called before destruction of members @@ -178,14 +178,15 @@ namespace db0::object_model new ((void*)this) Object(unique_addr, ext_refs); } - Object::ObjectStem Object::tryUnloadStem(db0::swine_ptr &fixture, Address address, std::uint16_t instance_id) + Object::ObjectStem Object::tryUnloadStem(db0::swine_ptr &fixture, Address address, + std::uint16_t instance_id, AccessFlags access_mode) { std::size_t size_of; if (!fixture->isAddressValid(address, REALM_ID, &size_of)) { return {}; } // Unload from a verified address - ObjectVType stem(db0::tag_verified(), fixture->myPtr(address), size_of); + ObjectVType stem(db0::tag_verified(), fixture->myPtr(address), size_of, access_mode); if (instance_id && stem->m_header.m_instance_id != instance_id) { // instance ID validation failed return {}; @@ -193,9 +194,10 @@ namespace db0::object_model return stem; } - Object::ObjectStem Object::unloadStem(db0::swine_ptr &fixture, Address address, std::uint16_t instance_id) + Object::ObjectStem Object::unloadStem(db0::swine_ptr &fixture, Address address, + std::uint16_t instance_id, AccessFlags access_mode) { - auto result = tryUnloadStem(fixture, address, instance_id); + auto result = tryUnloadStem(fixture, address, instance_id, access_mode); if (!result) { THROWF(db0::InputException) << "Invalid UUID or object has been deleted"; } @@ -916,7 +918,7 @@ namespace db0::object_model assert(member.first != StorageClass::DELETED && member.first != StorageClass::UNDEFINED); // NOTE: offset is required for lo-fi members return unloadMember( - fixture, member.first, member.second, field_id.maybeOffset() + fixture, member.first, member.second, field_id.maybeOffset(), this->getMemberFlags() ); } @@ -939,7 +941,7 @@ namespace db0::object_model // NOTE: offset is required for lo-fi members return unloadMember( - fixture, member.first, member.second, field_id.getOffset() + fixture, member.first, member.second, field_id.getOffset(), this->getMemberFlags() ); } @@ -1391,11 +1393,13 @@ namespace db0::object_model auto fixture = this->getFixture(); forAll([&](const std::string &name, const XValue &xvalue, unsigned int offset) -> bool { // all references convert to UUID - auto py_member = unloadMember(fixture, xvalue.m_type, xvalue.m_value, offset); + auto py_member = unloadMember( + fixture, xvalue.m_type, xvalue.m_value, offset, this->getMemberFlags() + ); return f(name, py_member); }); } - + bool Object::forAll(XValue xvalue, std::function f) const { assert(xvalue.m_type == StorageClass::PACK_2); diff --git a/src/dbzero/object_model/object/Object.hpp b/src/dbzero/object_model/object/Object.hpp index 4b426c32..e19d2dc4 100644 --- a/src/dbzero/object_model/object/Object.hpp +++ b/src/dbzero/object_model/object/Object.hpp @@ -127,13 +127,14 @@ DB0_PACKED_END // Unload from address with a known type (possibly a base type) // NOTE: unload works faster if type_hint is the exact object's type struct with_type_hint {}; - Object(db0::swine_ptr &, Address, std::shared_ptr type_hint, with_type_hint); - + Object(db0::swine_ptr &, Address, std::shared_ptr type_hint, + with_type_hint, AccessFlags = {}); + // Unload from stem with a known type (possibly a base type) // NOTE: unload works faster if type_hint is the exact object's type Object(db0::swine_ptr &, ObjectStem &&, std::shared_ptr type_hint, with_type_hint); - Object(db0::swine_ptr &, Address); + Object(db0::swine_ptr &, Address, AccessFlags = {}); Object(db0::swine_ptr &, std::shared_ptr, std::pair ref_counts, const PosVT::Data &, unsigned int pos_vt_offset); Object(db0::swine_ptr &, ObjectStem &&, std::shared_ptr); @@ -147,8 +148,10 @@ DB0_PACKED_END void dropInstance(FixtureLock &); // Unload the object stem, to retrieve its type - static ObjectStem tryUnloadStem(db0::swine_ptr &, Address, std::uint16_t instance_id = 0); - static ObjectStem unloadStem(db0::swine_ptr &, Address, std::uint16_t instance_id = 0); + static ObjectStem tryUnloadStem(db0::swine_ptr &, Address, + std::uint16_t instance_id = 0, AccessFlags = {}); + static ObjectStem unloadStem(db0::swine_ptr &, Address, + std::uint16_t instance_id = 0, AccessFlags = {}); // Called to finalize adding members void endInit(); diff --git a/src/dbzero/object_model/set/Set.cpp b/src/dbzero/object_model/set/Set.cpp index ac57e576..b9543d2e 100644 --- a/src/dbzero/object_model/set/Set.cpp +++ b/src/dbzero/object_model/set/Set.cpp @@ -30,9 +30,9 @@ namespace db0::object_model SetIndex bindex(*fixture, item); return { key, bindex }; } - - Set::Set(db0::swine_ptr &fixture) - : super_t(fixture) + + Set::Set(db0::swine_ptr &fixture, AccessFlags access_mode) + : super_t(fixture, access_mode) , m_index(*fixture) { modify().m_index_ptr = m_index.getAddress(); @@ -51,9 +51,9 @@ namespace db0::object_model } modify().m_size = set.size(); } - - Set::Set(db0::swine_ptr &fixture, Address address) - : super_t(super_t::tag_from_address(), fixture, address) + + Set::Set(db0::swine_ptr &fixture, Address address, AccessFlags access_mode) + : super_t(super_t::tag_from_address(), fixture, address, access_mode) , m_index(myPtr((*this)->m_index_ptr)) { } @@ -81,7 +81,7 @@ namespace db0::object_model auto it = bindex.beginJoin(1); while (!it.is_end()) { auto [storage_class, value] = (*it); - auto member = unloadMember(fixture, storage_class, value); + auto member = unloadMember(fixture, storage_class, value, 0, getMemberFlags()); append(fixture, key, member.get()); ++it; } @@ -155,7 +155,7 @@ namespace db0::object_model auto fixture = this->getFixture(); while (!it.is_end()) { auto [storage_class, value] = *it; - auto member = unloadMember(fixture, storage_class, value); + auto member = unloadMember(fixture, storage_class, value, 0, getMemberFlags()); if (LangToolkit::compare(key_value, member.get())) { if (bindex.size() == 1) { m_index.erase(iter); @@ -186,7 +186,7 @@ namespace db0::object_model auto it = bindex.beginJoin(1); while (!it.is_end()) { auto [storage_class, value] = *it; - auto member = unloadMember(fixture, storage_class, value); + auto member = unloadMember(fixture, storage_class, value, 0, getMemberFlags()); if (LangToolkit::compare(key_value, member.get())) { return member; } @@ -214,7 +214,7 @@ namespace db0::object_model auto it = bindex.beginJoin(1); auto [storage_class, value] = *it; auto fixture = this->getFixture(); - auto member = unloadMember(fixture, storage_class, value); + auto member = unloadMember(fixture, storage_class, value, 0, getMemberFlags()); if (bindex.size() == 1) { m_index.erase(iter); bindex.destroy(); @@ -239,7 +239,7 @@ namespace db0::object_model auto it = bindex.beginJoin(1); while (!it.is_end()) { auto [storage_class, value] = *it; - auto member = unloadMember(fixture, storage_class, value); + auto member = unloadMember(fixture, storage_class, value, 0, getMemberFlags()); if (LangToolkit::compare(key_value, member.get())) { return true; } diff --git a/src/dbzero/object_model/set/Set.hpp b/src/dbzero/object_model/set/Set.hpp index 7eb249c3..1aa3c291 100644 --- a/src/dbzero/object_model/set/Set.hpp +++ b/src/dbzero/object_model/set/Set.hpp @@ -22,14 +22,13 @@ namespace db0::object_model { -DB0_PACKED_BEGIN - using Fixture = db0::Fixture; using TypedItem_Address = ValueT_Address; using SetIndex = CollectionIndex; using set_item = db0::key_value>; class SetIterator; +DB0_PACKED_BEGIN struct DB0_PACKED_ATTR o_set: public db0::o_fixed { // common object header @@ -42,6 +41,7 @@ DB0_PACKED_BEGIN return m_header.hasRefs(); } }; +DB0_PACKED_END class Set: public db0::ObjectBase, StorageClass::DB0_SET> { @@ -56,11 +56,11 @@ DB0_PACKED_BEGIN // as null placeholder Set() = default; - explicit Set(db0::swine_ptr &); + explicit Set(db0::swine_ptr &, AccessFlags = {}); explicit Set(tag_no_gc, db0::swine_ptr &, const Set &); - explicit Set(db0::swine_ptr &, Address); + explicit Set(db0::swine_ptr &, Address, AccessFlags = {}); ~Set(); - + void operator=(Set &&); void append(FixtureLock &, std::size_t key, ObjectSharedPtr lang_value); @@ -103,6 +103,4 @@ DB0_PACKED_BEGIN void restoreIterators(); }; -DB0_PACKED_END - } \ No newline at end of file diff --git a/src/dbzero/object_model/set/SetIterator.cpp b/src/dbzero/object_model/set/SetIterator.cpp index 744df581..87a1aee2 100644 --- a/src/dbzero/object_model/set/SetIterator.cpp +++ b/src/dbzero/object_model/set/SetIterator.cpp @@ -33,7 +33,7 @@ namespace db0::object_model auto item = *m_join_iterator; auto [storage_class, value] = item; - auto member = unloadMember(fixture, storage_class, value); + auto member = unloadMember(fixture, storage_class, value, 0, m_member_flags); ++m_join_iterator; if (m_join_iterator.is_end()) { ++m_iterator; diff --git a/src/dbzero/object_model/tags/ObjectIterable.cpp b/src/dbzero/object_model/tags/ObjectIterable.cpp index 90b940fd..d03b31bd 100644 --- a/src/dbzero/object_model/tags/ObjectIterable.cpp +++ b/src/dbzero/object_model/tags/ObjectIterable.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -29,7 +30,7 @@ namespace db0::object_model } return std::move(query_iterator); } - + ObjectIterable::ObjectIterable(db0::swine_ptr fixture, std::unique_ptr &&ft_query_iterator, std::shared_ptr type, TypeObjectPtr lang_type, std::vector > &&query_observers, const std::vector &filters) @@ -39,7 +40,8 @@ namespace db0::object_model , m_query_observers(std::move(query_observers)) , m_filters(filters) , m_type(type) - , m_lang_type(lang_type) + , m_lang_type(lang_type) + , m_access_mode(getAccessMode(type)) { } @@ -53,6 +55,7 @@ namespace db0::object_model , m_filters(filters) , m_type(type) , m_lang_type(lang_type) + , m_access_mode(getAccessMode(type)) { } @@ -66,13 +69,15 @@ namespace db0::object_model , m_filters(filters) , m_type(type) , m_lang_type(lang_type) + , m_access_mode(getAccessMode(type)) { } ObjectIterable::ObjectIterable(db0::swine_ptr fixture, const ClassFactory &class_factory, - std::unique_ptr &&ft_query_iterator, std::unique_ptr &&sorted_iterator, + std::unique_ptr &&ft_query_iterator, std::unique_ptr &&sorted_iterator, std::shared_ptr factory, std::vector > &&query_observers, - std::vector &&filters, std::shared_ptr type, TypeObjectPtr lang_type, const SliceDef &slice_def) + std::vector &&filters, std::shared_ptr type, TypeObjectPtr lang_type, + const SliceDef &slice_def, AccessFlags access_mode) : m_fixture(fixture) , m_class_factory(class_factory) , m_query_iterator(std::move(ft_query_iterator)) @@ -83,6 +88,7 @@ namespace db0::object_model , m_type(type) , m_lang_type(lang_type) , m_slice_def(slice_def) + , m_access_mode(access_mode) { } @@ -94,6 +100,7 @@ namespace db0::object_model , m_type(other.m_type) , m_lang_type(other.m_lang_type) , m_slice_def(other.m_slice_def) + , m_access_mode(other.m_access_mode) { m_filters.insert(m_filters.end(), filters.begin(), filters.end()); @@ -115,6 +122,7 @@ namespace db0::object_model , m_type(other.m_type) , m_lang_type(other.m_lang_type) , m_slice_def(other.m_slice_def.combineWith(slice_def)) + , m_access_mode(other.m_access_mode) { std::unique_ptr query_iterator; std::unique_ptr sorted_iterator; @@ -125,8 +133,8 @@ namespace db0::object_model m_sorted_iterator = other.m_sorted_iterator->beginSorted(); } } - - ObjectIterable::ObjectIterable(const ObjectIterable &other, std::unique_ptr &&sorted_iterator, + + ObjectIterable::ObjectIterable(const ObjectIterable &other, std::unique_ptr &&sorted_iterator, std::vector > &&query_observers, const std::vector &filters) : m_fixture(other.m_fixture) , m_class_factory(other.m_class_factory) @@ -138,6 +146,7 @@ namespace db0::object_model , m_type(other.m_type) , m_lang_type(other.m_lang_type) , m_slice_def(other.m_slice_def) + , m_access_mode(other.m_access_mode) { m_filters.insert(m_filters.end(), filters.begin(), filters.end()); } @@ -153,6 +162,7 @@ namespace db0::object_model , m_type(other.m_type) , m_lang_type(other.m_lang_type) , m_slice_def(other.m_slice_def) + , m_access_mode(other.m_access_mode) { m_filters.insert(m_filters.end(), filters.begin(), filters.end()); } @@ -292,7 +302,7 @@ namespace db0::object_model auto &class_factory = fixture_->get(); return std::unique_ptr(new ObjectIterable(fixture_, class_factory, std::move(query_iterator), - std::move(sorted_iterator), factory, {}, {}, nullptr, nullptr, is_sliced ? SliceDef{start, stop, step} : SliceDef{})); + std::move(sorted_iterator), factory, {}, {}, nullptr, nullptr, is_sliced ? SliceDef{start, stop, step} : SliceDef{}, {})); } double ObjectIterable::compareTo(const ObjectIterable &other) const @@ -419,4 +429,54 @@ namespace db0::object_model return true; } + AccessFlags ObjectIterable::getAccessMode(std::shared_ptr type) const + { + if (type) { + return type->isNoCache() ? AccessFlags { AccessOptions::no_cache } : AccessFlags {}; + } + return {}; + } + + void getItemsByIndices(const ObjectIterable &iterable, const std::vector &indices, + std::function callback) + { + std::vector > sorted_indices; + sorted_indices.reserve(indices.size()); + for (unsigned int ord = 0; ord < indices.size(); ++ord) { + sorted_indices.emplace_back(indices[ord], ord); + } + std::sort(sorted_indices.begin(), sorted_indices.end(), + [](const auto &lhs, const auto &rhs) { + return lhs.first < rhs.first; + }); + + // access items in sorted order, populating the callback + auto iter = iterable.iter(); + std::uint64_t current_index = 0; + ObjectIterable::ObjectSharedPtr last_item; + for (const auto &[index, ord] : sorted_indices) { + if (current_index > index) { + // duplicate item + assert(last_item.get()); + callback(ord, last_item); + continue; + } + + if (current_index < index) { + auto to_skip = index - current_index; + if (iter->skip(to_skip) < to_skip) { + THROWF(db0::IndexException) << "Index " << index << " out of range"; + } + current_index = index; + } + + last_item = iter->next(); + if (!last_item) { + THROWF(db0::IndexException) << "Index " << index << " out of range"; + } + ++current_index; + callback(ord, last_item); + } + } + } diff --git a/src/dbzero/object_model/tags/ObjectIterable.hpp b/src/dbzero/object_model/tags/ObjectIterable.hpp index 9c1af7d2..64e20d1e 100644 --- a/src/dbzero/object_model/tags/ObjectIterable.hpp +++ b/src/dbzero/object_model/tags/ObjectIterable.hpp @@ -1,6 +1,9 @@ #pragma once #include +#include +#include +#include #include #include #include @@ -64,7 +67,7 @@ namespace db0::object_model // Construct sliced ObjectIterable(const ObjectIterable &, const SliceDef &); - + // Construct sorted ObjectIterable(const ObjectIterable &, std::unique_ptr &&, std::vector > && = {}, const std::vector & = {}); @@ -138,18 +141,27 @@ namespace db0::object_model std::vector m_filters; std::shared_ptr m_type = nullptr; TypeObjectSharedPtr m_lang_type = nullptr; - const SliceDef m_slice_def = {}; + const SliceDef m_slice_def = {}; mutable ObjectSharedPtr m_lang_context; + // object access mode (e.g. no_cache) + const AccessFlags m_access_mode; // iter constructor ObjectIterable(db0::swine_ptr, const ClassFactory &, std::unique_ptr &&, std::unique_ptr &&, std::shared_ptr, std::vector > &&, - std::vector &&filters, std::shared_ptr, TypeObjectPtr lang_type, const SliceDef & = {}); + std::vector &&filters, std::shared_ptr, TypeObjectPtr lang_type, const SliceDef & = {}, + AccessFlags access_mode = {}); // get the base iterator, possibly initialized from the factory const BaseIterator &getBaseIterator(std::unique_ptr &) const; // retrieve pointer to the already initialized iterator BaseIterator *getIteratorPtr() const; + + AccessFlags getAccessMode(std::shared_ptr) const; }; + // Retrieve items by specific indices from the iterable + void getItemsByIndices(const ObjectIterable &, const std::vector &, + std::function); + } \ No newline at end of file diff --git a/src/dbzero/object_model/tags/ObjectIterator.cpp b/src/dbzero/object_model/tags/ObjectIterator.cpp index b252e521..4ed452a9 100644 --- a/src/dbzero/object_model/tags/ObjectIterator.cpp +++ b/src/dbzero/object_model/tags/ObjectIterator.cpp @@ -21,14 +21,14 @@ namespace db0::object_model , m_slice(m_iterator_ptr, slice_def) { } - + ObjectIterator::ObjectIterator(db0::swine_ptr fixture, std::unique_ptr &&sorted_iterator, std::shared_ptr type, TypeObjectPtr lang_type, std::vector > &&query_observers, const std::vector &filters, const SliceDef &slice_def) : ObjectIterable(fixture, std::move(sorted_iterator), type, lang_type, {}, filters) , m_iterator_ptr(m_sorted_iterator.get()) , m_decoration(std::move(query_observers)) - , m_slice(m_iterator_ptr, slice_def) + , m_slice(m_iterator_ptr, slice_def) { } @@ -36,7 +36,7 @@ namespace db0::object_model : ObjectIterable(other, filters) , m_iterator_ptr(getIteratorPtr()) , m_decoration(std::move(m_query_observers)) - , m_slice(m_iterator_ptr, m_slice_def) + , m_slice(m_iterator_ptr, m_slice_def) { } @@ -50,7 +50,7 @@ namespace db0::object_model { for (;;) { if (!m_slice.isEnd()) { - // collect decorators if any exist + // Collect decorators if any exist if (!m_decoration.empty()) { auto it = m_decoration.m_query_observers.begin(); for (auto &decor: m_decoration.m_decorators) { @@ -77,13 +77,23 @@ namespace db0::object_model } } + std::size_t ObjectIterator::skip(std::size_t count) + { + std::size_t skipped = 0; + while (skipped < count && !m_slice.isEnd()) { + m_slice.next(); + ++skipped; + } + return skipped; + } + ObjectIterator::ObjectSharedPtr ObjectIterator::unload(db0::swine_ptr &fixture, Address address) const { // unload as typed if class is known if (m_type) { - return LangToolkit::unloadObject(fixture, address, m_type, m_lang_type.get()); + return LangToolkit::unloadObject(fixture, address, m_type, m_lang_type.get(), m_access_mode); } else { - return LangToolkit::unloadObject(fixture, address, m_class_factory, m_lang_type.get()); + return LangToolkit::unloadObject(fixture, address, m_class_factory, m_lang_type.get(), 0, m_access_mode); } } diff --git a/src/dbzero/object_model/tags/ObjectIterator.hpp b/src/dbzero/object_model/tags/ObjectIterator.hpp index b99dc89e..99de257d 100644 --- a/src/dbzero/object_model/tags/ObjectIterator.hpp +++ b/src/dbzero/object_model/tags/ObjectIterator.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -41,7 +42,7 @@ namespace db0::object_model // Construct iterator with additional filters ObjectIterator(const ObjectIterable &, const std::vector & = {}); - + virtual ~ObjectIterator() = default; /** @@ -58,6 +59,10 @@ namespace db0::object_model return m_decoration.m_decorators; } + // Try to skip specified number of items + // @return number of actually skipped items + std::size_t skip(std::size_t count); + protected: friend class ObjectIterable; // iterator_ptr valid both in case of m_query_iterator and m_sorted_iterator @@ -81,7 +86,7 @@ namespace db0::object_model }; Decoration m_decoration; - Slice m_slice; + Slice m_slice; // Unload object by address (must be from this iterator) skipping instance ID validation virtual ObjectSharedPtr unload(Address) const; diff --git a/src/dbzero/object_model/tuple/Tuple.cpp b/src/dbzero/object_model/tuple/Tuple.cpp index 2810746e..9dee6b31 100644 --- a/src/dbzero/object_model/tuple/Tuple.cpp +++ b/src/dbzero/object_model/tuple/Tuple.cpp @@ -72,7 +72,7 @@ namespace db0::object_model } auto [storage_class, value] = getData()->items()[i]; auto fixture = this->getFixture(); - return unloadMember(fixture, storage_class, value); + return unloadMember(fixture, storage_class, value, 0, this->getMemberFlags()); } void Tuple::setItem(FixtureLock &fixture, std::size_t i, ObjectSharedPtr lang_value) @@ -103,7 +103,7 @@ namespace db0::object_model auto fixture = this->getFixture(); for (auto &elem: this->const_ref().items()) { auto [elem_storage_class, elem_value] = elem; - if (unloadMember(fixture, elem_storage_class, elem_value) == lang_value) { + if (unloadMember(fixture, elem_storage_class, elem_value, 0, this->getMemberFlags()) == lang_value) { count += 1; } } @@ -116,7 +116,7 @@ namespace db0::object_model auto fixture = this->getFixture(); for (auto &elem: this->const_ref().items()){ auto [elem_storage_class, elem_value] = elem; - if (unloadMember(fixture, elem_storage_class, elem_value) == lang_value) { + if (unloadMember(fixture, elem_storage_class, elem_value, 0, this->getMemberFlags()) == lang_value) { return index; } index += 1; diff --git a/src/dbzero/object_model/tuple/TupleIterator.cpp b/src/dbzero/object_model/tuple/TupleIterator.cpp index 9e3b7056..58e48217 100644 --- a/src/dbzero/object_model/tuple/TupleIterator.cpp +++ b/src/dbzero/object_model/tuple/TupleIterator.cpp @@ -15,7 +15,7 @@ namespace db0::object_model auto [storage_class, value] = *m_iterator; ++m_iterator; auto fixture = m_collection->getFixture(); - return unloadMember(fixture, storage_class, value); + return unloadMember(fixture, storage_class, value, 0, m_member_flags); } bool TupleIterator::is_end() const { diff --git a/src/dbzero/object_model/value/Member.cpp b/src/dbzero/object_model/value/Member.cpp index 4ff265f1..fa632694 100644 --- a/src/dbzero/object_model/value/Member.cpp +++ b/src/dbzero/object_model/value/Member.cpp @@ -361,9 +361,9 @@ namespace db0::object_model // STRING_REF specialization template <> typename PyToolkit::ObjectSharedPtr unloadMember( - db0::swine_ptr &fixture, Value value, unsigned int) + db0::swine_ptr &fixture, Value value, unsigned int, AccessFlags access_mode) { - db0::v_object string_ref(fixture->myPtr(value.asAddress())); + db0::v_object string_ref(fixture->myPtr(value.asAddress()), access_mode); auto str_ptr = string_ref->get(); auto result = Py_OWN(PyUnicode_FromStringAndSize(str_ptr.get_raw(), str_ptr.size())); if (!result) { @@ -374,59 +374,59 @@ namespace db0::object_model // INT64 specialization template <> typename PyToolkit::ObjectSharedPtr unloadMember( - db0::swine_ptr &fixture, Value value, unsigned int) + db0::swine_ptr &fixture, Value value, unsigned int, AccessFlags) { return Py_OWN(PyLong_FromLongLong(value.cast())); } // FLOAT specialization template <> typename PyToolkit::ObjectSharedPtr unloadMember( - db0::swine_ptr &fixture, Value value, unsigned int) + db0::swine_ptr &fixture, Value value, unsigned int, AccessFlags) { return Py_OWN(PyFloat_FromDouble(value.cast())); } // OBJECT_REF specialization template <> typename PyToolkit::ObjectSharedPtr unloadMember( - db0::swine_ptr &fixture, Value value, unsigned int) + db0::swine_ptr &fixture, Value value, unsigned int, AccessFlags) { auto &class_factory = fixture->template get(); return PyToolkit::unloadObject(fixture, value.asAddress(), class_factory); } - + // DB0_LIST specialization template <> typename PyToolkit::ObjectSharedPtr unloadMember( - db0::swine_ptr &fixture, Value value, unsigned int) + db0::swine_ptr &fixture, Value value, unsigned int, AccessFlags access_mode) { - return PyToolkit::unloadList(fixture, value.asAddress()); + return PyToolkit::unloadList(fixture, value.asAddress(), 0, access_mode); } // DB0_INDEX specialization template <> typename PyToolkit::ObjectSharedPtr unloadMember( - db0::swine_ptr &fixture, Value value, unsigned int) + db0::swine_ptr &fixture, Value value, unsigned int, AccessFlags access_mode) { - return PyToolkit::unloadIndex(fixture, value.asAddress()); + return PyToolkit::unloadIndex(fixture, value.asAddress(), 0, access_mode); } // DB0_SET specialization template <> typename PyToolkit::ObjectSharedPtr unloadMember( - db0::swine_ptr &fixture, Value value, unsigned int) + db0::swine_ptr &fixture, Value value, unsigned int, AccessFlags access_mode) { - return PyToolkit::unloadSet(fixture, value.asAddress()); + return PyToolkit::unloadSet(fixture, value.asAddress(), 0, access_mode); } // DB0_DICT specialization template <> typename PyToolkit::ObjectSharedPtr unloadMember( - db0::swine_ptr &fixture, Value value, unsigned int) + db0::swine_ptr &fixture, Value value, unsigned int, AccessFlags access_mode) { - return PyToolkit::unloadDict(fixture, value.asAddress()); + return PyToolkit::unloadDict(fixture, value.asAddress(), 0, access_mode); } // BYTES specialization template <> typename PyToolkit::ObjectSharedPtr unloadMember( - db0::swine_ptr &fixture, Value value, unsigned int) + db0::swine_ptr &fixture, Value value, unsigned int, AccessFlags access_mode) { - db0::v_object bytes = fixture->myPtr(value.asAddress()); + db0::v_object bytes(fixture->myPtr(value.asAddress()), access_mode); auto bytes_ptr = bytes->getBuffer(); auto result = Py_OWN(PyBytes_FromStringAndSize(reinterpret_cast(bytes_ptr), bytes->size())); if (!result) { @@ -437,7 +437,7 @@ namespace db0::object_model // DATETIME specialization template <> typename PyToolkit::ObjectSharedPtr unloadMember( - db0::swine_ptr &fixture, Value value, unsigned int) + db0::swine_ptr &fixture, Value value, unsigned int, AccessFlags) { auto result = Py_OWN(db0::python::uint64ToPyDatetime(value.cast())); if (!result) { @@ -448,7 +448,7 @@ namespace db0::object_model // DATETIME with TZ specialization template <> typename PyToolkit::ObjectSharedPtr unloadMember( - db0::swine_ptr &fixture, Value value, unsigned int) + db0::swine_ptr &fixture, Value value, unsigned int, AccessFlags) { auto result = Py_OWN(db0::python::uint64ToPyDatetimeWithTZ(value.cast())); if (!result) { @@ -459,7 +459,7 @@ namespace db0::object_model // DATE specialization template <> typename PyToolkit::ObjectSharedPtr unloadMember( - db0::swine_ptr &fixture, Value value, unsigned int) + db0::swine_ptr &fixture, Value value, unsigned int, AccessFlags) { auto result = Py_OWN(db0::python::uint64ToPyDate(value.cast())); if (!result) { @@ -470,7 +470,7 @@ namespace db0::object_model // Time specialization template <> typename PyToolkit::ObjectSharedPtr unloadMember( - db0::swine_ptr &fixture, Value value, unsigned int) + db0::swine_ptr &fixture, Value value, unsigned int, AccessFlags) { auto result = Py_OWN(db0::python::uint64ToPyTime(value.cast())); if (!result) { @@ -481,7 +481,7 @@ namespace db0::object_model // Time with Timezone specialization template <> typename PyToolkit::ObjectSharedPtr unloadMember( - db0::swine_ptr &fixture, Value value, unsigned int) + db0::swine_ptr &fixture, Value value, unsigned int, AccessFlags) { auto result = Py_OWN(db0::python::uint64ToPyTimeWithTz(value.cast())); if (!result) { @@ -492,7 +492,7 @@ namespace db0::object_model // DECIMAL specialization template <> typename PyToolkit::ObjectSharedPtr unloadMember( - db0::swine_ptr &fixture, Value value, unsigned int) + db0::swine_ptr &fixture, Value value, unsigned int, AccessFlags) { auto result = Py_OWN(db0::python::uint64ToPyDecimal(value.cast())); if (!result) { @@ -503,23 +503,23 @@ namespace db0::object_model // NONE specialization template <> typename PyToolkit::ObjectSharedPtr unloadMember( - db0::swine_ptr &fixture, Value value, unsigned int) + db0::swine_ptr &fixture, Value value, unsigned int, AccessFlags) { Py_RETURN_NONE; } // DB0_TUPLE specialization template <> typename PyToolkit::ObjectSharedPtr unloadMember( - db0::swine_ptr &fixture, Value value, unsigned int) - { - return PyToolkit::unloadTuple(fixture, value.asAddress()); + db0::swine_ptr &fixture, Value value, unsigned int, AccessFlags access_mode) + { + return PyToolkit::unloadTuple(fixture, value.asAddress(), 0, access_mode); } // DB0_SERIALIZED specialization template <> typename PyToolkit::ObjectSharedPtr unloadMember( - db0::swine_ptr &fixture, Value value, unsigned int) + db0::swine_ptr &fixture, Value value, unsigned int, AccessFlags access_mode) { - db0::v_object bytes = fixture->myPtr(value.asAddress()); + db0::v_object bytes(fixture->myPtr(value.asAddress()), access_mode); std::vector buffer; buffer.resize(bytes->size()); std::copy(bytes->getBuffer(), bytes->getBuffer() + bytes->size(), buffer.begin()); @@ -535,7 +535,7 @@ namespace db0::object_model // ENUM value specialization template <> typename PyToolkit::ObjectSharedPtr unloadMember( - db0::swine_ptr &fixture, Value value, unsigned int) + db0::swine_ptr &fixture, Value value, unsigned int, AccessFlags) { auto &enum_factory = fixture->get(); auto enum_value_uid = EnumValue_UID(value.cast()); @@ -544,7 +544,7 @@ namespace db0::object_model // ENUM value specialization template <> typename PyToolkit::ObjectSharedPtr unloadMember( - db0::swine_ptr &fixture, Value value, unsigned int) + db0::swine_ptr &fixture, Value value, unsigned int, AccessFlags) { // NOTE: we use common constant encoding (0 = None, 1 = False, 2 = True) return Py_OWN(db0::python::PyBool_fromBool(value.cast() == 2)); @@ -552,14 +552,14 @@ namespace db0::object_model // DB0_BYTES_ARRAY specialization template <> typename PyToolkit::ObjectSharedPtr unloadMember( - db0::swine_ptr &fixture, Value value, unsigned int) + db0::swine_ptr &fixture, Value value, unsigned int, AccessFlags access_mode) { - return PyToolkit::unloadByteArray(fixture, value.asAddress()); + return PyToolkit::unloadByteArray(fixture, value.asAddress(), access_mode); } // OBJECT_WEAK_REF template <> typename PyToolkit::ObjectSharedPtr unloadMember( - db0::swine_ptr &fixture, Value value, unsigned int) + db0::swine_ptr &fixture, Value value, unsigned int, AccessFlags) { auto address = value.asUniqueAddress(); // NOTE: instance_id not validated since it's a trusted reference @@ -573,7 +573,7 @@ namespace db0::object_model // OBJECT_LONG_WEAK_REF template <> typename PyToolkit::ObjectSharedPtr unloadMember( - db0::swine_ptr &fixture, Value value, unsigned int) + db0::swine_ptr &fixture, Value value, unsigned int, AccessFlags) { LongWeakRef weak_ref(fixture, value.asAddress()); auto other_fixture = fixture->getWorkspace().getFixture(weak_ref->m_fixture_uuid); @@ -589,7 +589,7 @@ namespace db0::object_model // CLASS specialization template <> typename PyToolkit::ObjectSharedPtr unloadMember( - db0::swine_ptr &fixture, Value value, unsigned int) + db0::swine_ptr &fixture, Value value, unsigned int, AccessFlags) { auto &class_factory = fixture->get(); auto class_item = class_factory.getTypeByAddr(value.asUniqueAddress().getAddress()); @@ -599,14 +599,14 @@ namespace db0::object_model // PACK-2 specialization template <> typename PyToolkit::ObjectSharedPtr unloadMember( - db0::swine_ptr &fixture, Value value, unsigned int offset) + db0::swine_ptr &fixture, Value value, unsigned int offset, AccessFlags) { auto val_code = lofi_store<2>::fromValue(value).get(offset); return PyToolkit::getTypeManager().getLangConstant(val_code); } - + template <> void registerUnloadMemberFunctions( - std::vector &, Value, unsigned int)> &functions) + std::vector &, Value, unsigned int, AccessFlags)> &functions) { functions.resize(static_cast(StorageClass::COUNT)); std::fill(functions.begin(), functions.end(), nullptr); diff --git a/src/dbzero/object_model/value/Member.hpp b/src/dbzero/object_model/value/Member.hpp index e7230086..10cc0cfa 100644 --- a/src/dbzero/object_model/value/Member.hpp +++ b/src/dbzero/object_model/value/Member.hpp @@ -52,27 +52,29 @@ namespace db0::object_model } template typename LangToolkit::ObjectSharedPtr unloadMember( - db0::swine_ptr &fixture, o_typed_item typed_item, unsigned int offset = 0) + db0::swine_ptr &fixture, o_typed_item typed_item, unsigned int offset = 0, AccessFlags access_mode = {}) { - return unloadMember(fixture, typed_item.m_storage_class, typed_item.m_value, offset); + return unloadMember( + fixture, typed_item.m_storage_class, typed_item.m_value, offset, access_mode + ); } template typename LangToolkit::ObjectSharedPtr unloadMember( - db0::swine_ptr &fixture, Value value, unsigned int offset = 0); + db0::swine_ptr &fixture, Value value, unsigned int offset = 0, AccessFlags access_mode = {}); // register StorageClass specializations template void registerUnloadMemberFunctions( - std::vector &, Value, unsigned int)> &functions); + std::vector &, Value, unsigned int, AccessFlags)> &functions); /** * @param name optional name (for error reporting only) * @param offset optional offset for lo-fi members (default = 0) */ template typename LangToolkit::ObjectSharedPtr unloadMember( - db0::swine_ptr &fixture, StorageClass storage_class, Value value, unsigned int offset = 0) + db0::swine_ptr &fixture, StorageClass storage_class, Value value, unsigned int offset = 0, AccessFlags access_mode = {}) { // create member function pointer - using UnloadMemberFunc = typename LangToolkit::ObjectSharedPtr (*)(db0::swine_ptr &, Value, unsigned int); + using UnloadMemberFunc = typename LangToolkit::ObjectSharedPtr (*)(db0::swine_ptr &, Value, unsigned int, AccessFlags); static std::vector unload_member_functions; if (unload_member_functions.empty()) { registerUnloadMemberFunctions(unload_member_functions); @@ -80,7 +82,7 @@ namespace db0::object_model assert(static_cast(storage_class) < unload_member_functions.size()); assert(unload_member_functions[static_cast(storage_class)]); - return unload_member_functions[static_cast(storage_class)](fixture, value, offset); + return unload_member_functions[static_cast(storage_class)](fixture, value, offset, access_mode); } // unreference a member (decref / destroy where applicable)