IOWA 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (502) hide show
  1. checksums.yaml +7 -0
  2. data/CONTRIBUTORS +14 -0
  3. data/README.md +23 -0
  4. data/RELEASE_NOTES +77 -0
  5. data/ToDo +21 -0
  6. data/components/CRUDList/CRUDList.html +13 -0
  7. data/components/CRUDList/CRUDList.iwa +136 -0
  8. data/components/Content/Content.html +0 -0
  9. data/components/Content/Content.iwa +143 -0
  10. data/components/Content/example/README +9 -0
  11. data/components/Content/example/cgi/iowa.cgi +10 -0
  12. data/components/Content/example/demo.rb +30 -0
  13. data/components/Content/example/doc/index.html +7 -0
  14. data/components/Content/example/iowa/Content.html +1 -0
  15. data/components/Content/example/iowa/Content.iwa +1 -0
  16. data/components/Content/example/iowa/Main.html +6 -0
  17. data/components/Content/example/iowa/Main.iwa +3 -0
  18. data/components/Content/example/iowa/_content/body +7 -0
  19. data/components/Content/example/iowa/_content/body2 +3 -0
  20. data/components/Content/example/iowa/_content/title +2 -0
  21. data/components/Content/example/iowa/app.cnf +8 -0
  22. data/components/Content/example/iowa/app.rb +8 -0
  23. data/components/Content/example/webrick.rb +38 -0
  24. data/components/Include/Include.html +1 -0
  25. data/components/Include/Include.iwa +30 -0
  26. data/components/Include/readme +5 -0
  27. data/components/JumpTo/JumpTo.html +8 -0
  28. data/components/JumpTo/JumpTo.iwa +8 -0
  29. data/components/JumpTo/readme +6 -0
  30. data/doc/Architecture.txt +6 -0
  31. data/doc/History.txt +33 -0
  32. data/doc/StandardDispatcher.txt +19 -0
  33. data/examples/blog/README +1 -0
  34. data/examples/hello_world/README +17 -0
  35. data/examples/hello_world/htdocs/hello_world_html.html +24 -0
  36. data/examples/hello_world/htdocs/hello_world_ruby.html +41 -0
  37. data/examples/hello_world/iowa/HelloWorld.html +14 -0
  38. data/examples/hello_world/iowa/HelloWorld.iwa +31 -0
  39. data/examples/hello_world/iowa/Index.html +16 -0
  40. data/examples/hello_world/iowa/Index.iwa +5 -0
  41. data/examples/hello_world/iowa/iowa_hello_world.cnf +19 -0
  42. data/examples/hello_world/iowa/iowa_hello_world.rb +5 -0
  43. data/examples/hello_world/iowa/mapfile.cnf +6 -0
  44. data/examples/hw1/iowa/Main.html +1 -0
  45. data/examples/hw1/iowa/README +9 -0
  46. data/examples/hw1/iowa/hw.rb +4 -0
  47. data/examples/hw2/iowa/Main.html +10 -0
  48. data/examples/hw2/iowa/Main.iwa +7 -0
  49. data/examples/hw2/iowa/README +16 -0
  50. data/examples/hw2/iowa/hw.rb +4 -0
  51. data/examples/hw3/iowa/Main.html +11 -0
  52. data/examples/hw3/iowa/Main.iwa +7 -0
  53. data/examples/hw3/iowa/README +22 -0
  54. data/examples/hw3/iowa/hw.rb +4 -0
  55. data/examples/hw4/iowa/Greetings.html +10 -0
  56. data/examples/hw4/iowa/Greetings.iwa +9 -0
  57. data/examples/hw4/iowa/Main.html +12 -0
  58. data/examples/hw4/iowa/Main.iwa +10 -0
  59. data/examples/hw4/iowa/README +28 -0
  60. data/examples/hw4/iowa/hw.rb +4 -0
  61. data/examples/hw5/iowa/Footer.html +2 -0
  62. data/examples/hw5/iowa/Greetings.html +4 -0
  63. data/examples/hw5/iowa/Greetings.iwa +12 -0
  64. data/examples/hw5/iowa/Header.html +6 -0
  65. data/examples/hw5/iowa/Main.html +12 -0
  66. data/examples/hw5/iowa/Main.iwa +13 -0
  67. data/examples/hw5/iowa/README +16 -0
  68. data/examples/hw5/iowa/hw.rb +4 -0
  69. data/examples/template_server/iowa/Content.iwa +121 -0
  70. data/examples/template_server/iowa/Content.view +0 -0
  71. data/examples/template_server/iowa/DBContentDispatcher.rb +112 -0
  72. data/examples/template_server/iowa/DBContentPage.html +3 -0
  73. data/examples/template_server/iowa/DBContentPage.iwa +85 -0
  74. data/examples/template_server/iowa/app.cnf +13 -0
  75. data/examples/template_server/iowa/app.rb +5 -0
  76. data/ext/Classifier/classifier.c +256 -0
  77. data/ext/Classifier/ext_help.h +14 -0
  78. data/ext/Classifier/extconf.rb +5 -0
  79. data/ext/Classifier/tst.h +40 -0
  80. data/ext/Classifier/tst_cleanup.c +24 -0
  81. data/ext/Classifier/tst_delete.c +146 -0
  82. data/ext/Classifier/tst_grow_node_free_list.c +38 -0
  83. data/ext/Classifier/tst_init.c +41 -0
  84. data/ext/Classifier/tst_insert.c +192 -0
  85. data/ext/Classifier/tst_search.c +68 -0
  86. data/ext/http11/README +11 -0
  87. data/ext/http11/ext_help.h +15 -0
  88. data/ext/http11/extconf.rb +5 -0
  89. data/ext/http11/http11.c +534 -0
  90. data/ext/http11/http11.c.dif +422 -0
  91. data/ext/http11/http11_parser.c +1243 -0
  92. data/ext/http11/http11_parser.c.dif +193 -0
  93. data/ext/http11/http11_parser.h +49 -0
  94. data/ext/http11/http11_parser.h.dif +20 -0
  95. data/ext/http11/http11_parser.rl +192 -0
  96. data/ext/httpmachine/Makefile +149 -0
  97. data/ext/httpmachine/extconf.rb +33 -0
  98. data/ext/httpmachine/http.cpp +430 -0
  99. data/ext/httpmachine/http.h +156 -0
  100. data/ext/httpmachine/rubyhttp.cpp +165 -0
  101. data/external/mime-types/LICENCE +18 -0
  102. data/external/mime-types/README +46 -0
  103. data/external/mime-types/doc/classes/MIME.html +120 -0
  104. data/external/mime-types/doc/classes/MIME/InvalidContentType.html +119 -0
  105. data/external/mime-types/doc/classes/MIME/Type.html +866 -0
  106. data/external/mime-types/doc/classes/MIME/Type.src/M000010.html +22 -0
  107. data/external/mime-types/doc/classes/MIME/Type.src/M000011.html +18 -0
  108. data/external/mime-types/doc/classes/MIME/Type.src/M000012.html +19 -0
  109. data/external/mime-types/doc/classes/MIME/Type.src/M000013.html +18 -0
  110. data/external/mime-types/doc/classes/MIME/Type.src/M000014.html +26 -0
  111. data/external/mime-types/doc/classes/MIME/Type.src/M000015.html +33 -0
  112. data/external/mime-types/doc/classes/MIME/Type.src/M000016.html +27 -0
  113. data/external/mime-types/doc/classes/MIME/Type.src/M000017.html +35 -0
  114. data/external/mime-types/doc/classes/MIME/Type.src/M000018.html +34 -0
  115. data/external/mime-types/doc/classes/MIME/Type.src/M000019.html +24 -0
  116. data/external/mime-types/doc/classes/MIME/Type.src/M000020.html +38 -0
  117. data/external/mime-types/doc/classes/MIME/Type.src/M000021.html +22 -0
  118. data/external/mime-types/doc/classes/MIME/Type.src/M000022.html +18 -0
  119. data/external/mime-types/doc/classes/MIME/Type.src/M000023.html +18 -0
  120. data/external/mime-types/doc/classes/MIME/Type.src/M000024.html +18 -0
  121. data/external/mime-types/doc/classes/MIME/Type.src/M000025.html +18 -0
  122. data/external/mime-types/doc/classes/MIME/Type.src/M000026.html +18 -0
  123. data/external/mime-types/doc/classes/MIME/Type.src/M000027.html +18 -0
  124. data/external/mime-types/doc/classes/MIME/Type.src/M000028.html +18 -0
  125. data/external/mime-types/doc/classes/MIME/Type.src/M000029.html +18 -0
  126. data/external/mime-types/doc/classes/MIME/Type.src/M000030.html +19 -0
  127. data/external/mime-types/doc/classes/MIME/Type.src/M000031.html +26 -0
  128. data/external/mime-types/doc/classes/MIME/Types.html +459 -0
  129. data/external/mime-types/doc/classes/MIME/Types.src/M000001.html +19 -0
  130. data/external/mime-types/doc/classes/MIME/Types.src/M000002.html +32 -0
  131. data/external/mime-types/doc/classes/MIME/Types.src/M000003.html +21 -0
  132. data/external/mime-types/doc/classes/MIME/Types.src/M000004.html +18 -0
  133. data/external/mime-types/doc/classes/MIME/Types.src/M000005.html +26 -0
  134. data/external/mime-types/doc/classes/MIME/Types.src/M000006.html +18 -0
  135. data/external/mime-types/doc/classes/MIME/Types.src/M000007.html +18 -0
  136. data/external/mime-types/doc/classes/MIME/Types.src/M000008.html +18 -0
  137. data/external/mime-types/doc/classes/MIME/Types.src/M000009.html +18 -0
  138. data/external/mime-types/doc/created.rid +1 -0
  139. data/external/mime-types/doc/files/ChangeLog.html +320 -0
  140. data/external/mime-types/doc/files/README.html +145 -0
  141. data/external/mime-types/doc/files/lib/mime/types_rb.html +101 -0
  142. data/external/mime-types/doc/fr_class_index.html +30 -0
  143. data/external/mime-types/doc/fr_file_index.html +29 -0
  144. data/external/mime-types/doc/fr_method_index.html +57 -0
  145. data/external/mime-types/doc/index.html +24 -0
  146. data/external/mime-types/doc/rdoc-style.css +208 -0
  147. data/external/mime-types/lib/mime/types.rb +1558 -0
  148. data/external/package.rb +672 -0
  149. data/external/test_support.rb +95 -0
  150. data/external/tmail/README +7 -0
  151. data/external/tmail/tmail.rb +4 -0
  152. data/external/tmail/tmail/address.rb +222 -0
  153. data/external/tmail/tmail/base64.rb +52 -0
  154. data/external/tmail/tmail/compat.rb +39 -0
  155. data/external/tmail/tmail/config.rb +50 -0
  156. data/external/tmail/tmail/encode.rb +447 -0
  157. data/external/tmail/tmail/header.rb +895 -0
  158. data/external/tmail/tmail/info.rb +14 -0
  159. data/external/tmail/tmail/loader.rb +1 -0
  160. data/external/tmail/tmail/mail.rb +869 -0
  161. data/external/tmail/tmail/mailbox.rb +386 -0
  162. data/external/tmail/tmail/mbox.rb +1 -0
  163. data/external/tmail/tmail/net.rb +260 -0
  164. data/external/tmail/tmail/obsolete.rb +123 -0
  165. data/external/tmail/tmail/parser.rb +1475 -0
  166. data/external/tmail/tmail/parser.y +372 -0
  167. data/external/tmail/tmail/port.rb +356 -0
  168. data/external/tmail/tmail/scanner.rb +17 -0
  169. data/external/tmail/tmail/scanner_r.rb +243 -0
  170. data/external/tmail/tmail/stringio.rb +256 -0
  171. data/external/tmail/tmail/textutils.rb +197 -0
  172. data/external/tmail/tmail/tmail.rb +1 -0
  173. data/external/tmail/tmail/utils.rb +23 -0
  174. data/external/win32-process/README +133 -0
  175. data/external/win32-process/lib/win32/process.rb +561 -0
  176. data/external/windows-pr/README +145 -0
  177. data/external/windows-pr/doc/conversion_guide.txt +25 -0
  178. data/external/windows-pr/lib/windows/clipboard.rb +72 -0
  179. data/external/windows-pr/lib/windows/console.rb +323 -0
  180. data/external/windows-pr/lib/windows/device_io.rb +88 -0
  181. data/external/windows-pr/lib/windows/directory.rb +80 -0
  182. data/external/windows-pr/lib/windows/error.rb +313 -0
  183. data/external/windows-pr/lib/windows/eventlog.rb +120 -0
  184. data/external/windows-pr/lib/windows/file.rb +349 -0
  185. data/external/windows-pr/lib/windows/filesystem.rb +16 -0
  186. data/external/windows-pr/lib/windows/handle.rb +31 -0
  187. data/external/windows-pr/lib/windows/library.rb +76 -0
  188. data/external/windows-pr/lib/windows/limits.rb +13 -0
  189. data/external/windows-pr/lib/windows/memory.rb +117 -0
  190. data/external/windows-pr/lib/windows/msvcrt/buffer.rb +48 -0
  191. data/external/windows-pr/lib/windows/msvcrt/file.rb +18 -0
  192. data/external/windows-pr/lib/windows/msvcrt/string.rb +46 -0
  193. data/external/windows-pr/lib/windows/national.rb +557 -0
  194. data/external/windows-pr/lib/windows/path.rb +296 -0
  195. data/external/windows-pr/lib/windows/pipe.rb +77 -0
  196. data/external/windows-pr/lib/windows/process.rb +171 -0
  197. data/external/windows-pr/lib/windows/registry.rb +238 -0
  198. data/external/windows-pr/lib/windows/security.rb +89 -0
  199. data/external/windows-pr/lib/windows/service.rb +183 -0
  200. data/external/windows-pr/lib/windows/shell.rb +88 -0
  201. data/external/windows-pr/lib/windows/sound.rb +52 -0
  202. data/external/windows-pr/lib/windows/synchronize.rb +161 -0
  203. data/external/windows-pr/lib/windows/system_info.rb +70 -0
  204. data/external/windows-pr/lib/windows/unicode.rb +138 -0
  205. data/external/windows-pr/lib/windows/window.rb +22 -0
  206. data/iowa.gemspec +45 -0
  207. data/microprojects/DiskCache/LICENSE +28 -0
  208. data/microprojects/DiskCache/README +17 -0
  209. data/microprojects/DiskCache/external/package.rb +608 -0
  210. data/microprojects/DiskCache/external/test_support.rb +8 -0
  211. data/microprojects/DiskCache/setup.rb +22 -0
  212. data/microprojects/DiskCache/src/iowa/Association.rb +67 -0
  213. data/microprojects/DiskCache/src/iowa/Constants.rb +159 -0
  214. data/microprojects/DiskCache/src/iowa/DiskStore.rb +377 -0
  215. data/microprojects/DiskCache/src/iowa/Hash.rb +63 -0
  216. data/microprojects/DiskCache/src/iowa/Lockfile.rb +575 -0
  217. data/microprojects/DiskCache/src/iowa/Mutex.rb +142 -0
  218. data/microprojects/DiskCache/src/iowa/caches/DiskCache.rb +605 -0
  219. data/microprojects/DiskCache/src/iowa/caches/LRUCache.rb +287 -0
  220. data/microprojects/DiskCache/test/TC_DiskCache.rb +218 -0
  221. data/microprojects/LRUCache/LICENSE +28 -0
  222. data/microprojects/LRUCache/README +13 -0
  223. data/microprojects/LRUCache/external/package.rb +608 -0
  224. data/microprojects/LRUCache/external/test_support.rb +8 -0
  225. data/microprojects/LRUCache/setup.rb +22 -0
  226. data/microprojects/LRUCache/src/iowa/Association.rb +57 -0
  227. data/microprojects/LRUCache/src/iowa/Constants.rb +159 -0
  228. data/microprojects/LRUCache/src/iowa/Hash.rb +63 -0
  229. data/microprojects/LRUCache/src/iowa/Mutex.rb +129 -0
  230. data/microprojects/LRUCache/src/iowa/caches/LRUCache.rb +287 -0
  231. data/microprojects/LRUCache/test/TC_LRUCache.rb +65 -0
  232. data/microprojects/LinkedList/LICENSE +28 -0
  233. data/microprojects/LinkedList/README +13 -0
  234. data/microprojects/LinkedList/external/package.rb +608 -0
  235. data/microprojects/LinkedList/external/test_support.rb +8 -0
  236. data/microprojects/LinkedList/setup.rb +22 -0
  237. data/microprojects/LinkedList/src/iowa/LinkedList.rb +165 -0
  238. data/microprojects/LinkedList/test/TC_LinkedList.rb +42 -0
  239. data/microprojects/README +8 -0
  240. data/setup.rb +116 -0
  241. data/share/iowa/app_skeleton/Main.html +8 -0
  242. data/share/iowa/app_skeleton/Main.iwa +15 -0
  243. data/share/iowa/app_skeleton/app.cnf +48 -0
  244. data/share/iowa/app_skeleton/app.rb +58 -0
  245. data/share/iowa/app_skeleton/models/model.rb +49 -0
  246. data/src/ihc.rb +223 -0
  247. data/src/iowa.cgi +29 -0
  248. data/src/iowa.rb +637 -0
  249. data/src/iowa/AbstractCache.rb +96 -0
  250. data/src/iowa/AcceptLanguage.rb +76 -0
  251. data/src/iowa/Application.rb +928 -0
  252. data/src/iowa/ApplicationStats.rb +72 -0
  253. data/src/iowa/Association.rb +67 -0
  254. data/src/iowa/BindingsParser.rb +62 -0
  255. data/src/iowa/Breakpoint.rb +273 -0
  256. data/src/iowa/CSS.rb +564 -0
  257. data/src/iowa/Client.rb +192 -0
  258. data/src/iowa/Component.rb +405 -0
  259. data/src/iowa/ComponentProxy.rb +26 -0
  260. data/src/iowa/Config.rb +21 -0
  261. data/src/iowa/Constants.rb +226 -0
  262. data/src/iowa/Context.rb +218 -0
  263. data/src/iowa/ContextLogger.rb +16 -0
  264. data/src/iowa/DbPool.rb +222 -0
  265. data/src/iowa/DetachedComponent.rb +18 -0
  266. data/src/iowa/Dispatcher.rb +27 -0
  267. data/src/iowa/DynamicElements.rb +471 -0
  268. data/src/iowa/Element.rb +100 -0
  269. data/src/iowa/Email.rb +287 -0
  270. data/src/iowa/Extensions/AllExtensions.rb +4 -0
  271. data/src/iowa/Extensions/Class.rb +94 -0
  272. data/src/iowa/Extensions/Date.rb +88 -0
  273. data/src/iowa/Extensions/DateTime.rb +88 -0
  274. data/src/iowa/Extensions/Hash.rb +22 -0
  275. data/src/iowa/Extensions/Kernel.rb +6 -0
  276. data/src/iowa/Extensions/Numeric.rb +47 -0
  277. data/src/iowa/Extensions/Object.rb +11 -0
  278. data/src/iowa/Extensions/String.rb +60 -0
  279. data/src/iowa/Extensions/Time.rb +89 -0
  280. data/src/iowa/Extensions/TimeExtensions.rb +6 -0
  281. data/src/iowa/Form.rb +368 -0
  282. data/src/iowa/Hash.rb +85 -0
  283. data/src/iowa/ISAAC.rb +175 -0
  284. data/src/iowa/ImageSize.rb +279 -0
  285. data/src/iowa/IowaComponentMixins.rb +7 -0
  286. data/src/iowa/JSON-lexer.rb +296 -0
  287. data/src/iowa/JSON-objects.rb +201 -0
  288. data/src/iowa/KeyValueCoding.rb +91 -0
  289. data/src/iowa/LinkedList.rb +175 -0
  290. data/src/iowa/Loader.rb +22 -0
  291. data/src/iowa/Lockfile.rb +575 -0
  292. data/src/iowa/Logger.rb +74 -0
  293. data/src/iowa/Monkey.rb +20 -0
  294. data/src/iowa/Mutex.rb +142 -0
  295. data/src/iowa/Policy.rb +70 -0
  296. data/src/iowa/Pool.rb +243 -0
  297. data/src/iowa/PrettyException.rb +1091 -0
  298. data/src/iowa/Request.rb +244 -0
  299. data/src/iowa/Response.rb +133 -0
  300. data/src/iowa/Session.rb +354 -0
  301. data/src/iowa/SessionStats.rb +78 -0
  302. data/src/iowa/String.rb +65 -0
  303. data/src/iowa/Tag.rb +101 -0
  304. data/src/iowa/TemplateParser.rb +236 -0
  305. data/src/iowa/Util.rb +314 -0
  306. data/src/iowa/Webcache.rb +122 -0
  307. data/src/iowa/caches/BiLevelCache.rb +65 -0
  308. data/src/iowa/caches/ClassLimitedCache.rb +67 -0
  309. data/src/iowa/caches/DiskCache.rb +609 -0
  310. data/src/iowa/caches/DiskStore.rb +380 -0
  311. data/src/iowa/caches/LRUCache-alternative.rb +155 -0
  312. data/src/iowa/caches/LRUCache.rb +290 -0
  313. data/src/iowa/caches/SimpleLRUCache.rb +112 -0
  314. data/src/iowa/dispatchers/StandardDispatcher.rb +396 -0
  315. data/src/iowa/dispatchers/StandardDispatcherWithClassifier.rb +93 -0
  316. data/src/iowa/js/iowa_jsonrpc.js +381 -0
  317. data/src/iowa/js/jsonrpc.js +187 -0
  318. data/src/iowa/js/jsonrpc_async.js +261 -0
  319. data/src/iowa/loaders/DiskLoader.rb +50 -0
  320. data/src/iowa/loggers/Analogger.rb +54 -0
  321. data/src/iowa/loggers/AsyncLogger.rb +54 -0
  322. data/src/iowa/loggers/BitBucket.rb +38 -0
  323. data/src/iowa/loggers/Log4R.rb +13 -0
  324. data/src/iowa/loggers/Log4rLogger.rb +48 -0
  325. data/src/iowa/loggers/Logger.rb +29 -0
  326. data/src/iowa/loggers/RubyLogger.rb +9 -0
  327. data/src/iowa/pools/DBConnectionPool.rb +53 -0
  328. data/src/iowa/request/Apache.rb +90 -0
  329. data/src/iowa/request/EMHybrid.rb +59 -0
  330. data/src/iowa/request/ENV.rb +80 -0
  331. data/src/iowa/request/FCGI.rb +68 -0
  332. data/src/iowa/request/HTTPMachine.rb +75 -0
  333. data/src/iowa/request/Mongrel.rb +68 -0
  334. data/src/iowa/request/WEBrick.rb +48 -0
  335. data/src/iowa/version.rb +3 -0
  336. data/src/iowa/webrick/HTTPServer.rb +43 -0
  337. data/src/iowa/webrick/WEBrickServlet.rb +28 -0
  338. data/src/iowa_fcgi_handler.rb +101 -0
  339. data/src/iowa_httpmachine.rb +141 -0
  340. data/src/iowa_hybrid.rb +193 -0
  341. data/src/iowa_hybrid_cluster.rb +231 -0
  342. data/src/iowa_mongrel.rb +136 -0
  343. data/src/iowa_webrick.rb +194 -0
  344. data/src/iowa_webrick_legacy.rb +104 -0
  345. data/src/mod_iowa.rb +104 -0
  346. data/tcss.rb +61 -0
  347. data/test/README.windows +12 -0
  348. data/test/TC_AcceptLanguage.rb +61 -0
  349. data/test/TC_AppConfig.rb +43 -0
  350. data/test/TC_AppConfig/cgi/iowa.cgi +7 -0
  351. data/test/TC_AppConfig/doc/index.html +1 -0
  352. data/test/TC_AppConfig/iowa/Main.html +4 -0
  353. data/test/TC_AppConfig/iowa/Main.iwa +17 -0
  354. data/test/TC_AppConfig/iowa/README +1 -0
  355. data/test/TC_AppConfig/iowa/app.cnf +19 -0
  356. data/test/TC_AppConfig/iowa/app.rb +8 -0
  357. data/test/TC_AppConfig/webrick.rb +38 -0
  358. data/test/TC_Association.rb +29 -0
  359. data/test/TC_BiLevelCache.rb +71 -0
  360. data/test/TC_CGI_Adaptor.rb +55 -0
  361. data/test/TC_CGI_Adaptor/cgi/iowa.cgi +7 -0
  362. data/test/TC_CGI_Adaptor/doc/index.html +1 -0
  363. data/test/TC_CGI_Adaptor/iowa/Main.html +8 -0
  364. data/test/TC_CGI_Adaptor/iowa/Main.iwa +14 -0
  365. data/test/TC_CGI_Adaptor/iowa/README +1 -0
  366. data/test/TC_CGI_Adaptor/iowa/app.cnf +8 -0
  367. data/test/TC_CGI_Adaptor/iowa/app.rb +8 -0
  368. data/test/TC_CGI_Adaptor/webrick.rb +38 -0
  369. data/test/TC_CSS.rb +660 -0
  370. data/test/TC_ClassLimitedCache.rb +89 -0
  371. data/test/TC_Classifier.rb +80 -0
  372. data/test/TC_DbPool.rb +127 -0
  373. data/test/TC_DiskCache.rb +218 -0
  374. data/test/TC_Hybrid.rb +58 -0
  375. data/test/TC_Hybrid/doc/thing.txt +1 -0
  376. data/test/TC_Hybrid/iowa/Main.html +3 -0
  377. data/test/TC_Hybrid/iowa/Main.iwa +7 -0
  378. data/test/TC_Hybrid/iowa/NewPage.html +1 -0
  379. data/test/TC_Hybrid/iowa/NewPage.iwa +5 -0
  380. data/test/TC_Hybrid/iowa/app.cnf +10 -0
  381. data/test/TC_Hybrid/iowa/app.rb +5 -0
  382. data/test/TC_IOWAFunctions/doc/Ajax1.html +1 -0
  383. data/test/TC_IOWAFunctions/doc/Ajax1.iwa +1 -0
  384. data/test/TC_IOWAFunctions/doc/index.html +1 -0
  385. data/test/TC_IOWAFunctions/doc/js/dojo.js +9686 -0
  386. data/test/TC_IOWAFunctions/iowa/Ajax1.html +40 -0
  387. data/test/TC_IOWAFunctions/iowa/Ajax1.iwa +23 -0
  388. data/test/TC_IOWAFunctions/iowa/AjaxWidget.iwa +19 -0
  389. data/test/TC_IOWAFunctions/iowa/AjaxWidget.view +22 -0
  390. data/test/TC_IOWAFunctions/iowa/DanielTest.html +9 -0
  391. data/test/TC_IOWAFunctions/iowa/DanielTest.iwa +10 -0
  392. data/test/TC_IOWAFunctions/iowa/IntervalWidget.html +1 -0
  393. data/test/TC_IOWAFunctions/iowa/IntervalWidget.iwa +14 -0
  394. data/test/TC_IOWAFunctions/iowa/Main.html +1 -0
  395. data/test/TC_IOWAFunctions/iowa/NestedRepeat1.html +12 -0
  396. data/test/TC_IOWAFunctions/iowa/NestedRepeat1.iwa +24 -0
  397. data/test/TC_IOWAFunctions/iowa/RPCResponse.iwa +7 -0
  398. data/test/TC_IOWAFunctions/iowa/RPCResponse.view +1 -0
  399. data/test/TC_IOWAFunctions/iowa/Repeat1.iwa +31 -0
  400. data/test/TC_IOWAFunctions/iowa/Repeat1.view +9 -0
  401. data/test/TC_IOWAFunctions/iowa/Repeat2.iwa +32 -0
  402. data/test/TC_IOWAFunctions/iowa/Repeat2.view +11 -0
  403. data/test/TC_IOWAFunctions/iowa/Repeat3.iwa +44 -0
  404. data/test/TC_IOWAFunctions/iowa/Repeat3.view +18 -0
  405. data/test/TC_IOWAFunctions/iowa/TesCon.html +1 -0
  406. data/test/TC_IOWAFunctions/iowa/TesCon.iwa +5 -0
  407. data/test/TC_IOWAFunctions/iowa/app.cnf +19 -0
  408. data/test/TC_IOWAFunctions/iowa/app.rb +9 -0
  409. data/test/TC_IOWAFunctions/iowa/mapfile.cnf +8 -0
  410. data/test/TC_ISAAC.rb +52 -0
  411. data/test/TC_ImageSize.rb +84 -0
  412. data/test/TC_ImageSize/img.bmp +0 -0
  413. data/test/TC_ImageSize/img.gif +0 -0
  414. data/test/TC_ImageSize/img.jpg +0 -0
  415. data/test/TC_ImageSize/img.pcx +0 -0
  416. data/test/TC_ImageSize/img.pgm +7144 -0
  417. data/test/TC_ImageSize/img.png +0 -0
  418. data/test/TC_ImageSize/img.ppm +0 -0
  419. data/test/TC_ImageSize/img.psd +0 -0
  420. data/test/TC_ImageSize/img.tiff +0 -0
  421. data/test/TC_ImageSize/img.xbm +22 -0
  422. data/test/TC_KeyValueCoding.rb +35 -0
  423. data/test/TC_LRUCache.rb +296 -0
  424. data/test/TC_LinkedList.rb +46 -0
  425. data/test/TC_Lockfile.rb +106 -0
  426. data/test/TC_Minimal.rb +45 -0
  427. data/test/TC_Minimal/app.cnf +8 -0
  428. data/test/TC_Minimal/cgi-bin/iowa.cgi +11 -0
  429. data/test/TC_Minimal/doc/index.html +1 -0
  430. data/test/TC_Minimal/iowa/Main.html +1 -0
  431. data/test/TC_Minimal/iowa/README +1 -0
  432. data/test/TC_Minimal/iowa/app.rb +3 -0
  433. data/test/TC_Minimal/webrick.rb +38 -0
  434. data/test/TC_Mongrel.rb +58 -0
  435. data/test/TC_Mongrel/doc/thing.txt +1 -0
  436. data/test/TC_Mongrel/iowa/Main.html +3 -0
  437. data/test/TC_Mongrel/iowa/Main.iwa +7 -0
  438. data/test/TC_Mongrel/iowa/NewPage.html +1 -0
  439. data/test/TC_Mongrel/iowa/NewPage.iwa +5 -0
  440. data/test/TC_Mongrel/iowa/app.cnf +10 -0
  441. data/test/TC_Mongrel/iowa/app.rb +5 -0
  442. data/test/TC_NoSubclass.rb +56 -0
  443. data/test/TC_NoSubclass/cgi/iowa.cgi +7 -0
  444. data/test/TC_NoSubclass/doc/index.html +1 -0
  445. data/test/TC_NoSubclass/iowa/Main.html +8 -0
  446. data/test/TC_NoSubclass/iowa/Main.iwa +14 -0
  447. data/test/TC_NoSubclass/iowa/README +1 -0
  448. data/test/TC_NoSubclass/iowa/app.cnf +8 -0
  449. data/test/TC_NoSubclass/iowa/app.rb +5 -0
  450. data/test/TC_NoSubclass/webrick.rb +38 -0
  451. data/test/TC_Pool.rb +139 -0
  452. data/test/TC_RenderedCache/doc/thing.txt +1 -0
  453. data/test/TC_RenderedCache/iowa/BigPage.html +1 -0
  454. data/test/TC_RenderedCache/iowa/BigPage.iwa +12 -0
  455. data/test/TC_RenderedCache/iowa/Main.html +3 -0
  456. data/test/TC_RenderedCache/iowa/Main.iwa +7 -0
  457. data/test/TC_RenderedCache/iowa/NewPage.html +1 -0
  458. data/test/TC_RenderedCache/iowa/NewPage.iwa +11 -0
  459. data/test/TC_RenderedCache/iowa/app.cnf +13 -0
  460. data/test/TC_RenderedCache/iowa/app.rb +5 -0
  461. data/test/TC_RenderedCache/iowa/mapfile.map +4 -0
  462. data/test/TC_ResourceURL.rb +73 -0
  463. data/test/TC_ResourceURL/iowa/Main.html +2 -0
  464. data/test/TC_ResourceURL/iowa/Main.iwa +10 -0
  465. data/test/TC_ResourceURL/iowa/app.cnf +10 -0
  466. data/test/TC_ResourceURL/iowa/app.rb +5 -0
  467. data/test/TC_SimpleDetached.rb +41 -0
  468. data/test/TC_StandardDispatcher.rb +362 -0
  469. data/test/TC_StandardDispatcherWithClassifier.rb +358 -0
  470. data/test/TC_String.rb +24 -0
  471. data/test/TC_Tag.rb +41 -0
  472. data/test/TC_Webrick.rb +56 -0
  473. data/test/TC_Webrick/doc/thing.txt +1 -0
  474. data/test/TC_Webrick/iowa/Main.html +3 -0
  475. data/test/TC_Webrick/iowa/Main.iwa +7 -0
  476. data/test/TC_Webrick/iowa/NewPage.html +1 -0
  477. data/test/TC_Webrick/iowa/NewPage.iwa +5 -0
  478. data/test/TC_Webrick/iowa/app.cnf +10 -0
  479. data/test/TC_Webrick/iowa/app.rb +5 -0
  480. data/test/tc_template.rb +15 -0
  481. data/test/tests.conf +19 -0
  482. data/utils/CVS/Entries +3 -0
  483. data/utils/CVS/Repository +1 -0
  484. data/utils/CVS/Root +1 -0
  485. data/utils/QuickCert-1.0.2.tar.gz +0 -0
  486. data/utils/QuickCert-1.0.2/InstalledFiles +7 -0
  487. data/utils/QuickCert-1.0.2/MANIFEST +10 -0
  488. data/utils/QuickCert-1.0.2/Makefile +15 -0
  489. data/utils/QuickCert-1.0.2/README +56 -0
  490. data/utils/QuickCert-1.0.2/bin/QuickCert +355 -0
  491. data/utils/QuickCert-1.0.2/config.save +12 -0
  492. data/utils/QuickCert-1.0.2/data/examples/ruby/QuickCert/README +60 -0
  493. data/utils/QuickCert-1.0.2/data/examples/ruby/QuickCert/drbssl_c.rb +26 -0
  494. data/utils/QuickCert-1.0.2/data/examples/ruby/QuickCert/drbssl_s.rb +35 -0
  495. data/utils/QuickCert-1.0.2/data/examples/ruby/QuickCert/qc_config +21 -0
  496. data/utils/QuickCert-1.0.2/lib/QuickCert/defaults.rb +28 -0
  497. data/utils/QuickCert-1.0.2/setup.rb +1312 -0
  498. data/utils/iowa_apps +422 -0
  499. data/utils/smtp_sink.rb +9 -0
  500. data/utils/startup_template.cnf +27 -0
  501. data/utils/startup_template.rb +73 -0
  502. metadata +551 -0
