SegmentUtilImplementations.cpp
Go to the documentation of this file.
1/*
2* This file is part of ArmarX.
3*
4* ArmarX is free software; you can redistribute it and/or modify
5* it under the terms of the GNU General Public License version 2 as
6* published by the Free Software Foundation.
7*
8* ArmarX is distributed in the hope that it will be useful, but
9* WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11* GNU General Public License for more details.
12*
13* You should have received a copy of the GNU General Public License
14* along with this program. If not, see <http://www.gnu.org/licenses/>.
15*
16* @package ArmarX
17* @author Mirko Waechter( mirko.waechter at kit dot edu)
18* @date 2016
19* @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20* GNU General Public License
21*/
23
24#include <Ice/Connection.h>
25#include <Ice/ObjectAdapter.h>
26#include <IceUtil/UUID.h>
27
33
36
37namespace memoryx
38{
39
43
44 auto
46 {
47 std::unique_lock lock(tokenMutex);
48
49 if (!lockToken.empty() && c.ctx.count("token") > 0 && c.ctx.at("token") == lockToken)
50 {
51 return ScopedSharedLockPtr();
52 }
54 }
55
56 auto
58 {
59 std::unique_lock lock(tokenMutex);
60
61 if (!lockToken.empty() && c.ctx.count("token") > 0 && c.ctx.at("token") == lockToken)
62 {
63 return ScopedUniqueLockPtr();
64 }
66 }
67
68 std::string
69 SegmentUtilImplementations::getJSONEntityById(const std::string& id, const Ice::Current&) const
70 {
71 EntityBasePtr entity = getEntityById(id);
72 if (!entity)
73 {
74 throw EntityNotFoundException();
75 }
77 json->setIceObject("entity", entity);
78 return json->asString(true);
79 }
80
81 EntityBaseList
83 bool includeMetaEntities,
84 const Ice::Current& c) const
85 {
86 auto comp = [](const EntityBasePtr& e1, const EntityBasePtr& e2)
87 { return e1->getId() < e2->getId(); };
88
89 std::set<EntityBasePtr, decltype(comp)> result(comp);
90 std::set<EntityBasePtr, decltype(comp)> searchList(comp);
91 EntityPtr root = EntityPtr::dynamicCast(getEntityById(id, c));
92 searchList.insert(root);
93 result.insert(root);
94 auto all = getAllEntities(c);
95 std::string attribName = "parentEntityRefs";
96
97 while (!searchList.empty())
98 {
99 EntityPtr curParent = EntityPtr::dynamicCast(*searchList.begin());
100 auto curParentRef = getEntityRefById(curParent->getId(), c);
101 searchList.erase(searchList.begin());
102 for (EntityBasePtr& entity : all)
103 {
104 if (!entity->hasAttribute(attribName, c))
105 {
106 continue;
107 }
108 auto attr = entity->getAttribute(attribName, c);
109 for (int i = 0; i < attr->size(); ++i)
110 {
112 armarx::VariantPtr::dynamicCast(attr->getValueAt(i, c))->get<EntityRef>();
113 if (ref->equals(curParentRef))
114 {
115 ARMARX_INFO_S << ref->entityName << " is parent of " << entity->getName();
116 if (result.count(entity) ==
117 0) // if already in result list, this item was already in search list
118 {
119 searchList.insert(entity);
120 }
121 result.insert(entity);
122 }
123 }
124 }
125 }
126
127 if (!includeMetaEntities)
128 {
129 EntityBaseList filteredResult;
130 std::copy_if(result.begin(),
131 result.end(),
132 std::back_inserter(filteredResult),
133 [](const EntityBasePtr& entity) { return !entity->isMetaEntity(); });
134 return filteredResult;
135 }
136 return EntityBaseList(result.begin(), result.end());
137 }
138
139 EntityBaseList
141 bool includeMetaEntities,
142 const Ice::Current& c) const
143 {
144 auto entity = getEntityByName(entityName);
145 if (entity)
146 {
147 return getEntityWithChildrenById(entity->getId(), includeMetaEntities);
148 }
149 else
150 {
151 return EntityBaseList();
152 }
153 }
154
155 SegmentLockBasePtr
157 {
159 SegmentLockBasePtr lock = new SegmentLock(!c.con);
160 {
161 std::unique_lock mutexLock(tokenMutex);
162 lockToken = lock->token = IceUtil::generateUUID();
163 }
164 ARMARX_CHECK_EXPRESSION(c.adapter) << "Ice::Current must not be empty";
165 lock->segment =
166 EntityMemorySegmentInterfacePrx::uncheckedCast(c.adapter->createProxy(c.id));
168 {
169 keepAliveCheckTask->stop();
170 }
172 this,
174 lock->keepAliveIntervalMs * 2,
175 false,
176 "KeepAliveChecker",
177 false);
178 {
179 std::unique_lock lock(keepAliveTimestampMutex);
181 }
182 keepAliveCheckTask->start();
183
184 return lock;
185 }
186
187 bool
188 SegmentUtilImplementations::keepLockAlive(const std::string& token, const Ice::Current&)
189 {
190 {
191 std::unique_lock lock(tokenMutex);
192 if (token != lockToken)
193 {
194 throw InvalidLockTokenException();
195 }
196 }
197
198 if (writeLock)
199 {
200 std::unique_lock lock(keepAliveTimestampMutex);
202 return true;
203 }
204
205 return false;
206 }
207
208 bool
209 SegmentUtilImplementations::unlockSegment(const SegmentLockBasePtr& lock, const Ice::Current& c)
210 {
211 std::unique_lock mutexLock(tokenMutex);
212
213 if (lock->token != lockToken)
214 {
215 throw InvalidLockTokenException();
216 }
217 if (!writeLock)
218 {
219 return false;
220 }
221 writeLock.reset();
222 lockToken.clear();
223 return true;
224 }
225
226 bool
228 const Ice::Current& c)
229 {
230 std::unique_lock mutexLock(tokenMutex);
231
232 if (token != lockToken)
233 {
234 throw InvalidLockTokenException();
235 }
236 if (!writeLock)
237 {
238 return false;
239 }
240 writeLock.reset();
241 lockToken.clear();
242 return true;
243 }
244
245 void
247 {
248 std::unique_lock lock(keepAliveTimestampMutex);
249
250 auto age = (IceUtil::Time::now() - keepAliveTimestamp);
251 if (age.toMilliSeconds() > keepAliveCheckTask->getInterval() && writeLock)
252 {
253 writeLock.reset();
254
255 {
256 std::unique_lock mutexLock(tokenMutex);
257 lockToken.clear();
258 }
259
260 ARMARX_WARNING_S << "Segment lock of segment '" << getSegmentName()
261 << "' did not receive keep-alive in time ("
262 << age.toMilliSecondsDouble()
263 << " ms, interval: " << keepAliveCheckTask->getInterval()
264 << " ) - unlocking segment";
265 }
266 }
267
269 {
270 if (keepAliveTask)
271 {
272 unlock();
273 keepAliveTask->stop();
274 }
275 }
276
277 SegmentLock::SegmentLock(bool start_watchdog)
278 {
279 if (start_watchdog)
280 {
282 }
283 }
284
285 void
286 SegmentLock::unlock(const Ice::Current& c)
287 {
288 try
289 {
290 if (keepAliveTask)
291 {
292 keepAliveTask->stop();
293 }
294
295 segment->unlockSegmentWithToken(this->token);
296 }
297 catch (...)
298 {
299 }
300 }
301
302 void
304 {
306 this, &SegmentLock::keepAlive, keepAliveIntervalMs, false, "KeepAliveTask", false);
307 keepAliveTask->start();
308 }
309
310 void
315
316 void
318 {
319 try
320 {
321 segment->keepLockAlive(this->token);
322 }
323 catch (...)
324 {
325 }
326 }
327
328} // namespace memoryx
constexpr T c
The JSONObject class is used to represent and (de)serialize JSON objects.
Definition JSONObject.h:44
The periodic task executes one thread method repeatedly using the time period specified in the constr...
static IceUtil::Time GetTime(TimeMode timeMode=TimeMode::VirtualTime)
Get the current time.
Definition TimeUtil.cpp:42
The EntityRef class is used to store references to Entities as values in other Entity instances.
Definition EntityRef.h:47
armarx::PeriodicTask< SegmentLock >::pointer_type keepAliveTask
void unlock(const Ice::Current &c=Ice::emptyCurrent) override
SegmentLock(bool start_watchdog=false)
std::unique_lock< std::shared_mutex > ScopedUniqueLock
std::string getJSONEntityById(const std::string &id, const Ice::Current &) const override
bool unlockSegmentWithToken(const std::string &token, const Ice::Current &c) override
std::unique_ptr< ScopedSharedLock > ScopedSharedLockPtr
bool unlockSegment(const SegmentLockBasePtr &lock, const Ice::Current &c) override
EntityBaseList getEntityWithChildrenByName(const std::string &, bool includeMetaEntities, const Ice::Current &c=Ice::emptyCurrent) const override
ScopedSharedLockPtr getReadLock(const Ice::Current &c) const
ScopedUniqueLockPtr getWriteLock(const Ice::Current &c) const
std::unique_lock< std::shared_mutex > ScopedSharedLock
bool keepLockAlive(const std::string &token, const Ice::Current &) override
armarx::PeriodicTask< SegmentUtilImplementations >::pointer_type keepAliveCheckTask
std::unique_ptr< ScopedSharedLock > ScopedUniqueLockPtr
EntityBaseList getEntityWithChildrenById(const std::string &id, bool includeMetaEntities, const Ice::Current &c=Ice::emptyCurrent) const override
SegmentLockBasePtr lockSegment(const Ice::Current &c) override
#define ARMARX_CHECK_EXPRESSION(expression)
This macro evaluates the expression and if it turns out to be false it will throw an ExpressionExcept...
#define ARMARX_INFO_S
Definition Logging.h:202
#define ARMARX_WARNING_S
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:213
IceInternal::Handle< JSONObject > JSONObjectPtr
Definition JSONObject.h:34
VirtualRobot headers.
IceInternal::Handle< EntityRef > EntityRefPtr
Definition EntityRef.h:38
IceInternal::Handle< Entity > EntityPtr
Typedef of EntityPtr as IceInternal::Handle<Entity> for convenience.
Definition Entity.h:45