1 /*
2 * Copyright 2003-2021 The Music Player Daemon Project
3 * http://www.musicpd.org
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "Manager.hxx"
21 #include "lib/fmt/ExceptionFormatter.hxx"
22 #include "event/Loop.hxx"
23 #include "util/DeleteDisposer.hxx"
24 #include "util/Domain.hxx"
25 #include "Log.hxx"
26
27 #include <string.h>
28
29 static constexpr Domain nfs_domain("nfs");
30
31 void
OnNfsConnectionError(std::exception_ptr && e)32 NfsManager::ManagedConnection::OnNfsConnectionError(std::exception_ptr &&e) noexcept
33 {
34 FmtError(nfs_domain, "NFS error on '{}:{}': {}",
35 GetServer(), GetExportName(), e);
36
37 /* defer deletion so the caller
38 (i.e. NfsConnection::OnSocketReady()) can still use this
39 object */
40 manager.ScheduleDelete(*this);
41 }
42
43 inline bool
operator ()(const LookupKey a,const ManagedConnection & b) const44 NfsManager::Compare::operator()(const LookupKey a,
45 const ManagedConnection &b) const noexcept
46 {
47 int result = strcmp(a.server, b.GetServer());
48 if (result != 0)
49 return result < 0;
50
51 result = strcmp(a.export_name, b.GetExportName());
52 return result < 0;
53 }
54
55 inline bool
operator ()(const ManagedConnection & a,const LookupKey b) const56 NfsManager::Compare::operator()(const ManagedConnection &a,
57 const LookupKey b) const noexcept
58 {
59 int result = strcmp(a.GetServer(), b.server);
60 if (result != 0)
61 return result < 0;
62
63 result = strcmp(a.GetExportName(), b.export_name);
64 return result < 0;
65 }
66
67 inline bool
operator ()(const ManagedConnection & a,const ManagedConnection & b) const68 NfsManager::Compare::operator()(const ManagedConnection &a,
69 const ManagedConnection &b) const noexcept
70 {
71 int result = strcmp(a.GetServer(), b.GetServer());
72 if (result != 0)
73 return result < 0;
74
75 result = strcmp(a.GetExportName(), b.GetExportName());
76 return result < 0;
77 }
78
~NfsManager()79 NfsManager::~NfsManager() noexcept
80 {
81 assert(!GetEventLoop().IsAlive() || GetEventLoop().IsInside());
82
83 CollectGarbage();
84
85 connections.clear_and_dispose(DeleteDisposer());
86 }
87
88 NfsConnection &
GetConnection(const char * server,const char * export_name)89 NfsManager::GetConnection(const char *server, const char *export_name) noexcept
90 {
91 assert(server != nullptr);
92 assert(export_name != nullptr);
93 assert(GetEventLoop().IsInside());
94
95 Map::insert_commit_data hint;
96 auto result = connections.insert_check(LookupKey{server, export_name},
97 Compare(), hint);
98 if (result.second) {
99 auto c = new ManagedConnection(*this, GetEventLoop(),
100 server, export_name);
101 connections.insert_commit(*c, hint);
102 return *c;
103 } else {
104 return *result.first;
105 }
106 }
107
108 void
CollectGarbage()109 NfsManager::CollectGarbage() noexcept
110 {
111 assert(!GetEventLoop().IsAlive() || GetEventLoop().IsInside());
112
113 garbage.clear_and_dispose(DeleteDisposer());
114 }
115
116 void
OnIdle()117 NfsManager::OnIdle() noexcept
118 {
119 CollectGarbage();
120 }
121