1 module geario.util.pool.PooledObject;
2 
3 import core.atomic;
4 import std.datetime;
5 
6 import geario.util.pool.PooledObjectState;
7 
8 /**
9  * Defines the wrapper that is used to track the additional information, such as
10  * state, for the pooled objects.
11  * <p>
12  * Implementations of this class are required to be thread-safe.
13  *
14  * @param <T> the type of object in the pool
15  *
16  */
17 class PooledObject(T) {
18     private size_t _id;
19     private T _obj;
20     private PooledObjectState _state;
21     private SysTime _createTime;
22     private SysTime _lastBorrowTime;
23     private SysTime _lastUseTime;
24     private SysTime _lastReturnTime;
25     private shared long _borrowedCount = 0;
26     private static shared size_t _counter;
27 
28     this(T obj) {
29         _obj = obj;
30         _state = PooledObjectState.IDLE;
31         _createTime = Clock.currTime;
32         _id = atomicOp!("+=")(_counter, 1);
33     }
34 
35     size_t Id() {
36         return _id;
37     }
38 
39     /**
40      * Obtains the underlying object that is wrapped by this instance of
41      * {@link PooledObject}.
42      *
43      * @return The wrapped object
44      */
45     T GetObject() {
46         return _obj;
47     }  
48 
49     SysTime CreateTime() {
50         return _createTime;
51     }    
52 
53     SysTime LastBorrowTime() {
54         return _lastBorrowTime;
55     }
56 
57     SysTime LastReturnTime() {
58         return _lastReturnTime;
59     }
60 
61     /**
62      * Get the number of times this object has been borrowed.
63      * @return The number of times this object has been borrowed.
64      */
65     long BorrowedCount() {
66         return _borrowedCount;
67     }
68 
69     /**
70      * Returns the state of this object.
71      * @return state
72      */
73     PooledObjectState State() {
74         return _state;
75     }
76 
77     /**
78      * Allocates the object.
79      *
80      * @return {@code true} if the original state was {@link PooledObjectState#IDLE IDLE}
81      */
82     bool Allocate() {
83         if (_state == PooledObjectState.IDLE) {
84             _state = PooledObjectState.ALLOCATED;
85             _lastBorrowTime = Clock.currTime;
86             _lastUseTime = _lastBorrowTime;
87             atomicOp!("+=")(_borrowedCount, 1);
88             // if (logAbandoned) {
89             //     borrowedBy.fillInStackTrace();
90             // }
91             return true;
92         } 
93         
94         // else if (state == PooledObjectState.EVICTION) {
95         //     // TODO Allocate anyway and ignore eviction test
96         //     state = PooledObjectState.EVICTION_RETURN_TO_HEAD;
97         //     return false;
98         // }
99         // TODO if validating and testOnBorrow == true then pre-allocate for
100         // performance
101         return false;        
102     }
103 
104     /**
105      * Deallocates the object and sets it {@link PooledObjectState#IDLE IDLE}
106      * if it is currently {@link PooledObjectState#ALLOCATED ALLOCATED}.
107      *
108      * @return {@code true} if the state was {@link PooledObjectState#ALLOCATED ALLOCATED}
109      */
110     bool Deallocate() {
111 
112         if (_state == PooledObjectState.ALLOCATED || _state == PooledObjectState.RETURNING) {
113             _state = PooledObjectState.IDLE;
114             _lastReturnTime = Clock.currTime;
115             return true;
116         }
117 
118         return false;
119     }
120 
121     /**
122      * Sets the state to {@link PooledObjectState#INVALID INVALID}
123      */
124     void Invalidate() { // synchronized
125         _state = PooledObjectState.INVALID;
126     }
127 
128 
129     /**
130      * Marks the pooled object as abandoned.
131      */
132     void Abandoned() { // synchronized
133         _state = PooledObjectState.ABANDONED;
134     }
135 
136     /**
137      * Marks the object as returning to the pool.
138      */
139     void Returning() { // synchronized
140         _state = PooledObjectState.RETURNING;
141     }
142 
143     bool IsIdle() {
144         return _state == PooledObjectState.IDLE;
145     }
146 
147     bool IsInUse() {
148         return _state == PooledObjectState.ALLOCATED;
149     }
150 
151     bool IsInvalid() {
152         return _state == PooledObjectState.INVALID;
153     }
154 }