Skip to content

Commit

Permalink
Custom resolve complex MatchSpec in Solver (#3233)
Browse files Browse the repository at this point in the history
* Add ObjPool::current_error

* Support reference_wrapper in MatchSpec::contains

* Rename subdir > platform in solv-cpp

* Add Matcher as namespace callback

* Add MatcherFlags

* Redefine MatchSpec::is_simple

* Add VersionSpec::from_predicate

* Refactor reinstall jobs

* Fix MatchSpec::is_simple

* Handle complex MatchSpec in solver

* Add version cache in Matcher

* Add more pool namespace tests

* Handle exception in ObjPool callback

* Try removing SOLVABLE_PROVIDES

* Add unsolvable complex spec test

* Fix Database callback exceptions

* Add channel in Matcher

* Adapt channel_specific tests

* Fix updates
  • Loading branch information
AntoinePrv committed Mar 19, 2024
1 parent 25431a6 commit 43e38ef
Show file tree
Hide file tree
Showing 27 changed files with 1,182 additions and 420 deletions.
1 change: 1 addition & 0 deletions libmamba/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ set(
# Solver libsolv implementation
${LIBMAMBA_SOURCE_DIR}/solver/libsolv/database.cpp
${LIBMAMBA_SOURCE_DIR}/solver/libsolv/helpers.cpp
${LIBMAMBA_SOURCE_DIR}/solver/libsolv/matcher.cpp
${LIBMAMBA_SOURCE_DIR}/solver/libsolv/parameters.cpp
${LIBMAMBA_SOURCE_DIR}/solver/libsolv/repo_info.cpp
${LIBMAMBA_SOURCE_DIR}/solver/libsolv/solver.cpp
Expand Down
55 changes: 29 additions & 26 deletions libmamba/ext/solv-cpp/include/solv-cpp/pool.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#ifndef MAMBA_SOLV_POOL_HPP
#define MAMBA_SOLV_POOL_HPP

#include <functional>
#include <memory>
#include <optional>
#include <stdexcept>
Expand Down Expand Up @@ -44,6 +45,11 @@ namespace solv
auto raw() -> raw_ptr;
auto raw() const -> const_raw_ptr;

auto current_error() const -> std::string_view;

void set_current_error(raw_str_view msg);
void set_current_error(const std::string& msg);

/**
* Get the current distribution type of the pool.
*
Expand Down Expand Up @@ -285,6 +291,22 @@ namespace solv
template <typename UnaryFunc>
void for_each_installed_solvable(UnaryFunc&& func);

/** Rethrow exception thrown in callback. */
void rethrow_potential_callback_exception() const;

protected:

using UserCallback = std::function<OffsetId(ObjPoolView, StringId, StringId)>;

/**
* A wrapper around user callback to handle exceptions.
*
* This cannot be set in this class since this is only a view type but can be checked
* for errors.
*/
struct NamespaceCallbackWrapper;


private:

raw_ptr m_pool;
Expand All @@ -302,6 +324,8 @@ namespace solv
~ObjPool();

using ObjPoolView::raw;
using ObjPoolView::current_error;
using ObjPoolView::set_current_error;
using ObjPoolView::disttype;
using ObjPoolView::set_disttype;
using ObjPoolView::find_string;
Expand Down Expand Up @@ -337,6 +361,7 @@ namespace solv
using ObjPoolView::for_each_solvable;
using ObjPoolView::for_each_installed_solvable_id;
using ObjPoolView::for_each_installed_solvable;
using ObjPoolView::rethrow_potential_callback_exception;

/** Set the callback to handle libsolv messages.
*
Expand All @@ -347,8 +372,9 @@ namespace solv
template <typename Func>
void set_debug_callback(Func&& callback);

template <typename Func>
void set_namespace_callback(Func&& callback);
using UserCallback = ObjPoolView::UserCallback;

void set_namespace_callback(UserCallback&& callback);

private:

Expand All @@ -358,7 +384,7 @@ namespace solv
};

std::unique_ptr<void, void (*)(void*)> m_user_debug_callback;
std::unique_ptr<void, void (*)(void*)> m_user_namespace_callback;
std::unique_ptr<NamespaceCallbackWrapper> m_user_namespace_callback;
// Must be deleted before the debug callback
std::unique_ptr<::Pool, ObjPool::PoolDeleter> m_pool = nullptr;
};
Expand Down Expand Up @@ -531,28 +557,5 @@ namespace solv

::pool_setdebugcallback(raw(), debug_callback, m_user_debug_callback.get());
}

template <typename Func>
void ObjPool::set_namespace_callback(Func&& callback)
{
static_assert(
std::is_nothrow_invocable_v<Func, ObjPoolView, StringId, StringId>,
"User callback must be marked noexcept."
);

m_user_namespace_callback.reset(new Func(std::forward<Func>(callback)));
m_user_namespace_callback.get_deleter() = [](void* ptr)
{ delete reinterpret_cast<Func*>(ptr); };

// Wrap the user callback in the libsolv function type that must cast the callback ptr
auto namespace_callback = [](::Pool* pool, void* user_data, StringId name, StringId ver
) noexcept -> OffsetId
{
auto* user_namespace_callback = reinterpret_cast<Func*>(user_data);
return (*user_namespace_callback)(ObjPoolView(pool), name, ver); // noexcept
};

::pool_setnamespacecallback(raw(), namespace_callback, m_user_namespace_callback.get());
}
}
#endif
10 changes: 5 additions & 5 deletions libmamba/ext/solv-cpp/include/solv-cpp/solvable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,11 @@ namespace solv
auto channel() const -> std::string_view;

/**
* The sub-directory of the solvable.
* The platform of the solvable.
*
* @see ObjSolvableView::set_subdir
**/
auto subdir() const -> std::string_view;
auto platform() const -> std::string_view;

/**
* Queue of ``DependencyId``.
Expand Down Expand Up @@ -254,7 +254,7 @@ namespace solv
void set_channel(const std::string& str) const;

/**
* Set the sub-directory of the solvable.
* Set the platform of the solvable.
*
* This has no effect for libsolv and is purely for data storing.
* This may not be the same as @ref ObjRepoViewConst::channel, for instance the install
Expand All @@ -263,8 +263,8 @@ namespace solv
* @note A call to @ref ObjRepoView::internalize is required for this attribute to
* be available for lookup.
*/
void set_subdir(raw_str_view str) const;
void set_subdir(const std::string& str) const;
void set_platform(raw_str_view str) const;
void set_platform(const std::string& str) const;

/** Set the dependencies of the solvable. */
void set_dependencies(const ObjQueue& q, DependencyMarker marker = 0) const;
Expand Down
71 changes: 70 additions & 1 deletion libmamba/ext/solv-cpp/src/pool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
// The full license is in the file LICENSE, distributed with this software.

#include <cassert>
#include <exception>
#include <limits>
#include <memory>
#include <stdexcept>

#include <solv/conda.h>
Expand Down Expand Up @@ -38,6 +40,21 @@ namespace solv
return m_pool;
}

auto ObjPoolView::current_error() const -> std::string_view
{
return ::pool_errstr(m_pool);
}

void ObjPoolView::set_current_error(raw_str_view msg)
{
::pool_error(m_pool, -1, "%s", msg);
}

void ObjPoolView::set_current_error(const std::string& msg)
{
return set_current_error(msg.c_str());
}

auto ObjPoolView::disttype() const -> DistType
{
return raw()->disttype;
Expand Down Expand Up @@ -323,6 +340,24 @@ namespace solv
return std::nullopt;
}

struct ObjPoolView::NamespaceCallbackWrapper
{
UserCallback callback;
std::exception_ptr error = nullptr;
};

void ObjPoolView::rethrow_potential_callback_exception() const
{
if (auto callback = reinterpret_cast<NamespaceCallbackWrapper*>(raw()->nscallbackdata))
{
if (auto error = callback->error)
{
callback->error = nullptr;
std::rethrow_exception(error);
}
}
}

/*******************************
* Implementation of ObjPool *
*******************************/
Expand All @@ -335,11 +370,45 @@ namespace solv
ObjPool::ObjPool()
: ObjPoolView(nullptr)
, m_user_debug_callback(nullptr, [](void* /*ptr*/) {})
, m_user_namespace_callback(nullptr, [](void* /*ptr*/) {})
, m_user_namespace_callback(nullptr)
, m_pool(::pool_create())
{
ObjPoolView::m_pool = m_pool.get();
}

ObjPool::~ObjPool() = default;

void ObjPool::set_namespace_callback(UserCallback&& callback)
{
m_user_namespace_callback = std::make_unique<NamespaceCallbackWrapper>();

// Set the callback
m_user_namespace_callback->callback = [wrapper = m_user_namespace_callback.get(),
callback = std::move(callback
)](ObjPoolView pool, StringId name, StringId ver
) mutable noexcept -> OffsetId
{
auto error = std::exception_ptr(nullptr);
try
{
std::swap(error, wrapper->error);
return callback(pool, name, ver);
}
catch (...)
{
wrapper->error = std::current_exception();
return 0;
}
};

// Wrap the user callback in the libsolv function type that must cast the callback ptr
auto libsolv_callback = +[](::Pool* pool, void* user_data, StringId name, StringId ver
) noexcept -> OffsetId
{
auto* user_namespace_callback = reinterpret_cast<NamespaceCallbackWrapper*>(user_data);
return user_namespace_callback->callback(ObjPoolView(pool), name, ver); // noexcept
};

::pool_setnamespacecallback(raw(), libsolv_callback, m_user_namespace_callback.get());
}
}
8 changes: 4 additions & 4 deletions libmamba/ext/solv-cpp/src/solvable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -352,20 +352,20 @@ namespace solv
return set_channel(str.c_str());
}

