PageRenderTime 48ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/wojilu/Data/Cache/MemoryDB.cs

https://bitbucket.org/kingshine/wojilu
C# | 496 lines | 345 code | 131 blank | 20 comment | 54 complexity | 6fc82113464d8c8c6a0d56518fd5a15c MD5 | raw file
Possible License(s): MIT
  1. /*
  2. * Copyright 2010 www.wojilu.com
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. using System;
  17. using System.Collections;
  18. using System.Collections.Specialized;
  19. using System.Collections.Generic;
  20. using System.IO;
  21. using System.Reflection;
  22. using System.Text;
  23. using System.Web;
  24. using wojilu.ORM;
  25. using wojilu.Serialization;
  26. using wojilu.Web;
  27. namespace wojilu.Data {
  28. internal class MemoryDB {
  29. private static readonly ILog logger = LogManager.GetLogger( typeof( MemoryDB ) );
  30. private static IDictionary objectList = Hashtable.Synchronized( new Hashtable() );
  31. private static IDictionary indexList = Hashtable.Synchronized( new Hashtable() );
  32. public static IDictionary GetObjectsMap() {
  33. return objectList;
  34. }
  35. public static IDictionary GetIndexMap() {
  36. return indexList;
  37. }
  38. private static Object objLock = new object();
  39. private static Object chkLock = new object();
  40. private static IList GetObjectsByName( Type t ) {
  41. if (isCheckFileDB( t )) {
  42. lock (chkLock) {
  43. if (isCheckFileDB( t )) {
  44. loadDataFromFile( t );
  45. _hasCheckedFileDB[t] = true;
  46. }
  47. }
  48. }
  49. return (objectList[t.FullName] as IList);
  50. }
  51. private static Hashtable _hasCheckedFileDB = new Hashtable();
  52. private static Boolean isCheckFileDB( Type t ) {
  53. if (_hasCheckedFileDB[t] == null) return true;
  54. return false;
  55. }
  56. private static void loadDataFromFile( Type t ) {
  57. if (wojilu.IO.File.Exists( getCachePath( t ) )) {
  58. IList list = getListWithIndex( wojilu.IO.File.Read( getCachePath( t ) ), t );
  59. objectList[t.FullName] = list;
  60. }
  61. else {
  62. objectList[t.FullName] = new ArrayList();
  63. }
  64. }
  65. private static IList getListWithIndex( String jsonString, Type t ) {
  66. IList list = new ArrayList();
  67. if (strUtil.IsNullOrEmpty( jsonString )) return list;
  68. List<object> lists = JsonParser.Parse( jsonString ) as List<object>;
  69. foreach (Dictionary<String, object> map in lists) {
  70. CacheObject obj = JSON.setValueToObject( t, map ) as CacheObject;
  71. int index = list.Add( obj );
  72. addIdIndex( t.FullName, obj.Id, index );
  73. makeIndexByInsert( obj );
  74. }
  75. return list;
  76. }
  77. private static void Serialize( Type t ) {
  78. Serialize( t, GetObjectsByName( t ) );
  79. }
  80. private static void Serialize( Type t, IList list ) {
  81. String target = SimpleJsonString.ConvertList( list );
  82. if (strUtil.IsNullOrEmpty( target )) return;
  83. String absolutePath = getCachePath( t );
  84. lock (objLock) {
  85. wojilu.IO.File.Write( absolutePath, target );
  86. }
  87. }
  88. private static void UpdateObjects( String key, IList list ) {
  89. objectList[key] = list;
  90. }
  91. //------------------------------------------------------------------------------
  92. internal static CacheObject FindById( Type t, int id ) {
  93. IList list = GetObjectsByName( t );
  94. if (list.Count > 0) {
  95. int objIndex = getIndex( t.FullName, id );
  96. if (objIndex >= 0 && objIndex < list.Count) {
  97. return list[objIndex] as CacheObject;
  98. }
  99. }
  100. return null;
  101. }
  102. internal static IList FindBy( Type t, String propertyName, Object val ) {
  103. String propertyKey = getPropertyKey( t.FullName, propertyName );
  104. NameValueCollection valueCollection = getValueCollection( propertyKey );
  105. String ids = valueCollection[val.ToString()];
  106. if (strUtil.IsNullOrEmpty( ids )) return new ArrayList();
  107. IList results = new ArrayList();
  108. String[] arrItem = ids.Split( ',' );
  109. foreach (String strId in arrItem) {
  110. int id = cvt.ToInt( strId );
  111. if (id < 0) continue;
  112. CacheObject obj = FindById( t, id );
  113. if (obj != null) results.Add( obj );
  114. }
  115. return results;
  116. }
  117. internal static IList FindAll( Type t ) {
  118. return new ArrayList( GetObjectsByName( t ) );
  119. }
  120. internal static void Insert( CacheObject obj ) {
  121. Type t = obj.GetType();
  122. String _typeFullName = t.FullName;
  123. IList list = FindAll( t );
  124. obj.Id = getNextId( list );
  125. int index = list.Add( obj );
  126. addIdIndex( _typeFullName, obj.Id, index );
  127. UpdateObjects( _typeFullName, list );
  128. makeIndexByInsert( obj );
  129. if (isInMemory( t )) return;
  130. Serialize( t );
  131. }
  132. internal static void InsertByIndex( CacheObject obj, String propertyName, Object pValue ) {
  133. Type t = obj.GetType();
  134. String _typeFullName = t.FullName;
  135. IList list = FindAll( t );
  136. obj.Id = getNextId( list );
  137. int index = list.Add( obj );
  138. addIdIndex( _typeFullName, obj.Id, index );
  139. UpdateObjects( _typeFullName, list );
  140. makeIndexByInsert( obj, propertyName, pValue );
  141. if (isInMemory( t )) return;
  142. Serialize( t );
  143. }
  144. internal static void InsertByIndex( CacheObject obj, Dictionary<String, Object> dic ) {
  145. Type t = obj.GetType();
  146. String _typeFullName = t.FullName;
  147. IList list = FindAll( t );
  148. obj.Id = getNextId( list );
  149. int index = list.Add( obj );
  150. addIdIndex( _typeFullName, obj.Id, index );
  151. UpdateObjects( _typeFullName, list );
  152. foreach (KeyValuePair<String, Object> kv in dic) {
  153. makeIndexByInsert( obj, kv.Key, kv.Value );
  154. }
  155. if (isInMemory( t )) return;
  156. Serialize( t );
  157. }
  158. internal static Result Update( CacheObject obj ) {
  159. Type t = obj.GetType();
  160. makeIndexByUpdate( obj );
  161. if (isInMemory( t )) return new Result();
  162. try {
  163. Serialize( t );
  164. return new Result();
  165. }
  166. catch (Exception ex) {
  167. throw ex;
  168. }
  169. }
  170. internal static Result updateByIndex( CacheObject obj, Dictionary<String, Object> dic ) {
  171. Type t = obj.GetType();
  172. makeIndexByUpdate( obj );
  173. if (isInMemory( t )) return new Result();
  174. try {
  175. Serialize( t );
  176. return new Result();
  177. }
  178. catch (Exception ex) {
  179. throw ex;
  180. }
  181. }
  182. internal static void Delete( CacheObject obj ) {
  183. Type t = obj.GetType();
  184. String _typeFullName = t.FullName;
  185. makeIndexByDelete( obj );
  186. IList list = FindAll( t );
  187. list.Remove( obj );
  188. UpdateObjects( _typeFullName, list );
  189. deleteIdIndex( _typeFullName, obj.Id );
  190. if (isInMemory( t )) return;
  191. Serialize( t, list );
  192. }
  193. private static int getNextId( IList list ) {
  194. if (list.Count == 0) return 1;
  195. CacheObject preObject = list[list.Count - 1] as CacheObject;
  196. return preObject.Id + 1;
  197. }
  198. private static Boolean isInMemory( Type t ) {
  199. return rft.GetAttribute( t, typeof( NotSaveAttribute ) ) != null;
  200. }
  201. //----------------------------------------------------------------------------------------------
  202. private static Object objIndexLock = new object();
  203. private static Object objIndexLockInsert = new object();
  204. private static Object objIndexLockUpdate = new object();
  205. private static Object objIndexLockDelete = new object();
  206. private static void makeIndexByInsert( CacheObject cacheObject, String propertyName, Object pValue ) {
  207. if (cacheObject == null || pValue == null) return;
  208. Type t = cacheObject.GetType();
  209. String propertyKey = getPropertyKey( t.FullName, propertyName );
  210. lock (objIndexLock) {
  211. NameValueCollection valueCollection = getValueCollection( propertyKey );
  212. valueCollection.Add( pValue.ToString(), cacheObject.Id.ToString() );
  213. indexList[propertyKey] = valueCollection;
  214. }
  215. }
  216. private static void makeIndexByInsert( CacheObject cacheObject ) {
  217. if (cacheObject == null) return;
  218. Type t = cacheObject.GetType();
  219. PropertyInfo[] properties = getProperties( t );
  220. foreach (PropertyInfo p in properties) {
  221. String propertyKey = getPropertyKey( t.FullName, p.Name );
  222. lock (objIndexLockInsert) {
  223. NameValueCollection valueCollection = getValueCollection( propertyKey );
  224. addNewValueMap( valueCollection, cacheObject, p );
  225. }
  226. }
  227. }
  228. private static void makeIndexByUpdate( CacheObject cacheObject ) {
  229. if (cacheObject == null) return;
  230. Type t = cacheObject.GetType();
  231. PropertyInfo[] properties = getProperties( t );
  232. foreach (PropertyInfo p in properties) {
  233. String propertyKey = getPropertyKey( t.FullName, p.Name );
  234. lock (objIndexLockUpdate) {
  235. NameValueCollection valueCollection = getValueCollection( propertyKey );
  236. deleteOldValueIdMap( valueCollection, cacheObject.Id );
  237. addNewValueMap( valueCollection, cacheObject, p );
  238. }
  239. }
  240. }
  241. private static void makeIndexByUpdate( CacheObject cacheObject, String propertyName, Object pValue ) {
  242. if (cacheObject == null || pValue == null) return;
  243. Type t = cacheObject.GetType();
  244. String propertyKey = getPropertyKey( t.FullName, propertyName );
  245. lock (objIndexLockUpdate) {
  246. NameValueCollection valueCollection = getValueCollection( propertyKey );
  247. deleteOldValueIdMap( valueCollection, cacheObject.Id );
  248. valueCollection.Add( pValue.ToString(), cacheObject.Id.ToString() );
  249. indexList[propertyKey] = valueCollection;
  250. }
  251. }
  252. private static void makeIndexByDelete( CacheObject cacheObject ) {
  253. if (cacheObject == null) return;
  254. Type t = cacheObject.GetType();
  255. PropertyInfo[] properties = getProperties( t );
  256. foreach (PropertyInfo p in properties) {
  257. String propertyKey = getPropertyKey( t.FullName, p.Name );
  258. lock (objIndexLockDelete) {
  259. NameValueCollection valueCollection = getValueCollection( propertyKey );
  260. deleteOldValueIdMap( valueCollection, cacheObject.Id );
  261. }
  262. }
  263. }
  264. private static PropertyInfo[] getProperties( Type t ) {
  265. return t.GetProperties( BindingFlags.Public | BindingFlags.Instance );
  266. }
  267. private static NameValueCollection getValueCollection( String propertyKey ) {
  268. NameValueCollection valueCollection = indexList[propertyKey] as NameValueCollection;
  269. if (valueCollection == null) valueCollection = new NameValueCollection();
  270. return valueCollection;
  271. }
  272. private static void addNewValueMap( NameValueCollection valueCollection, CacheObject cacheObject, PropertyInfo p ) {
  273. Attribute attr = rft.GetAttribute( p, typeof( NotSaveAttribute ) );
  274. if (attr != null) return;
  275. String propertyKey = getPropertyKey( cacheObject.GetType().FullName, p.Name );
  276. Object pValue = rft.GetPropertyValue( cacheObject, p.Name );
  277. if (pValue == null || strUtil.IsNullOrEmpty( pValue.ToString() )) return;
  278. valueCollection.Add( pValue.ToString(), cacheObject.Id.ToString() );
  279. indexList[propertyKey] = valueCollection;
  280. }
  281. // TODO 优化
  282. private static void deleteOldValueIdMap( NameValueCollection valueCollection, int oid ) {
  283. foreach (String key in valueCollection.AllKeys) {
  284. String val = valueCollection[key];
  285. String[] arrItem = val.Split( ',' );
  286. StringBuilder result = new StringBuilder();
  287. foreach (String strId in arrItem) {
  288. int id = cvt.ToInt( strId );
  289. if (id == oid) continue;
  290. result.Append( strId );
  291. result.Append( "," );
  292. }
  293. String resultStr = result.ToString();
  294. if (strUtil.HasText( resultStr ))
  295. valueCollection[key] = resultStr.Trim().TrimEnd( ',' );
  296. else
  297. valueCollection.Remove( key );
  298. }
  299. }
  300. private static String getPropertyKey( String typeFullName, String propertyName ) {
  301. return typeFullName + "_" + propertyName;
  302. }
  303. //-------------------------- Id Index --------------------------------
  304. private static IDictionary GetIdIndexMap( String key ) {
  305. if (objectList[key] == null) {
  306. objectList[key] = new Hashtable();
  307. }
  308. return (objectList[key] as IDictionary);
  309. }
  310. private static void UpdateIdIndexMap( String key, IDictionary map ) {
  311. objectList[key] = map;
  312. }
  313. private static void clearIdIndexMap( String key ) {
  314. objectList.Remove( key );
  315. }
  316. private static void addIdIndex( String typeFullName, int oid, int index ) {
  317. String key = getIdIndexMapKey( typeFullName );
  318. IDictionary indexMap = GetIdIndexMap( key );
  319. indexMap[oid] = index;
  320. UpdateIdIndexMap( key, indexMap );
  321. }
  322. private static void deleteIdIndex( String typeFullName, int oid ) {
  323. String key = getIdIndexMapKey( typeFullName );
  324. clearIdIndexMap( key );
  325. IList results = objectList[typeFullName] as IList;
  326. foreach (CacheObject obj in results) {
  327. addIdIndex( typeFullName, obj.Id, results.IndexOf( obj ) );
  328. }
  329. IDictionary indexMap = GetIdIndexMap( key );
  330. UpdateIdIndexMap( key, indexMap );
  331. }
  332. private static int getIndex( String typeFullName, int oid ) {
  333. int result = -1;
  334. Object objIndex = GetIdIndexMap( getIdIndexMapKey( typeFullName ) )[oid];
  335. if (objIndex != null) {
  336. result = (int)objIndex;
  337. }
  338. return result;
  339. }
  340. private static String getIdIndexMapKey( String typeFullName ) {
  341. return String.Format( "{0}_oid_index", typeFullName );
  342. }
  343. //----------------------------------------------------------
  344. private static String getCachePath( Type t ) {
  345. if (SystemInfo.IsWeb == false) {
  346. return getCacheFileName( t.FullName );
  347. }
  348. return getWebCacheFileName( t.FullName );
  349. }
  350. private static String getCacheFileName( String name ) {
  351. return PathHelper.CombineAbs( new String[] {
  352. AppDomain.CurrentDomain.BaseDirectory,
  353. cfgHelper.FrameworkRoot,
  354. "data",
  355. name + fileExt
  356. } );
  357. }
  358. private static String getWebCacheFileName( String name ) {
  359. String rpath = strUtil.Join( cfgHelper.FrameworkRoot, "data" );
  360. rpath = strUtil.Join( rpath, name + fileExt );
  361. return PathHelper.Map( rpath );
  362. }
  363. private static readonly String fileExt = ".config";
  364. }
  365. }