version 0.3.19
[fms.git] / include / freenet / iindexrequester.h
1 #ifndef _iindexrequester_\r
2 #define _iindexrequester_\r
3 \r
4 #include "../idatabase.h"\r
5 #include "../ilogger.h"\r
6 #include "../option.h"\r
7 #include "../stringfunctions.h"\r
8 #include "ifreenetregistrable.h"\r
9 #include "ifcpconnected.h"\r
10 #include "ifcpmessagehandler.h"\r
11 #include "iperiodicprocessor.h"\r
12 \r
13 #include <Poco/DateTime.h>\r
14 #include <Poco/Timestamp.h>\r
15 #include <Poco/Timespan.h>\r
16 \r
17 #ifdef XMEM\r
18         #include <xmem.h>\r
19 #endif\r
20 \r
21 template <class IDTYPE>\r
22 class IIndexRequester:public IFreenetRegistrable,public IFCPConnected,public IFCPMessageHandler,public IPeriodicProcessor,public IDatabase,public ILogger\r
23 {\r
24 public:\r
25         IIndexRequester();\r
26         IIndexRequester(FCPv2 *fcp);\r
27         virtual ~IIndexRequester()              {}\r
28 \r
29         virtual void FCPConnected();\r
30         virtual void FCPDisconnected();\r
31         virtual const bool HandleMessage(FCPMessage &message);\r
32 \r
33         virtual void Process();\r
34 \r
35         virtual void RegisterWithThread(FreenetMasterThread *thread);\r
36 \r
37 protected:\r
38         void InitializeIIndexRequester();\r
39         virtual void Initialize()=0;            // initialize m_maxrequests and m_fcpuniquename\r
40         virtual void PopulateIDList()=0;\r
41         virtual void StartRequest(const IDTYPE &id)=0;\r
42         virtual const bool HandleAllData(FCPMessage &message)=0;\r
43         virtual const bool HandleGetFailed(FCPMessage &message)=0;\r
44         virtual void RemoveFromRequestList(const IDTYPE id);\r
45 \r
46         Poco::DateTime m_tempdate;\r
47         Poco::DateTime m_lastreceived;\r
48         Poco::DateTime m_lastpopulated;\r
49         std::string m_messagebase;\r
50         std::map<IDTYPE,bool> m_ids;                    // map of all ids we know and whether we have requested file from them yet\r
51         std::vector<IDTYPE> m_requesting;               // list of ids we are currently requesting from\r
52 \r
53         // these MUST be populated by child class\r
54         int m_maxrequests;\r
55         std::string m_fcpuniquename;\r
56 \r
57 };\r
58 \r
59 template <class IDTYPE>\r
60 IIndexRequester<IDTYPE>::IIndexRequester()\r
61 {\r
62         InitializeIIndexRequester();\r
63 }\r
64 \r
65 template <class IDTYPE>\r
66 IIndexRequester<IDTYPE>::IIndexRequester(FCPv2 *fcp):IFCPConnected(fcp)\r
67 {\r
68         InitializeIIndexRequester();\r
69 }\r
70 \r
71 template <class IDTYPE>\r
72 void IIndexRequester<IDTYPE>::FCPConnected()\r
73 {\r
74         // make sure variables have been initialized by the derived class\r
75         if(m_maxrequests==-1)\r
76         {\r
77                 m_log->fatal("IIndexRequester<IDTYPE>::FCPConnected maxrequests not initialized correctly!");\r
78         }\r
79         if(m_fcpuniquename=="")\r
80         {\r
81                 m_log->fatal("IIndexRequester<IDTYPE>::FCPConnected fcpuniquename not initialized correctly!");\r
82         }\r
83         if(m_fcpuniquename.find("|")!=std::string::npos)\r
84         {\r
85                 m_log->fatal("IIndexRequester<IDTYPE>::FCPConnected fcpuniquename contains | character!  This is not a valid character!");\r
86         }\r
87 \r
88         m_lastreceived=Poco::Timestamp();\r
89         m_requesting.clear();\r
90         PopulateIDList();\r
91         m_lastpopulated=Poco::Timestamp();\r
92 }\r
93 \r
94 template <class IDTYPE>\r
95 void IIndexRequester<IDTYPE>::FCPDisconnected()\r
96 {\r
97         \r
98 }\r
99 \r
100 template <class IDTYPE>\r
101 const bool IIndexRequester<IDTYPE>::HandleMessage(FCPMessage &message)\r
102 {\r
103 \r
104         if(message["Identifier"].find(m_fcpuniquename)==0)\r
105         {\r
106 \r
107                 m_lastreceived=Poco::Timestamp();\r
108 \r
109                 if(message.GetName()=="DataFound")\r
110                 {\r
111                         return true;\r
112                 }\r
113 \r
114                 if(message.GetName()=="AllData")\r
115                 {\r
116                         return HandleAllData(message);\r
117                 }\r
118 \r
119                 if(message.GetName()=="GetFailed")\r
120                 {\r
121                         return HandleGetFailed(message);\r
122                 }\r
123 \r
124                 if(message.GetName()=="IdentifierCollision")\r
125                 {\r
126                         // remove one of the ids from the requesting list\r
127                         IDTYPE id;\r
128                         std::vector<std::string> idparts;\r
129                         StringFunctions::Split(message["Identifier"],"|",idparts);\r
130                         StringFunctions::Convert(idparts[1],id);\r
131                         RemoveFromRequestList(id);\r
132                         return true;\r
133                 }\r
134         }\r
135 \r
136         return false;\r
137 }\r
138 \r
139 template <class IDTYPE>\r
140 void IIndexRequester<IDTYPE>::InitializeIIndexRequester()\r
141 {\r
142         m_maxrequests=-1;\r
143         m_fcpuniquename="";\r
144 \r
145         Option::Instance()->Get("MessageBase",m_messagebase);\r
146         m_tempdate=Poco::Timestamp();\r
147         m_lastreceived=Poco::Timestamp();\r
148         m_lastpopulated=Poco::Timestamp();\r
149         m_lastpopulated-=Poco::Timespan(0,0,10,0,0);\r
150 }\r
151 \r
152 template <class IDTYPE>\r
153 void IIndexRequester<IDTYPE>::Process()\r
154 {\r
155         Poco::DateTime now;\r
156 \r
157         // max is the smaller of the config value or the total number of ids we will request from\r
158         typename std::map<IDTYPE,bool>::size_type max=m_maxrequests>m_ids.size() ? m_ids.size() : m_maxrequests;\r
159 \r
160         // try to keep up to max requests going\r
161         if(m_requesting.size()<max)\r
162         {\r
163                 typename std::map<IDTYPE,bool>::iterator i=m_ids.begin();\r
164 \r
165                 while(i!=m_ids.end() && (*i).second==true)\r
166                 {\r
167                         i++;\r
168                 }\r
169 \r
170                 if(i!=m_ids.end())\r
171                 {\r
172                         StartRequest((*i).first);\r
173                 }\r
174                 else\r
175                 {\r
176                         // we requested from all ids in the list, repopulate the list (only every 10 minutes)\r
177                         if(m_lastpopulated<(now-Poco::Timespan(0,0,10,0,0)))\r
178                         {\r
179                                 PopulateIDList();\r
180                                 m_lastpopulated=Poco::Timestamp();\r
181                         }\r
182                 }\r
183         }\r
184         // special case - if there were 0 ids on the list when we started then we will never get a chance to repopulate the list\r
185         // this will recheck for ids every minute\r
186         if(m_ids.size()==0 && m_tempdate<(now-Poco::Timespan(0,0,1,0,0)))\r
187         {\r
188                 PopulateIDList();\r
189                 m_tempdate=now;\r
190         }\r
191         // if we haven't received any messages to this object in 10 minutes, clear the requests and repopulate id list\r
192         if(m_ids.size()>0 && m_lastreceived<(now-Poco::Timespan(0,0,10,0,0)))\r
193         {\r
194                 m_log->error("IIndexRequester<IDTYPE>::Process "+m_fcpuniquename+" Object has not received any messages in 10 minutes.  Restarting requests.");\r
195                 FCPConnected();\r
196         }\r
197 \r
198 }\r
199 \r
200 template <class IDTYPE>\r
201 void IIndexRequester<IDTYPE>::RegisterWithThread(FreenetMasterThread *thread)\r
202 {\r
203         thread->RegisterFCPConnected(this);\r
204         thread->RegisterFCPMessageHandler(this);\r
205         thread->RegisterPeriodicProcessor(this);\r
206 }\r
207 \r
208 template <class IDTYPE>\r
209 void IIndexRequester<IDTYPE>::RemoveFromRequestList(const IDTYPE id)\r
210 {\r
211         typename std::vector<IDTYPE>::iterator i=m_requesting.begin();\r
212         while(i!=m_requesting.end() && (*i)!=id)\r
213         {\r
214                 i++;\r
215         }\r
216         if(i!=m_requesting.end())\r
217         {\r
218                 m_requesting.erase(i);\r
219         }\r
220 }\r
221 \r
222 #endif  // _iindexrequester_\r