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