Step by step to build webim (2) -- message Cache

Source: Internet
Author: User

Webim Series

In step-by-step webim creation (1), we have introduced how to implement a simple webim. However, this webim has a problem that every time a message listener is added, you must access the database once to check whether there are any messages. Obviously, if there are many users, the pressure on the database is quite high. One way to solve this problem is to first cache the message in the memory and do not immediately write the message to the database until the cache is full. This article describes how to implement message caching.

Basic Ideas

A message Cache Management class is implemented to cache all messages by users. Each user corresponds to a list <message> and stores the new messages received by the user, message Cache Management uses a hashtable to save the list <message> corresponding to all users.

ImplementationCodeAs follows:

 Public class  Messagecachemanagement  {  Static  Messagecachemanagement  M_instance =  New  Messagecachemanagement  ();  Static public Messagecachemanagement  Instance {  Get  {  Return  M_instance ;}}  Private  Messagecachemanagement (){}  Int32  M_count = 0;  Hashtable  M_cache =  New  Hashtable  ();  List  <  Message  > Getusermessagecache ( String  User ){  If  (! M_cache.containskey (User) {m_cache.add (user,  New  List  <  Message  > ());}  Return  M_cache [user]  As  List  <  Message  > ;}  /// <Summary> ///  Clear Cache /// </Summary>  Public void  Clear (){  Lock  (M_cache ){  List  <  Message  > Msgs =  New  List  <  Message  > ();  Foreach  (  Dictionaryentry  Ent  In M_cache) {(Ent. Value  As  List  <  Message  >). Clear () ;}m_count = 0 ;}}  /// <Summary> ///  Retrieve All cached messages  /// </Summary> /// <returns> </returns>  Public  List  <  Message  > Getall (){  Lock  (M_cache ){ List  <  Message  > Msgs =  New  List  <  Message  > ();  Foreach  (  Dictionaryentry  Ent  In  M_cache ){  Foreach  (  Message  MSG  In  Ent. Value As  List  <  Message  >) {Msgs. Add (MSG );}}  Return  Msgs ;}}  /// <Summary> ///  Minimum Time for obtaining cached messages of a user  /// </Summary>  Public  Nullable  <  Datetime  > Getmincreatedtime (  String  User ){ Lock  (M_cache ){  List  <  Message  > Usermsgs = getusermessagecache (User );  Return  Usermsgs. Count = 0?  Null  :  New  Nullable  <  Datetime  > (Usermsgs [0]. createdtime );}}  /// <Summary> ///  Insert a message into the cache /// </Summary> /// <Param name = "user"> </param> /// <Param name = "MSG"> </param>  Public void  Insert (  String  User,  Message  MSG ){  List  <  Message  > Usermsgs =  Null  ;  Lock  (M_cache) {usermsgs = getusermessagecache (User );}  Lock (Usermsgs) {usermsgs. Add (MSG); m_count ++ ;}}  /// <Summary> ///  Find the message whose recipient is user and whose sending time is later than from in the cache  /// </Summary>  Public  List  <  Message  > Find (  String  User,  Datetime  From ){  List  <  Message  > Usermsgs = Null  ;  Lock  (M_cache) {usermsgs = getusermessagecache (User );}  Lock  (Usermsgs ){  List  <  Message  > Msgs =  New  List  <  Message  > ();  Int  I = 0;  While (I <usermsgs. Count & usermsgs [I]. createdtime <= from) I ++;  While  (I <usermsgs. Count) {msgs. Add (usermsgs [I]); I ++ ;}  Return  Msgs ;}}  /// <Summary> ///  Retrieve total messages  /// </Summary>  Public  Int32  Count {  Get  {  Return  M_count ;}}} 

Add message listener

After the message cache is added, the process for adding a message listener must also be modified. The specific idea is to first obtain the sending time of the earliest message sent by the message receiver in the cache. Obviously, if the listener's from is greater than or equal to the minimum sending time, you can directly access the cache without accessing the database. Modify the code:

 /// <Summary> ///  Add a message listener. If a message that meets the listener conditions is found, false is returned. No listener is added.  ///  If no message meeting the listener condition is found, true is returned, and the listener is added to m_listeners.  /// </Summary>  Public bool  Addlistener (  String  Aggreger,  String  Sender,  Nullable  <  Datetime  > From, Webim_asyncresult  Asynresult ){  Messagelistener  Listener =  New  Messagelistener  (Aggreger, sender, from, asynresult );  Lock  (M_lock ){  If  (! M_listeners.containskey (receiver) {m_listeners.add (receiver,  New  List  <  Messagelistener  > ());}  List  < Messagelistener  > Listeners = m_listeners [Cycler]  As  List  <  Messagelistener  >;  // Obtain the minimum sending time of the message cached by the consumer  Nullable  <  Datetime  > Min =  Messagecachemanagement  . Instance. getmincreatedtime (Consumer ER );  List  <  Message  > Messages = New  List  <  Message  > ();  // When from> = the minimum time for messages cached in memory, you do not need to query the database  If  (Min =  Null  | From =  Null  | From. value <min. Value ){  // Query the database  Messages. addrange (find (receiver er, sender, from ));}  // Query in cache  Messages. addrange (  Messagecachemanagement . Instance. Find (aggreger, from. Value ));  If  (Messages. Count = 0 ){  // Insert the listener  Listeners. Add (listener );}  Else  {  // Send a message  Listener. Send (messages );}  Return  Messages. Count = 0 ;}} 

Send message

After the message cache is added, the message sending process must also be modified. The specific idea is to save the message to the cache and then determine the total number of cached messages. If the maximum number of messages is exceeded, write messages to the database. Modify the code to (you can modify max_cache_count to modify the maximum number of cached messages ):

 /// <Summary> /// Insert a new message. After the message is inserted, check whether there is a qualified listener in m_listeners. If yes, send the message.  /// </Summary>  Public  Message  Newmessage (  String  Aggreger,  String  Sender,  Datetime  Createdtime,  String  Content ){  Lock  (M_lock ){  Message  Message =  New Message  (Sender, aggreger, content, createdtime, ++ m_maxkey );  List  <  Message  > Messages =  New  List  <  Message  > (); Messages. Add (Message );  If  (M_listeners.containskey (receiver )){  List  <  Messagelistener  > Listeners = m_listeners [Cycler]  As List  <  Messagelistener  >;  List  <  Messagelistener  > Removelisteners =  New  List  <  Messagelistener  > ();  Foreach  (  Messagelistener  Listener  In  Listeners ){  If (Listener. Sender =  "*"  |  String  . Compare (listener. Sender, sender,  True  ) = 0) & (listener. From =  Null  | Message. createdtime> listener. From) {listener. Send (messages); removelisteners. Add (listener); system. threading.  Threadpool  . Queueuserworkitem (  New  System. threading.  Waitcallback (Listener. Complete ));}}  Foreach  (  Messagelistener  Listener  In  Removelisteners ){  // Remove the listener  Listeners. Remove (listener );}}  Messagecachemanagement  . Instance. insert (receiver, message );  If  (  Messagecachemanagement . Instance. Count> = max_cache_count ){// When the maximum value of the cache is exceeded, all messages in the cache are written to the database.  // Start the transaction  Sqlitetransaction  Trans = m_conn.begintransaction ();  Try  {  List  <  Message  > Cachemsgs =  Messagecachemanagement  . Instance. getall ();  Foreach  (  Message  MSG In  Cachemsgs ){    Sqlitecommand  Cmd =  New  Sqlitecommand  (  "Insert into message (author er, sender, content, createdtime, key) values (?,?,?,?,?) "  , M_conn); cmd. Parameters. Add (  "Cycler"  ,  Dbtype  . String). value = msg. Cycler; cmd. Parameters. Add (  "Sender" ,  Dbtype  . String). value = msg. Sender; cmd. Parameters. Add (  "Content"  ,  Dbtype  . String). value = msg. content; cmd. Parameters. Add (  "Createdtime"  ,  Dbtype  . Datetime). value = msg. createdtime; cmd. Parameters. Add (  "Key"  ,  Dbtype  . Int64). value = MSG. Key; cmd. executenonquery ();} Trans. Commit ();} Catch  {TRANS. rollback ();}  Messagecachemanagement  . Instance. Clear ();}  Return  Message ;}} 

 

Source code download (this timeSource codeOnly the messagemanagement. CS file has been modified. If you have any questions, contact me via webim)

If this article is helpful to you, do not forget to recommend

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.