Resolve "Toggle Free Look with Hotkey"
[ryzomcore.git] / ryzom / server / src / ai_data_service / ai_service.cpp
blob7bc04c9c875f2fb2d8f36f3fd82080f4cf72c9b9
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 //===================================================================
22 ***
23 when a service goes down I must remember that the managers are no longer running
24 in the normal way I can try to bring them back up on the remaining services
26 ***
27 when a service comes up and the rest of the services are over-loaded it would be
28 good to be able to load ballance (if loading is fast enough)
29 - tell new service to load static data and prepare to launch.
30 - wait for new service to say 'ready'
31 - tell old service to transfer to new service (ie: save to ram & transmit to new service)
32 - * old service must continue to forward packets to the new service to ensure smooth continuation
33 - old service tells me when he's down
34 - new service tells me when he's up
36 ***
37 Need to deal with 'save's as well...
39 ***
40 Need init() and release() in order to register message callbacks, etc?
44 //-------------------------------------------------------------------------
45 // Some global variables
46 uint32 GlobalServicesUp=0;
47 NLMISC_VARIABLE(uint32, GlobalServicesUp, "ServicesUp");
50 #include "nel/misc/debug.h"
52 #include "ai_manager.h"
53 #include "ai_service.h"
54 #include "ai_files.h"
55 #include "messages.h"
57 //===================================================================
59 //---------------------------------------------------
60 // INSTANTIATED CLASS: Public methods
62 // a few read accessors
63 NLNET::TServiceId CAIService::id() const
65 // compute the index of this AIService class instance in the array of
66 // CAIService (this is stored in the _services array)
67 return NLNET::TServiceId(this-_services);
70 bool CAIService::isUp() const
72 return _isUp;
76 uint CAIService::powerCPU() const
78 return _powerCPU;
81 uint CAIService::powerRAM() const
83 return _powerRAM;
87 // assign a given manager to this service (ie open and run it)
88 void CAIService::assignMgr(sint mgrId)
90 // get a pointer to the manager in question
91 CAIManager *m=CAIManager::getManagerById(mgrId);
92 if (m==NULL)
93 return;
95 // if this method has not been called by the manager's own method then ping pong
96 if (!m->isAssigned())
98 m->assign(id());
99 return;
102 // if the manager is assigned to a different service then bomb
103 if (m->serviceId()!=id())
105 nlwarning("Cannot assign manager %04d (%s) to service %d as it is already assigned to service %d",
106 mgrId, m->name().c_str(), id().get(), m->serviceId().get());
107 return;
110 // if the service is up then send it a message to launch the manager
111 if (isUp())
113 // std::string dataBuf
114 // dataBuf.resize(binFileSize(id()));
115 // FILE *f=fopen(binFileName(id()),"rb");
116 // if (f==NULL)
117 // {
118 // nlinfo("Failed to load action list file: %s (try 'aiMake')",binFileName(id()));
119 // return false;
120 // }
121 // if (fread(dataBuf.buffer(),1,binFileSize(id()),f) != binFileSize(id()))
122 // {
123 // nlinfo("Read error in binary file: %s",binFileName(id()));
124 // return false;
125 // }
126 // fclose(f);
127 // CMsgAIUploadActions(id(),dataBuf).send();
128 // CMsgAIOpenMgrs(mgrId,m->name()).send(id());
129 m->setIsUp(true);
131 // return true;
133 // return false;
137 // unassign a manager currently running on this service (ie close it)
138 void CAIService::unassignMgr(sint mgrId)
140 // if the manager isn't assigned to this service then bomb
141 if (CAIManager::getManagerById(mgrId)->serviceId()!=id())
143 nlwarning("Cannot stop manager %04d (%s) on service %d as it is assigned to service %d",
144 mgrId, CAIManager::getManagerById(mgrId)->name().c_str(), id().get(), CAIManager::getManagerById(mgrId)->serviceId().get());
145 return;
148 // transfer control to the singleton to finish the work
149 closeMgr(mgrId);
153 // reassign a manager currently assigned to this service to another service
154 void CAIService::reassignMgr(sint mgrId, NLNET::TServiceId serviceId)
156 // get a pointerto the service
157 CAIService *s=getServiceById(serviceId);
158 if (s==NULL)
159 return;
161 // this is a very simple implementation of control transfer... should be revised later
162 unassignMgr(mgrId);
163 s->assignMgr(mgrId);
168 //---------------------------------------------------
169 // INSTANTIATED CLASS: Private methods
171 CAIService::CAIService()
173 // if the following assert fails it's because a CAIService object has
174 // been instantiated outside of the singleton's array
175 nlassert(id().get() < maxServices());
179 //===================================================================
180 // *** END OF THE INSTANTIATED CLASS *** START OF THE SINGLETON ***
181 //===================================================================
184 //---------------------------------------------------
185 // SINGLETON: Data
187 class CAIService CAIService::_services[RYAI_AI_SERVICE_MAX_SERVICES];
192 //---------------------------------------------------
193 // SINGLETON: Public methods
195 // get the number of allocated managers
196 uint CAIService::numServices()
198 uint count=0;
199 for (uint i=0;i<maxServices();i++)
200 if (_services[i].isUp())
201 count++;
202 return count;
206 // get a pointer to the manager with given handle (0..maxManagers-1)
207 CAIService *CAIService::getServiceById(NLNET::TServiceId id)
209 if (id.get() >= maxServices())
211 nlwarning("CAIService::getServiceById(id): id %d not in range 0..%d",id.get(),maxServices()-1);
212 return NULL;
214 return &(_services[NLNET::TServiceId8(id).get()]);
218 // get a pointer to the manager with given index (0..numManagers-1)
219 CAIService *CAIService::getServiceByIdx(uint idx)
221 uint count=0;
222 for (uint i=0;i<maxServices();i++)
223 if (_services[i].isUp())
225 if (idx==count)
226 return &(_services[i]);
227 count++;
229 nlwarning("CAIService::getServiceByIdx(idx): idx (%d)>=maxServices (%d)",idx,count);
230 return NULL;
234 // select a service to assign the manager to and assign it
235 // if no services are available then the manager is queued until one
236 // becomes available
237 // managers opened via this interface are queued back up and re-launched
238 // if their service goes down
239 void CAIService::openMgr(sint mgrId)
241 // get a pointer to the manager in question
242 CAIManager *m=CAIManager::getManagerById(mgrId);
243 if (m==NULL)
244 return;
245 m->setIsOpen(true);
249 // close a manager (on whichever service its running)
250 void CAIService::closeMgr(sint mgrId)
252 // get a pointer to the manager in question
253 CAIManager *m=CAIManager::getManagerById(mgrId);
254 if (m==NULL)
255 return;
257 // if the manager is flagged as up and running on a service then shut it down
258 if (m->isUp())
260 CAIService *s=getServiceById(m->serviceId());
261 if (s!=NULL && s->isUp())
263 // send a message to the service to stop the manager
264 CMsgAICloseMgrs(mgrId).send(m->serviceId());
266 // clear the manager's isUp() flag
267 m->setIsUp(false);
270 // if the manager is assigned to a service then transfer control to the manager's close()
271 if (m->isAssigned())
272 m->close();
275 // update routine called by service_main update every net loop
276 void CAIService::update()
278 #define IN_TRANSIT_PACKET_LIMIT 1
280 for (uint i=0;i<maxServices();i++)
282 CAIService &s=_services[i];
283 if (s.isUp())
285 // see whether we have enough spare capacity to start sending data about a new manager
286 // if so look through the managers for any that are awaiting assignment
287 if (s._dataSentCount+s._dataToSend.size()-s._dataAckCount<IN_TRANSIT_PACKET_LIMIT)
289 // look for the heaviest manager that doesn't blow my quotas
290 uint best=~0u;
291 uint bestScore=0;
292 for (uint j=0;j<CAIManager::maxManagers();j++)
294 CAIManager *m=CAIManager::getManagerById(j);
295 if (m->isOpen() && !m->isAssigned())
296 if (m->weightRAM()<=s._unusedPowerRAM && m->weightCPU()<=s._unusedPowerCPU)
297 if (m->weightRAM()+m->weightCPU()/2>=bestScore)
299 best=j;
300 bestScore=m->weightRAM()+m->weightCPU()/2;
303 // if we found a manager then go ahead and assign it
304 if (best!=~0u)
305 s.assignMgr(best);
308 // if we have data waiting to be sent then send it
309 while (!s._dataToSend.empty() && s._dataSentCount-s._dataAckCount<IN_TRANSIT_PACKET_LIMIT)
311 NLNET::CUnifiedNetwork::getInstance()->send( s.id(), *(s._dataToSend.begin()) );
312 s._dataToSend.pop_front();
313 s._dataSentCount++;
318 #undef IN_TRANSIT_PACKET_LIMIT
322 //===================================================================