2012-09-28 13 views
11

मुझे अपने वेबपैप में निबर्ननेट दौड़ की स्थिति में कोई समस्या है।इकाई लोड करते समय nhibernate दौड़ स्थिति

मुझे लॉग 4नेट के पुराने संस्करणों का उपयोग करते समय यह हो रहा है (1.2.10 में तय किया जाना चाहिए), हालांकि मैंने इसका अनुभव भी किया है। इस वजह से हमने अभी लॉगऑनेट को अक्षम कर दिया है, क्योंकि दौड़ की स्थिति आईआईएस को दुर्घटनाग्रस्त कर देती है और उत्पादन में होने के लिए यह अस्वीकार्य है। यह एक इकाई लोड करते समय हुआ (नीचे stacktrace देखें)। इसके अलावा, रावेनडीबी में भी इसी तरह की समस्या आई है, यह link देखें, और यहां एनएचबर्ननेट के बिना एक उदाहरण link देखें।

स्टैकट्रेस: ​​

Server Error in '/' Application. 
Probable I/O race condition detected while copying memory. The I/O package is not thread safe by default. In multithreaded applications, a stream must be accessed in a thread-safe way, such as a thread-safe wrapper returned by TextReader's or TextWriter's Synchronized methods. This also applies to classes like StreamWriter and StreamReader. 
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 

Exception Details: System.IndexOutOfRangeException: Probable I/O race condition detected while copying memory. The I/O package is not thread safe by default. In multithreaded applications, a stream must be accessed in a thread-safe way, such as a thread-safe wrapper returned by TextReader's or TextWriter's Synchronized methods. This also applies to classes like StreamWriter and StreamReader. 

Source Error: 


