RemoteHandleControlBlock.h
Go to the documentation of this file.
1 /*
2  * This file is part of ArmarX.
3  *
4  * Copyright (C) 2011-2016, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
5  *
6  * ArmarX is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  * ArmarX is distributed in the hope that it will be useful, but
11  * 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
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  *
18 * @package ArmarXCore
19 * @author Raphael Grimm ( raphael dot grimm at kit dot edu)
20 * @date 2016
21 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22 * GNU General Public License
23 */
24 #pragma once
25 
26 #include <atomic>
27 #include <chrono>
28 #include <condition_variable>
29 #include <functional>
30 #include <memory>
31 #include <thread>
32 
33 #include <Ice/ObjectAdapter.h>
34 #include <IceUtil/UUID.h>
35 
36 #include <ArmarXCore/interface/core/util/distributed/RemoteHandle/RemoteHandleControlBlock.h>
37 
38 #include "../../../ArmarXManager.h"
39 #include "../../../services/tasks/PeriodicTask.h"
41 
42 namespace armarx
43 {
44  class RemoteHandleControlBlock;
46 
47  /**
48  * @brief This holds the shared state of all RemoteHandleControlBlocks for one armarx manager.
49  * It holds a thread responsible for deleting them when their usecount reaches zero and the deletion delay has passed.
50  */
52  {
53  public:
54  /**
55  * @brief The amount of time (in ms) required to pass after a RemoteHandleControlBlock's usecount has reacht zero, before it is deleted.
56  */
57  static const unsigned int DEFAULT_DELETION_DELAY;
59 
60  SharedRemoteHandleState(unsigned int deletionDelayMs);
62 
64 
65  private:
66  void sweep();
67 
68  std::mutex stateMutex;
69 
70  //must not invalidate other iterators on erase (ok for std::set)
71  std::set<RemoteHandleControlBlockPtr> rhs;
72  std::chrono::milliseconds deletionDelay;
74  };
75 
76  /**
77  * @brief The RemoteHandleControlBlock is the equivalent of the std::shared_ptr's contol_block for a remote handle.
78  * It does reference counting and object deletion.
79  *
80  * This class is created on server side and a ClientSideRemoteHandleControlBlock is send to the client.
81  * Only create the class by calling RemoteHandleControlBlock::create.
82  *
83  * A direct pointer can be used to force the deletion of the managed object.
84  * The deletion has to be done by a passed deleter (it may hold the only pointer to the managed object or execute code to remove the object from some structure).
85  * The deleter should do any unregistering for the managed object (e.g. remove the object from from an ice object adapter)
86  *
87  * a object may leak if a connection error stops the message send when a handle is deleted (this stops the usecount from reaching zero).
88  * a object may be deleted with handles still alive if:
89  * 1) the object's deletion was forced
90  * 2) a scenario equivalent to this:
91  * pc A has the object and sends a handle to B
92  * pc B has now the only handle
93  * pc B now sends the handle to pc C and delets the handle before C deserialized the object (this could be done via a broadcast)
94  * The handle is deserialized after the deletion timeout set via property (default 3 sec) has passed.
95  * This scenario is possible but should not happen on a stable LAN if ice objects are not keept in a serialized form for a longer period.
96  *
97  * (for more info: \ref ArmarXCore-Tutorials-RemoteHandles "RemoteHandle tutorial")
98  *
99  * \ingroup Distributed
100  */
101  class RemoteHandleControlBlock : virtual public RemoteHandleControlBlockInterface
102  {
103  public:
104  using clock = std::chrono::steady_clock;
105  inline static int64_t now();
106 
107  /**
108  * @brief Returned by a call to RemoteHandleControlBlock::create.
109  * It holds a direct handle to the controlblock (can be used to keep the RemoteHandleControlBlock alive (but not the managed object)) (this pointer may be deleted).
110  * And The ClientSideRemoteHandleControlBlock keeping the managed object alive. (send this to the client)
111  */
113  {
115  ClientSideRemoteHandleControlBlockBasePtr clientSideRemoteHandleControlBlock;
116  };
117 
118  /**
119  * @brief Creates a new RemoteHandleControlBlock.
120  * @param objectAdapter The adapter used to register the RemoteHandleControlBlock to ice.
121  * @param managedObjectPrx A Proxy to the managed object.
122  * @param deleter A functor cleaning up the managed object. (has to delete it and unregister it)
123  * The Functor may have the only pointer keeping the managed object alive.
124  * @return A direct pointer to the created RemoteHandleControlBlock and the ClientSideRemoteHandleControlBlock keeping the managed object alive.
125  */
126  template <class Deleter>
127  static ManagementData
128  create(ArmarXManagerPtr manager, Ice::ObjectPrx managedObjectPrx, Deleter deleter);
129 
130  /**
131  * @brief Increments the usecount.
132  * DO NOT CALL IT. (if you do, you are responsible to call decrementUseCount!)
133  */
134  inline void incrementUseCount(const Ice::Current& = Ice::emptyCurrent) override;
135  /**
136  * @brief decrements the useCount.
137  * DO NOT CALL IT. (except you have called incrementUseCount)
138  */
139  void decrementUseCount(const Ice::Current& = Ice::emptyCurrent) override;
140  /**
141  * @return Returns the current use count.
142  */
143  inline Ice::Long getUseCount(const Ice::Current& = Ice::emptyCurrent) const override;
144 
145  /**
146  * @return A new ClientSideRemoteHandleControlBlock.
147  */
148  ClientSideRemoteHandleControlBlockBasePtr
149  getClientSideRemoteHandleControlBlock(const Ice::Current& = Ice::emptyCurrent) override;
150  inline Ice::ObjectPrx
151  getManagedObjectProxy(const Ice::Current& = Ice::emptyCurrent) const override;
152 
153  /**
154  * @brief Call this when you want to force the deletion of the managed object.
155  * It will be deleted ignoring the usecount.
156  * This may be used to ensure the deletion of all objects created by yout server when shutting down.
157  * This may be necessary if a client's decrementUseCount was lost by the network.
158  */
159  void
161  {
162  forcedDeletion = true;
163  }
164 
165  private:
167  Ice::ObjectPrx managedObjectPrx,
168  std::function<void(void)> deleter);
171 
172  /**
173  * @brief Does all cleanup for this object.
174  */
175  inline void cleanup();
176 
177  /**
178  * @brief The adapter used to register this RemoteHandleControlBlock
179  */
180  Ice::ObjectAdapterPtr objectAdapter;
181  std::function<void(void)> deleter;
182  Ice::ObjectPrx managedObjectProxy;
183  /**
184  * @brief A proxy to this RemoteHandleControlBlock (used when creating a new ClientSideRemoteHandleControlBlock)
185  */
186  RemoteHandleControlBlockInterfacePrx selfProxy;
187 
188  mutable std::atomic<uint64_t> useCount{0};
189  mutable std::mutex mtx;
190  mutable clock::time_point lastTimeUseCountReachedZero;
191  mutable std::atomic_bool forcedDeletion{false};
192 
193  friend struct SharedRemoteHandleState;
194  };
195 
196  void
198  {
199  ++useCount;
200  }
201 
202  Ice::Long
203  RemoteHandleControlBlock::getUseCount(const Ice::Current&) const
204  {
205  return useCount;
206  }
207 
208  Ice::ObjectPrx
210  {
211  return managedObjectProxy;
212  }
213 
214  void
215  RemoteHandleControlBlock::cleanup()
216  {
217  //delete payload
218  deleter();
219  deleter = []() {
220  }; //do this to delete objects keept alive by the deleter (it may hold a unique_ptr)
221  //clean up proxy
222  objectAdapter->remove(selfProxy->ice_getIdentity());
223  }
224 
225  template <class Deleter>
226  RemoteHandleControlBlock::ManagementData
228  Ice::ObjectPrx managedObjectPrx,
229  Deleter deleter)
230  {
232  manager->getAdapter(), std::move(managedObjectPrx), std::move(deleter)};
233  auto clientSideRemoteHandleControlBlock = block->getClientSideRemoteHandleControlBlock();
234  manager->getSharedRemoteHandleState()->add(block);
235  return {block, clientSideRemoteHandleControlBlock};
236  }
237 } // namespace armarx
armarx::SharedRemoteHandleState
This holds the shared state of all RemoteHandleControlBlocks for one armarx manager.
Definition: RemoteHandleControlBlock.h:51
armarx::SharedRemoteHandleState::add
void add(RemoteHandleControlBlockPtr rh)
Definition: RemoteHandleControlBlock.cpp:96
ClientSideRemoteHandleControlBlock.h
armarx::RemoteHandleControlBlock::incrementUseCount
void incrementUseCount(const Ice::Current &=Ice::emptyCurrent) override
Increments the usecount.
Definition: RemoteHandleControlBlock.h:197
armarx::RemoteHandleControlBlock::ManagementData
Returned by a call to RemoteHandleControlBlock::create.
Definition: RemoteHandleControlBlock.h:112
armarx::SharedRemoteHandleState::~SharedRemoteHandleState
~SharedRemoteHandleState()
Definition: RemoteHandleControlBlock.cpp:82
IceInternal::Handle< RemoteHandleControlBlock >
armarx::RemoteHandleControlBlock::ManagementData::directHandle
RemoteHandleControlBlockPtr directHandle
Definition: RemoteHandleControlBlock.h:114
armarx::RemoteHandleControlBlock::clock
std::chrono::steady_clock clock
Definition: RemoteHandleControlBlock.h:104
armarx::RemoteHandleControlBlock::decrementUseCount
void decrementUseCount(const Ice::Current &=Ice::emptyCurrent) override
decrements the useCount.
Definition: RemoteHandleControlBlock.cpp:31
armarx::RemoteHandleControlBlock::ManagementData::clientSideRemoteHandleControlBlock
ClientSideRemoteHandleControlBlockBasePtr clientSideRemoteHandleControlBlock
Definition: RemoteHandleControlBlock.h:115
armarx::RemoteHandleControlBlock::getUseCount
Ice::Long getUseCount(const Ice::Current &=Ice::emptyCurrent) const override
Definition: RemoteHandleControlBlock.h:203
armarx::RemoteHandleControlBlock::forceDeletion
void forceDeletion()
Call this when you want to force the deletion of the managed object.
Definition: RemoteHandleControlBlock.h:160
armarx::VariantType::Long
const VariantTypeId Long
Definition: Variant.h:918
armarx::RemoteHandleControlBlock::getClientSideRemoteHandleControlBlock
ClientSideRemoteHandleControlBlockBasePtr getClientSideRemoteHandleControlBlock(const Ice::Current &=Ice::emptyCurrent) override
Definition: RemoteHandleControlBlock.cpp:42
armarx::RemoteHandleControlBlock::getManagedObjectProxy
Ice::ObjectPrx getManagedObjectProxy(const Ice::Current &=Ice::emptyCurrent) const override
Definition: RemoteHandleControlBlock.h:209
armarx::RemoteHandleControlBlock
The RemoteHandleControlBlock is the equivalent of the std::shared_ptr's contol_block for a remote han...
Definition: RemoteHandleControlBlock.h:101
armarx::RemoteHandleControlBlock::now
static int64_t now()
IceUtil::Handle
Definition: forward_declarations.h:30
armarx::SharedRemoteHandleState::SharedRemoteHandleState
SharedRemoteHandleState(unsigned int deletionDelayMs)
Definition: RemoteHandleControlBlock.cpp:73
armarx::SharedRemoteHandleState::DEFAULT_DELETION_DELAY
static const unsigned int DEFAULT_DELETION_DELAY
The amount of time (in ms) required to pass after a RemoteHandleControlBlock's usecount has reacht ze...
Definition: RemoteHandleControlBlock.h:57
armarx::PeriodicTask
Definition: ArmarXManager.h:70
armarx::RemoteHandleControlBlock::create
static ManagementData create(ArmarXManagerPtr manager, Ice::ObjectPrx managedObjectPrx, Deleter deleter)
Creates a new RemoteHandleControlBlock.
Definition: RemoteHandleControlBlock.h:227
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:27