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.
- checksums.yaml +7 -0
- data/CONTRIBUTORS +14 -0
- data/README.md +23 -0
- data/RELEASE_NOTES +77 -0
- data/ToDo +21 -0
- data/components/CRUDList/CRUDList.html +13 -0
- data/components/CRUDList/CRUDList.iwa +136 -0
- data/components/Content/Content.html +0 -0
- data/components/Content/Content.iwa +143 -0
- data/components/Content/example/README +9 -0
- data/components/Content/example/cgi/iowa.cgi +10 -0
- data/components/Content/example/demo.rb +30 -0
- data/components/Content/example/doc/index.html +7 -0
- data/components/Content/example/iowa/Content.html +1 -0
- data/components/Content/example/iowa/Content.iwa +1 -0
- data/components/Content/example/iowa/Main.html +6 -0
- data/components/Content/example/iowa/Main.iwa +3 -0
- data/components/Content/example/iowa/_content/body +7 -0
- data/components/Content/example/iowa/_content/body2 +3 -0
- data/components/Content/example/iowa/_content/title +2 -0
- data/components/Content/example/iowa/app.cnf +8 -0
- data/components/Content/example/iowa/app.rb +8 -0
- data/components/Content/example/webrick.rb +38 -0
- data/components/Include/Include.html +1 -0
- data/components/Include/Include.iwa +30 -0
- data/components/Include/readme +5 -0
- data/components/JumpTo/JumpTo.html +8 -0
- data/components/JumpTo/JumpTo.iwa +8 -0
- data/components/JumpTo/readme +6 -0
- data/doc/Architecture.txt +6 -0
- data/doc/History.txt +33 -0
- data/doc/StandardDispatcher.txt +19 -0
- data/examples/blog/README +1 -0
- data/examples/hello_world/README +17 -0
- data/examples/hello_world/htdocs/hello_world_html.html +24 -0
- data/examples/hello_world/htdocs/hello_world_ruby.html +41 -0
- data/examples/hello_world/iowa/HelloWorld.html +14 -0
- data/examples/hello_world/iowa/HelloWorld.iwa +31 -0
- data/examples/hello_world/iowa/Index.html +16 -0
- data/examples/hello_world/iowa/Index.iwa +5 -0
- data/examples/hello_world/iowa/iowa_hello_world.cnf +19 -0
- data/examples/hello_world/iowa/iowa_hello_world.rb +5 -0
- data/examples/hello_world/iowa/mapfile.cnf +6 -0
- data/examples/hw1/iowa/Main.html +1 -0
- data/examples/hw1/iowa/README +9 -0
- data/examples/hw1/iowa/hw.rb +4 -0
- data/examples/hw2/iowa/Main.html +10 -0
- data/examples/hw2/iowa/Main.iwa +7 -0
- data/examples/hw2/iowa/README +16 -0
- data/examples/hw2/iowa/hw.rb +4 -0
- data/examples/hw3/iowa/Main.html +11 -0
- data/examples/hw3/iowa/Main.iwa +7 -0
- data/examples/hw3/iowa/README +22 -0
- data/examples/hw3/iowa/hw.rb +4 -0
- data/examples/hw4/iowa/Greetings.html +10 -0
- data/examples/hw4/iowa/Greetings.iwa +9 -0
- data/examples/hw4/iowa/Main.html +12 -0
- data/examples/hw4/iowa/Main.iwa +10 -0
- data/examples/hw4/iowa/README +28 -0
- data/examples/hw4/iowa/hw.rb +4 -0
- data/examples/hw5/iowa/Footer.html +2 -0
- data/examples/hw5/iowa/Greetings.html +4 -0
- data/examples/hw5/iowa/Greetings.iwa +12 -0
- data/examples/hw5/iowa/Header.html +6 -0
- data/examples/hw5/iowa/Main.html +12 -0
- data/examples/hw5/iowa/Main.iwa +13 -0
- data/examples/hw5/iowa/README +16 -0
- data/examples/hw5/iowa/hw.rb +4 -0
- data/examples/template_server/iowa/Content.iwa +121 -0
- data/examples/template_server/iowa/Content.view +0 -0
- data/examples/template_server/iowa/DBContentDispatcher.rb +112 -0
- data/examples/template_server/iowa/DBContentPage.html +3 -0
- data/examples/template_server/iowa/DBContentPage.iwa +85 -0
- data/examples/template_server/iowa/app.cnf +13 -0
- data/examples/template_server/iowa/app.rb +5 -0
- data/ext/Classifier/classifier.c +256 -0
- data/ext/Classifier/ext_help.h +14 -0
- data/ext/Classifier/extconf.rb +5 -0
- data/ext/Classifier/tst.h +40 -0
- data/ext/Classifier/tst_cleanup.c +24 -0
- data/ext/Classifier/tst_delete.c +146 -0
- data/ext/Classifier/tst_grow_node_free_list.c +38 -0
- data/ext/Classifier/tst_init.c +41 -0
- data/ext/Classifier/tst_insert.c +192 -0
- data/ext/Classifier/tst_search.c +68 -0
- data/ext/http11/README +11 -0
- data/ext/http11/ext_help.h +15 -0
- data/ext/http11/extconf.rb +5 -0
- data/ext/http11/http11.c +534 -0
- data/ext/http11/http11.c.dif +422 -0
- data/ext/http11/http11_parser.c +1243 -0
- data/ext/http11/http11_parser.c.dif +193 -0
- data/ext/http11/http11_parser.h +49 -0
- data/ext/http11/http11_parser.h.dif +20 -0
- data/ext/http11/http11_parser.rl +192 -0
- data/ext/httpmachine/Makefile +149 -0
- data/ext/httpmachine/extconf.rb +33 -0
- data/ext/httpmachine/http.cpp +430 -0
- data/ext/httpmachine/http.h +156 -0
- data/ext/httpmachine/rubyhttp.cpp +165 -0
- data/external/mime-types/LICENCE +18 -0
- data/external/mime-types/README +46 -0
- data/external/mime-types/doc/classes/MIME.html +120 -0
- data/external/mime-types/doc/classes/MIME/InvalidContentType.html +119 -0
- data/external/mime-types/doc/classes/MIME/Type.html +866 -0
- data/external/mime-types/doc/classes/MIME/Type.src/M000010.html +22 -0
- data/external/mime-types/doc/classes/MIME/Type.src/M000011.html +18 -0
- data/external/mime-types/doc/classes/MIME/Type.src/M000012.html +19 -0
- data/external/mime-types/doc/classes/MIME/Type.src/M000013.html +18 -0
- data/external/mime-types/doc/classes/MIME/Type.src/M000014.html +26 -0
- data/external/mime-types/doc/classes/MIME/Type.src/M000015.html +33 -0
- data/external/mime-types/doc/classes/MIME/Type.src/M000016.html +27 -0
- data/external/mime-types/doc/classes/MIME/Type.src/M000017.html +35 -0
- data/external/mime-types/doc/classes/MIME/Type.src/M000018.html +34 -0
- data/external/mime-types/doc/classes/MIME/Type.src/M000019.html +24 -0
- data/external/mime-types/doc/classes/MIME/Type.src/M000020.html +38 -0
- data/external/mime-types/doc/classes/MIME/Type.src/M000021.html +22 -0
- data/external/mime-types/doc/classes/MIME/Type.src/M000022.html +18 -0
- data/external/mime-types/doc/classes/MIME/Type.src/M000023.html +18 -0
- data/external/mime-types/doc/classes/MIME/Type.src/M000024.html +18 -0
- data/external/mime-types/doc/classes/MIME/Type.src/M000025.html +18 -0
- data/external/mime-types/doc/classes/MIME/Type.src/M000026.html +18 -0
- data/external/mime-types/doc/classes/MIME/Type.src/M000027.html +18 -0
- data/external/mime-types/doc/classes/MIME/Type.src/M000028.html +18 -0
- data/external/mime-types/doc/classes/MIME/Type.src/M000029.html +18 -0
- data/external/mime-types/doc/classes/MIME/Type.src/M000030.html +19 -0
- data/external/mime-types/doc/classes/MIME/Type.src/M000031.html +26 -0
- data/external/mime-types/doc/classes/MIME/Types.html +459 -0
- data/external/mime-types/doc/classes/MIME/Types.src/M000001.html +19 -0
- data/external/mime-types/doc/classes/MIME/Types.src/M000002.html +32 -0
- data/external/mime-types/doc/classes/MIME/Types.src/M000003.html +21 -0
- data/external/mime-types/doc/classes/MIME/Types.src/M000004.html +18 -0
- data/external/mime-types/doc/classes/MIME/Types.src/M000005.html +26 -0
- data/external/mime-types/doc/classes/MIME/Types.src/M000006.html +18 -0
- data/external/mime-types/doc/classes/MIME/Types.src/M000007.html +18 -0
- data/external/mime-types/doc/classes/MIME/Types.src/M000008.html +18 -0
- data/external/mime-types/doc/classes/MIME/Types.src/M000009.html +18 -0
- data/external/mime-types/doc/created.rid +1 -0
- data/external/mime-types/doc/files/ChangeLog.html +320 -0
- data/external/mime-types/doc/files/README.html +145 -0
- data/external/mime-types/doc/files/lib/mime/types_rb.html +101 -0
- data/external/mime-types/doc/fr_class_index.html +30 -0
- data/external/mime-types/doc/fr_file_index.html +29 -0
- data/external/mime-types/doc/fr_method_index.html +57 -0
- data/external/mime-types/doc/index.html +24 -0
- data/external/mime-types/doc/rdoc-style.css +208 -0
- data/external/mime-types/lib/mime/types.rb +1558 -0
- data/external/package.rb +672 -0
- data/external/test_support.rb +95 -0
- data/external/tmail/README +7 -0
- data/external/tmail/tmail.rb +4 -0
- data/external/tmail/tmail/address.rb +222 -0
- data/external/tmail/tmail/base64.rb +52 -0
- data/external/tmail/tmail/compat.rb +39 -0
- data/external/tmail/tmail/config.rb +50 -0
- data/external/tmail/tmail/encode.rb +447 -0
- data/external/tmail/tmail/header.rb +895 -0
- data/external/tmail/tmail/info.rb +14 -0
- data/external/tmail/tmail/loader.rb +1 -0
- data/external/tmail/tmail/mail.rb +869 -0
- data/external/tmail/tmail/mailbox.rb +386 -0
- data/external/tmail/tmail/mbox.rb +1 -0
- data/external/tmail/tmail/net.rb +260 -0
- data/external/tmail/tmail/obsolete.rb +123 -0
- data/external/tmail/tmail/parser.rb +1475 -0
- data/external/tmail/tmail/parser.y +372 -0
- data/external/tmail/tmail/port.rb +356 -0
- data/external/tmail/tmail/scanner.rb +17 -0
- data/external/tmail/tmail/scanner_r.rb +243 -0
- data/external/tmail/tmail/stringio.rb +256 -0
- data/external/tmail/tmail/textutils.rb +197 -0
- data/external/tmail/tmail/tmail.rb +1 -0
- data/external/tmail/tmail/utils.rb +23 -0
- data/external/win32-process/README +133 -0
- data/external/win32-process/lib/win32/process.rb +561 -0
- data/external/windows-pr/README +145 -0
- data/external/windows-pr/doc/conversion_guide.txt +25 -0
- data/external/windows-pr/lib/windows/clipboard.rb +72 -0
- data/external/windows-pr/lib/windows/console.rb +323 -0
- data/external/windows-pr/lib/windows/device_io.rb +88 -0
- data/external/windows-pr/lib/windows/directory.rb +80 -0
- data/external/windows-pr/lib/windows/error.rb +313 -0
- data/external/windows-pr/lib/windows/eventlog.rb +120 -0
- data/external/windows-pr/lib/windows/file.rb +349 -0
- data/external/windows-pr/lib/windows/filesystem.rb +16 -0
- data/external/windows-pr/lib/windows/handle.rb +31 -0
- data/external/windows-pr/lib/windows/library.rb +76 -0
- data/external/windows-pr/lib/windows/limits.rb +13 -0
- data/external/windows-pr/lib/windows/memory.rb +117 -0
- data/external/windows-pr/lib/windows/msvcrt/buffer.rb +48 -0
- data/external/windows-pr/lib/windows/msvcrt/file.rb +18 -0
- data/external/windows-pr/lib/windows/msvcrt/string.rb +46 -0
- data/external/windows-pr/lib/windows/national.rb +557 -0
- data/external/windows-pr/lib/windows/path.rb +296 -0
- data/external/windows-pr/lib/windows/pipe.rb +77 -0
- data/external/windows-pr/lib/windows/process.rb +171 -0
- data/external/windows-pr/lib/windows/registry.rb +238 -0
- data/external/windows-pr/lib/windows/security.rb +89 -0
- data/external/windows-pr/lib/windows/service.rb +183 -0
- data/external/windows-pr/lib/windows/shell.rb +88 -0
- data/external/windows-pr/lib/windows/sound.rb +52 -0
- data/external/windows-pr/lib/windows/synchronize.rb +161 -0
- data/external/windows-pr/lib/windows/system_info.rb +70 -0
- data/external/windows-pr/lib/windows/unicode.rb +138 -0
- data/external/windows-pr/lib/windows/window.rb +22 -0
- data/iowa.gemspec +45 -0
- data/microprojects/DiskCache/LICENSE +28 -0
- data/microprojects/DiskCache/README +17 -0
- data/microprojects/DiskCache/external/package.rb +608 -0
- data/microprojects/DiskCache/external/test_support.rb +8 -0
- data/microprojects/DiskCache/setup.rb +22 -0
- data/microprojects/DiskCache/src/iowa/Association.rb +67 -0
- data/microprojects/DiskCache/src/iowa/Constants.rb +159 -0
- data/microprojects/DiskCache/src/iowa/DiskStore.rb +377 -0
- data/microprojects/DiskCache/src/iowa/Hash.rb +63 -0
- data/microprojects/DiskCache/src/iowa/Lockfile.rb +575 -0
- data/microprojects/DiskCache/src/iowa/Mutex.rb +142 -0
- data/microprojects/DiskCache/src/iowa/caches/DiskCache.rb +605 -0
- data/microprojects/DiskCache/src/iowa/caches/LRUCache.rb +287 -0
- data/microprojects/DiskCache/test/TC_DiskCache.rb +218 -0
- data/microprojects/LRUCache/LICENSE +28 -0
- data/microprojects/LRUCache/README +13 -0
- data/microprojects/LRUCache/external/package.rb +608 -0
- data/microprojects/LRUCache/external/test_support.rb +8 -0
- data/microprojects/LRUCache/setup.rb +22 -0
- data/microprojects/LRUCache/src/iowa/Association.rb +57 -0
- data/microprojects/LRUCache/src/iowa/Constants.rb +159 -0
- data/microprojects/LRUCache/src/iowa/Hash.rb +63 -0
- data/microprojects/LRUCache/src/iowa/Mutex.rb +129 -0
- data/microprojects/LRUCache/src/iowa/caches/LRUCache.rb +287 -0
- data/microprojects/LRUCache/test/TC_LRUCache.rb +65 -0
- data/microprojects/LinkedList/LICENSE +28 -0
- data/microprojects/LinkedList/README +13 -0
- data/microprojects/LinkedList/external/package.rb +608 -0
- data/microprojects/LinkedList/external/test_support.rb +8 -0
- data/microprojects/LinkedList/setup.rb +22 -0
- data/microprojects/LinkedList/src/iowa/LinkedList.rb +165 -0
- data/microprojects/LinkedList/test/TC_LinkedList.rb +42 -0
- data/microprojects/README +8 -0
- data/setup.rb +116 -0
- data/share/iowa/app_skeleton/Main.html +8 -0
- data/share/iowa/app_skeleton/Main.iwa +15 -0
- data/share/iowa/app_skeleton/app.cnf +48 -0
- data/share/iowa/app_skeleton/app.rb +58 -0
- data/share/iowa/app_skeleton/models/model.rb +49 -0
- data/src/ihc.rb +223 -0
- data/src/iowa.cgi +29 -0
- data/src/iowa.rb +637 -0
- data/src/iowa/AbstractCache.rb +96 -0
- data/src/iowa/AcceptLanguage.rb +76 -0
- data/src/iowa/Application.rb +928 -0
- data/src/iowa/ApplicationStats.rb +72 -0
- data/src/iowa/Association.rb +67 -0
- data/src/iowa/BindingsParser.rb +62 -0
- data/src/iowa/Breakpoint.rb +273 -0
- data/src/iowa/CSS.rb +564 -0
- data/src/iowa/Client.rb +192 -0
- data/src/iowa/Component.rb +405 -0
- data/src/iowa/ComponentProxy.rb +26 -0
- data/src/iowa/Config.rb +21 -0
- data/src/iowa/Constants.rb +226 -0
- data/src/iowa/Context.rb +218 -0
- data/src/iowa/ContextLogger.rb +16 -0
- data/src/iowa/DbPool.rb +222 -0
- data/src/iowa/DetachedComponent.rb +18 -0
- data/src/iowa/Dispatcher.rb +27 -0
- data/src/iowa/DynamicElements.rb +471 -0
- data/src/iowa/Element.rb +100 -0
- data/src/iowa/Email.rb +287 -0
- data/src/iowa/Extensions/AllExtensions.rb +4 -0
- data/src/iowa/Extensions/Class.rb +94 -0
- data/src/iowa/Extensions/Date.rb +88 -0
- data/src/iowa/Extensions/DateTime.rb +88 -0
- data/src/iowa/Extensions/Hash.rb +22 -0
- data/src/iowa/Extensions/Kernel.rb +6 -0
- data/src/iowa/Extensions/Numeric.rb +47 -0
- data/src/iowa/Extensions/Object.rb +11 -0
- data/src/iowa/Extensions/String.rb +60 -0
- data/src/iowa/Extensions/Time.rb +89 -0
- data/src/iowa/Extensions/TimeExtensions.rb +6 -0
- data/src/iowa/Form.rb +368 -0
- data/src/iowa/Hash.rb +85 -0
- data/src/iowa/ISAAC.rb +175 -0
- data/src/iowa/ImageSize.rb +279 -0
- data/src/iowa/IowaComponentMixins.rb +7 -0
- data/src/iowa/JSON-lexer.rb +296 -0
- data/src/iowa/JSON-objects.rb +201 -0
- data/src/iowa/KeyValueCoding.rb +91 -0
- data/src/iowa/LinkedList.rb +175 -0
- data/src/iowa/Loader.rb +22 -0
- data/src/iowa/Lockfile.rb +575 -0
- data/src/iowa/Logger.rb +74 -0
- data/src/iowa/Monkey.rb +20 -0
- data/src/iowa/Mutex.rb +142 -0
- data/src/iowa/Policy.rb +70 -0
- data/src/iowa/Pool.rb +243 -0
- data/src/iowa/PrettyException.rb +1091 -0
- data/src/iowa/Request.rb +244 -0
- data/src/iowa/Response.rb +133 -0
- data/src/iowa/Session.rb +354 -0
- data/src/iowa/SessionStats.rb +78 -0
- data/src/iowa/String.rb +65 -0
- data/src/iowa/Tag.rb +101 -0
- data/src/iowa/TemplateParser.rb +236 -0
- data/src/iowa/Util.rb +314 -0
- data/src/iowa/Webcache.rb +122 -0
- data/src/iowa/caches/BiLevelCache.rb +65 -0
- data/src/iowa/caches/ClassLimitedCache.rb +67 -0
- data/src/iowa/caches/DiskCache.rb +609 -0
- data/src/iowa/caches/DiskStore.rb +380 -0
- data/src/iowa/caches/LRUCache-alternative.rb +155 -0
- data/src/iowa/caches/LRUCache.rb +290 -0
- data/src/iowa/caches/SimpleLRUCache.rb +112 -0
- data/src/iowa/dispatchers/StandardDispatcher.rb +396 -0
- data/src/iowa/dispatchers/StandardDispatcherWithClassifier.rb +93 -0
- data/src/iowa/js/iowa_jsonrpc.js +381 -0
- data/src/iowa/js/jsonrpc.js +187 -0
- data/src/iowa/js/jsonrpc_async.js +261 -0
- data/src/iowa/loaders/DiskLoader.rb +50 -0
- data/src/iowa/loggers/Analogger.rb +54 -0
- data/src/iowa/loggers/AsyncLogger.rb +54 -0
- data/src/iowa/loggers/BitBucket.rb +38 -0
- data/src/iowa/loggers/Log4R.rb +13 -0
- data/src/iowa/loggers/Log4rLogger.rb +48 -0
- data/src/iowa/loggers/Logger.rb +29 -0
- data/src/iowa/loggers/RubyLogger.rb +9 -0
- data/src/iowa/pools/DBConnectionPool.rb +53 -0
- data/src/iowa/request/Apache.rb +90 -0
- data/src/iowa/request/EMHybrid.rb +59 -0
- data/src/iowa/request/ENV.rb +80 -0
- data/src/iowa/request/FCGI.rb +68 -0
- data/src/iowa/request/HTTPMachine.rb +75 -0
- data/src/iowa/request/Mongrel.rb +68 -0
- data/src/iowa/request/WEBrick.rb +48 -0
- data/src/iowa/version.rb +3 -0
- data/src/iowa/webrick/HTTPServer.rb +43 -0
- data/src/iowa/webrick/WEBrickServlet.rb +28 -0
- data/src/iowa_fcgi_handler.rb +101 -0
- data/src/iowa_httpmachine.rb +141 -0
- data/src/iowa_hybrid.rb +193 -0
- data/src/iowa_hybrid_cluster.rb +231 -0
- data/src/iowa_mongrel.rb +136 -0
- data/src/iowa_webrick.rb +194 -0
- data/src/iowa_webrick_legacy.rb +104 -0
- data/src/mod_iowa.rb +104 -0
- data/tcss.rb +61 -0
- data/test/README.windows +12 -0
- data/test/TC_AcceptLanguage.rb +61 -0
- data/test/TC_AppConfig.rb +43 -0
- data/test/TC_AppConfig/cgi/iowa.cgi +7 -0
- data/test/TC_AppConfig/doc/index.html +1 -0
- data/test/TC_AppConfig/iowa/Main.html +4 -0
- data/test/TC_AppConfig/iowa/Main.iwa +17 -0
- data/test/TC_AppConfig/iowa/README +1 -0
- data/test/TC_AppConfig/iowa/app.cnf +19 -0
- data/test/TC_AppConfig/iowa/app.rb +8 -0
- data/test/TC_AppConfig/webrick.rb +38 -0
- data/test/TC_Association.rb +29 -0
- data/test/TC_BiLevelCache.rb +71 -0
- data/test/TC_CGI_Adaptor.rb +55 -0
- data/test/TC_CGI_Adaptor/cgi/iowa.cgi +7 -0
- data/test/TC_CGI_Adaptor/doc/index.html +1 -0
- data/test/TC_CGI_Adaptor/iowa/Main.html +8 -0
- data/test/TC_CGI_Adaptor/iowa/Main.iwa +14 -0
- data/test/TC_CGI_Adaptor/iowa/README +1 -0
- data/test/TC_CGI_Adaptor/iowa/app.cnf +8 -0
- data/test/TC_CGI_Adaptor/iowa/app.rb +8 -0
- data/test/TC_CGI_Adaptor/webrick.rb +38 -0
- data/test/TC_CSS.rb +660 -0
- data/test/TC_ClassLimitedCache.rb +89 -0
- data/test/TC_Classifier.rb +80 -0
- data/test/TC_DbPool.rb +127 -0
- data/test/TC_DiskCache.rb +218 -0
- data/test/TC_Hybrid.rb +58 -0
- data/test/TC_Hybrid/doc/thing.txt +1 -0
- data/test/TC_Hybrid/iowa/Main.html +3 -0
- data/test/TC_Hybrid/iowa/Main.iwa +7 -0
- data/test/TC_Hybrid/iowa/NewPage.html +1 -0
- data/test/TC_Hybrid/iowa/NewPage.iwa +5 -0
- data/test/TC_Hybrid/iowa/app.cnf +10 -0
- data/test/TC_Hybrid/iowa/app.rb +5 -0
- data/test/TC_IOWAFunctions/doc/Ajax1.html +1 -0
- data/test/TC_IOWAFunctions/doc/Ajax1.iwa +1 -0
- data/test/TC_IOWAFunctions/doc/index.html +1 -0
- data/test/TC_IOWAFunctions/doc/js/dojo.js +9686 -0
- data/test/TC_IOWAFunctions/iowa/Ajax1.html +40 -0
- data/test/TC_IOWAFunctions/iowa/Ajax1.iwa +23 -0
- data/test/TC_IOWAFunctions/iowa/AjaxWidget.iwa +19 -0
- data/test/TC_IOWAFunctions/iowa/AjaxWidget.view +22 -0
- data/test/TC_IOWAFunctions/iowa/DanielTest.html +9 -0
- data/test/TC_IOWAFunctions/iowa/DanielTest.iwa +10 -0
- data/test/TC_IOWAFunctions/iowa/IntervalWidget.html +1 -0
- data/test/TC_IOWAFunctions/iowa/IntervalWidget.iwa +14 -0
- data/test/TC_IOWAFunctions/iowa/Main.html +1 -0
- data/test/TC_IOWAFunctions/iowa/NestedRepeat1.html +12 -0
- data/test/TC_IOWAFunctions/iowa/NestedRepeat1.iwa +24 -0
- data/test/TC_IOWAFunctions/iowa/RPCResponse.iwa +7 -0
- data/test/TC_IOWAFunctions/iowa/RPCResponse.view +1 -0
- data/test/TC_IOWAFunctions/iowa/Repeat1.iwa +31 -0
- data/test/TC_IOWAFunctions/iowa/Repeat1.view +9 -0
- data/test/TC_IOWAFunctions/iowa/Repeat2.iwa +32 -0
- data/test/TC_IOWAFunctions/iowa/Repeat2.view +11 -0
- data/test/TC_IOWAFunctions/iowa/Repeat3.iwa +44 -0
- data/test/TC_IOWAFunctions/iowa/Repeat3.view +18 -0
- data/test/TC_IOWAFunctions/iowa/TesCon.html +1 -0
- data/test/TC_IOWAFunctions/iowa/TesCon.iwa +5 -0
- data/test/TC_IOWAFunctions/iowa/app.cnf +19 -0
- data/test/TC_IOWAFunctions/iowa/app.rb +9 -0
- data/test/TC_IOWAFunctions/iowa/mapfile.cnf +8 -0
- data/test/TC_ISAAC.rb +52 -0
- data/test/TC_ImageSize.rb +84 -0
- data/test/TC_ImageSize/img.bmp +0 -0
- data/test/TC_ImageSize/img.gif +0 -0
- data/test/TC_ImageSize/img.jpg +0 -0
- data/test/TC_ImageSize/img.pcx +0 -0
- data/test/TC_ImageSize/img.pgm +7144 -0
- data/test/TC_ImageSize/img.png +0 -0
- data/test/TC_ImageSize/img.ppm +0 -0
- data/test/TC_ImageSize/img.psd +0 -0
- data/test/TC_ImageSize/img.tiff +0 -0
- data/test/TC_ImageSize/img.xbm +22 -0
- data/test/TC_KeyValueCoding.rb +35 -0
- data/test/TC_LRUCache.rb +296 -0
- data/test/TC_LinkedList.rb +46 -0
- data/test/TC_Lockfile.rb +106 -0
- data/test/TC_Minimal.rb +45 -0
- data/test/TC_Minimal/app.cnf +8 -0
- data/test/TC_Minimal/cgi-bin/iowa.cgi +11 -0
- data/test/TC_Minimal/doc/index.html +1 -0
- data/test/TC_Minimal/iowa/Main.html +1 -0
- data/test/TC_Minimal/iowa/README +1 -0
- data/test/TC_Minimal/iowa/app.rb +3 -0
- data/test/TC_Minimal/webrick.rb +38 -0
- data/test/TC_Mongrel.rb +58 -0
- data/test/TC_Mongrel/doc/thing.txt +1 -0
- data/test/TC_Mongrel/iowa/Main.html +3 -0
- data/test/TC_Mongrel/iowa/Main.iwa +7 -0
- data/test/TC_Mongrel/iowa/NewPage.html +1 -0
- data/test/TC_Mongrel/iowa/NewPage.iwa +5 -0
- data/test/TC_Mongrel/iowa/app.cnf +10 -0
- data/test/TC_Mongrel/iowa/app.rb +5 -0
- data/test/TC_NoSubclass.rb +56 -0
- data/test/TC_NoSubclass/cgi/iowa.cgi +7 -0
- data/test/TC_NoSubclass/doc/index.html +1 -0
- data/test/TC_NoSubclass/iowa/Main.html +8 -0
- data/test/TC_NoSubclass/iowa/Main.iwa +14 -0
- data/test/TC_NoSubclass/iowa/README +1 -0
- data/test/TC_NoSubclass/iowa/app.cnf +8 -0
- data/test/TC_NoSubclass/iowa/app.rb +5 -0
- data/test/TC_NoSubclass/webrick.rb +38 -0
- data/test/TC_Pool.rb +139 -0
- data/test/TC_RenderedCache/doc/thing.txt +1 -0
- data/test/TC_RenderedCache/iowa/BigPage.html +1 -0
- data/test/TC_RenderedCache/iowa/BigPage.iwa +12 -0
- data/test/TC_RenderedCache/iowa/Main.html +3 -0
- data/test/TC_RenderedCache/iowa/Main.iwa +7 -0
- data/test/TC_RenderedCache/iowa/NewPage.html +1 -0
- data/test/TC_RenderedCache/iowa/NewPage.iwa +11 -0
- data/test/TC_RenderedCache/iowa/app.cnf +13 -0
- data/test/TC_RenderedCache/iowa/app.rb +5 -0
- data/test/TC_RenderedCache/iowa/mapfile.map +4 -0
- data/test/TC_ResourceURL.rb +73 -0
- data/test/TC_ResourceURL/iowa/Main.html +2 -0
- data/test/TC_ResourceURL/iowa/Main.iwa +10 -0
- data/test/TC_ResourceURL/iowa/app.cnf +10 -0
- data/test/TC_ResourceURL/iowa/app.rb +5 -0
- data/test/TC_SimpleDetached.rb +41 -0
- data/test/TC_StandardDispatcher.rb +362 -0
- data/test/TC_StandardDispatcherWithClassifier.rb +358 -0
- data/test/TC_String.rb +24 -0
- data/test/TC_Tag.rb +41 -0
- data/test/TC_Webrick.rb +56 -0
- data/test/TC_Webrick/doc/thing.txt +1 -0
- data/test/TC_Webrick/iowa/Main.html +3 -0
- data/test/TC_Webrick/iowa/Main.iwa +7 -0
- data/test/TC_Webrick/iowa/NewPage.html +1 -0
- data/test/TC_Webrick/iowa/NewPage.iwa +5 -0
- data/test/TC_Webrick/iowa/app.cnf +10 -0
- data/test/TC_Webrick/iowa/app.rb +5 -0
- data/test/tc_template.rb +15 -0
- data/test/tests.conf +19 -0
- data/utils/CVS/Entries +3 -0
- data/utils/CVS/Repository +1 -0
- data/utils/CVS/Root +1 -0
- data/utils/QuickCert-1.0.2.tar.gz +0 -0
- data/utils/QuickCert-1.0.2/InstalledFiles +7 -0
- data/utils/QuickCert-1.0.2/MANIFEST +10 -0
- data/utils/QuickCert-1.0.2/Makefile +15 -0
- data/utils/QuickCert-1.0.2/README +56 -0
- data/utils/QuickCert-1.0.2/bin/QuickCert +355 -0
- data/utils/QuickCert-1.0.2/config.save +12 -0
- data/utils/QuickCert-1.0.2/data/examples/ruby/QuickCert/README +60 -0
- data/utils/QuickCert-1.0.2/data/examples/ruby/QuickCert/drbssl_c.rb +26 -0
- data/utils/QuickCert-1.0.2/data/examples/ruby/QuickCert/drbssl_s.rb +35 -0
- data/utils/QuickCert-1.0.2/data/examples/ruby/QuickCert/qc_config +21 -0
- data/utils/QuickCert-1.0.2/lib/QuickCert/defaults.rb +28 -0
- data/utils/QuickCert-1.0.2/setup.rb +1312 -0
- data/utils/iowa_apps +422 -0
- data/utils/smtp_sink.rb +9 -0
- data/utils/startup_template.cnf +27 -0
- data/utils/startup_template.rb +73 -0
- 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
|