This repository has been archived on 2022-08-01. You can view files and clone it, but cannot push or open issues or pull requests.
EmerGen-e-tic/dat/cache/difffile-large/6/CacheHandler6_30.dn
2017-04-14 08:29:38 +01:00

267 lines
7.2 KiB
Text

/*
* EmerGen(e)tic 0.8
* Copyright © 2017 Ben Goldsworthy (rumperuu)
*
* A program to research the utility of genetic algorithms, applied to
* 'emergent' sytems.
*
* This file is part of EmerGen(e)tic.
*
* IMPROVEMENT(S): License (probably GNU GPLv3 tbh) goes here.
*/
/**
** This program serves as the base for each mutated CacheHandler,
** providing the functionality that is common to all of them.
**/
/**
** @author Ben Goldsworthy (rumperuu) <bgoldsworthy96 @ gmail.com>
** @version 1.0
**/
component provides cache.CacheHandler
requires io.Output out,
data.IntUtil iu,
util.RandomInt ir,
time.Calendar ic,
time.DateUtil du,
io.File {
static CachedResponse cache[]
static int arraySize
static Mutex cacheLock
/**
** Returns a requested item from the cache.
**
** @param resource The request item filepath
** @return The item from the cache
**/
CachedResponse CacheHandler:getCachedResponse(char filePath[]) {
// Converts the filepath to an array of bytes for the file.
File fd = new File(filePath, File.FILE_ACCESS_READ)
char resource[] = fd.read(fd.getSize())
fd.close()
// Returns the item if it's in the cache.
mutex(cacheLock) {
for (int i = 0; i < arraySize; i++) {
if (cache[i].resource == resource) {
cache[i].hits++
cache[i].lastUsed = ic.getTime()
return cache[i]
}
}
}
return null
}
/**
** Updates the cache if the requested item is not already present.
** If the cache is full, the method of determining the item to be
** replaced is subject to genetic mutation.
**
** @param ncr The new item to cache
**/
void CacheHandler:updateCache(CachedResponse ncr) {
mutex(cacheLock) {
// If the item is already in the cache, do nothing.
for (int i = 0; i < arraySize; i++) {
if (cache[i].resource == ncr.resource) {
cache[i].response = ncr.response
cache[i].resourceAge = ncr.resourceAge
return
}
}
// If the item is not, it must be added.
// As `ncr` was created on another component, its details must
// be copied to avoid a read-only exception.
CachedResponse newEntry = new CachedResponse()
newEntry.command = ncr.command
newEntry.resource = ncr.resource
newEntry.resourceAge = ncr.resourceAge
newEntry.mimeType = ncr.mimeType
newEntry.response = new byte[](ncr.response)
newEntry.contentSize = ncr.contentSize
// Initialises the cache if there isn't currently one.
if (cache == null) {
cache = new CachedResponse[CacheHandler.MAX_SIZE]()
}
// If the cache is full, determines which item to replace.
if (arraySize == CacheHandler.MAX_SIZE) {
int index
// BEGIN
index = nthMostRecentlyUsed(0)-nthMostFrequentlyUsed(0)
// END
cache[index % arraySize] = newEntry
//out.println("$(debugMSG) replacing: $(iu.intToString(index))")
// Otherwise, appends the item to the end of the cache.
} else {
cache[arraySize] = newEntry
arraySize++
}
}
}
/**
** Clears the cache completely.
**/
void CacheHandler:clearCache() {
mutex(cacheLock) {
cache = null
}
}
/**************************************************************************
* What follows are utility functions that a given chromosome of the
* `updateCache()` method may or may not call upon.
**************************************************************************/
// This method returns the index of the nth most frequently-used item in
// the cache.
int nthMostFrequentlyUsed(int n) {
int hits[]
for (int i = 0; i < arraySize; i++) hits[i] = 0
int i
int j
mutex(cacheLock) {
for (i = 0; i < arraySize; i++) {
for (j = 0; j < arraySize; j++) {
if (cache[i].hits == hits[j]) break
else if (hits[j] == 0) {
hits[j] = cache[i].hits
break
}
}
}
}
int k = 0
int nthHit = 0
for (i = 0; i < j; i++) {
if (hits[i] > nthHit) {
nthHit = hits[i]
k++
}
if (k == n) break
}
int itemIndices[]
mutex(cacheLock) {
j = 0
for (i = 0; i < arraySize; i++) {
if (cache[i].hits == nthHit) itemIndices[j++] = i
}
}
return resolve(itemIndices, "r")
}
// This method returns the index of the nth most recently-used item in
// the cache.
int nthMostRecentlyUsed(int n) {
DateTime useTimes[]
DateTime testTime = ic.getTime()
for (int i = 0; i < arraySize; i++) useTimes[i] = testTime
int i
int j
mutex(cacheLock) {
for (i = 0; i < arraySize; i++) {
for (j = 0; j < arraySize; j++) {
if (du.equal(cache[i].lastUsed, useTimes[j])) break
else if (du.equal(useTimes[j], testTime)) {
useTimes[j] = cache[i].lastUsed
break
}
}
}
}
int k = 0
DateTime nthUseTime = ic.getTime()
for (i = 0; i < j; i++) {
if (du.after(useTimes[i], nthUseTime)) {
nthUseTime = useTimes[i]
k++
}
if (k == n) break
}
int itemIndices[]
mutex(cacheLock) {
j = 0
for (i = 0; i < arraySize; i++) {
if (du.equal(cache[i].lastUsed, nthUseTime)) itemIndices[j++] = i
}
}
return resolve(itemIndices, "r")
}
// This method returns a random index.
int random() {
DateTime dt = ic.getTime()
int msec = dt.millisecond
ir.setSeed(msec)
return ir.get(CacheHandler.MAX_SIZE)
}
// This method resolves a multiple return in one of the methods above,
// as per the flag sent along with the list of indices.
// 'n' returns the newest, 'o' the oldest and 'r' a random index.
int resolve(int index[], char flag) {
DateTime dt = null
if (flag == "n") {
int newestItem = 0
int i = index.arrayLength-1
for (int j = 0; j < index.arrayLength; j++) {
if (dt == null) {
dt = cache[index[i]].timeAdded
newestItem = index[i]
} else {
if (du.before(dt, cache[index[i]].timeAdded)) {
dt = cache[index[i]].timeAdded
newestItem = index[i]
}
}
i--
}
return newestItem
} else if (flag == "o") {
int oldestItem = 0
for (int i = 0; i < index.arrayLength; i++) {
if (dt == null) {
dt = cache[index[i]].timeAdded
oldestItem = index[i]
} else {
if (du.before(cache[index[i]].timeAdded, dt)) {
dt = cache[index[i]].timeAdded
oldestItem = index[i]
}
}
}
return oldestItem
} else if (flag == "r") {
dt = ic.getTime()
int msec = dt.millisecond
ir.setSeed(msec)
return ir.get(index.arrayLength)
} else {
return 0
}
}
}