auto ObjSolvableViewConst::subdir() const -> std::string_view
auto ObjSolvableViewConst::platform() const -> std::string_view
{
return ptr_to_strview(::solvable_lookup_str(const_cast<::Solvable*>(raw()), SOLVABLE_MEDIADIR)
);
}

void ObjSolvableView::set_subdir(raw_str_view str) const
void ObjSolvableView::set_platform(raw_str_view str) const
{
::solvable_set_str(raw(), SOLVABLE_MEDIADIR, str);
}

void ObjSolvableView::set_subdir(const std::string& str) const
void ObjSolvableView::set_platform(const std::string& str) const
{
return set_subdir(str.c_str());
return set_platform(str.c_str());
}

auto ObjSolvableViewConst::dependencies(DependencyMarker marker) const -> ObjQueue
Expand Down
3 changes: 2 additions & 1 deletion libmamba/ext/solv-cpp/src/solver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,10 +180,11 @@ namespace solv
return val != 0;
}

auto ObjSolver::solve(const ObjPool& /* pool */, const ObjQueue& jobs) -> bool
auto ObjSolver::solve(const ObjPool& pool, const ObjQueue& jobs) -> bool
{
// pool is captured inside solver so we take it as a parameter to be explicit.
const auto n_pbs = ::solver_solve(raw(), const_cast<::Queue*>(jobs.raw()));
pool.rethrow_potential_callback_exception();
return n_pbs == 0;
}

Expand Down
6 changes: 6 additions & 0 deletions libmamba/ext/solv-cpp/tests/src/test_pool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ TEST_SUITE("solv::ObjPool")
CHECK_EQ(pool.disttype(), DISTTYPE_CONDA);
}

SUBCASE("Error")
{
pool.set_current_error("Some failure");
CHECK_EQ(pool.current_error(), "Some failure");
}

SUBCASE("Add strings")
{
const auto id_hello = pool.add_string("Hello");
Expand Down
Loading

0 comments on commit 43e38ef

Please sign in to comment.