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 <thread>
28 #include <condition_variable>
29 #include <chrono>
30 #include <functional>
31 #include <memory>
32 
33 #include <Ice/ObjectAdapter.h>
34 #include <IceUtil/UUID.h>
35 
36 #include <ArmarXCore/interface/core/util/distributed/RemoteHandle/RemoteHandleControlBlock.h>
38 #include "../../../services/tasks/PeriodicTask.h"
39 #include "../../../ArmarXManager.h"
40 
41 
42 namespace armarx
43 {
44  class RemoteHandleControlBlock;
46 
47 
48  /**
49  * @brief This holds the shared state of all RemoteHandleControlBlocks for one armarx manager.
50  * It holds a thread responsible for deleting them when their usecount reaches zero and the deletion delay has passed.
51  */
53  {
54  public:
55  /**
56  * @brief The amount of time (in ms) required to pass after a RemoteHandleControlBlock's usecount has reacht zero, before it is deleted.
57  */
58  static const unsigned int DEFAULT_DELETION_DELAY;
60 
61  SharedRemoteHandleState(unsigned int deletionDelayMs);
63 
65 
66  private:
67  void sweep();
68 
69  std::mutex stateMutex;
70 
71  //must not invalidate other iterators on erase (ok for std::set)
72  std::set<RemoteHandleControlBlockPtr> rhs;
73  std::chrono::milliseconds deletionDelay;
75  };
76 
77  /**
78  * @brief The RemoteHandleControlBlock is the equivalent of the std::shared_ptr's contol_block for a remote handle.
79  * It does reference counting and object deletion.
80  *
81  * This class is created on server side and a ClientSideRemoteHandleControlBlock is send to the client.
82  * Only create the class by calling RemoteHandleControlBlock::create.
83  *
84  * A direct pointer can be used to force the deletion of the managed object.
85  * 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).
86  * The deleter should do any unregistering for the managed object (e.g. remove the object from from an ice object adapter)
87  *
88  * a object may leak if a connection error stops the message send when a handle is deleted (this stops the usecount from reaching zero).
89  * a object may be deleted with handles still alive if:
90  * 1) the object's deletion was forced
91  * 2) a scenario equivalent to this:
92  * pc A has the object and sends a handle to B
93  * pc B has now the only handle
94  * 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)
95  * The handle is deserialized after the deletion timeout set via property (default 3 sec) has passed.
96  * 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.
97  *
98  * (for more info: \ref ArmarXCore-Tutorials-RemoteHandles "RemoteHandle tutorial")
99  *
100  * \ingroup Distributed
101  */
103  virtual public RemoteHandleControlBlockInterface
104  {
105  public:
106  using clock = std::chrono::steady_clock;
107  inline static int64_t now();
108  /**
109  * @brief Returned by a call to RemoteHandleControlBlock::create.
110  * 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).
111  * And The ClientSideRemoteHandleControlBlock keeping the managed object alive. (send this to the client)
112  */
114  {
116  ClientSideRemoteHandleControlBlockBasePtr clientSideRemoteHandleControlBlock;
117  };
118 
119  /**
120  * @brief Creates a new RemoteHandleControlBlock.
121  * @param objectAdapter The adapter used to register the RemoteHandleControlBlock to ice.
122  * @param managedObjectPrx A Proxy to the managed object.
123  * @param deleter A functor cleaning up the managed object. (has to delete it and unregister it)
124  * The Functor may have the only pointer keeping the managed object alive.
125  * @return A direct pointer to the created RemoteHandleControlBlock and the ClientSideRemoteHandleControlBlock keeping the managed object alive.
126  */
127  template<class Deleter>
128  static ManagementData 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 getClientSideRemoteHandleControlBlock(const Ice::Current& = Ice::emptyCurrent) override;
149  inline Ice::ObjectPrx getManagedObjectProxy(const Ice::Current& = Ice::emptyCurrent) const override;
150 
151  /**
152  * @brief Call this when you want to force the deletion of the managed object.
153  * It will be deleted ignoring the usecount.
154  * This may be used to ensure the deletion of all objects created by yout server when shutting down.
155  * This may be necessary if a client's decrementUseCount was lost by the network.
156  */
158  {
159  forcedDeletion = true;
160  }
161  private:
162  RemoteHandleControlBlock(Ice::ObjectAdapterPtr objectAdapter, Ice::ObjectPrx managedObjectPrx, std::function<void(void)> deleter);
165 
166  /**
167  * @brief Does all cleanup for this object.
168  */
169  inline void cleanup();
170 
171  /**
172  * @brief The adapter used to register this RemoteHandleControlBlock
173  */
174  Ice::ObjectAdapterPtr objectAdapter;
175  std::function<void(void)> deleter;
176  Ice::ObjectPrx managedObjectProxy;
177  /**
178  * @brief A proxy to this RemoteHandleControlBlock (used when creating a new ClientSideRemoteHandleControlBlock)
179  */
180  RemoteHandleControlBlockInterfacePrx selfProxy;
181 
182  mutable std::atomic<uint64_t> useCount {0};
183  mutable std::mutex mtx;
184  mutable clock::time_point lastTimeUseCountReachedZero;
185  mutable std::atomic_bool forcedDeletion {false};
186 
187  friend struct SharedRemoteHandleState;
188  };
189 
191  {
192  ++useCount;
193  }
194 
196  {
197  return useCount;
198  }
199 
200  Ice::ObjectPrx RemoteHandleControlBlock::getManagedObjectProxy(const Ice::Current&) const
201  {
202  return managedObjectProxy;
203  }
204 
205  void RemoteHandleControlBlock::cleanup()
206  {
207  //delete payload
208  deleter();
209  deleter = []() {}; //do this to delete objects keept alive by the deleter (it may hold a unique_ptr)
210  //clean up proxy
211  objectAdapter->remove(selfProxy->ice_getIdentity());
212  }
213 
214  template<class Deleter>
215  RemoteHandleControlBlock::ManagementData RemoteHandleControlBlock::create(ArmarXManagerPtr manager, Ice::ObjectPrx managedObjectPrx, Deleter deleter)
216  {
217  RemoteHandleControlBlockPtr block = new RemoteHandleControlBlock {manager->getAdapter(), std::move(managedObjectPrx), std::move(deleter)};
218  auto clientSideRemoteHandleControlBlock = block->getClientSideRemoteHandleControlBlock();
219  manager->getSharedRemoteHandleState()->add(block);
220  return {block, clientSideRemoteHandleControlBlock};
221  }
222 }
armarx::SharedRemoteHandleState
This holds the shared state of all RemoteHandleControlBlocks for one armarx manager.
Definition: RemoteHandleControlBlock.h:52
armarx::SharedRemoteHandleState::add
void add(RemoteHandleControlBlockPtr rh)
Definition: RemoteHandleControlBlock.cpp:89
ClientSideRemoteHandleControlBlock.h
armarx::RemoteHandleControlBlock::incrementUseCount
void incrementUseCount(const Ice::Current &=Ice::emptyCurrent) override
Increments the usecount.
Definition: RemoteHandleControlBlock.h:190
armarx::RemoteHandleControlBlock::ManagementData
Returned by a call to RemoteHandleControlBlock::create.
Definition: RemoteHandleControlBlock.h:113
armarx::SharedRemoteHandleState::~SharedRemoteHandleState
~SharedRemoteHandleState()
Definition: RemoteHandleControlBlock.cpp:76
IceInternal::Handle< RemoteHandleControlBlock >
armarx::RemoteHandleControlBlock::ManagementData::directHandle
RemoteHandleControlBlockPtr directHandle
Definition: RemoteHandleControlBlock.h:115
armarx::RemoteHandleControlBlock::clock
std::chrono::steady_clock clock
Definition: RemoteHandleControlBlock.h:106
armarx::RemoteHandleControlBlock::decrementUseCount
void decrementUseCount(const Ice::Current &=Ice::emptyCurrent) override
decrements the useCount.
Definition: RemoteHandleControlBlock.cpp:33
armarx::RemoteHandleControlBlock::ManagementData::clientSideRemoteHandleControlBlock
ClientSideRemoteHandleControlBlockBasePtr clientSideRemoteHandleControlBlock
Definition: RemoteHandleControlBlock.h:116
armarx::RemoteHandleControlBlock::getUseCount
Ice::Long getUseCount(const Ice::Current &=Ice::emptyCurrent) const override
Definition: RemoteHandleControlBlock.h:195
armarx::RemoteHandleControlBlock::forceDeletion
void forceDeletion()
Call this when you want to force the deletion of the managed object.
Definition: RemoteHandleControlBlock.h:157
armarx::VariantType::Long
const VariantTypeId Long
Definition: Variant.h:917
armarx::RemoteHandleControlBlock::getClientSideRemoteHandleControlBlock
ClientSideRemoteHandleControlBlockBasePtr getClientSideRemoteHandleControlBlock(const Ice::Current &=Ice::emptyCurrent) override
Definition: RemoteHandleControlBlock.cpp:43
armarx::RemoteHandleControlBlock::getManagedObjectProxy
Ice::ObjectPrx getManagedObjectProxy(const Ice::Current &=Ice::emptyCurrent) const override
Definition: RemoteHandleControlBlock.h:200
armarx::RemoteHandleControlBlock
The RemoteHandleControlBlock is the equivalent of the std::shared_ptr's contol_block for a remote han...
Definition: RemoteHandleControlBlock.h:102
armarx::RemoteHandleControlBlock::now
static int64_t now()
IceUtil::Handle
Definition: forward_declarations.h:29
armarx::SharedRemoteHandleState::SharedRemoteHandleState
SharedRemoteHandleState(unsigned int deletionDelayMs)
Definition: RemoteHandleControlBlock.cpp:69
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:58
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:215
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:28