1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
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.
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 //===================================================================
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
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
37 Need to deal with 'save's as well...
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"
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
76 uint
CAIService::powerCPU() const
81 uint
CAIService::powerRAM() const
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
);
95 // if this method has not been called by the manager's own method then ping pong
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());
110 // if the service is up then send it a message to launch the manager
113 // std::string dataBuf
114 // dataBuf.resize(binFileSize(id()));
115 // FILE *f=fopen(binFileName(id()),"rb");
118 // nlinfo("Failed to load action list file: %s (try 'aiMake')",binFileName(id()));
121 // if (fread(dataBuf.buffer(),1,binFileSize(id()),f) != binFileSize(id()))
123 // nlinfo("Read error in binary file: %s",binFileName(id()));
127 // CMsgAIUploadActions(id(),dataBuf).send();
128 // CMsgAIOpenMgrs(mgrId,m->name()).send(id());
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());
148 // transfer control to the singleton to finish the work
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
);
161 // this is a very simple implementation of control transfer... should be revised later
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 //---------------------------------------------------
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()
199 for (uint i
=0;i
<maxServices();i
++)
200 if (_services
[i
].isUp())
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);
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
)
222 for (uint i
=0;i
<maxServices();i
++)
223 if (_services
[i
].isUp())
226 return &(_services
[i
]);
229 nlwarning("CAIService::getServiceByIdx(idx): idx (%d)>=maxServices (%d)",idx
,count
);
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
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
);
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
);
257 // if the manager is flagged as up and running on a service then shut it down
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
270 // if the manager is assigned to a service then transfer control to the manager's 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
];
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
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
)
300 bestScore
=m
->weightRAM()+m
->weightCPU()/2;
303 // if we found a manager then go ahead and assign it
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();
318 #undef IN_TRANSIT_PACKET_LIMIT
322 //===================================================================