blob: ad770ef1de7ef913162f74fe19ebc89aa5165c19 [file] [log] [blame]
/** @file
A brief file description
@section license License
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include <ts/ts.h>
#include <inttypes.h>
#include <sys/types.h>
#include <openssl/md5.h>
#include <string>
#include <iostream>
#include <math.h>
#include <sys/stat.h>
#include <map>
#include <aio.h>
#include <queue>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
using namespace std;
/**
* The basic type used for keys and values in cache.
*/
class datum
{
public:
int operator<(const datum & x) const
{
uint64_t min = 0;
if (x.dsize < dsize)
{
min = x.dsize;
} else
{
min = dsize;
}
int rval = strncmp(dptr, x.dptr, min);
if (rval > 0) {
return 0;
} else if (rval < 0) {
return 1;
} else {
return (dsize < x.dsize);
}
}
const char *dptr;
uint64_t dsize;
};
/**
* Object that maintains state of an open file in cache.
*/
class openFile
{
public:
openFile():fd(-1), refcount(0), exclusive(false), truncated(false)
{
fd = -1;
}
openFile(int tmpFd, bool excl):fd(tmpFd), refcount(1), exclusive(excl), truncated(false)
{
}
int fd;
int32_t refcount;
bool exclusive;
bool truncated;
};
/**
* Allocator template to new and return objects.
*/
template<class T> class Allocator {
public:
Allocator() {
pthread_mutex_init(&_mutex, NULL);
}
T *pop()
{
if (pthread_mutex_lock(&_mutex) != 0) {
return 0;
}
T *x;
if (_queue.size() == 0) {
x = new T();
//cout << "new" << endl;
} else {
x = _queue.front();
_queue.pop();
//cout << "old" << endl;
}
if (pthread_mutex_unlock(&_mutex) != 0) {
abort();
}
return x;
}
void push(T * x)
{
if (pthread_mutex_lock(&_mutex) != 0) {
abort();
}
_queue.push(x);
if (pthread_mutex_unlock(&_mutex) != 0) {
abort();
}
}
private:
queue<T *>_queue;
pthread_mutex_t _mutex;
};
/**
* Simple filesystem cache.
* A disk cache that uses the filesystem to cache objects. There should only be one
* cache object in use for a directory.
*/
class DiskCache
{
public:
DiskCache();
// synchronous methods
int32_t read(const datum & key, datum & value, const uint64_t size, const uint64_t offset = 0);
int32_t write(const datum & key, const datum & value);
int32_t remove(const datum & key);
int32_t lock(const datum & key, bool exclusive);
int32_t unlock(const datum & key);
// aio methods
int32_t aioRead(const datum & key, datum & value, const uint64_t size, const uint64_t offset = 0);
int32_t aioWrite(const datum & key, const datum & value);
static void aioReadDone(sigval_t x);
static void aioWriteDone(sigval_t x);
// setters and getters
void setTopDirectory(const string & directory)
{
_topDirectory = directory;
}
string getTopDirectory(const string & directory)
{
return _topDirectory;
}
void setNumberDirectories(const uint32_t directories);
uint32_t getNumberDirectories() const
{
return _totalDirectories;
}
int64_t getSize(const datum & key);
/// Makes the entire directory hierarchy
int makeDirectories()
{
if (mkdir(_topDirectory.c_str(), 0755) != 0) {
if (errno != EEXIST) {
INKDebug("cache_plugin", "Couldn't create the top cache directory: %s", _topDirectory.c_str());
INKError("cache_plugin", "Couldn't create the top cache directory: %s", _topDirectory.c_str());
return 1;
}
}
return _makeDirectoryRecursive(_topDirectory, _totalDirectories);
}
private:
// private helper methods
int _getFileDescriptor(const datum & key, const bool exclusive, const bool truncating = false);
void _makePath(const datum & key, string & path) const;
int _makeDirectoryRecursive(const string & path, uint32_t numberDirectories) const;
// private data members for keeping track of that cache
map<datum, openFile> _openFiles;
static const uint32_t _directoryWidth = 256; /// XXX - *MUST* be a power of 2
string _topDirectory;
uint32_t _totalDirectories;
uint32_t _directoryDepth;
pthread_mutex_t _mutex;
static Allocator<struct aiocb>_aioRequests;
};