@@ -0,0 +1,142 @@
1
+ module Iowa
2
+
3
+ # Iowa::Mutex is a slight modification of the standard Ruby Mutex class.
4
+ # This class changes the array operations used to manage the queue of
5
+ # threads waiting for a lock in order to get better memory management
6
+ # behavior from the array. This mutex will also not block if the thread
7
+ # holding a lock on a mutex calls lock on that mutex again. If nested
8
+ # locking occurs, the locks must be matched by an equal number of unlocks
9
+ # before the mutex will actually be unlocked.
10
+
11
+ class Mutex
12
+
13
+ # Creates a new Mutex.
14
+
15
+ def initialize
16
+ @waiting = []
17
+ @locked = false;
18
+ @nested_locks = 0
19
+ @waiting.taint # enable tainted comunication
20
+ self.taint
21
+ end
22
+
23
+
24
+ # Returns the thread that holds the lock or +false+ if the mutex is not locked.
25
+
26
+ def locked?
27
+ @locked
28
+ end
29
+
30
+
31
+ # Attempts to obtain the lock and returns immediately. Returns +true+ if the
32
+ # lock was granted.
33
+
34
+ def try_lock
35
+ @nested_locks += 1 and return true if @locked == Thread.current
36
+ result = false
37
+ Thread.critical = true
38
+ unless @locked
39
+ @locked = Thread.current
40
+ result = true
41
+ end
42
+ Thread.critical = false
43
+ result
44
+ end
45
+
46
+
47
+ # Attempts to obtain a lock on the mutex. Block if a lock can not be
48
+ # obtained immediately and waits until the lock can be obtained.
49
+ # If this thread already holds this lock, returns immediately.
50
+ # Returns the mutex.
51
+
52
+ def lock
53
+ if @locked == Thread.current
54
+ @nested_locks += 1
55
+ else
56
+ while (Thread.critical = true; @locked)
57
+ @waiting.unshift Thread.current
58
+ Thread.stop
59
+ end
60
+ @locked = Thread.current
61
+ Thread.critical = false
62
+ end
63
+ self
64
+ end
65
+
66
+
67
+ # Releases this thread's lock on the mutex and wakes the next thread
68
+ # waiting for the lock, if any.
69
+
70
+ def unlock
71
+ return unless @locked
72
+ if @nested_locks > 0
73
+ @nested_locks -= 1
74
+ else
75
+ Thread.critical = true
76
+ @locked = false
77
+ begin
78
+ t = @waiting.pop
79
+ t.wakeup if t
80
+ rescue ThreadError
81
+ retry
82
+ end
83
+ Thread.critical = false
84
+ begin
85
+ t.run if t
86
+ rescue ThreadError
87
+ end
88
+ end
89
+ self
90
+ end
91
+
92
+
93
+ # If the mutex is locked, unlocks the mutex, wakes one waiting thread, and
94
+ # yields in a critical section.
95
+
96
+ def exclusive_unlock
97
+ return unless @locked
98
+ if @nested_locks > 0
99
+ @nested_locks -= 1
100
+ else
101
+ Thread.exclusive do
102
+ @locked = false
103
+ begin
104
+ t = @waiting.pop
105
+ t.wakeup if t
106
+ rescue ThreadError
107
+ retry
108
+ end
109
+ yield
110
+ end
111
+ end
112
+ self
113
+ end
114
+
115
+
116
+ # Obtains a lock, runs the block, and releases the lock when the block
117
+ # completes. See the example under Mutex.
118
+
119
+ def synchronize
120
+ lock
121
+ begin
122
+ yield
123
+ ensure
124
+ unlock
125
+ end
126
+ end
127
+
128
+ def synchronize_unless(cnd)
129
+ unless cnd
130
+ lock
131
+ begin
132
+ yield
133
+ ensure
134
+ unlock
135
+ end
136
+ else
137
+ yield
138
+ end
139
+ end
140
+
141
+ end
142
+ end
@@ -0,0 +1,605 @@
1
+ require 'iowa/Mutex'
2
+ require 'iowa/Lockfile'
3
+ require 'digest/sha2'
4
+ require 'fileutils'
5
+ require 'find'
6
+ require 'tmpdir'
7
+ require 'iowa/LRUCache'
8
+
9
+ module Iowa
10
+
11
+ module Caches
12
+
13
+ # DiskCache is an LRU cache, but it's data store is not a RAM store.
14
+ # Rather, it serializes its objects to disk. Generally, if an item
15
+ # is found in an DiskCache, it should be freshened into an in-RAM
16
+ # cache and deleted from the DiskCache.
17
+ #
18
+ # The intent of this cache is that it can, with flat RAM usage,
19
+ # cache, indefinitely, an arbitrary number of elements.
20
+ # So, there needs to be a fast way of representing the cache and
21
+ # and queue to disk. The TTL cache from the standard LRUCache
22
+ # is not needed because the filesystem will provide that information.
23
+ # The filesystem will also be used to preserve the other data, as well.
24
+ #
25
+ # The system will implement the cache as an on-disk linked list.
26
+ # By storing the elements in disk buckets based on a very simple
27
+ # hasing of the keys, we'll avoid storing all files into the same
28
+ # directory, and by storing files according to a hashing of the key,
29
+ # we allow efficient lookup of a cache entry. Each entry will have
30
+ # a data file accompanying it that will encode the key of the
31
+ # element ahead of it and behind it in the cache. There will also
32
+ # be a special data file that will encode the first and last
33
+ # elements in the list.
34
+ # This will permit rapid access to an individual element, and
35
+ # manipulation of the list without keeping in RAM any permanent
36
+ # state information on the list.
37
+ #
38
+ # Locking can be done with just a mutex, or if used in a
39
+ # multiprocess capacity, locking can be done with a lockfile from
40
+ # Iowa::Lockfile.
41
+ #
42
+
43
+ class DiskCache
44
+
45
+ DEFAULT_BUCKET_WIDTH = 2
46
+ DEFAULT_BUCKET_DEPTH = 2
47
+
48
+ class NoCacheDir < Exception
49
+ def initialize(*args)
50
+ @bad_dir = args[0]
51
+ end
52
+
53
+ def to_s
54
+ "The cache directory (#{@bad_dir}) does not exist."
55
+ end
56
+ end
57
+
58
+ class DirNotEmpty < Exception
59
+ def initialize(*args)
60
+ @bad_dir = args[0]
61
+ end
62
+
63
+ def to_s
64
+ "The cache directory (#{@bad_dir}) is not empty."
65
+ end
66
+ end
67
+
68
+ class DeletedValue
69
+ attr_accessor :val
70
+ def initialize(v)
71
+ @val = v
72
+ end
73
+ end
74
+
75
+ def initialize(arg1, force = nil, width = DEFAULT_BUCKET_WIDTH, depth = DEFAULT_BUCKET_DEPTH, use_lockfile = false)
76
+ @transaction_cache = []
77
+ @transaction_lock = [nil,Iowa::Mutex.new]
78
+ @cache_dir = nil
79
+ if arg1.respond_to?(:keys)
80
+ oargs = arg1
81
+ arg1 = Iowa::Hash.new
82
+ arg1.step_merge!(oargs)
83
+ arg1.stringify_keys!
84
+ if arg1[Cdirectory]
85
+ @cache_dir = arg1[Cdirectory]
86
+ else
87
+ @cache_dir = File.join(Dir::tmpdir,"tmp#{Time.now.to_f}")
88
+ FileUtils.mkdir(@cache_dir)
89
+ end
90
+ set_cachefile_paths
91
+ force = arg1[Cforce] || force
92
+ arg1[Cmaxsize] ||= getdata(@cache_maxsize) if FileTest.exist?(@cache_maxsize)
93
+ arg1[Cttl] ||= getdata(@cache_maxttl) if FileTest.exist?(@cache_maxttl)
94
+ arg1[Cmaxsize] ||= 1000
95
+ @bucket_depth = arg1[Cdepth] || depth
96
+ @bucket_width = arg1[Cwidth] || width
97
+ @use_lockfile = arg1[Cuse_lockfile] || use_lockfile
98
+ else
99
+ @cache_dir = arg1
100
+ set_cachefile_paths
101
+ arg1 = {}
102
+ arg1[Cmaxsize] = getdata(@cache_maxsize) if FileTest.exist?(@cache_maxsize)
103
+ arg1[Cttl] = getdata(@cache_maxttl) if FileTest.exist?(@cache_maxttl)
104
+ @bucket_depth = depth
105
+ @bucket_width = width
106
+ @use_lockfile = use_lockfile
107
+ end
108
+
109
+ if arg1.kind_of? ::Hash
110
+ oargs = arg1
111
+ arg1 = Iowa::Hash.new
112
+ arg1.step_merge!(oargs)
113
+ end
114
+ arg1.stringify_keys! if arg1.respond_to? :stringify_keys!
115
+ @max = arg1[Cmaxsize]
116
+ @maxttl = arg1[Cttl]
117
+
118
+ @bucket_depth_array = (0..(@bucket_depth - 1)).to_a
119
+ @locked = false
120
+
121
+ unless @use_lockfile
122
+ @mutex = Iowa::Mutex.new
123
+ else
124
+ @lockfile = Iowa::Lockfile.new(File::join(@cache_dir,'cachelock.lck'))
125
+ end
126
+
127
+ if !FileTest.exist?(@cache_dir)
128
+ if force
129
+ # Force creation of the directory.
130
+ FileUtils.mkdir_p(@cache_dir)
131
+ else
132
+ # Dir doesn't exist, and we aren't forcing, so throw exception.
133
+ raise Iowa::Caches::DiskCache::NoCacheDir.new(@cache_dir)
134
+ end
135
+ end
136
+
137
+ # Check to see if directory is empty.
138
+ # If empty, create head and tail files.
139
+ # If not empty, and lacks head and tail files, and create new, empty
140
+ # head and tail files if force is set, or throw exception if unset.
141
+ # If it has head and tail files, cheer and move on.
142
+
143
+ lock_cache do
144
+ if Dir[File.join(@cache_dir,'*')].length == 0
145
+ create_head_and_tail_files
146
+ else
147
+ if !(FileTest.exist?(@cache_head) and FileTest.exist?(@cache_tail))
148
+ if force
149
+ create_head_and_tail_files
150
+ else
151
+ raise Iowa::Caches::DiskCache::DirNotEmpty
152
+ end
153
+ end
154
+ end
155
+ end
156
+
157
+ # Yay. There is an existing cache!
158
+
159
+ putdata(@max,@cache_maxsize)
160
+ putdata(@maxttl,@cache_maxttl)
161
+ end
162
+
163
+ # Check to see if the cache contains the given key.
164
+
165
+ def include?(key)
166
+ if !@bypass_transactions and transaction_cache_include?(key)
167
+ if transaction_cache_get(key).is_a?(DeletedValue)
168
+ false
169
+ else
170
+ true
171
+ end
172
+ else
173
+ FileTest.exist?(datafile_for_key(key))
174
+ end
175
+ end
176
+
177
+ # Remove a key/value pair from the cache, by key.
178
+
179
+ def delete(key)
180
+ lock_cache do
181
+ if !@bypass_transactions and transaction_cache_include?(key)
182
+ tcg = transaction_cache_get(key)
183
+ unless tcg.is_a?(DeletedValue)
184
+ @transaction_cache.last[key] = DeletedValue.new(tcg)
185
+ end
186
+ elsif FileTest.exist?(datafile_for_key(key))
187
+ if @transaction_lock[0] and @transaction_cache.length > 0
188
+ @transaction_cache.last[key] = DeletedValue.new(self[key])
189
+ else
190
+ # Open the inf file and find this elements head and tail.
191
+
192
+ links = getdata(linkfile_for_key(key),false)
193
+
194
+ # Delete the dat file and the inf file.
195
+
196
+ File::unlink(linkfile_for_key(key))
197
+ File::unlink(datafile_for_key(key))
198
+ File::unlink(keyfile_for_key(key))
199
+
200
+ # Open the inf file for the head and tail and point them
201
+ # at eachother.
202
+
203
+ if links[:head]
204
+ headlink_file = File.join(path_for_hash(links[:head]),"#{links[:head]}.inf")
205
+ headlinks = getdata(headlink_file,false)
206
+ headlinks[:tail] = links[:tail]
207
+ putdata(headlinks,headlink_file)
208
+ else
209
+
210
+ # This element is the head of the list. So, it's tail is the new head.
211
+
212
+ putdata(links[:tail],@cache_head)
213
+ end
214
+
215
+ if links[:tail]
216
+ taillink_file = File.join(path_for_hash(links[:tail]),"#{links[:tail]}.inf")
217
+ taillinks = getdata(taillink_file,false)
218
+ taillinks[:head] = links[:head]
219
+ putdata(taillinks,taillink_file)
220
+ else
221
+
222
+ # This element is the tail of the list. So, it's head is the new tail.
223
+
224
+ putdata(links[:head],@cache_tail)
225
+ end
226
+
227
+ # Finally, reduce the cache counter.
228
+
229
+ new_count = getdata(@cache_count,false) - 1
230
+ putdata(new_count,@cache_count)
231
+ end
232
+ end
233
+ end
234
+ end
235
+
236
+ # Return the element identified by the given key.
237
+
238
+ def [](key)
239
+ r = nil
240
+ lock_cache do
241
+ if !@bypass_transactions and transaction_cache_include?(key)
242
+ transaction_cache_get(key)
243
+ else
244
+ datafile = datafile_for_key(key)
245
+ if FileTest.exist?(datafile)
246
+ #r = getdata(datafile)
247
+ FileUtils::touch(datafile)
248
+ links = getdata(linkfile_for_key(key),false)
249
+
250
+ if links[:head]
251
+ headlink_file = File.join(path_for_hash(links[:head]),"#{links[:head]}.inf")
252
+ headlinks = getdata(headlink_file,false)
253
+ headlinks[:tail] = links[:tail]
254
+ putdata(headlinks,headlink_file)
255
+ else
256
+ putdata(links[:tail],@cache_head)
257
+ end
258
+
259
+ if links[:tail]
260
+ taillink_file = File.join(path_for_hash(links[:tail]),"#{links[:tail]}.inf")
261
+ taillinks = getdata(taillink_file,false)
262
+ taillinks[:head] = links[:head]
263
+ putdata(taillinks,taillink_file)
264
+ else
265
+ putdata(links[:head],@cache_tail)
266
+ end
267
+
268
+ current_head = getdata(@cache_head,false)
269
+ current_key_hash = hash_for_key(key)
270
+ unless current_key_hash == current_head
271
+ current_tail = getdata(@cache_tail,false)
272
+ putdata({:head => nil, :tail => current_head},linkfile_for_key(key))
273
+ putdata(current_key_hash,@cache_head)
274
+ putdata(current_key_hash,@cache_tail) unless current_tail
275
+ if current_head
276
+ taillink_file = File.join(path_for_hash(current_head),"#{current_head}.inf")
277
+ taillinks = getdata(taillink_file,false)
278
+ taillinks[:head] = current_key_hash
279
+ putdata(taillinks,taillink_file)
280
+ end
281
+ end
282
+ r = getdata(datafile,false)
283
+ end
284
+ end
285
+ end
286
+ r
287
+ end
288
+
289
+ def prune
290
+ tail = getdata(@cache_tail)
291
+ delete(getdata(File.join(path_for_hash(tail),"#{tail}.key"))) if tail
292
+ end
293
+
294
+ def attach(key, val)
295
+ # Values are always attached at the head of the list.
296
+ lock_cache do
297
+ already_in_cache = include?(key)
298
+
299
+ putdata((getdata(@cache_count) + 1),@cache_count,false) unless already_in_cache
300
+ # Write the data file.
301
+ putdata(val,datafile_for_key(key))
302
+ # Write the key file.
303
+ putdata(key,keyfile_for_key(key)) unless already_in_cache
304
+
305
+ if already_in_cache
306
+ links = getdata(linkfile_for_key(key),false)
307
+
308
+ if links[:head]
309
+ headlink_file = File.join(path_for_hash(links[:head]),"#{links[:head]}.inf")
310
+ headlinks = getdata(headlink_file,false)
311
+ headlinks[:tail] = links[:tail]
312
+ putdata(headlinks,headlink_file)
313
+ else
314
+ putdata(links[:tail],@cache_head)
315
+ end
316
+
317
+ if links[:tail]
318
+ taillink_file = File.join(path_for_hash(links[:tail]),"#{links[:tail]}.inf")
319
+ taillinks = getdata(taillink_file,false)
320
+ taillinks[:head] = links[:head]
321
+ putdata(taillinks,taillink_file)
322
+ else
323
+ putdata(links[:head],@cache_tail)
324
+ end
325
+ end
326
+
327
+ # Get the current head of the list.
328
+ current_head = getdata(@cache_head,false)
329
+ current_key_hash = hash_for_key(key)
330
+ unless current_key_hash == current_head
331
+ # Get the current tail of the list.
332
+ current_tail = getdata(@cache_tail,false)
333
+ # Write the link file for the new head.
334
+ putdata({:head => nil, :tail => current_head},linkfile_for_key(key))
335
+ # Change the cache_head so it points to the new head.
336
+ putdata(current_key_hash,@cache_head)
337
+ # If the tail wasn't pointint to anything, the list was empty.
338
+ # Point it to this record.
339
+ putdata(current_key_hash,@cache_tail) unless current_tail
340
+ # Change the old head so that it points to the new element as its head.
341
+ if current_head
342
+ taillink_file = File.join(path_for_hash(current_head),"#{current_head}.inf")
343
+ taillinks = getdata(taillink_file,false)
344
+ taillinks[:head] = current_key_hash
345
+ putdata(taillinks,taillink_file)
346
+ end
347
+ end
348
+ end
349
+ end
350
+
351
+ # Set the element of the cache identified by the given key.
352
+
353
+ def []=(key, val)
354
+ lock_cache do
355
+ if !@bypass_transactions and @transaction_cache.length > 0
356
+ @transaction_cache.last[key] = val
357
+ else
358
+ attach(key, val)
359
+ mxsz = getdata(@cache_maxsize,false)
360
+ if mxsz > 0
361
+ prune while getdata(@cache_count,false) > mxsz
362
+ end
363
+ maxttl = getdata(@cache_maxttl,false)
364
+ if maxttl
365
+ expiration = Time.now.to_i - maxttl
366
+ prune while (getdata(@cache_count,false) > 0) && (File::stat(datafile_for_key(getdata(@cache_tail,false))).mtime.to_i < expiration)
367
+ end
368
+ end
369
+ end
370
+ end
371
+
372
+ # Allows one to set the maximum size of the cache queue. If the queue
373
+ # is currently larger than the size that it is being set to, elements
374
+ # will be expired until the queue is at the maximum size.
375
+
376
+ def size=(max)
377
+ lock_cache do
378
+ prune while getdata(@cache_count,false) > max
379
+ putdata(max,@cache_maxsize)
380
+ end
381
+ end
382
+ alias maxsize= size=
383
+
384
+ # Return the maximum size of the cache.
385
+ def maxsize
386
+ getdata(@cache_maxsize)
387
+ end
388
+
389
+ # Return the current size of the cache.
390
+ def size
391
+ getdata(@cache_count)
392
+ end
393
+
394
+ def ttl=(newttl)
395
+ newttl = newttl ? newttl.to_i : nil
396
+ if @maxttl
397
+ lock_cache do
398
+ expiration = Time.now.to_i - newttl
399
+ prune while (getdata(@cache_count,false) > 0) && (File::stat(datafile_for_key(getdata(@cache_tail,false))).mtime.to_i < expiration)
400
+ end
401
+ end
402
+ putdata(newttl,@cache_maxttl)
403
+ end
404
+ alias maxttl= ttl=
405
+
406
+ def ttl
407
+ getdata(@maxttl)
408
+ end
409
+
410
+ # Return a copy of current set of keys to cache elements.
411
+ def queue
412
+ r = []
413
+ #Find::find(@cache_dir) do |p|
414
+ # if p =~ /#{File::SEPARATOR}[^#{File::SEPARATOR}]+.key$/
415
+ # r.push getdata(p)
416
+ # end
417
+ #end
418
+ n = getdata(@cache_head)
419
+ loop do
420
+ links = getdata(File.join(path_for_hash(n),"#{n}.inf"))
421
+ r.push getdata(File.join(path_for_hash(n),"#{n}.key"))
422
+ break if links[:tail] == nil
423
+ n = links[:tail]
424
+ end
425
+ r
426
+ end
427
+
428
+ def transaction(&b)
429
+ Thread.critical = true
430
+ if @transaction_lock[0] and @transaction_cache.length > 0
431
+ if Thread.current == @transaction_lock[0]
432
+ Thread.critical = false
433
+ inner_transaction(b)
434
+ return true
435
+ end
436
+ else
437
+ @transaction_lock[0] = Thread.current
438
+ end
439
+ Thread.critical = false
440
+ @transaction_lock[1].synchronize {inner_transaction(b)}
441
+ @transaction_lock[0] = nil
442
+ end
443
+
444
+ def commit(final = false)
445
+ Thread.critical = true
446
+ transactions = @transaction_cache.pop
447
+ q = transactions.queue
448
+ (q.length - 1).downto(0) do |x|
449
+ k = q[x]
450
+ v = transactions[k]
451
+ if v.is_a?(DeletedValue)
452
+ @bypass_transactions = true
453
+ self.delete(k)
454
+ @bypass_transactions = false
455
+ else
456
+ @bypass_transactions = true
457
+ self[k] = transactions[k]
458
+ @bypass_transactions = false
459
+ end
460
+ end
461
+ unless final
462
+ @transaction_cache.push Iowa::Caches::LRUCache.new({:maxsize => 4294967296})
463
+ end
464
+ Thread.critical = false
465
+ end
466
+
467
+ def rollback
468
+ Thread.critical = true
469
+ @transaction_cache.pop
470
+ @transaction_cache.push Iowa::Caches::LRUCache.new({:maxsize => 4294967296})
471
+ Thread.critical = true
472
+ end
473
+
474
+ private
475
+
476
+ def inner_transaction(blk)
477
+ @transaction_cache.push Iowa::Caches::LRUCache.new({:maxsize => 4294967296})
478
+ blk.call
479
+ Thread.critical = true
480
+ commit(true)
481
+ Thread.critical = false
482
+ end
483
+
484
+ def transaction_cache_include?(key)
485
+ @transaction_cache.each do |tc|
486
+ return true if tc.include? key
487
+ end
488
+ false
489
+ end
490
+
491
+ def transaction_cache_get(key)
492
+ (@transaction_cache.length - 1).downto(0) do |x|
493
+ return @transaction_cache[x][key] if @transaction_cache[x].include?(key)
494
+ end
495
+ nil
496
+ end
497
+
498
+ def lock_cache
499
+ Thread.critical = true
500
+ transaction_in_progress = (@transaction_lock[0] and @transaction_cache.length > 0) ? true : false
501
+ @transaction_lock[0] = Thread.current unless transaction_in_progress
502
+ Thread.critical = false if transaction_in_progress
503
+ @transaction_lock[1].synchronize_unless(@transaction_lock[0] == Thread.current) do
504
+ Thread.critical = false unless transaction_in_progress
505
+ unless @locked
506
+ begin
507
+ if @use_lockfile
508
+ @lockfile.lock {@locked = true; yield}
509
+ else
510
+ @mutex.synchronize {@locked = true; yield}
511
+ end
512
+ ensure
513
+ @locked = false
514
+ end
515
+ else
516
+ yield
517
+ end
518
+ end
519
+ @transaction_lock[0] = nil unless transaction_in_progress
520
+ end
521
+
522
+ def create_head_and_tail_files
523
+ putdata(nil,@cache_head)
524
+ putdata(nil,@cache_tail)
525
+ putdata(0,@cache_count)
526
+ putdata(@max,@cache_maxsize)
527
+ putdata(@maxttl,@cache_maxttl)
528
+ end
529
+
530
+ def hash_for_key(key)
531
+ k = Marshal.dump(key)
532
+ "#{Digest::SHA512.new(k).hexdigest}"
533
+ end
534
+
535
+ def path_for_hash(hash)
536
+ # Take the hash key and break it apart by bucket_depth and bucket_width
537
+ # to return the path to the directory that should contain the
538
+ # cache element.
539
+ File.join(@cache_dir,@bucket_depth_array.collect {|d| hash[(d * @bucket_width),@bucket_width]})
540
+ end
541
+
542
+ def datafile_for_key(key)
543
+ h = hash_for_key(key)
544
+ File.join(path_for_hash(h),"#{h}.dat")
545
+ end
546
+
547
+ def linkfile_for_key(key)
548
+ h = hash_for_key(key)
549
+ File.join(path_for_hash(h),"#{h}.inf")
550
+ end
551
+
552
+ def keyfile_for_key(key)
553
+ h = hash_for_key(key)
554
+ File.join(path_for_hash(h),"#{h}.key")
555
+ end
556
+
557
+ def getdata(filename,do_lock = true)
558
+ r = nil
559
+ if do_lock
560
+ lock_cache do
561
+ if FileTest::exist?(filename)
562
+ File.open(filename) {|fh| r = Marshal.load(fh)}
563
+ end
564
+ end
565
+ else
566
+ if FileTest::exist?(filename)
567
+ File.open(filename) {|fh| r = Marshal.load(fh)}
568
+ end
569
+ end
570
+ r
571
+ end
572
+
573
+ def getdata_worker(filename)
574
+ if FileTest::exist?(filename)
575
+ File.open(filename) {|fh| Marshal.load(fh)}
576
+ else
577
+ nil
578
+ end
579
+ end
580
+
581
+ def putdata(value,filename,do_lock = true)
582
+ if do_lock
583
+ lock_cache do
584
+ putdata_worker(value,filename)
585
+ end
586
+ else
587
+ putdata_worker(value,filename)
588
+ end
589
+ end
590
+
591
+ def putdata_worker(value,filename)
592
+ FileUtils.mkdir_p(File::dirname(filename)) unless FileTest.exist?(File::dirname(filename))
593
+ File.open(filename,'w') {|fh| Marshal.dump(value,fh)}
594
+ end
595
+
596
+ def set_cachefile_paths
597
+ @cache_head = File.join(@cache_dir,'cache_head.inf')
598
+ @cache_tail = File.join(@cache_dir,'cache_tail.inf')
599
+ @cache_count = File.join(@cache_dir,'cache_count.inf')
600
+ @cache_maxsize = File.join(@cache_dir,'cache_maxsize.inf')
601
+ @cache_maxttl = File.join(@cache_dir,'cache_maxttl.inf')
602
+ end
603
+ end
604
+ end
605
+ end