-
Notifications
You must be signed in to change notification settings - Fork 1
/
bankAccountPool.cpp
349 lines (297 loc) · 8.88 KB
/
bankAccountPool.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
/**
* @Author: Izhar Shaikh <izhar>
* @Date: 2017-03-03T19:20:49-05:00
* @Email: [email protected]
* @Filename: bankAccountPool.cpp
* @Last modified by: izhar
* @Last modified time: 2017-03-06T04:50:27-05:00
* @License: MIT
*/
#include "bankAccount.hpp"
#include "debugMacros.hpp"
#include <stdbool.h>
#include <assert.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
using namespace std;
// Global varibale to hold pointer to bankAccountPool shared memory (mmap)
// This will hold the address of the next available memory block for adding
// bank account to the pool
static node_t* sPoolBlock = NULL;
// flag to hold the NumberOfAccounts in the pool
static int64_t sPoolSpace = 0;
// flag to mark that we are initalized
static bool is_initialized = false;
// This one is a struct for a bankAccount which will reside in
// a bank account pool (which is an AVL Tree)
struct bankAccountNode
{
int height;
bankAccount_t account;
node_t* left;
node_t* right;
};
// -- Initialize the account pool
static void initPoolSpace(void *blockAddr, int64_t NumberOfAccounts)
{
if( is_initialized == false){
// mark that we are done
is_initialized = true;
// Set the sPoolBlock address to point to memory mapped by main()
sPoolBlock = (node_t*) blockAddr;
sPoolSpace = NumberOfAccounts;
node_t *lastAddr = sPoolBlock + NumberOfAccounts;
dbg_trace("Account Pool Initialized at Addr: " << sPoolBlock << " , " \
"Total Accounts: " << NumberOfAccounts << " , " \
"Total Size: " << (float) (sizeof(node_t)*NumberOfAccounts) << " , " \
"Each Account Size: " << sizeof(node_t) << " , " \
"End Addr: " << lastAddr );
}
}
// -- Create and return a new bankAccount node to be added to the accountPool
static node_t* getNewNode(int64_t accountNumber, int64_t accountBalance)
{
if( is_initialized == false){
dbg_trace("bankAccountPool is not Initialized yet!");
return NULL;
}
if(sPoolSpace == 0){
dbg_trace("bankAccountPool is Full!");
return NULL;
}
// Point to current head of the mapped memory
node_t* newNode = sPoolBlock;
newNode->height = 1;
newNode->left = NULL;
newNode->right = NULL;
newNode->account.init();
newNode->account.setAccountNumber(accountNumber);
newNode->account.setBalance(accountBalance);
// Update the head of the mapped memory and decrement the poolSpace count
++sPoolBlock;
--sPoolSpace;
if(sPoolSpace == 0){
dbg_trace("bankAccountPool is now full. No more space!");
}
return newNode;
}
// A utility function to get height of the tree
static int height(node_t *N)
{
if (N == NULL)
return 0;
return N->height;
}
// A utility function to get maximum of two integers
static int max(int a, int b)
{
return (a > b)? a : b;
}
// A utility function to right rotate subtree rooted with y
// See the diagram given above.
static node_t *rightRotate(node_t *y)
{
node_t *x = y->left;
node_t *T2 = x->right;
// Perform rotation
x->right = y;
y->left = T2;
// Update heights
y->height = max(height(y->left), height(y->right))+1;
x->height = max(height(x->left), height(x->right))+1;
// Return new root
return x;
}
// A utility function to left rotate subtree rooted with x
// See the diagram given above.
static node_t *leftRotate(node_t *x)
{
node_t *y = x->right;
node_t *T2 = y->left;
// Perform rotation
y->left = x;
x->right = T2;
// Update heights
x->height = max(height(x->left), height(x->right))+1;
y->height = max(height(y->left), height(y->right))+1;
// Return new root
return y;
}
// Get Balance factor of node N
static int getBalance(node_t *N)
{
if (N == NULL)
return 0;
return height(N->left) - height(N->right);
}
// Recursive function to insert key in subtree rooted
// with node and returns new root of subtree.
static node_t* insert(node_t* node, int64_t key, int64_t value)
{
/* 1. Perform the normal BST insertion */
if (node == NULL)
return(getNewNode(key, value));
if (key < node->account.getAccountNumber())
node->left = insert(node->left, key, value);
else if (key > node->account.getAccountNumber())
node->right = insert(node->right, key, value);
else // Equal keys are not allowed in BST
return node;
/* 2. Update height of this ancestor node */
node->height = 1 + max(height(node->left),
height(node->right));
/* 3. Get the balance factor of this ancestor
node to check whether this node became
unbalanced */
int balance = getBalance(node);
// If this node becomes unbalanced, then
// there are 4 cases
// Left Left Case
if (balance > 1 && key < node->left->account.getAccountNumber())
return rightRotate(node);
// Right Right Case
if (balance < -1 && key > node->right->account.getAccountNumber())
return leftRotate(node);
// Left Right Case
if (balance > 1 && key > node->left->account.getAccountNumber())
{
node->left = leftRotate(node->left);
return rightRotate(node);
}
// Right Left Case
if (balance < -1 && key < node->right->account.getAccountNumber())
{
node->right = rightRotate(node->right);
return leftRotate(node);
}
/* return the (unchanged) node pointer */
return node;
}
// retrieves the handle to the requested node
static node_t* getNode(node_t *node, int64_t key)
{
if(node == NULL){
return node;
}
int64_t currentKey = node->account.getAccountNumber();
if(key < currentKey){
return getNode(node->left, key);
}
else if(key > currentKey){
return getNode(node->right, key);
}
else {
// we found it, return
return node;
}
}
// Postorder
void destroyAccountPool(node_t *node)
{
if(node == NULL){
return;
}
destroyAccountPool(node->left);
destroyAccountPool(node->right);
node->account.destroy();
}
#ifdef DEBUG_TEST
// Prints account pool (Inorder)
void printAccountPool(node_t *node)
{
if(node == NULL){
return;
}
printAccountPool(node->left);
dbg_trace("Acc Number: " << node->account.getAccountNumber() << " , "\
"Balance: " << node->account.getBalance());
printAccountPool(node->right);
}
#endif
// --------- bankAccountPool --------
// bankAccountPool :: bankAccountPool()
// {
// // TODO:: Remove
// print_output("**Current PID: " << getpid());
//
// this->handle = NULL;
// this->poolMemory = NULL;
// this->poolSize = 0;
// this->totalAccounts = 0;
// }
void bankAccountPool :: initPool(int64_t NumberOfAccounts)
{
if( is_initialized == true ){
return;
}
this->handle = NULL;
this->poolMemory = NULL;
this->poolSize = 0;
this->totalAccounts = 0;
// mmap or malloc the memory here;
// this will be shared among processess
// this->poolMemory = malloc(NumberOfAccounts * sizeof(node_t));
this->poolSize = NumberOfAccounts * sizeof(node_t);
this->poolMemory = mmap(NULL, this->poolSize, \
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if(this->poolMemory == MAP_FAILED){
print_output("PPID: " << getppid() << " , " \
"PID: " << getpid() << " , " \
"Failed to map the memory for bankAccountPool! Exiting!");
exit(1);
}
// Initialize the pool space now so our accountPool nodes will be allocated
// memory from this space
initPoolSpace(poolMemory, NumberOfAccounts);
}
void bankAccountPool :: deInitPool()
{
// destroy account pool first
destroyAccountPool(this->handle);
// unmap the accountPool shared memory
// free(this->poolMemory);
int status = munmap(this->poolMemory, this->poolSize);
if(status != 0){
print_output("PPID: " << getppid() << " , " \
"PID: " << getpid() << " , " \
"Failed to unmap the accountPool memory! Exiting!");
exit(1);
}
}
// retrieves current handle to the bankAccountPool
// (this points to the root node in AVL tree)
poolHandle_t bankAccountPool :: getPoolHandle()
{
return this->handle;
}
// retrieves the current count of bank accounts in the pool
int64_t bankAccountPool :: getTotalAccounts()
{
return this->totalAccounts;
}
// Inserts a new bank account to the pool
void bankAccountPool :: addAccount(int64_t accountNumber, \
int64_t balance) {
// Keep the current handle updated with the root node
this->handle = insert(this->handle, accountNumber, balance);
this->totalAccounts++;
}
// retrieves the handle to account requested
bankAccount_t* bankAccountPool :: at(int64_t accountNumber)
{
poolHandle_t requestedNode = NULL;
bankAccount_t *requestedAccount = NULL;
// Get the requested node
requestedNode = getNode(this->handle, accountNumber);
// return the account handle
requestedAccount = &requestedNode->account;
return requestedAccount;
}
#ifdef DEBUG_TEST
// -- debug print --
void bankAccountPool :: dbgPrintAccountPool()
{
printAccountPool(this->handle);
}
#endif