diff --git a/.gitignore b/.gitignore index 1859752..d2a4130 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,155 @@ -.vscode/ -bin/ -obj/ -project.lock.json -Program.exe + +# Created by https://www.gitignore.io/api/gradle,intellij,jetbrains,intellij+all + +### Intellij ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff: +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/dictionaries + +# Sensitive or high-churn files: +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.xml +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml + +# Mongo Explorer plugin: +.idea/**/mongoSettings.xml + +## File-based project format: +*.iws + +## Plugin-specific files: + +# IntelliJ +/out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Ruby plugin and RubyMine +/.rakeTasks + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +### Intellij Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +.idea/sonarlint + +### Intellij+all ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff: + +# Sensitive or high-churn files: + +# Gradle: + +# CMake + +# Mongo Explorer plugin: + +## File-based project format: + +## Plugin-specific files: + +# IntelliJ + +# mpeltonen/sbt-idea plugin + +# JIRA plugin + +# Cursive Clojure plugin + +# Ruby plugin and RubyMine + +# Crashlytics plugin (for Android Studio and IntelliJ) + +### Intellij+all Patch ### +# Ignores the whole idea folder +# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 + +.idea/ + +### JetBrains ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff: + +# Sensitive or high-churn files: + +# Gradle: + +# CMake + +# Mongo Explorer plugin: + +## File-based project format: + +## Plugin-specific files: + +# IntelliJ + +# mpeltonen/sbt-idea plugin + +# JIRA plugin + +# Cursive Clojure plugin + +# Ruby plugin and RubyMine + +# Crashlytics plugin (for Android Studio and IntelliJ) + +### JetBrains Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin + +### Gradle ### +.gradle +**/build/ + +# Ignore Gradle GUI config +gradle-app.setting + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar + +# Cache of project +.gradletasknamecache + +# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 +# gradle/wrapper/gradle-wrapper.properties + + +# End of https://www.gitignore.io/api/gradle,intellij,jetbrains,intellij+all diff --git a/LICENSE.md b/LICENSE.md deleted file mode 100644 index dcc7f57..0000000 --- a/LICENSE.md +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016 adrianveliz - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/Program.cs b/Program.cs deleted file mode 100755 index e0483fd..0000000 --- a/Program.cs +++ /dev/null @@ -1,211 +0,0 @@ -using System; -using System.Threading; -using System.Collections; -using System.Collections.Generic; -//using System.Collections.NonGeneric; - -// Cache that uses finalize to revive objects. -// @author Adrian Veliz -// - - -namespace ConsoleApplication -{ - public class Program - { - public static MyCacheableObject mco = null; - public static void Main(string[] args) - { - - #pragma warning disable 219 - int size = 20; - MyCache cache = new MyCache(size); - mco = new MyCacheableObject("0"); - cache.addEntry("0", mco); - - for (int i = 1; i < 5; i++) - { - MyCacheableObject temp = new MyCacheableObject(i.ToString()); - cache.addEntry(i.ToString(), temp); - temp = null;//csc and dotnet require this in order to work correctly, dmcs does not - } - - sleepAndPrintCount(cache); - - - GC.Collect();//All but one entry will be finalized - MyCacheableObject mco2 = cache.getEntry("3");//Example of getting object before finalize - sleepAndPrintCount(cache); - Console.WriteLine("One entry reachable from root set, another entry gotten after gc before finalize so it is not tracked."); - - mco2 = null; - GC.Collect(); - sleepAndPrintCount(cache); - Console.WriteLine("One entry reachable from root set, second chance added to lru tracking"); - - - mco = null; - GC.Collect(); - sleepAndPrintCount(cache); - Console.WriteLine("All entries should now be lru tracked"); - #pragma warning restore 219 - } - - public static void sleepAndPrintCount(MyCache cache) - { - System.Threading.Thread.Sleep(1000);//Make time for finalize to run - Console.WriteLine("Count of elements: " + cache.LRUCount()); - } - } - - public class MyCache - { - // Dictionary to contain the cache. - static Dictionary _cache; - static ArrayList _lru; - static int _size = 50; - - public MyCache(int size) - { - _cache = new Dictionary(); - _lru = new ArrayList(); - _size = size; - } - - public void addEntry(string key, MyCacheableObject value) - { - try - { - value.setCache(this); - // ressurection tracking enabled, allow calls to get during EWR - //GC.SuppressFinalize(this); - //GC.ReRegisterForFinalize(this); - _cache.Add(key, new WeakReference(value, true));//ressurection tracking enabled - } - catch (ArgumentException) - { - _lru.Remove(value);//does nothing if does not exist, O(n) - } - } - - public MyCacheableObject getEntry(string key) - { - if (_cache.ContainsKey(key)) - { - MyCacheableObject mco = _cache[key].Target as MyCacheableObject; - GC.SuppressFinalize(mco); - GC.ReRegisterForFinalize(mco); - _lru.Remove(mco); - mco.setGet(true); - return mco; - } - return null; - } - - public void LRU(MyCacheableObject mco) - { - GC.SuppressFinalize(mco); - _lru.Insert(0, mco); - evict(); - } - - public void evict() - { - if (_lru.Count >= _size && _size > 0) - { - try - { - _lru.RemoveAt(_size-1); - } - #pragma warning disable 0168 - catch (System.ArgumentOutOfRangeException ex) - #pragma warning restore 0168 - { - //This should not happen but DMCS complains that this - // exception is not caught. The complier will then - // complain that the variable is never used. - Console.WriteLine("Hmmm.... You should not be seeing this."); - } - } - } - - public int LRUCount() - { - return _lru.Count; - } - } - - public class MyCacheableObject - { - //WeakReference _cache = null; - MyCache _cache; - string _value; - bool _get = false; - - public MyCacheableObject(string value) - { - _value = value; - } - - public override string ToString() - { - return _value; - } - - public override bool Equals(Object obj) - { - MyCacheableObject mco = obj as MyCacheableObject; - - if (mco == null) - return false; - - return _value.Equals(mco.ToString()); - } - - public override int GetHashCode() - { - return this.ToString().GetHashCode(); - } - - public void setCache(MyCache cache) - { - //_cache = new WeakReference(cache); - _cache = cache; - } - - public bool gotten() - { - return this._get; - } - - public void setGet(bool gotten) - { - this._get = gotten; - } - - ~MyCacheableObject() - { - //MyCache cache = _cache.Target as MyCache; - if (_cache != null) - { - Console.WriteLine("Finalized: " + this._value); - if(this.gotten())//this object has been gotten, second chance before adding to LRU - { - this.setGet(false); - } - else - { - _cache.LRU(this); - } - //GC.SuppressFinalize(this);//I know this looks weird, trust me. Don't delete - GC.ReRegisterForFinalize(this); - } - else - { - //This call to suppress is not necessary since it was not reregistered - GC.SuppressFinalize(this); - //Console.WriteLine("Cache does not exist. Do not revive."); - } - } - } -} diff --git a/README.md b/README.md deleted file mode 100644 index 973a7f1..0000000 --- a/README.md +++ /dev/null @@ -1,27 +0,0 @@ -# FinalCache -FinalCache uses LRU to evict entries. However it does not use access-history to compute LRU. Rather when objects become unused they become managed by LRU. Usage is determined by the garbage collector. - -## .NET Core (Cross-Platform) - - -> dotnet build - -> dotnet run - - -## Linux: - -Required: Mono SDK - -> dmcs Program.cs - -> ./Program.exe - - -## Windows: - -Required: Visual Studio or Microsoft Build Tools/SDK - -> csc Program.cs - -> .\Program.exe diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..67df445 --- /dev/null +++ b/build.gradle @@ -0,0 +1,33 @@ +buildscript { + ext.kotlin_version = '1.2.70' + + repositories { + mavenCentral() + } + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +version '1.0-SNAPSHOT' + +apply plugin: 'java' +apply plugin: 'kotlin' + +sourceCompatibility = 1.8 + +repositories { + mavenCentral() +} + +dependencies { + compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" + testCompile group: 'junit', name: 'junit', version: '4.12' +} + +compileKotlin { + kotlinOptions.jvmTarget = "1.8" +} +compileTestKotlin { + kotlinOptions.jvmTarget = "1.8" +} \ No newline at end of file diff --git a/cacheSizeRaw.txt b/cacheSizeRaw.txt new file mode 100644 index 0000000..e20db7e --- /dev/null +++ b/cacheSizeRaw.txt @@ -0,0 +1,112 @@ +intervalMax: 30 +intervalMin: 0 +intervalMax: 53 +intervalMin: 30 +intervalMax: 53 +intervalMin: 53 +intervalMax: 61 +intervalMin: 53 +intervalMax: 78 +intervalMin: 61 +intervalMax: 78 +intervalMin: 78 +intervalMax: 78 +intervalMin: 78 +intervalMax: 78 +intervalMin: 78 +intervalMax: 125 +intervalMin: 78 +intervalMax: 127 +intervalMin: 126 +intervalMax: 133 +intervalMin: 127 +intervalMax: 146 +intervalMin: 133 +intervalMax: 147 +intervalMin: 146 +intervalMax: 157 +intervalMin: 146 +intervalMax: 208 +intervalMin: 158 +intervalMax: 208 +intervalMin: 208 +intervalMax: 208 +intervalMin: 208 +intervalMax: 208 +intervalMin: 208 +intervalMax: 212 +intervalMin: 208 +intervalMax: 212 +intervalMin: 212 +intervalMax: 232 +intervalMin: 212 +intervalMax: 234 +intervalMin: 232 +intervalMax: 241 +intervalMin: 234 +intervalMax: 251 +intervalMin: 241 +intervalMax: 283 +intervalMin: 252 +intervalMax: 316 +intervalMin: 283 +intervalMax: 333 +intervalMin: 316 +intervalMax: 375 +intervalMin: 333 +intervalMax: 393 +intervalMin: 375 +intervalMax: 393 +intervalMin: 393 +intervalMax: 393 +intervalMin: 393 +intervalMax: 393 +intervalMin: 393 +intervalMax: 393 +intervalMin: 393 +intervalMax: 393 +intervalMin: 393 +intervalMax: 393 +intervalMin: 393 +intervalMax: 393 +intervalMin: 393 +intervalMax: 409 +intervalMin: 392 +intervalMax: 412 +intervalMin: 409 +intervalMax: 419 +intervalMin: 412 +intervalMax: 426 +intervalMin: 419 +intervalMax: 433 +intervalMin: 426 +intervalMax: 437 +intervalMin: 433 +intervalMax: 436 +intervalMin: 436 +intervalMax: 436 +intervalMin: 436 +intervalMax: 437 +intervalMin: 436 +intervalMax: 437 +intervalMin: 437 +intervalMax: 437 +intervalMin: 437 +intervalMax: 437 +intervalMin: 437 +intervalMax: 437 +intervalMin: 437 +intervalMax: 437 +intervalMin: 437 +intervalMax: 438 +intervalMin: 436 +intervalMax: 438 +intervalMin: 438 +intervalMax: 438 +intervalMin: 438 +intervalMax: 440 +intervalMin: 438 +intervalMax: 441 +intervalMin: 440 +intervalMax: 442 +intervalMin: 441 diff --git a/cache_csharp.csproj b/cache_csharp.csproj deleted file mode 100644 index f808441..0000000 --- a/cache_csharp.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - - Exe - netcoreapp1.1 - - - - - - diff --git a/figure_1.png b/figure_1.png new file mode 100644 index 0000000..6e59c47 Binary files /dev/null and b/figure_1.png differ diff --git a/fire_log.sh b/fire_log.sh new file mode 100644 index 0000000..78f9c98 --- /dev/null +++ b/fire_log.sh @@ -0,0 +1,4 @@ +#!/bin/bash +export MOZ_LOG=timestamp,cache2:5 +export MOZ_LOG_FILE=/tmp/cache-log.txt +~/Downloads/firefox/firefox & # currently testing with firefox 56 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..b981662 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..43fee1d --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Tue Jun 19 14:21:09 MDT 2018 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.7-bin.zip diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..cccdd3d --- /dev/null +++ b/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..e95643d --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/parsers/__init__.py b/parsers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/parsers/grapher.py b/parsers/grapher.py new file mode 100644 index 0000000..65225be --- /dev/null +++ b/parsers/grapher.py @@ -0,0 +1,25 @@ +import matplotlib.pyplot as plt +import numpy as np +import sys +import os + +resultsFiles = os.listdir("results") +alldata = [] +for resultFile in resultsFiles: + with open("results/" + resultFile) as rawFile: + data = [] + for line in rawFile: + if "intervalDooms" in line: + data.append(int(line.split("= ")[1])) + + alldata.insert(0, data) # os.listdir() lists files in opposite order than you'd thing + +plt.boxplot(alldata) + +plt.xlabel('Interval Size') +plt.ylabel('Dooms per interval') + +axes = plt.axes() +axes.set_xticklabels(['50', '250', '500']) + +plt.show() diff --git a/parsers/histographer.py b/parsers/histographer.py new file mode 100644 index 0000000..033f7fe --- /dev/null +++ b/parsers/histographer.py @@ -0,0 +1,16 @@ +import matplotlib.pyplot as plt +import numpy as np +import sys + + +data = [] +for line in sys.stdin: + data.append(int(line.split(" ")[1])) + +plt.hist(data) + +plt.title("Entry Lifetime") +plt.xlabel("Lifetime in Accesses") +plt.ylabel("Frequency") + +plt.show() diff --git a/parsers/racechecker.py b/parsers/racechecker.py new file mode 100644 index 0000000..e6185cb --- /dev/null +++ b/parsers/racechecker.py @@ -0,0 +1,34 @@ +from datetime import datetime as dt + +invaliddates = 0 +dates = [] +with open('../resources/fire_logs/16klog.txt') as fp: + for line in fp: + # no need to include the UTC thing + try: + date = dt.strptime(line[:26], '%Y-%m-%d %H:%M:%S.%f') + dates.append(date) + except: + # some lines only have a single element? + # they just report offsets and some other + # stuff, no idea why they don't have a date + # print(line) + invaliddates += 1 + +print(invaliddates) +date_ordinals = [d.timestamp() for d in dates] +print(type(date_ordinals)) +print(type(date_ordinals[0])) + +if sorted(date_ordinals) == date_ordinals: + print("In sorted order...") +else: + print("The events here did not occur the way you think they did") + +# if len(date_ordinals) == 1: +# print("uniq") +# elif (max(date_ordinals) - min(date_ordinals)) == len(date_ordinals) - 1: +# print("consecutive") +# else: +# print("not consecutive") + diff --git a/parsers/sizeGrapher.py b/parsers/sizeGrapher.py new file mode 100644 index 0000000..9af7462 --- /dev/null +++ b/parsers/sizeGrapher.py @@ -0,0 +1,18 @@ +import matplotlib.pyplot as plt +import numpy as np +import sys + +maxs = [] +mins = [] + +for line in sys.stdin: + if "Max" in line: + maxs.append(int(line.split(": ")[1])) + if "Min" in line: + mins.append(int(line.split(": ")[1])) + +x = np.linspace(0, 20, len(maxs)) + +plt.plot(x, maxs, '-b', label='Max') +plt.plot(x, mins, '-r', label='Min') +plt.show() diff --git a/results/results050.txt b/results/results050.txt new file mode 100644 index 0000000..e0f2e23 --- /dev/null +++ b/results/results050.txt @@ -0,0 +1,390 @@ +intervalNum = 1 +intervalHit = 52 +intervalDooms = 1 +intervalNum = 2 +intervalHit = 29 +intervalDooms = 1 +intervalNum = 3 +intervalHit = 32 +intervalDooms = 2 +intervalNum = 4 +intervalHit = 30 +intervalDooms = 3 +intervalNum = 5 +intervalHit = 10 +intervalDooms = 2 +intervalNum = 6 +intervalHit = 4 +intervalDooms = 6 +intervalNum = 7 +intervalHit = 10 +intervalDooms = 2 +intervalNum = 8 +intervalHit = 4 +intervalDooms = 1 +intervalNum = 9 +intervalHit = 10 +intervalDooms = 8 +intervalNum = 10 +intervalHit = 2 +intervalDooms = 4 +intervalNum = 11 +intervalHit = 0 +intervalDooms = 9 +intervalNum = 12 +intervalHit = 2 +intervalDooms = 13 +intervalNum = 13 +intervalHit = 12 +intervalDooms = 12 +intervalNum = 14 +intervalHit = 4 +intervalDooms = 2 +intervalNum = 15 +intervalHit = 2 +intervalDooms = 31 +intervalNum = 16 +intervalHit = 2 +intervalDooms = 6 +intervalNum = 17 +intervalHit = 70 +intervalDooms = 3 +intervalNum = 18 +intervalHit = 18 +intervalDooms = 5 +intervalNum = 19 +intervalHit = 22 +intervalDooms = 9 +intervalNum = 20 +intervalHit = 12 +intervalDooms = 35 +intervalNum = 21 +intervalHit = 10 +intervalDooms = 10 +intervalNum = 22 +intervalHit = 12 +intervalDooms = 10 +intervalNum = 23 +intervalHit = 4 +intervalDooms = 12 +intervalNum = 24 +intervalHit = 2 +intervalDooms = 4 +intervalNum = 25 +intervalHit = 14 +intervalDooms = 2 +intervalNum = 26 +intervalHit = 81 +intervalDooms = 1 +intervalNum = 27 +intervalHit = 202 +intervalDooms = 2 +intervalNum = 28 +intervalHit = 42 +intervalDooms = 1 +intervalNum = 29 +intervalHit = 10 +intervalDooms = 1 +intervalNum = 30 +intervalHit = 12 +intervalDooms = 1 +intervalNum = 31 +intervalHit = 92 +intervalDooms = 1 +intervalNum = 32 +intervalHit = 37 +intervalDooms = 2 +intervalNum = 33 +intervalHit = 42 +intervalDooms = 1 +intervalNum = 34 +intervalHit = 18 +intervalDooms = 1 +intervalNum = 35 +intervalHit = 39 +intervalDooms = 1 +intervalNum = 36 +intervalHit = 12 +intervalDooms = 1 +intervalNum = 37 +intervalHit = 24 +intervalDooms = 2 +intervalNum = 38 +intervalHit = 22 +intervalDooms = 1 +intervalNum = 39 +intervalHit = 28 +intervalDooms = 1 +intervalNum = 40 +intervalHit = 0 +intervalDooms = 1 +intervalNum = 41 +intervalHit = 2 +intervalDooms = 1 +intervalNum = 42 +intervalHit = 9 +intervalDooms = 3 +intervalNum = 43 +intervalHit = 12 +intervalDooms = 1 +intervalNum = 44 +intervalHit = 12 +intervalDooms = 5 +intervalNum = 45 +intervalHit = 4 +intervalDooms = 3 +intervalNum = 46 +intervalHit = 72 +intervalDooms = 4 +intervalNum = 47 +intervalHit = 14 +intervalDooms = 4 +intervalNum = 48 +intervalHit = 64 +intervalDooms = 1 +intervalNum = 49 +intervalHit = 22 +intervalDooms = 7 +intervalNum = 50 +intervalHit = 22 +intervalDooms = 2 +intervalNum = 51 +intervalHit = 26 +intervalDooms = 2 +intervalNum = 52 +intervalHit = 20 +intervalDooms = 1 +intervalNum = 53 +intervalHit = 20 +intervalDooms = 1 +intervalNum = 54 +intervalHit = 167 +intervalDooms = 3 +intervalNum = 55 +intervalHit = 44 +intervalDooms = 3 +intervalNum = 56 +intervalHit = 78 +intervalDooms = 1 +intervalNum = 57 +intervalHit = 24 +intervalDooms = 3 +intervalNum = 58 +intervalHit = 30 +intervalDooms = 3 +intervalNum = 59 +intervalHit = 7 +intervalDooms = 19 +intervalNum = 60 +intervalHit = 0 +intervalDooms = 2 +intervalNum = 61 +intervalHit = 8 +intervalDooms = 2 +intervalNum = 62 +intervalHit = 2 +intervalDooms = 3 +intervalNum = 63 +intervalHit = 12 +intervalDooms = 9 +intervalNum = 64 +intervalHit = 12 +intervalDooms = 12 +intervalNum = 65 +intervalHit = 9 +intervalDooms = 8 +intervalNum = 66 +intervalHit = 10 +intervalDooms = 1 +intervalNum = 67 +intervalHit = 51 +intervalDooms = 6 +intervalNum = 68 +intervalHit = 19 +intervalDooms = 15 +intervalNum = 69 +intervalHit = 17 +intervalDooms = 9 +intervalNum = 70 +intervalHit = 111 +intervalDooms = 1 +intervalNum = 71 +intervalHit = 27 +intervalDooms = 8 +intervalNum = 72 +intervalHit = 21 +intervalDooms = 17 +intervalNum = 73 +intervalHit = 15 +intervalDooms = 6 +intervalNum = 74 +intervalHit = 16 +intervalDooms = 19 +intervalNum = 75 +intervalHit = 12 +intervalDooms = 12 +intervalNum = 76 +intervalHit = 16 +intervalDooms = 18 +intervalNum = 77 +intervalHit = 11 +intervalDooms = 18 +intervalNum = 78 +intervalHit = 0 +intervalDooms = 21 +intervalNum = 79 +intervalHit = 14 +intervalDooms = 17 +intervalNum = 80 +intervalHit = 46 +intervalDooms = 15 +intervalNum = 81 +intervalHit = 180 +intervalDooms = 3 +intervalNum = 82 +intervalHit = 88 +intervalDooms = 5 +intervalNum = 83 +intervalHit = 10 +intervalDooms = 1 +intervalNum = 84 +intervalHit = 12 +intervalDooms = 2 +intervalNum = 85 +intervalHit = 2 +intervalDooms = 1 +intervalNum = 86 +intervalHit = 11 +intervalDooms = 17 +intervalNum = 87 +intervalHit = 36 +intervalDooms = 1 +intervalNum = 88 +intervalHit = 122 +intervalDooms = 4 +intervalNum = 89 +intervalHit = 0 +intervalDooms = 1 +intervalNum = 90 +intervalHit = 44 +intervalDooms = 11 +intervalNum = 91 +intervalHit = 4 +intervalDooms = 5 +intervalNum = 92 +intervalHit = 74 +intervalDooms = 15 +intervalNum = 93 +intervalHit = 4 +intervalDooms = 15 +intervalNum = 94 +intervalHit = 18 +intervalDooms = 24 +intervalNum = 95 +intervalHit = 10 +intervalDooms = 10 +intervalNum = 96 +intervalHit = 5 +intervalDooms = 21 +intervalNum = 97 +intervalHit = 2 +intervalDooms = 6 +intervalNum = 98 +intervalHit = 36 +intervalDooms = 6 +intervalNum = 99 +intervalHit = 0 +intervalDooms = 2 +intervalNum = 100 +intervalHit = 0 +intervalDooms = 7 +intervalNum = 101 +intervalHit = 8 +intervalDooms = 10 +intervalNum = 102 +intervalHit = 7 +intervalDooms = 6 +intervalNum = 103 +intervalHit = 9 +intervalDooms = 5 +intervalNum = 104 +intervalHit = 2 +intervalDooms = 4 +intervalNum = 105 +intervalHit = 54 +intervalDooms = 12 +intervalNum = 106 +intervalHit = 12 +intervalDooms = 1 +intervalNum = 107 +intervalHit = 3 +intervalDooms = 35 +intervalNum = 108 +intervalHit = 0 +intervalDooms = 11 +intervalNum = 109 +intervalHit = 4 +intervalDooms = 4 +intervalNum = 110 +intervalHit = 6 +intervalDooms = 20 +intervalNum = 111 +intervalHit = 2 +intervalDooms = 34 +intervalNum = 112 +intervalHit = 0 +intervalDooms = 3 +intervalNum = 113 +intervalHit = 2 +intervalDooms = 36 +intervalNum = 114 +intervalHit = 40 +intervalDooms = 100 +intervalNum = 115 +intervalHit = 84 +intervalDooms = 24 +intervalNum = 116 +intervalHit = 6 +intervalDooms = 14 +intervalNum = 117 +intervalHit = 142 +intervalDooms = 7 +intervalNum = 118 +intervalHit = 14 +intervalDooms = 7 +intervalNum = 119 +intervalHit = 9 +intervalDooms = 4 +intervalNum = 120 +intervalHit = 58 +intervalDooms = 3 +intervalNum = 121 +intervalHit = 2 +intervalDooms = 2 +intervalNum = 122 +intervalHit = 49 +intervalDooms = 1 +intervalNum = 123 +intervalHit = 2 +intervalDooms = 1 +intervalNum = 124 +intervalHit = 45 +intervalDooms = 1 +intervalNum = 125 +intervalHit = 0 +intervalDooms = 2 +intervalNum = 126 +intervalHit = 0 +intervalDooms = 1 +intervalNum = 127 +intervalHit = 0 +intervalDooms = 1 +intervalNum = 128 +intervalHit = 0 +intervalDooms = 20 +intervalNum = 129 +intervalHit = 1 +intervalDooms = 31 +intervalNum = 130 +intervalHit = 0 +intervalDooms = 15 diff --git a/results/results250.txt b/results/results250.txt new file mode 100644 index 0000000..325ac8d --- /dev/null +++ b/results/results250.txt @@ -0,0 +1,150 @@ +intervalNum = 1 +intervalHit = 52 +intervalDooms = 1 +intervalNum = 2 +intervalHit = 93 +intervalDooms = 7 +intervalNum = 3 +intervalHit = 28 +intervalDooms = 13 +intervalNum = 4 +intervalHit = 12 +intervalDooms = 31 +intervalNum = 5 +intervalHit = 16 +intervalDooms = 29 +intervalNum = 6 +intervalHit = 74 +intervalDooms = 25 +intervalNum = 7 +intervalHit = 62 +intervalDooms = 59 +intervalNum = 8 +intervalHit = 26 +intervalDooms = 27 +intervalNum = 9 +intervalHit = 87 +intervalDooms = 2 +intervalNum = 10 +intervalHit = 202 +intervalDooms = 2 +intervalNum = 11 +intervalHit = 156 +intervalDooms = 4 +intervalNum = 12 +intervalHit = 79 +intervalDooms = 3 +intervalNum = 13 +intervalHit = 57 +intervalDooms = 2 +intervalNum = 14 +intervalHit = 58 +intervalDooms = 4 +intervalNum = 15 +intervalHit = 28 +intervalDooms = 2 +intervalNum = 16 +intervalHit = 35 +intervalDooms = 10 +intervalNum = 17 +intervalHit = 76 +intervalDooms = 7 +intervalNum = 18 +intervalHit = 78 +intervalDooms = 5 +intervalNum = 19 +intervalHit = 70 +intervalDooms = 11 +intervalNum = 20 +intervalHit = 207 +intervalDooms = 5 +intervalNum = 21 +intervalHit = 122 +intervalDooms = 4 +intervalNum = 22 +intervalHit = 54 +intervalDooms = 6 +intervalNum = 23 +intervalHit = 15 +intervalDooms = 23 +intervalNum = 24 +intervalHit = 45 +intervalDooms = 33 +intervalNum = 25 +intervalHit = 51 +intervalDooms = 6 +intervalNum = 26 +intervalHit = 36 +intervalDooms = 24 +intervalNum = 27 +intervalHit = 111 +intervalDooms = 1 +intervalNum = 28 +intervalHit = 63 +intervalDooms = 31 +intervalNum = 29 +intervalHit = 16 +intervalDooms = 19 +intervalNum = 30 +intervalHit = 12 +intervalDooms = 12 +intervalNum = 31 +intervalHit = 41 +intervalDooms = 74 +intervalNum = 32 +intervalHit = 226 +intervalDooms = 18 +intervalNum = 33 +intervalHit = 88 +intervalDooms = 5 +intervalNum = 34 +intervalHit = 32 +intervalDooms = 15 +intervalNum = 35 +intervalHit = 161 +intervalDooms = 11 +intervalNum = 36 +intervalHit = 44 +intervalDooms = 12 +intervalNum = 37 +intervalHit = 78 +intervalDooms = 20 +intervalNum = 38 +intervalHit = 37 +intervalDooms = 70 +intervalNum = 39 +intervalHit = 38 +intervalDooms = 21 +intervalNum = 40 +intervalHit = 26 +intervalDooms = 25 +intervalNum = 41 +intervalHit = 66 +intervalDooms = 29 +intervalNum = 42 +intervalHit = 7 +intervalDooms = 52 +intervalNum = 43 +intervalHit = 8 +intervalDooms = 39 +intervalNum = 44 +intervalHit = 126 +intervalDooms = 160 +intervalNum = 45 +intervalHit = 6 +intervalDooms = 14 +intervalNum = 46 +intervalHit = 142 +intervalDooms = 9 +intervalNum = 47 +intervalHit = 81 +intervalDooms = 12 +intervalNum = 48 +intervalHit = 51 +intervalDooms = 3 +intervalNum = 49 +intervalHit = 47 +intervalDooms = 2 +intervalNum = 50 +intervalHit = 0 +intervalDooms = 7 diff --git a/results/results500.txt b/results/results500.txt new file mode 100644 index 0000000..68e4538 --- /dev/null +++ b/results/results500.txt @@ -0,0 +1,90 @@ +intervalNum = 1 +intervalHit = 52 +intervalDooms = 1 +intervalNum = 2 +intervalHit = 119 +intervalDooms = 17 +intervalNum = 3 +intervalHit = 30 +intervalDooms = 48 +intervalNum = 4 +intervalHit = 96 +intervalDooms = 52 +intervalNum = 5 +intervalHit = 153 +intervalDooms = 76 +intervalNum = 6 +intervalHit = 244 +intervalDooms = 3 +intervalNum = 7 +intervalHit = 193 +intervalDooms = 6 +intervalNum = 8 +intervalHit = 93 +intervalDooms = 5 +intervalNum = 9 +intervalHit = 52 +intervalDooms = 4 +intervalNum = 10 +intervalHit = 108 +intervalDooms = 16 +intervalNum = 11 +intervalHit = 148 +intervalDooms = 16 +intervalNum = 12 +intervalHit = 207 +intervalDooms = 5 +intervalNum = 13 +intervalHit = 146 +intervalDooms = 7 +intervalNum = 14 +intervalHit = 47 +intervalDooms = 34 +intervalNum = 15 +intervalHit = 47 +intervalDooms = 29 +intervalNum = 16 +intervalHit = 47 +intervalDooms = 2 +intervalNum = 17 +intervalHit = 36 +intervalDooms = 24 +intervalNum = 18 +intervalHit = 159 +intervalDooms = 26 +intervalNum = 19 +intervalHit = 35 +intervalDooms = 36 +intervalNum = 20 +intervalHit = 35 +intervalDooms = 50 +intervalNum = 21 +intervalHit = 240 +intervalDooms = 43 +intervalNum = 22 +intervalHit = 106 +intervalDooms = 7 +intervalNum = 23 +intervalHit = 175 +intervalDooms = 24 +intervalNum = 24 +intervalHit = 122 +intervalDooms = 32 +intervalNum = 25 +intervalHit = 75 +intervalDooms = 89 +intervalNum = 26 +intervalHit = 80 +intervalDooms = 39 +intervalNum = 27 +intervalHit = 27 +intervalDooms = 105 +intervalNum = 28 +intervalHit = 132 +intervalDooms = 177 +intervalNum = 29 +intervalHit = 223 +intervalDooms = 21 +intervalNum = 30 +intervalHit = 98 +intervalDooms = 5 diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..1ff1e76 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,2 @@ +rootProject.name = 'cache-java' + diff --git a/src/main/java/FinalCache.java b/src/main/java/FinalCache.java new file mode 100644 index 0000000..a4cca2d --- /dev/null +++ b/src/main/java/FinalCache.java @@ -0,0 +1,120 @@ +import java.util.HashMap; +import java.util.Map; +import java.util.TreeMap; + + +public class FinalCache { + private Map cache; + private LruCache doomed; + private int doomedSize;//of lru + + /** + * for the Histogram + */ + static class Tracker{ + int gets; + int addedAt; + int removedAt; + boolean removed; + + Tracker(){} + + Tracker(int addedAt){this.addedAt = addedAt;} + + @Override + public String toString() { + return String.format("gets: %d addedAt: %d removed: %s removedAt: %d", gets, addedAt, removed, removedAt); + } + } + Map trackingMap; + + public FinalCache(int doomedSize){ + this.doomedSize = doomedSize; + cache = new HashMap<>(doomedSize); + doomed = new LruCache<>(doomedSize); + trackingMap = new HashMap<>(); + } + + public int size(){ + return cache.size()+doomed.size(); + } + + public void remove(K key){ + if(key == null) return; + cache.remove(key); + doomed.remove(key); + + //TODO removed at... + if(trackingMap.containsKey(key)){ + trackingMap.get(key).removed = true; + } + } + + public void add(K key, V val) { + cache.remove(key); + cache.putIfAbsent(key,val); + doomed.remove(key); + //TODO added at... + if(!trackingMap.containsKey(key)){ + trackingMap.putIfAbsent(key, new Tracker()); + } + } + + public void add(K key, V val, int addedAt){ + cache.remove(key); + cache.putIfAbsent(key, val); + doomed.remove(key); + if(!trackingMap.containsKey(key)){ + trackingMap.putIfAbsent(key, new Tracker(addedAt)); + } + } + + public V get(K key) { + if(key == null) return null; + if(doomed.containsKey(key)){//doomed contains key + V c = doomed.get(key); + trackingMap.get(key).gets++; + return c; + } + + else if(cache.containsKey(key)){ + trackingMap.get(key).gets++; + doomed.remove(key); + return cache.get(key); + } + return null; + } + + public boolean containsKey(K key){ + return cache.containsKey(key) || doomed.containsKey(key); + } + + //to be called when entry is doomed + public void update(K key){ + if(cache.containsKey(key)){ + //move from cache to doomed set + V c = cache.get(key); + cache.remove(key); + doomed.remove(key); + doomed.putIfAbsent(key, c); + } + else if(doomed.containsKey(key)) { + System.out.println("That's odd: "+key.toString()); + } + else{ + //System.out.println("Doom without an add:"+key.toString()); + } + } + + public int getDoomedSetAmountDoomed(){ + return doomed.getAmountDoomed(); + } + + public void resetDoomedSetAmountDoomed(){ + doomed.resetAmountDoomed(); + } + + public K getRecentEvection(){ + return doomed.getRecentEviction(); + } +} diff --git a/src/main/java/IntervalFinalCache.java b/src/main/java/IntervalFinalCache.java new file mode 100644 index 0000000..c0f7679 --- /dev/null +++ b/src/main/java/IntervalFinalCache.java @@ -0,0 +1,53 @@ +public class IntervalFinalCache { + private FinalCache cache; + private LruCache interval; + private int initialFinalCacheSize, intervalSize; + + public IntervalFinalCache(int intervalSize){ + this(10, intervalSize); + } + + public IntervalFinalCache(int initialFinalCacheSize, int intervalSize){ + this.initialFinalCacheSize = initialFinalCacheSize; + cache = new FinalCache<>(initialFinalCacheSize); + + this.intervalSize = intervalSize; + interval = new LruCache<>(intervalSize); + } + + public void add(K key, V val) { + cache.add(key, val); + } + + public V get(K key) { + //null if nothing + return cache.get(key); + } + + //meant to be called with items that are doomed + //tracking LRU on them + public void addToInterval(K key, V val){ + interval.put(key, val); + } + + //meant to be called when interval has elapsed + //dumps entire interval into finalcache + //the interval, whatever it is (time, accesses etc) is + //meant to be handled outside of this class. + public void dumpInterval(){ + interval.forEach((K, V) -> cache.add(K, V)); + interval.clear(); + } + + public void remove(K key){ + cache.remove(key); + } + + public int getDoomedSetAmountDoomed(){ + return cache.getDoomedSetAmountDoomed(); + } + + public void resetDoomedSetAmountDoomed(){ + cache.resetDoomedSetAmountDoomed(); + } +} diff --git a/src/main/java/LruCache.java b/src/main/java/LruCache.java new file mode 100644 index 0000000..281f25e --- /dev/null +++ b/src/main/java/LruCache.java @@ -0,0 +1,66 @@ +import java.util.*; + +public class LruCache extends LinkedHashMap { + private int size; + private K recentEviction; + private int amountDoomed; + + /** + * An interface for being alerted when an entry is evicted from this cache + * passes in the entry evicted + */ + interface OnEntryEvictedListener{ + void onEntryEvicted(String key, String val); + } + + //a list of listeners to be notified when an entry is evicted + private List listeners; + + public LruCache(int size) { + //size + //load factor + //set access order to be true + super(size, .75f, true); + this.size = size; + recentEviction = null; + + //size 10 why not? + listeners = new ArrayList<>(10); + } + + public void addOnEntryEvictedListener(OnEntryEvictedListener listener){ + listeners.add(listener); + } + + //called for maintenance + //specifies to remove the least recently used when + //the size has grown to be equal to the size + //the client has stipulated + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + if (size() > size) { + this.amountDoomed++; + recentEviction = eldest.getKey(); + //notify listeners + listeners.forEach(listener -> { + listener.onEntryEvicted(eldest.getKey().toString(), eldest.getValue().toString()); + }); + return true; + } + return false; + } + + public K getRecentEviction() { + return recentEviction; + } + + public void resetAmountDoomed(){ + amountDoomed = 0; + } + + public int getAmountDoomed(){ + return amountDoomed; + } +} + + diff --git a/src/main/java/NenovCache.java b/src/main/java/NenovCache.java new file mode 100644 index 0000000..14b94f3 --- /dev/null +++ b/src/main/java/NenovCache.java @@ -0,0 +1,128 @@ +/** + * Author: Aleksandr Diamond on 5/29/2018 + * Assignment: cache-java + * Purpose: + */ +public class NenovCache { + //cache for strongly referenced entries + //it is string to boolean so we can + //know if it has been doomed recently + LruCache strongCache; + + //cache for entries that have been evicted into + //a weak reference from the strongCache + FinalCache weakCache; + + //size of strongCache + int strongCacheSize; + NenovCache(int strongCacheSize){ + this.strongCacheSize = strongCacheSize; + this.strongCache = new LruCache<>(strongCacheSize); + this.weakCache = new FinalCache<>(0); + this.strongCache.addOnEntryEvictedListener(NenovCache.this::onStrongEntryEvicted); + } + + /** + * Adds the specified key-val pair if there is room. + * Assumes that entry has not been doomed as of yet + * @param key The key to be added to the cache + */ + public void add(String key){ + if(this.strongCacheSize == 0) + { + weakCache.add(key,null); + } + else if(!strongCache.containsKey(key)||!weakCache.containsKey(key)) + { + strongCache.remove(key); + strongCache.putIfAbsent(key,false); + weakCache.remove(key); + } + } + + /** + * To be called when a doom even happens + * @param entry The entry that has been doomed + */ + public void update(String entry){ + //if it is in strongCache and if it has not been doomed + if(strongCache.containsKey(entry) ){//&& !strongCache.get(entry)){ + //set the flag to true because its been doomed + //it will be set back if the entry is accessed + strongCache.replace(entry, true); + } + else if(weakCache.containsKey(entry)){ + //if its in the weakCache just remove it + weakCache.remove(entry); + } + } + + /** + * + * @param key The key to be removed from the cache + */ + public void remove(String key){ + strongCache.remove(key); + weakCache.remove(key); + } + + /** + * + * @param key The key to be tested + * @return True if in this cache, false otherwise + */ + public boolean containsKey(String key){ + return strongCache.containsKey(key) || weakCache.containsKey(key); + } + + /** + * A simulated get function. Used to update the caches + * order and eviction policies. + * @param key Entry to retrieve + * @return If key is in strongcache return its flag value. Otherwise return whether key is in weakcache. + */ + public boolean get(String key){ + if (strongCacheSize == 0) + { + return weakCache.containsKey(key); + } + if(strongCache.containsKey(key)){ + boolean flag = strongCache.get(key);//its been accessed so set flag to false + strongCache.replace(key,flag); + return true ;//strongCache.get(key); + } + else if(weakCache.containsKey(key)) { + weakCache.remove(key); + strongCache.putIfAbsent(key, false); + strongCache.get(key); + return true; + } + else{ + return false; + } + } + + /** + * + * @return The combined size of the strong and weak caches + */ + public int size(){ + return strongCache.size() + weakCache.size(); + } + + /** + * Notified when LRU strongCache evicts an entry + * @param key The key of the evicted entry + * @param val The val of the evicted entry + */ + protected void onStrongEntryEvicted(String key, String val){ + //has to do with how java treats nested interfaces + //and generics... + //val will always be boolean because of the way this model works + if(!Boolean.parseBoolean(val)){ + //value can be null + weakCache.add(key, null); + } + //otherwise the entry is removed + } +} diff --git a/src/test/java/AddOnMissLruTest.java b/src/test/java/AddOnMissLruTest.java new file mode 100644 index 0000000..d4d8a66 --- /dev/null +++ b/src/test/java/AddOnMissLruTest.java @@ -0,0 +1,63 @@ +import java.io.FileNotFoundException; + +/** TODO, Collect + * Regular additions, + * Adds because of misses, + * Num of Evictions (regular as well) + */ + +public class AddOnMissLruTest extends TestUtils{ + LruCache cache; + LruCache addOnMissCache; + int lruHits, addOnMissHits; + int adds, addsOnMiss; + int evictions;//evictions from addOnMissCache + + AddOnMissLruTest(int size){ + cache = new LruCache<>(size); + addOnMissCache = new LruCache<>(size); + addOnMissCache.addOnEntryEvictedListener((key, val) -> evictions++); + } + + @Override + void newEntryHandler(String entry) { + cache.put(entry, entry); + addOnMissCache.put(entry, entry); + adds++; + } + + @Override + void accessHandler(String entry) { + //symbolic 'gets' to maintain lru + if(cache.get(entry) != null) lruHits++; + + if(addOnMissCache.get(entry) != null){ + addOnMissHits++; + } + else { + //add on miss + addOnMissCache.put(entry, entry); + addsOnMiss++; + } + } + + public static void main(String[] args) throws FileNotFoundException { + AddOnMissLruTest test; + int[] sizes = + {50, 100, 250, 500, 1000, 1200, + 2000, 3000, 4000, 5000, 6000, 7000, + 8000, 9000, 10_000}; + for (int size : sizes) { + test = new AddOnMissLruTest(size); + test.iterateLogs(); + System.out.println("test of size " + size); + System.out.println("test.addOnMissHits = " + test.addOnMissHits); + System.out.println("test.addsOnMiss = " + test.addsOnMiss); + System.out.println("test.adds = " + test.adds); + System.out.println("test.evictions = " + test.evictions); + System.out.println(); + } + + + } +} diff --git a/src/test/java/AddOnMissNenovTest.java b/src/test/java/AddOnMissNenovTest.java new file mode 100644 index 0000000..babacc9 --- /dev/null +++ b/src/test/java/AddOnMissNenovTest.java @@ -0,0 +1,49 @@ +import java.io.FileNotFoundException; +public class AddOnMissNenovTest extends TestUtils{ + NenovCache cache; + int hits; + + AddOnMissNenovTest(int size){ + cache = new NenovCache(size); + } + + @Override + void newEntryHandler(String entry) { + cache.add(entry); + } + + @Override + void accessHandler(String entry) { + if(!cache.containsKey(entry)) { + cache.add(entry); + } else { + cache.get(entry); + hits++; + } + } + + @Override + void doomHandler(String entry) { + cache.update(entry); + } + + @Override + void removalHandler(String entry) { + cache.remove(entry); + } + + public static void main(String[] args) throws FileNotFoundException { + AddOnMissNenovTest test; + + int[] sizes = + {50, 100, 250, 500, 1000, 1200, + 2000, 3000, 4000, 5000, 6000, 7000, + 8000, 9000, 10_000}; + for (int size : sizes) { + System.out.println("Starting test of size: " + size); + test = new AddOnMissNenovTest(size); + test.iterateLogs(); + System.out.println("test.hits = " + test.hits); + } + } +} diff --git a/src/test/java/FiguresTest.java b/src/test/java/FiguresTest.java new file mode 100644 index 0000000..4663cac --- /dev/null +++ b/src/test/java/FiguresTest.java @@ -0,0 +1,61 @@ +import java.io.File; +import java.io.FileNotFoundException; +import java.io.PrintStream; +import java.util.HashSet; + +public class FiguresTest extends TestUtils{ + int additions; + int removals; + int dooms; + int accesses; + + /** + * Holds the unique keys associated with each addition + */ + HashSet keys = new HashSet<>(); + + /** + * Miss was unavoidable if there was an access but never an add for an entry + */ + int unavoidableMisses; + + @Override + void newEntryHandler(String entry) { + additions++; + keys.add(entry); + } + + @Override + void removalHandler(String entry) { + removals++; + } + + @Override + void doomHandler(String entry) { + dooms++; + } + + @Override + void accessHandler(String entry) { + accesses++; + if(!keys.contains(entry)){ + unavoidableMisses++; + } + } + + public static void main(String[] args) throws FileNotFoundException { + FiguresTest test = new FiguresTest(); +// System.setOut(new PrintStream(new File("addKeys.txt"))); + try { + test.iterateLogs(); + System.out.println("test.additions = " + test.additions); + System.out.println("unique additions = " + test.keys.size()); + System.out.println("test.dooms = " + test.dooms); + System.out.println("test.removals = " + test.removals); + System.out.println("test.accesses = " + test.accesses); + System.out.println("test.unavoidableMisses = " + test.unavoidableMisses); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + } +} diff --git a/src/test/java/FinalCacheTest.java b/src/test/java/FinalCacheTest.java new file mode 100644 index 0000000..c6cb072 --- /dev/null +++ b/src/test/java/FinalCacheTest.java @@ -0,0 +1,190 @@ +import java.io.File; +import java.io.FileNotFoundException; +import java.io.PrintStream; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Scanner; + +public class FinalCacheTest extends TestUtils{ + FinalCache cache; + int hits; + int maxSize = Integer.MIN_VALUE; + FinalCacheTest(int size){ + cache = new FinalCache<>(size); + } + + @Override + void newEntryHandler(String entry) { + //no need to have value, just + //keeping track of keys + //adding this as val to not + //break check for lruhits + cache.add(entry, "");//entry); + maxSize = Math.max(maxSize, cache.size()); + } + + @Override + void accessHandler(String entry) { + if(cache.get(entry) != null) hits++; + maxSize = Math.max(maxSize, cache.size()); + } + + @Override + void doomHandler(String entry) { + cache.update(entry); + maxSize = Math.max(maxSize, cache.size()); + } + + @Override + void removalHandler(String entry) { + cache.remove(entry); + maxSize = Math.max(maxSize, cache.size()); + } + + + public static void main(String[] args) throws FileNotFoundException { + FinalCacheTest t; + int[] nums = + {0, 50, 100, 250, 500, 1000 , 1200, + 2000, 3000, 4000, 5000, 6000, 7000, + 8000, 9000, 10_000}; + for(int size : nums){ + t = new FinalCacheTest(size); + System.out.println("Starting test of size " + size); + t.iterateLogs(); + System.out.println("t.maxSize = " + t.maxSize); + System.out.println("t.fcachehits = " + t.hits); + System.out.println(); + System.out.println(); + } + + /* + int size = 50; + int lruhits = 0; + int removals = 0; + int accesses = 0, intervalSize = 100; + int potential = 0; + int fcacheRemovals = 0; + int fcacheDoomed = 0; + int dooms = 0; + int fcacheHits = 0; + + int maxSize = 0; + + FinalCache cache = new FinalCache<>(100); + LruCache lcache = new LruCache<>(10_000); + + Map trackerMap = new HashMap<>(); + + System.setOut(new PrintStream(new File("sizeRaw.txt"))); + + File fire_logs = new File("resources/fire_logs"); + for(File logFile : fire_logs.listFiles()){//all files in this directory + Scanner in = new Scanner(logFile); + //iterate over each log in each file + for(String log = null; in.hasNextLine(); log = in.nextLine()){ + if(log == null) continue; + if(TestUtils.isNewEntry(log)){ + accesses++; + if (accesses == 100) { + accesses = 0; + System.out.println("Cache Size: " + cache.size()); + } + + String id = TestUtils.newEntryKey(log); + + cache.add(id.trim(), log); + + maxSize = Math.max(maxSize, cache.size()); + + lcache.put(id, log); + + //only add if its not there + if(!trackerMap.containsKey(id.trim())){ + trackerMap.put(id.trim(), new Tracker(accesses)); + } + //get key of most recent eviction +// String recentLruEviction = lcache.getRecentEviction(); +// if(cache.get(recentLruEviction) != null){ +// potential++; +// } + } + else if(TestUtils.isDoom(log)){ + dooms++; + String id = TestUtils.doomKey(log); +// if(cache.get(id) != null){ +// fcacheDoomed++; +// } + cache.update(id); + + String recentEvection = cache.getRecentEvection(); + if(recentEvection != null){//at beginning when doomed set isnt full + trackerMap.get(recentEvection).removed = true; + trackerMap.get(recentEvection).removedAt = accesses; + } + + } + else if(TestUtils.isAccess(log) && TestUtils.hasKey(log)){ + accesses++; + if (accesses == 100) { + accesses = 0; + System.out.println("Cache Size: " + cache.size()); + } + + String id = TestUtils.accessKey(log); + if(lcache.get(id.trim()) != null){ + lruhits++; + } + if(cache.get(id.trim()) != null){ + fcacheHits++; + trackerMap.get(id.trim()).gets++; + } + } + else if(TestUtils.isRemoval(log)){ + //remove from finalcache + String id = TestUtils.removalKey(log); + if(cache.get(id) != null){ + id = id.trim(); + fcacheRemovals++; + + trackerMap.get(id.trim()).removed = true; + trackerMap.get(id.trim()).removedAt = accesses; + } + cache.remove(id); + removals++; + } + + } + in.close(); + } + */ + +// System.out.println("actual duplication: " + (fcacheHits - lruhits)); +// System.out.println("lruhits = " + lruhits); +// System.out.println("fcacheHits = " + fcacheHits); +// System.setOut(new PrintStream(new File("histogramRaw.txt"))); + + +// for(String key : trackerMap.keySet()){ +// Tracker t = trackerMap.get(key); +// if(t.removed){//if entry was removed +// System.out.println("Lifetime: " + (t.removedAt - t.addedAt) + " Entry: " + key); +// } +// } + + +// System.out.println("Tracker gets " + totalGets); +// System.out.println(cache.i); + +// System.out.println("size = " + cache.size()); +// System.out.println("lruhits = " + lruhits); +// System.out.println("potential = " + potential); +// System.out.println("maxSize = " + maxSize); +// System.out.println("removals = " + removals); +// System.out.println("fcacheRemovals = " + fcacheRemovals); +// System.out.println("fcacheDoomed = " + fcacheDoomed); +// System.out.println("dooms = " + dooms); + } + +} diff --git a/src/test/java/HistogramTest.java b/src/test/java/HistogramTest.java new file mode 100644 index 0000000..7d05d7c --- /dev/null +++ b/src/test/java/HistogramTest.java @@ -0,0 +1,87 @@ +import java.io.File; +import java.io.FileNotFoundException; +import java.io.PrintStream; +import java.util.HashMap; +import java.util.Map; + +/** + * Author: Aleksandr Diamond on 5/24/2018 + * Assignment: cache-java + * Purpose: + */ +public class HistogramTest extends TestUtils{ + FinalCache cache = new FinalCache<>(0); + Map trackerMap = new HashMap<>(); + + //intervals of accesses + int accesses = 0; + + static class Tracker{ + int gets; + int addedAt; + int removedAt; + boolean removed; + Tracker(int addedAt){this.addedAt = addedAt;} + + @Override + public String toString() { + return String.format("gets: %d addedAt: %d removed: %s removedAt: %d", gets, addedAt, removed, removedAt); + } + } + + @Override + void newEntryHandler(String entry) { + accesses++; + cache.add(entry, null); + //to avoid duplicates messing up tracking data + if(!trackerMap.containsKey(entry)){ + trackerMap.put(entry, new Tracker(accesses)); + } + } + + @Override + void doomHandler(String entry) { + cache.update(entry); + String recentEviction = cache.getRecentEvection(); + if(recentEviction != null){//at beginning when doomed set isnt full + trackerMap.get(recentEviction).removed = true; + trackerMap.get(recentEviction).removedAt = accesses; + } + } + + @Override + void accessHandler(String entry) { + accesses++; + if(cache.containsKey(entry)){ + cache.get(entry);//so cache can update itself + trackerMap.get(entry).gets += 1; + } + } + + @Override + void removalHandler(String entry) { + if(cache.containsKey(entry)){ + trackerMap.get(entry).removed = true; + trackerMap.get(entry).removedAt = accesses; + } + cache.remove(entry); + } + + public static void main(String[] args) throws FileNotFoundException { + System.setOut(new PrintStream(new File("histogramRaw.txt"))); + HistogramTest test = new HistogramTest(); + test.iterateLogs(); + + for(String key : test.trackerMap.keySet()){ + Tracker val = test.trackerMap.get(key); + if(val.removed){ + System.out.println("Lifetime: " + (val.removedAt - val.addedAt) + " Entry: " + key); + } + else { + //this case seems to comprise the vast majority of entries. almost by a factor of 10 + //compared to the other case + System.out.println("Lifetime: " + (test.accesses - val.addedAt) + " Entry: " + key); + } + } + } +} diff --git a/src/test/java/IntervalFinalCacheTest.java b/src/test/java/IntervalFinalCacheTest.java new file mode 100644 index 0000000..fb215ea --- /dev/null +++ b/src/test/java/IntervalFinalCacheTest.java @@ -0,0 +1,75 @@ +import java.io.File; +import java.io.FileNotFoundException; +import java.io.PrintStream; +import java.util.Scanner; + +public class IntervalFinalCacheTest extends TestUtils{ + int interval; + int intervalSize = 0; + int hits = 0; + int accesses = 0; + //record lruhits and dooms over intervals + //evictions from doomed set over intervals + int intervalDooms = 0; + int intervalHit = 0; + int doomEvictions = 0; + + int dooms = 0; + + IntervalFinalCache cache; + + IntervalFinalCacheTest(int initialFinalCacheSize, int intervalSize){ + cache = new IntervalFinalCache<>(initialFinalCacheSize, intervalSize); + this.intervalSize = intervalSize; + } + + int intervalNum = 1; + + @Override + void newEntryHandler(String entry) { + cache.add(entry, entry); + } + + @Override + void doomHandler(String entry) { + cache.addToInterval(entry, entry); + intervalDooms++; + + //reset interval variables + if(interval < 0){ + System.out.println("intervalNum = " + intervalNum); + intervalNum++; + + cache.dumpInterval(); + System.out.println("intervalHit = " + intervalHit); + System.out.println("intervalDooms = " + intervalDooms); + intervalHit = 0; + interval = intervalSize; + intervalDooms = 0; + cache.resetDoomedSetAmountDoomed(); + } + } + + @Override + void accessHandler(String entry) { + interval--; + accesses++; + if(cache.get(entry) != null){ + intervalHit++; + } + } + + @Override + void removalHandler(String entry) { + cache.remove(entry); + } + + public static void main(String[] args) throws FileNotFoundException { + int[] sizes = {50, 250, 500}; + for(int size : sizes){ + IntervalFinalCacheTest test = new IntervalFinalCacheTest(0, size); + System.setOut(new PrintStream(new File("results" + size + ".txt"))); + test.iterateLogs(); + } + } +} diff --git a/src/test/java/LruTest.java b/src/test/java/LruTest.java new file mode 100644 index 0000000..1b98084 --- /dev/null +++ b/src/test/java/LruTest.java @@ -0,0 +1,65 @@ +import java.io.FileNotFoundException; + +public class LruTest extends TestUtils{ + //this is to get the potential and + //actual duplicates + FinalCache fcache = new FinalCache<>(0); + + //the main testing candidate + LruCache cache; + int lruhits, fcacheHits, potential; + LruTest(int size){ + cache = new LruCache<>(size); + cache.addOnEntryEvictedListener(this::onEntryEvicted); + } + + @Override + void newEntryHandler(String entry) { + //no need to have value, just + //keeping track of keys + //adding this as val to not + //break check for lruhits + cache.put(entry, entry); + fcache.add(entry, entry); + } + + @Override + void accessHandler(String entry) { + if(cache.get(entry) != null) lruhits++; + if(fcache.get(entry) != null) fcacheHits++; + } + + @Override + void doomHandler(String entry) { + fcache.update(entry); + } + + @Override + void removalHandler(String entry) { + fcache.remove(entry); + } + + public void onEntryEvicted(String key, String val){ + if(fcache.containsKey(key)){ + potential++; + } + } + + public static void main(String[] args) throws FileNotFoundException { + int[] sizes = + {50, 100, 250, 500, 1000, 1200, + 2000, 3000, 4000, 5000, 6000, 7000, + 8000, 9000, 10_000}; + + for(int size : sizes){ + LruTest test = new LruTest(size); + System.out.println("Test of size: " + size); + test.iterateLogs(); + System.out.println("lru.lruhits: " + test.lruhits); + System.out.println("test.fcacheHits: " + test.fcacheHits); + System.out.println("test.potential: " + test.potential); + System.out.println("in use misses: " + (test.fcacheHits - test.lruhits)); + System.out.println(); + } + } +} diff --git a/src/test/java/NenovCacheTest.java b/src/test/java/NenovCacheTest.java new file mode 100644 index 0000000..1f5bf9a --- /dev/null +++ b/src/test/java/NenovCacheTest.java @@ -0,0 +1,58 @@ +import java.io.FileNotFoundException; + +/** + * Author: Aleksandr Diamond on 5/29/2018 + * Assignment: cache-java + * Purpose: + */ +public class NenovCacheTest extends TestUtils{ + NenovCache cache; + int hits; + int maxNumOfEntries = Integer.MIN_VALUE; + + NenovCacheTest(int size){ + cache = new NenovCache(size); + } + + @Override + void newEntryHandler(String entry) { + cache.add(entry); + maxNumOfEntries = Math.max(cache.size(), maxNumOfEntries); + } + + @Override + void accessHandler(String entry) { + cache.get(entry); + if(cache.containsKey(entry)) hits++; + maxNumOfEntries = Math.max(cache.size(), maxNumOfEntries); + } + + @Override + void doomHandler(String entry) { + cache.update(entry); + maxNumOfEntries = Math.max(cache.size(), maxNumOfEntries); + } + + @Override + void removalHandler(String entry) { + cache.remove(entry); + maxNumOfEntries = Math.max(cache.size(), maxNumOfEntries); + } + + public static void main(String[] args) throws FileNotFoundException { + NenovCacheTest n = null; + int[] nums = + {0, 50, 100, 250, 500, 1000, 1200, + 2000, 3000, 4000, 5000, 6000, 7000, + 8000, 9000, 10_000}; + + for (int num : nums) { + System.out.println("Starting test of size: " + (num)); + n = new NenovCacheTest(num); + n.iterateLogs(); + System.out.println("lruhits: " + n.hits); + System.out.println("maxNumOfEntries: " + n.maxNumOfEntries); + System.out.println(); + } + } +} diff --git a/src/test/java/SizeTest.java b/src/test/java/SizeTest.java new file mode 100644 index 0000000..ae399e9 --- /dev/null +++ b/src/test/java/SizeTest.java @@ -0,0 +1,76 @@ +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.PrintStream; + +public class SizeTest extends TestUtils { + FinalCache cache = new FinalCache<>(100); + + /** + * Interval of access + */ + static final int intervalSize = 100; + + + int intervalMax, intervalMin; + + /** + * Holds current position of interval + */ + int counter; + + @Override + void newEntryHandler(String entry) { + intervalMax = Math.max(intervalMax, cache.size()); + intervalMin = Math.min(intervalMin, cache.size()); + onCacheAccess(); + + //doesnt need to have a value, just tracking entryset + cache.add(entry, null); + } + + @Override + void doomHandler(String entry) { + cache.update(entry); + } + + @Override + void accessHandler(String entry) { + intervalMax = Math.max(intervalMax, cache.size()); + intervalMin = Math.min(intervalMin, cache.size()); + onCacheAccess(); + + //to update caches sets, could change configuration + cache.get(entry); + } + + private void onCacheAccess() { + if(counter == intervalSize){ + System.out.println("intervalMax: " + intervalMax); + System.out.println("intervalMin: " + intervalMin); + //reset interval variables + counter = 0; + intervalMax = Integer.MIN_VALUE; + intervalMin = Integer.MAX_VALUE; + } + else { + counter++; + } + } + + @Override + void removalHandler(String entry) { + cache.remove(entry); + } + + public static void main(String[] args) throws FileNotFoundException { + System.setOut(new PrintStream("cacheSizeRaw.txt")); + SizeTest sizeTest = new SizeTest(); + try { + sizeTest.iterateLogs(); + } catch (FileNotFoundException e) { + System.out.println("Problem with files in " + sizeTest.logDir); + e.printStackTrace(); + } + } +} diff --git a/src/test/java/TestUtils.java b/src/test/java/TestUtils.java new file mode 100644 index 0000000..ec910e8 --- /dev/null +++ b/src/test/java/TestUtils.java @@ -0,0 +1,114 @@ +import java.io.File; +import java.io.FileNotFoundException; +import java.util.Objects; +import java.util.Scanner; + +public class TestUtils { + + //what we are considering an access + //they are in format we want + String[] accesses = { + "CacheFileMetadata::GetElement()", + "CacheFileMetadata::SetElement()" + }; + + File logDir = new File("resources/fire_logs"); + + boolean isAccess(String log){ + for(String val : accesses){ + if(log.contains(val)){ + return true; + } + } + return false; + } + + boolean isNewEntry(String log){ + if(log.contains("entryKey=~")) return false; + return log.contains("CacheStorageService::AddStorageEntry"); + } + + boolean hasKey(String log){ + return log.contains("key=predictor::http"); + } + + boolean isDoom(String log){ + return log.contains("dooming entry"); + } + + String newEntryKey(String log){ + int beginIndex = log.indexOf("entryKey=:") + 10; + int endIndex = log.indexOf(","); + + return log.substring(beginIndex, endIndex); + } + + String accessKey(String log){ + int beginIndex = log.indexOf("key=predictor::") + 15; + int endIndex = log.length() - 1;//hopefully gets rid of '[' + return log.substring(beginIndex, endIndex); + } + + boolean isRemoval(String log){ + return log.contains("CacheStorageService::RemoveEntryForceValid"); + } + + String removalKey(String log){ + //some entries are not prefixed with 'http' + try{ + int start = log.indexOf("entryKey=:"); + return log.substring(start); + } catch(Exception e){ + return null; + } + } + + String doomKey(String log){ + int start = log.indexOf("for") + 5; + int end = log.indexOf("because"); + try { + return log.substring(start, end).trim(); + }catch(StringIndexOutOfBoundsException e){ + return null; + } + } + + void iterateLogs() throws FileNotFoundException { + if(logDir == null || logDir.listFiles() == null){ + throw new FileNotFoundException("Problem with files in " + logDir); + } + for(File logFile : logDir.listFiles()){ + Scanner in = new Scanner(logFile); + for(String log = null; in.hasNextLine(); log = in.nextLine()){ + if(log == null) continue; + if(isNewEntry(log)){ + newEntryHandler(newEntryKey(log).trim()); + } + else if(isDoom(log)){ + String doomKey = doomKey(log); + if (doomKey != null) { + doomHandler(doomKey.trim()); + } + } + else if(isAccess(log) && hasKey(log)){ + accessHandler(accessKey(log).trim()); + } + else if(isRemoval(log)){ + String removalKey = removalKey(log); + if(removalKey != null){ + removalHandler(removalKey.trim()); + } + } + } + in.close(); + } + } + + void newEntryHandler(String entry){} + + void doomHandler(String entry){} + + void accessHandler(String entry){} + + void removalHandler(String entry){} +}