Line 105: 
Line 106:    if(webUser.Id > 0) { // logged in 
Line 107:     _user = session.Get<User>(webUser.Id); 
Line 108:     if(_user == null) { // session exists, but no user in DB with this id 
Line 109:      new SessionInit().Remove(); 


Source File: \App_Code\SessionInit.cs Line: 107 

Stack Trace: 


[IndexOutOfRangeException: Probable I/O race condition detected while copying memory. The I/O package is not thread safe by default. In multithreaded applications, a stream must be accessed in a thread-safe way, such as a thread-safe wrapper returned by TextReader's or TextWriter's Synchronized methods. This also applies to classes like StreamWriter and StreamReader.] 
    System.Buffer.InternalBlockCopy(Array src, Int32 srcOffsetBytes, Array dst, Int32 dstOffsetBytes, Int32 byteCount) +0 
    System.IO.StreamWriter.Write(Char[] buffer, Int32 index, Int32 count) +117 
    System.IO.TextWriter.WriteLine(String value) +204 
    System.IO.SyncTextWriter.WriteLine(String value) +63 
    NHibernate.AdoNet.AbstractBatcher.ExecuteReader(IDbCommand cmd) +71 
    NHibernate.Loader.Loader.GetResultSet(IDbCommand st, Boolean autoDiscoverTypes, Boolean callable, RowSelection selection, ISessionImplementor session) +580 
    NHibernate.Loader.Loader.DoQuery(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies) +275 
    NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies) +205 
    NHibernate.Loader.Loader.LoadEntity(ISessionImplementor session, Object id, IType identifierType, Object optionalObject, String optionalEntityName, Object optionalIdentifier, IEntityPersister persister) +590 

[GenericADOException: could not load an entity: [app.Presentation.User#338][SQL: SELECT user0_.userID as userID24_0_, user0_.instituteID as institut2_24_0_, user0_.email as email24_0_, user0_.password as password24_0_, user0_.username as username24_0_, user0_.mod_remarks as mod6_24_0_, user0_.lastLogin as lastLogin24_0_, user0_.active as active24_0_, user0_.isAcademic as isAcademic24_0_, user0_.created as created24_0_, (select p.firstName from ej_profile p where p.userID = user0_.userID) as formula11_0_, (select p.lastName from ej_profile p where p.userID = user0_.userID) as formula12_0_, (select p.timeZone from ej_profile p where p.userID = user0_.userID) as formula13_0_ FROM ej_user user0_ WHERE user0_.userID=?]] 
    NHibernate.Loader.Loader.LoadEntity(ISessionImplementor session, Object id, IType identifierType, Object optionalObject, String optionalEntityName, Object optionalIdentifier, IEntityPersister persister) +960 
    NHibernate.Loader.Entity.AbstractEntityLoader.Load(ISessionImplementor session, Object id, Object optionalObject, Object optionalId) +76 
    NHibernate.Loader.Entity.AbstractEntityLoader.Load(Object id, Object optionalObject, ISessionImplementor session) +32 
    NHibernate.Event.Default.DefaultLoadEventListener.LoadFromDatasource(LoadEvent event, IEntityPersister persister, EntityKey keyToLoad, LoadType options) +173 
    NHibernate.Event.Default.DefaultLoadEventListener.Load(LoadEvent event, IEntityPersister persister, EntityKey keyToLoad, LoadType options) +181 
    NHibernate.Event.Default.DefaultLoadEventListener.OnLoad(LoadEvent event, LoadType loadType) +1019 
    NHibernate.Impl.SessionImpl.FireLoad(LoadEvent event, LoadType loadType) +403 
    NHibernate.Impl.SessionImpl.Get(String entityName, Object id) +469 
    NHibernate.Impl.SessionImpl.Get(Type entityClass, Object id) +374 
    NHibernate.Impl.SessionImpl.Get(Object id) +391 
    SessionInit.GetCurrentUser(ISession session) in j:\dev\app\app_wwwroot\App_Code\SessionInit.cs:107 
    DynamicPage.OnPreInit(EventArgs e) in j:\dev\app\app_wwwroot\App_Code\DynamicPage.cs:24 
    MemberPage.OnPreInit(EventArgs e) in j:\dev\app\app_wwwroot\App_Code\MemberPage.cs:20 
    members_stocks_Default.OnPreInit(EventArgs e) in j:\dev\app\app_wwwroot\members\Default.aspx.cs:28 
    System.Web.UI.Page.PerformPreInit() +49 
    System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +1716 

उपयोगकर्ता के लिए मानचित्रण:

public class UserViewMapping : ClassMap<User> 
{ 
    public UserViewMapping() { 
     Table("ej_user"); 
     Id(s => s.Id, "userID").GeneratedBy.Native(); 
     Map(s => s.InstituteId, "instituteID"); 
     Map(s => s.Email, "email"); 
     Map(s => s.Password, "password"); 
     Map(s => s.Name, "username"); 
     Map(s => s.ModRemarks, "mod_remarks"); 
     Map(s => s.LastLogin, "lastLogin"); 
     Map(s => s.Active, "active"); 
     Map(s => s.IsAcademic, "isAcademic"); 
     Map(s => s.Created, "created"); 
     Map(s => s.FirstName).Formula("(select p.firstName from ej_profile p where p.userID = userID)"); 
     Map(s => s.LastName).Formula("(select p.lastName from ej_profile p where p.userID = userID)"); 
     Map(s => s.TimeZone).Formula("(select p.timeZone from ej_profile p where p.userID = userID)"); 
     HasMany<ProfileViewModel>(s => s.Profiles) 
      .Table("ej_profile") 
      .KeyColumn("userID") 
      .Cascade.All() 
      .Inverse(); 
} 

कुछ विवरण: मैं प्रश्नों और आदेश (और दो सत्र कारखानों) के लिए दो सत्रों का उपयोग के बाद से मैं का उपयोग कुछ हद तक एक CQRS की तरह पैटर्न। वस्तुओं को पढ़ने के लिए एक सत्र, परिवर्तन करने के लिए एक (यह मुझे मेरे डोमेन मॉडल को सरल रखने और मॉडलों को देखने में मदद करता है और कमांड मॉडल से संभवतः मैपिंग अलग करता है)।

मेरी विकास पर्यावरण (एकल उपयोगकर्ता) में उपयोगकर्ता व्यूमोडेल लोड करते समय दौड़ की स्थिति आई, लेकिन हम यह सुनिश्चित करते हैं कि यह उत्पादन में कभी नहीं होगा, क्योंकि यह आईआईएस 7 को दुर्घटनाग्रस्त कर दिया गया है। इसके अलावा, उत्पादन में कई उपयोगकर्ता होंगे, तो हो सकता है कि त्रुटि संभवतः अधिक बार हो।

इसके अलावा, हमारे पास बहुत सी विरासत कोड है जो डेटाबेस को पढ़ने/लिखने के लिए System.Data और MySQL.Data.MySqlClient.MySqlDataAdapter का उपयोग करता है। क्या यह प्रभाव का हो सकता है?

मैं एनएचबीर्नेट 3.1.0 का उपयोग कर रहा हूं (3.3.1 जीजी तक अपग्रेड करूँगा, लेकिन इसे पुन: उत्पन्न करना मुश्किल है), और मेरे मैपिंग के लिए फ्लेंट निबर्ननेट।

sessionfactories Global.asax में बनाए जाते हैं:

void Application_Start(object sender, EventArgs e) 
{ 
    QuerySessionFactory.Create(connectionString); 
    CommandSessionManager.Initialize(connString); 
} 

मेरे पृष्ठों मेरी DynamicPage जहां क्वेरी सत्र खोला है से विरासत, और बंद कर दिया:

public class DynamicPage : System.Web.UI.Page 
{ 
    protected override void OnPreInit(EventArgs e) 
    { 
     Session = QuerySessionFactory.Instance.OpenSession(); 
    } 

    protected override void OnUnload(EventArgs e) { 
     base.OnUnload(e); 
     Session.Close(); 
    } 
} 

SessionInit में (userID पढ़ता httpcontext.session से, और 'वेबसुर' बनाता है, उपयोगकर्ता को कुछ सरल जानकारी जैसे उपयोगकर्ता आईडी)। बाद में, मैंने लॉक को चारों ओर रखा है और उपयोगकर्ता को लेन-देन में अनुरोध प्राप्त हुआ है, यह सुनिश्चित नहीं है कि यह उपयोगी होगा या नहीं।

public IUser GetCurrentUser(ISession session) { 
     if(_user == null) { 
      var webUser = new SessionInit().Get; 

      if(webUser.Id > 0) { // logged in 
       lock(_lock) { 
        using(var tx = session.BeginTransaction()) { 
         _user = session.Get<User>(webUser.Id); 
         tx.Commit(); 
        } 
       } 
       if(_user == null) { // session exists, but no user in DB with this id 
        new SessionInit().Remove(); 
       } 
       ((User)_user)._currentUser = webUser; 
      } else { 
       if(webUser is CurrentUser && webUser.Id == 0) { 
        if(HttpContext.Current.Session != null) { 
         HttpContext.Current.Response.Cookies.Remove("ASPSESSID"); 
         HttpContext.Current.Request.Cookies.Remove("ASPSESSID"); 
         HttpContext.Current.Session.RemoveAll(); 
         HttpContext.Current.Session.Abandon(); 
        } 

        if(HttpContext.Current.Request.Url.Host.Contains("members")) 
         HttpContext.Current.Response.Redirect("/login"); 
       } else 
        if(webUser.Id == 0) { 
         var userId = webUser.Id; 
         var userName = webUser.UserName; 
         var loginUrl = webUser.LoginUrl; 
         var clientIp = webUser.ClientIp; 
         var isAdmin = webUser.IsAdmin(); 
         return new eLab.Presentation.Visitor(userId, userName, loginUrl, clientIp, isAdmin, webUser.Theme); 
        } 
      } 
      if (_user == null) 
       return new eLab.Presentation.Visitor(webUser.Id, webUser.UserName, webUser.LoginUrl, webUser.ClientIp, false, webUser.Theme); 
     } 
     return _user; 
} 

कमांड सत्र आवश्यकतानुसार उपयोग ब्लॉक में खोले और बंद हो जाते हैं।

स्टैकट्रैक के अनुसार, समस्या स्ट्रीमवाइटर -> System.Buffer में होती है, जिसे सिस्टम.IO.SyncTextWriter द्वारा फिर से बुलाया जाता है, जिसे System.IO.TextWriter के आसपास थ्रेड-सुरक्षित रैपर माना जाता है।

चूंकि यह टेक्स्टवाइटर में हुआ था, क्या थ्रेडसेफ टेक्स्टवाइटर का उपयोग करने के लिए इसके आसपास जाने का कोई तरीका है?

क्या डायनेमिक पेज में जिस तरह से मैं इसे करता हूं, सत्र को खोलना और बंद करना सुरक्षित है?

चूंकि यह पुन: पेश करना स्पष्ट रूप से कठिन है, इस पर विचार करने के बारे में कोई भी विचार भी स्वागत है।

[अद्यतन] एनएचबेर्नेट प्रोफाइलर ने बताया कि हमने एक मास्टर पेज में एक सत्र (एक ब्लॉक में) को भी खोला और बंद कर दिया है, क्योंकि वर्तमान उपयोगकर्ता के लिए कुछ अनुमतियों की जांच करने की आवश्यकता थी, इसलिए प्रति सत्र दो सत्र खोले गए निवेदन। मैंने इसे दोबारा प्रतिक्रिया दी है, इसलिए अब यह पृष्ठ सुपरक्लस में सत्र खोलने के बजाय, यह session_BeginRequest पर वैश्विक.एक्सएक्स में सत्र खोलता है और इसे एप्लिकेशन_इंडरक्वैस्ट पर फिर से बंद कर देता है, जहां सत्र HttpContext.Current.Items में रखा जाता है।

लेकिन अगर यह ठीक करता है तो परीक्षण का कोई निश्चित तरीका नहीं है।

+0

मुझे इस SO लेख में रूचि है। स्टैक ट्रेस में, आपके पास यह है: - \ सत्र सत्र। गेटक्रोरेंट यूज़र (आईएसशन सत्र) जे: \ dev \ app \ app_wwwroot \ App_Code \ SessionInit.cs: 107' सत्रInit.cs कोड में क्या है? –

+0

निक, मैंने सत्रInit.GetCurrentUser() के लिए कोड जोड़ा। अद्यतन देखें। – Stamppot

+0

मुझे हर बार यह समस्या मिल रही है और फिर भी NHBernate में एक ही स्थान पर - क्या आप यह सुनिश्चित करने के लिए प्रबंधित करते हैं कि कैसे ठीक किया जाए? –

उत्तर

12

स्टाम्पपॉट, इस समस्या को StackOverflow पर पोस्ट करने के लिए धन्यवाद; जैसा कि आप जानते हैं, वेब पर इस त्रुटि संदेश को खोजने के बारे में बहुत अधिक जानकारी नहीं है। मेरी टीम कुछ महीने पहले एक वेबपैप में इसी तरह की समस्या में भाग गई जो NHibernate और log4net का उपयोग करती है। (StringTemplate भी शामिल किया गया है हो सकता है।) हम "तय" पुनः निर्देशित Console.Out/त्रुटि Global.ascx.cs में धाराओं (प्रभावी रूप से उन्हें अक्षम) Application_Start() ईवेंट हैंडलर में शून्य पर से problen:

protected void Application_Start(object sender, EventArgs e) 
{ 
    Console.SetOut(new System.IO.StreamWriter(System.IO.Stream.Null)); 
    Console.SetError(new System.IO.StreamWriter(System.IO.Stream.Null)); 
} 

विवरण: हमारे मामले में, "संभावित दौड़ स्थिति ..." त्रुटि लोड से संबंधित थी। उत्पादन सर्वर पर, यह अपवाद प्रत्येक मौके पर कार्यकर्ता प्रक्रिया को दुर्घटनाग्रस्त कर देगा। आखिरकार हमने पाया कि एक छोटी सी अवधि में कई अनुरोधों के साथ वेबपैड में बाढ़ वाली एक स्क्रिप्ट चलाकर, इसे पुन: पेश करने के तरीके को कैसे बनाया जाए। अपवाद स्टैक निशान, जब NHibernate/StringTemplate/log4net स्रोत कोड से संबंधित होते हैं, तो कंसोल के उपयोग की ओर इशारा करते हैं। विभिन्न स्थितियों में लॉगिंग के लिए आउट/त्रुटि विधियां। ऐसी त्रुटि के लिए एक अजीब जगह की तरह लगता है --- ये विधियां considered to be thread-safe? नहीं हैं, हालांकि, हमने ऊपर दिए गए कार्यवाही को लागू करने के बाद, समस्या तुरंत गायब हो गई और बाद में वापस नहीं आई है। दुर्भाग्यवश, अन्य प्राथमिकताओं ने हमें गहराई से खोदने से रोक दिया --- लेकिन जो भी समस्या का मूल कारण है, वह किसी भी अन्य तरीके से प्रकट नहीं हुआ है।

+0

Awk, इस "फिक्स" के लिए धन्यवाद। अगर यह त्रुटियों को दूर रखता है तो मैं खुश हूं। – Stamppot

+0

बीटीडब्ल्यू, क्या आप इसे हर बार स्क्रिप्ट चलाने पर पुन: पेश कर सकते हैं?इस पर कोई विवरण, जैसे कि कितने समय के लिए अनुरोध करते हैं? यदि संभव हो तो स्क्रिप्ट स्वयं भी अच्छा होगा। – Stamppot

+3

@APW: हमने हाल ही में लॉग 4net को 1.2.12 तक अपग्रेड किया है जब हमने यह सटीक समस्या उत्पन्न की है। कोई विचार नहीं कि क्यों कंसोल आउट लिखना ऐसा करेगा। आपका फिक्स विश्व स्तर पर कंसोल लॉगिंग को अक्षम कर देगा जो निश्चित रूप से समस्या को हल करेगा। एक और (कम वैश्विक) चीज जो आप कर सकते हैं यह सुनिश्चित करता है कि, NHibernate के मामले में, "show_sql" कॉन्फ़िगरेशन विकल्प गलत पर सेट किया गया है। show_sql लिखता है * सीधे * कंसोल आउट करने के लिए, पूरी तरह से log4net से स्वतंत्र रूप से। मेरा मानना ​​है कि यह विशिष्ट मामला है जो ओपी की समस्याओं का कारण बन रहा है। –

0

@APW प्रदान किए गए समाधान के साथ समस्या यह है कि डिफ़ॉल्ट रूप से, StreamWriter थ्रेड सुरक्षित नहीं है। इसे यहां देखें: https://msdn.microsoft.com/en-us/library/system.io.streamwriter(v=vs.110).aspx

कंसोल पर "नया स्ट्रीमवाइटर" पास करके। * आप * गैर-थ्रेड सुरक्षित उदाहरण पास कर रहे हैं। तो मुझे लगता है कि यह फिर से इसी तरह की त्रुटि देखने के लिए समय की बात है।

असुरक्षित Stream.Null को लपेटने के लिए सही तरीका TextWriter.Synchronized विधि का उपयोग करेगा।

using System.IO; 
... 
var nullStream = TextWriter.Synchronized(TextWriter.Null); 
Console.SetOut(nullStream); 
Console.SetError(nullStream); 

यूपीडी: कृपया इसे अनदेखा करें। मैंने पाया है कि Console.SetOut किसी भी स्ट्रीम को TextWriter में लपेटना। सिंक्रनाइज़ (...)। Proof.

संबंधित मुद्दे