std::shared_ptr<detail::Client> neoref;
void service_shutdown() {
- if (neoref) {
- neoref = nullptr;
- }
- linger_op.reset();
+ // Ensure neorados object and operation live to the end of the
+ // function.
+ auto localop = std::move(linger_op);
+ [[maybe_unused]] auto localneo = std::move(neoref);
std::unique_lock l(m);
handlers.clear();
+ l.unlock();
+ if (localop) {
+ // We are being taken down and will execute no more
+ // handlers. Call `linger_cancel` to clean up properly in
+ // Objecter. (It doesn't call out to the OSD or anything.)
+ //
+ // Removal and decrement are guarded by `linger_op->canceled`
+ // so there's no risk of an underflow.
+ localop->objecter->linger_cancel(localop.get());
+ }
+ // The Notifier object is freed by the `linger_cancel` above.
}
public:
install(TARGETS
ceph_test_neorados_watch_notify
DESTINATION ${CMAKE_INSTALL_BINDIR})
+
+add_executable(ceph_test_neorados_leak_watch_notify leak_watch_notify.cc)
+target_link_libraries(ceph_test_neorados_leak_watch_notify global libneorados
+ neoradostest-support ${unittest_libs})
+install(TARGETS
+ ceph_test_neorados_leak_watch_notify
+ DESTINATION ${CMAKE_INSTALL_BINDIR})
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:nil -*-
+// vim: ts=8 sw=2 sts=2 expandtab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2026 Contributors to the Ceph Project
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation. See file COPYING.
+ *
+ */
+
+#include <iostream>
+#include <optional>
+
+#include <boost/asio.hpp>
+#include <boost/system/error_code.hpp>
+
+#include "include/neorados/RADOS.hpp"
+
+#include "common_tests.h"
+
+namespace asio = boost::asio;
+
+using boost::system::error_code;
+
+// Intentionally get a watch and don't unwatch it to make sure we call
+// `linger_cancel` and don't leak.
+
+int main()
+{
+ asio::io_context c;
+ std::string_view oid = "obj";
+
+ std::optional<neorados::RADOS> rados;
+ neorados::IOContext pool;
+ neorados::RADOS::Builder{}.build(c, [&](error_code ec, neorados::RADOS r_) {
+ rados = std::move(r_);
+ create_pool(*rados, get_temp_pool_name(),
+ [&](error_code ec, int64_t poolid) {
+ pool.set_pool(poolid);
+ rados->watch(oid, pool, [&](error_code, std::uint64_t cookie) {
+ std::cout << "Got watch: " << cookie << std::endl;
+ });
+ });
+ });
+ c.run();
+}