1 module hunt.util.pool.PooledObject; 2 3 import core.atomic; 4 import std.datetime; 5 6 import hunt.logging; 7 8 import hunt.util.pool.PooledObjectState; 9 10 /** 11 * Defines the wrapper that is used to track the additional information, such as 12 * state, for the pooled objects. 13 * <p> 14 * Implementations of this class are required to be thread-safe. 15 * 16 * @param <T> the type of object in the pool 17 * 18 */ 19 class PooledObject(T) { 20 private size_t _id; 21 private T _obj; 22 private shared PooledObjectState _state; 23 private SysTime _createTime; 24 private SysTime _lastBorrowTime; 25 private SysTime _lastUseTime; 26 private SysTime _lastReturnTime; 27 private shared long _borrowedCount = 0; 28 private static shared size_t _counter; 29 30 this() { 31 _state = PooledObjectState.UNUSABLE; 32 _createTime = Clock.currTime; 33 _id = atomicOp!("+=")(_counter, 1); 34 } 35 36 this(T obj) { 37 assert(obj !is null); 38 39 _obj = obj; 40 _state = PooledObjectState.IDLE; 41 _createTime = Clock.currTime; 42 _id = atomicOp!("+=")(_counter, 1); 43 } 44 45 // package void bind(T obj) { 46 // _obj = obj; 47 // _state = PooledObjectState.IDLE; 48 // } 49 50 size_t id() { 51 return _id; 52 } 53 54 /** 55 * Obtains the underlying object that is wrapped by this instance of 56 * {@link PooledObject}. 57 * 58 * @return The wrapped object 59 */ 60 T getObject() { 61 return _obj; 62 } 63 64 SysTime createTime() { 65 return _createTime; 66 } 67 68 SysTime lastBorrowTime() { 69 return _lastBorrowTime; 70 } 71 72 SysTime lastReturnTime() { 73 return _lastReturnTime; 74 } 75 76 /** 77 * Get the number of times this object has been borrowed. 78 * @return The number of times this object has been borrowed. 79 */ 80 long borrowedCount() { 81 return _borrowedCount; 82 } 83 84 /** 85 * Returns the state of this object. 86 * @return state 87 */ 88 PooledObjectState state() { 89 return _state; 90 } 91 92 /** 93 * Allocates the object. 94 * 95 * @return {@code true} if the original state was {@link PooledObjectState#IDLE IDLE} 96 */ 97 bool allocate() { 98 version(HUNT_POOL_DEBUG) tracef(toString()); 99 100 if(cas(&_state, PooledObjectState.IDLE, PooledObjectState.ALLOCATED)) { 101 _lastBorrowTime = Clock.currTime; 102 _lastUseTime = _lastBorrowTime; 103 atomicOp!("+=")(_borrowedCount, 1); 104 return true; 105 } else { 106 version(HUNT_DEBUG) warningf("allocate collision: %s", toString()); 107 } 108 109 return false; 110 } 111 112 113 /** 114 * Allocates the object. 115 * 116 * @return {@code true} if the original state was {@link PooledObjectState#IDLE IDLE} 117 */ 118 bool allocate(T obj) { 119 // version(HUNT_POOL_DEBUG) tracef(toString()); 120 121 if(cas(&_state, PooledObjectState.UNUSABLE, PooledObjectState.ALLOCATED)) { 122 _obj = obj; 123 _lastBorrowTime = Clock.currTime; 124 _lastUseTime = _lastBorrowTime; 125 atomicOp!("+=")(_borrowedCount, 1); 126 return true; 127 } else { 128 version(HUNT_DEBUG) warningf("allocate collision: %s", toString()); 129 } 130 131 return false; 132 } 133 134 /** 135 * Sets the state to {@link PooledObjectState#INVALID INVALID} 136 */ 137 void invalidate() { 138 _state = PooledObjectState.INVALID; 139 } 140 141 /** 142 * Marks the pooled object as abandoned. 143 */ 144 void abandoned() { 145 _state = PooledObjectState.ABANDONED; 146 } 147 148 /** 149 * Marks the object as returning to the pool. 150 */ 151 bool returning() { 152 version(HUNT_POOL_DEBUG_MORE) tracef(toString()); 153 if(cas(&_state, PooledObjectState.ALLOCATED, PooledObjectState.IDLE)) { 154 _lastReturnTime = Clock.currTime; 155 return true; 156 } 157 158 return false; 159 } 160 161 bool isIdle() { 162 return _state == PooledObjectState.IDLE; 163 } 164 165 bool isInUse() { 166 return _state == PooledObjectState.ALLOCATED; 167 } 168 169 bool isInvalid() { 170 return _state == PooledObjectState.INVALID; 171 } 172 173 bool isUnusable() { 174 return _state == PooledObjectState.UNUSABLE; 175 } 176 177 override string toString() { 178 import std.format; 179 string str = format("id: %d, state: %s, binded: {%s}", 180 id(), _state, _obj is null ? "null" : (cast(Object)_obj).toString()); 181 return str; 182 } 183 184 }