/
main.cpp
197 lines (167 loc) · 7.02 KB
/
main.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
/*!
* \file main.cpp
*
* \brief This class defines the attributes and methods represented by each node.
*
* \author Suraj Chafle <schafle@hawk.edu>
*
* \date Sun Jun 26 15:45:24 CDT 2016
*/
#include <iostream>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <ctime>
#include <thread>
#include <future>
#include "easylogging++.h"
#include "query.h"
#include "node.h"
#define ELPP_THREAD_SAFE
INITIALIZE_EASYLOGGINGPP
void send_messages(std::vector<std::string> children, int portNum, Node currentNode, std::string message){
for(std::vector<std::string>::iterator it = children.begin(); it != children.end(); ++it) {
if(!currentNode.send_message(*it, portNum, message ) ){ /* If Unsuccessful print the message */
LOG(ERROR) << "ERROR while sending query to children";
}
LOG(INFO) << "Sent the message to " << *it;
}
}
std::string asyncQuery( std::string index_location, std::string query, int max_pages, std::string uuid, std::string HostName)
{
return run_query( index_location, query, max_pages, uuid, HostName);
}
int main(int argc, char* argv[]){
if (argc < 2) {
std::cout << "Please provide some arguments" << std::endl;
std::cout << "Use -h/--help for reference" << std::endl;
exit(EXIT_FAILURE);
}
//[indexDirectory] [positionInCluster] [HostName] [FileName
std::string index_location = "."; // Set to current working directory if not passed as input
std::string HostName; // Must Have
std::string NodeDetailsFile = "filename.txt"; // Good to have
int posNum; // Must have
int portNum = 3033; // Should not be set in most cases;
// 3033 is our default sending port
// and 3034 is our default receiving port
int numOfBranches = 2;
int startNode = 0;
int i, j;
//Command line parsing
for (i=1; i< argc; i=i+2)
{
if(0 == strcmp(argv[i], "--indexdir"))
{
index_location = argv[i+1];
}
else if(0 == strcmp(argv[i], "--hostname"))
{
HostName = argv[i+1];
}
else if(0 == strcmp(argv[i], "--position"))
{
posNum = atoi(argv[i+1]);
}
else if(0 == strcmp(argv[i], "--numbranch"))
{
numOfBranches = atoi(argv[i+1]);
if (numOfBranches < 2){
std::cerr << "Num of Branches in tree must be greater than 2" << std::endl;
}
}
else if(0 == strcmp(argv[i], "--port"))
{
portNum = atoi(argv[i+1]);
}
else if(0 == strcmp(argv[i], "--startNode"))
{
startNode = atoi(argv[i+1]);
}
else if(0 == strcmp(argv[i], "--filename"))
{
NodeDetailsFile = argv[i+1];
}
else if(0 == strcmp(argv[i], "--help") | 0 == strcmp(argv[i], "-h"))
{
std::cout << "Use of search server:" << std::endl;
std::cout << "\t./binServer" << std::endl;
std::cout << "\t\t --indexdir ~/Index/location" << std::endl;
std::cout << "\t\t --hostname ec2.fulldomain.name.amazon.com" << std::endl;
std::cout << "\t\t --filename filename.txt" << std::endl;
std::cout << "\t\t --position 3" << std::endl;
std::cout << "\t\t --port 3033" << std::endl;
exit(EXIT_SUCCESS);
}
else
{
std::cout << "Use of search server:" << std::endl;
std::cout << "\t./binServer" << std::endl;
std::cout << "\t\t --indexdir ~/Index/location" << std::endl;
std::cout << "\t\t --hostname ec2.fulldomain.name.amazon.com" << std::endl;
std::cout << "\t\t --filename filename.txt" << std::endl;
std::cout << "\t\t --position 3" << std::endl;
std::cout << "\t\t --port 3033" << std::endl;
exit(EXIT_FAILURE);
}
}
/* Create a node object */
Node currentNode = Node( HostName, portNum, posNum, NodeDetailsFile);
LOG(INFO) << "Listening for input on port: "<< portNum;
/* Start listening on receivePort */
std::string received_string = currentNode.listenOnTheReceivePort(3033);
/* Get all the children */
std::vector<std::string> children = currentNode.get_children(startNode, numOfBranches);
int numOfChildren = children.size();
//std::cout << "I have "<< children.size() << " children." << std::endl;
std::clock_t start;
double duration;
int received_messages_count = 0;
std::string search_results;
std::string uuid;
/* If leaf send its name to parent and thats it*/
if(currentNode.am_i_leaf(startNode, numOfBranches)){
uuid = received_string.substr(0,36);
search_results = run_query( index_location, received_string.substr(36), 10, uuid, HostName); //10 is the default number of hits
LOG(INFO) << uuid << " Done searching!!";
LOG(INFO) << uuid << " Sending results back to parent " << currentNode.get_parent(startNode, numOfBranches) << std::endl;
currentNode.send_message(currentNode.get_parent(startNode, numOfBranches), 3034, search_results);
}
/* else if root send back to client */
else if(posNum == startNode){
start = std::clock();
// create a new thread to send all the messages
std::thread send (send_messages, children, 3033, currentNode, received_string);
send.join();
LOG(INFO) << "Done sending query to all the children; waiting for children to send the message back";
LOG(INFO) << "Starting async search in index";
uuid = received_string.substr(0,36);
auto future = std::async( asyncQuery, index_location, received_string.substr(36), 10, uuid, HostName); //Starting async query
std::string resultsFromChildren = currentNode.listenForMultipleReplies(3034, numOfChildren);
//LOG(INFO) << uuid << " Received results from children " << resultsFromChildren;
std::string searchResults = future.get();
LOG(INFO) << uuid << " Sending results back to parent " << currentNode.get_parent(startNode, numOfBranches);
duration = ( std::clock() - start ) / (double) CLOCKS_PER_SEC;
//currentNode.send_message("localhost", 3035, std::to_string(duration));
currentNode.send_message("localhost", 3035, "Received all messages in " + std::to_string(duration) + " seconds" + "\n" + searchResults + resultsFromChildren);
LOG(INFO) << "Received all messages in: "<< duration << " seconds" ;
}
/* Else open a connection for collecting result from child and then send back to parent */
else{
// create a new thread to send all the messages
std::thread send (send_messages, children, 3033, currentNode, received_string);
send.join();
LOG(INFO) << "Done sending query to all the children; waiting for children to send the message back";
LOG(INFO) << "Starting async search in index";
uuid = received_string.substr(0,36);
auto future = std::async( asyncQuery, index_location, received_string.substr(36), 10, uuid, HostName); //Starting async query
std::string resultsFromChildren = currentNode.listenForMultipleReplies(3034, numOfChildren);
std::string searchResults = future.get();
LOG(INFO) << uuid << " Sending results back to parent " << currentNode.get_parent(startNode, numOfBranches) << std::endl;
// For current implementation we are sending back the string we got from the parent
// When query collection is implemented we will send back the results for each query
currentNode.send_message(currentNode.get_parent(startNode, numOfBranches), 3034, searchResults + resultsFromChildren);
}
/* Make query irrespective of anything on the current node */
}