From 8ad450f83e70a45b79d9b058bf46854c7168a69c Mon Sep 17 00:00:00 2001 From: MW Date: Thu, 14 Feb 2008 18:59:03 +0000 Subject: [PATCH] More work on trying to get AvatarFactoryModule to play nicely with multiple threads --- .../Modules/AvatarFactoryModule.cs | 151 ++++++++++-------- 1 file changed, 84 insertions(+), 67 deletions(-) diff --git a/OpenSim/Region/Environment/Modules/AvatarFactoryModule.cs b/OpenSim/Region/Environment/Modules/AvatarFactoryModule.cs index 7933593dd2..f43657c4e9 100644 --- a/OpenSim/Region/Environment/Modules/AvatarFactoryModule.cs +++ b/OpenSim/Region/Environment/Modules/AvatarFactoryModule.cs @@ -57,34 +57,27 @@ namespace OpenSim.Region.Environment.Modules public bool TryGetAvatarAppearance(LLUUID avatarId, out AvatarAppearance appearance) { - appearance = CheckCache(avatarId); - if (appearance != null) - { - return true; - } - - //not in cache so check to see if another thread is already fetching it + //should only let one thread at a time do this part EventWaitHandle waitHandle = null; + bool fetchInProgress = false; lock (m_syncLock) { + appearance = CheckCache(avatarId); + if (appearance != null) + { + return true; + } + + //not in cache so check to see if another thread is already fetching it if (m_fetchesInProgress.TryGetValue(avatarId, out waitHandle)) { - waitHandle.WaitOne(); - appearance = CheckCache(avatarId); - if (appearance != null) - { - waitHandle = null; - return true; - } - else - { - waitHandle = null; - return false; - } + fetchInProgress = true; } else { + fetchInProgress = false; + //no thread already fetching this appearance, so add a wait handle to list //for any following threads that want the same appearance waitHandle = new EventWaitHandle(false, EventResetMode.ManualReset); @@ -92,62 +85,84 @@ namespace OpenSim.Region.Environment.Modules } } - - //this is the first thread to request this appearance - //so let it check the db and if not found then create a default appearance - //and add that to the cache - appearance = CheckDatabase(avatarId); - if (appearance != null) + if (fetchInProgress) { - //appearance has now been added to cache so lets pulse any waiting threads - lock (m_syncLock) + waitHandle.WaitOne(); + appearance = CheckCache(avatarId); + if (appearance != null) { - m_fetchesInProgress.Remove(avatarId); - waitHandle.Set(); + waitHandle = null; + return true; } - waitHandle = null; - return true; - } - - //not found a appearance for the user, so create a new default one - appearance = CreateDefault(avatarId); - if (appearance != null) - { - //update database - if (m_enablePersist) + else { - m_appearanceMapper.Add(avatarId.UUID, appearance); + waitHandle = null; + return false; } - //add appearance to dictionary cache - lock (m_avatarsAppearance) - { - m_avatarsAppearance[avatarId] = appearance; - } - - //appearance has now been added to cache so lets pulse any waiting threads - lock (m_syncLock) - { - m_fetchesInProgress.Remove(avatarId); - waitHandle.Set(); - } - waitHandle = null; - return true; } else { - //something went wrong, so release the wait handle and remove it - //all waiting threads will fail to find cached appearance - //but its better for them to fail than wait for ever - lock (m_syncLock) - { - m_fetchesInProgress.Remove(avatarId); - waitHandle.Set(); - } - waitHandle = null; - return false; - } + Thread.Sleep(5000); + //this is the first thread to request this appearance + //so let it check the db and if not found then create a default appearance + //and add that to the cache + appearance = CheckDatabase(avatarId); + if (appearance != null) + { + //appearance has now been added to cache so lets pulse any waiting threads + lock (m_syncLock) + { + m_fetchesInProgress.Remove(avatarId); + waitHandle.Set(); + } + // waitHandle.Close(); + waitHandle = null; + return true; + } + + //not found a appearance for the user, so create a new default one + appearance = CreateDefault(avatarId); + if (appearance != null) + { + //update database + if (m_enablePersist) + { + m_appearanceMapper.Add(avatarId.UUID, appearance); + } + + //add appearance to dictionary cache + lock (m_avatarsAppearance) + { + m_avatarsAppearance[avatarId] = appearance; + } + + //appearance has now been added to cache so lets pulse any waiting threads + lock (m_syncLock) + { + m_fetchesInProgress.Remove(avatarId); + waitHandle.Set(); + } + // waitHandle.Close(); + waitHandle = null; + return true; + } + else + { + //something went wrong, so release the wait handle and remove it + //all waiting threads will fail to find cached appearance + //but its better for them to fail than wait for ever + lock (m_syncLock) + { + m_fetchesInProgress.Remove(avatarId); + waitHandle.Set(); + } + //waitHandle.Close(); + waitHandle = null; + return false; + } + } } private AvatarAppearance CreateDefault(LLUUID avatarId) @@ -197,8 +212,10 @@ namespace OpenSim.Region.Environment.Modules public void Initialise(Scene scene, IConfigSource source) { - scene.RegisterModuleInterface(this); - scene.EventManager.OnNewClient += NewClient; + + scene.RegisterModuleInterface(this); + scene.EventManager.OnNewClient += NewClient; + if (m_scene == null) {