1 /*
2 Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is also distributed with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have included with MySQL.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License, version 2.0, for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25
26 #include <ndb_global.h>
27
28 #include "SHM_Transporter.hpp"
29 #include "TransporterInternalDefinitions.hpp"
30 #include <TransporterCallback.hpp>
31 #include <NdbSleep.h>
32 #include <NdbOut.hpp>
33
34 #include <sys/ipc.h>
35 #include <sys/shm.h>
36
37 #include <EventLogger.hpp>
38 extern EventLogger * g_eventLogger;
39
40 #if 0
41 #define DEBUG_FPRINTF(arglist) do { fprintf arglist ; } while (0)
42 #else
43 #define DEBUG_FPRINTF(a)
44 #endif
45
make_error_info(char info[],int sz)46 void SHM_Transporter::make_error_info(char info[], int sz)
47 {
48 snprintf(info,sz,"Shm key=%d sz=%d id=%d",
49 shmKey, shmSize, shmId);
50 }
51
52 bool
ndb_shm_create()53 SHM_Transporter::ndb_shm_create()
54 {
55 if (!isServer)
56 {
57 ndbout_c("Trying to create shared memory segment on the client side");
58 return false;
59 }
60 shmId = shmget(shmKey, shmSize, IPC_CREAT | 960);
61 if (shmId == -1)
62 {
63 DEBUG_FPRINTF((stderr, "(%u)shmget(IPC_CREAT)(%u) failed LINE:%d,shmId:%d,"
64 " errno %d(%s)\n",
65 localNodeId,
66 remoteNodeId,
67 __LINE__,
68 shmId,
69 errno,
70 strerror(errno)));
71 fprintf(stderr,
72 "ERROR: Failed to create SHM segment of size %u with errno: %d(%s)\n",
73 shmSize, errno, strerror(errno));
74 require(false);
75 return false;
76 }
77 return true;
78 }
79
80 bool
ndb_shm_get()81 SHM_Transporter::ndb_shm_get()
82 {
83 shmId = shmget(shmKey, shmSize, 0);
84 if (shmId == -1)
85 {
86 DEBUG_FPRINTF((stderr, "(%u)shmget(0)(%u) failed LINE:%d, shmId:%d,"
87 " errno %d(%s)\n",
88 localNodeId,
89 remoteNodeId,
90 __LINE__,
91 shmId,
92 errno,
93 strerror(errno)));
94 if (errno != ENOENT)
95 {
96 fprintf(stderr,
97 "ERROR: Failed to get SHM segment of size %u with errno: %d(%s)\n",
98 shmSize, errno, strerror(errno));
99 require(false);
100 }
101 return false;
102 }
103 return true;
104 }
105
106 bool
ndb_shm_attach()107 SHM_Transporter::ndb_shm_attach()
108 {
109 assert(shmBuf == 0);
110 shmBuf = (char *)shmat(shmId, 0, 0);
111 if (shmBuf == (char*)-1)
112 {
113 DEBUG_FPRINTF((stderr,
114 "(%u)shmat(%u) failed LINE:%d, shmId:%d,"
115 " errno %d(%s)\n",
116 localNodeId,
117 remoteNodeId,
118 __LINE__,
119 shmId,
120 errno,
121 strerror(errno)));
122 if (isServer)
123 shmctl(shmId, IPC_RMID, 0);
124 _shmSegCreated = false;
125 return false;
126 }
127 return true;
128 }
129
130 void
ndb_shm_destroy()131 SHM_Transporter::ndb_shm_destroy()
132 {
133 /**
134 * We have attached to the shared memory segment.
135 * The shared memory won't be removed until all
136 * attached processes have detached. To ensure
137 * that we remove the shared memory segment even
138 * after a crash we now remove it immediately.
139 * Otherwise the shared memory segment will be
140 * left after a crash.
141 */
142 const int res = shmctl(shmId, IPC_RMID, 0);
143 if(res == -1)
144 {
145 DEBUG_FPRINTF((stderr, "(%u)shmctl(IPC_RMID)(%u) failed LINE:%d, shmId:%d,"
146 " errno %d(%s)\n",
147 localNodeId,
148 remoteNodeId,
149 __LINE__,
150 shmId,
151 errno,
152 strerror(errno)));
153 return;
154 }
155 _shmSegCreated = false;
156 }
157
158 bool
checkConnected()159 SHM_Transporter::checkConnected()
160 {
161 struct shmid_ds info;
162 const int res = shmctl(shmId, IPC_STAT, &info);
163 if (res == -1)
164 {
165 DEBUG_FPRINTF((stderr, "(%u)checkConnected(%u) failed LINE:%d, shmId:%d,"
166 " errno %d(%s)\n",
167 localNodeId,
168 remoteNodeId,
169 __LINE__,
170 shmId,
171 errno,
172 strerror(errno)));
173 return false;
174 }
175
176 if (info.shm_nattch != 2)
177 {
178 DEBUG_FPRINTF((stderr, "(%u)checkConnected(%u) failed LINE:%d, nattch != 2",
179 localNodeId,
180 remoteNodeId,
181 __LINE__));
182 DBUG_PRINT("error", ("Already connected to node %d",
183 remoteNodeId));
184 return false;
185 }
186 return true;
187 }
188
189 void
detach_shm(bool rep_error)190 SHM_Transporter::detach_shm(bool rep_error)
191 {
192 if (_attached)
193 {
194 struct shmid_ds info;
195 const int ret_val = shmctl(shmId, IPC_STAT, &info);
196 if (ret_val != -1)
197 {
198 if (info.shm_nattch > 0)
199 {
200 /**
201 * Ensure that the last process to detach from the
202 * shared memory is the one that removes the mutexes.
203 * This ensures that we synchronize the removal of the
204 * mutexes and ensures also that we will destroy the
205 * mutexes before we detach the last shared memory user.
206 */
207 NdbMutex_Lock(serverMutex);
208 if (isServer)
209 {
210 * serverUpFlag = 0;
211 }
212 else
213 {
214 * clientUpFlag = 0;
215 }
216 bool last = (*serverUpFlag == 0 && clientUpFlag == 0);
217 NdbMutex_Unlock(serverMutex);
218 if (last)
219 {
220 remove_mutexes();
221 }
222 }
223 }
224 const int res = shmdt(shmBuf);
225 if(res == -1)
226 {
227 DEBUG_FPRINTF((stderr, "(%u)shmdt(%u) failed LINE:%d, shmId:%d,"
228 " errno %d(%s)\n",
229 localNodeId,
230 remoteNodeId,
231 __LINE__,
232 shmId,
233 errno,
234 strerror(errno)));
235 if (rep_error)
236 report_error(TE_SHM_UNABLE_TO_REMOVE_SEGMENT);
237 }
238 _attached = false;
239 DEBUG_FPRINTF((stderr, "(%u)shmdt(%d)\n",
240 localNodeId, remoteNodeId));
241 }
242
243 if (isServer && _shmSegCreated)
244 {
245 /**
246 * Normally should not happen.
247 */
248 assert(!rep_error);
249 const int res = shmctl(shmId, IPC_RMID, 0);
250 if(res == -1)
251 {
252 DEBUG_FPRINTF((stderr, "(%u)shmctl(IPC_RMID)(%u) failed LINE:%d,"
253 " shmId:%d, errno %d(%s)\n",
254 localNodeId,
255 remoteNodeId,
256 __LINE__,
257 shmId,
258 errno,
259 strerror(errno)));
260 if (rep_error)
261 report_error(TE_SHM_UNABLE_TO_REMOVE_SEGMENT);
262 }
263 DEBUG_FPRINTF((stderr, "(%u)shmctl(IPC_RMID)(%d)\n",
264 localNodeId, remoteNodeId));
265 }
266 _shmSegCreated = false;
267 if (reader != 0)
268 {
269 DEBUG_FPRINTF((stderr, "(%u)detach_shm(%u) LINE:%d",
270 localNodeId, __LINE__, remoteNodeId));
271 reader->~SHM_Reader();
272 writer->~SHM_Writer();
273 shmBuf = 0;
274 reader = 0;
275 writer = 0;
276 }
277 else
278 {
279 DEBUG_FPRINTF((stderr, "(%u)reader==0(%u) LINE:%d",
280 localNodeId, __LINE__, remoteNodeId));
281 }
282 }
283
284 void
disconnectImpl()285 SHM_Transporter::disconnectImpl()
286 {
287 DEBUG_FPRINTF((stderr, "(%u)disconnectImpl(%d)\n",
288 localNodeId, remoteNodeId));
289 disconnect_socket();
290 setupBuffersUndone();
291 }
292