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