cmogstored.git  about / heads / tags
alternative mogstored implementation for MogileFS
blob a0091bffd5f0de9f3e3a1028672a47629ce21089 3299 bytes (raw)
$ git show HEAD:ioutil.c	# shows this blob on the CLI

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
 
/*
 * Copyright (C) 2012-2020 all contributors <cmogstored-public@yhbt.net>
 * License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
 */
#include "cmogstored.h"

static pthread_mutex_t cleanup_lock = PTHREAD_MUTEX_INITIALIZER;

static pthread_mutex_t iou_lock = PTHREAD_MUTEX_INITIALIZER;
static Hash_table *dev_iou; /* maps system device IDs to utilization */
struct ioutil;
struct ioutil {
	dev_t st_dev;
	bool in_use;
	struct ioutil *free_next;
	char util[MOG_IOUTIL_LEN];
};

static size_t iou_hash(const void *entry, size_t tablesize)
{
	const struct ioutil *iou = entry;

	return iou->st_dev % tablesize;
}

static bool iou_cmp(const void *_a, const void *_b)
{
	const struct ioutil *a = _a;
	const struct ioutil *b = _b;

	return a->st_dev == b->st_dev;
}

__attribute__((destructor)) static void iou_destructor(void)
{
	hash_free(dev_iou);
}

__attribute__((constructor)) static void iou_constructor(void)
{
	dev_iou = hash_initialize(7, NULL, iou_hash, iou_cmp, free);
	mog_oom_if_null(dev_iou);
}

static bool cleanup_begin_i(void *ent, void *unused)
{
	struct ioutil *iou = ent;
	iou->in_use = false;
	return true;
}

void mog_iou_cleanup_begin(void)
{
	CHECK(int, 0, pthread_mutex_lock(&cleanup_lock));
	CHECK(int, 0, pthread_mutex_lock(&iou_lock));
	hash_do_for_each(dev_iou, cleanup_begin_i, NULL);
	CHECK(int, 0, pthread_mutex_unlock(&iou_lock));
}

static bool freelist_append(void *ent, void *f)
{
	struct ioutil *iou = ent;
	struct ioutil **free_head = f;

	if (iou->in_use)
		return true;

	assert(iou->free_next == NULL && "free_next set");

	/* prepend current item to the free list */
	iou->free_next = *free_head;
	*free_head = iou;

	return true;
}

void mog_iou_cleanup_finish(void)
{
	struct ioutil *fl = NULL;

	CHECK(int, 0, pthread_mutex_lock(&iou_lock));

	/* build up the free list */
	hash_do_for_each(dev_iou, freelist_append, &fl);

	/* release items in the free list */
	while (fl) {
		struct ioutil *next = fl->free_next;
		struct ioutil *found = hash_delete(dev_iou, fl);
		assert(found == fl && "freelist found does not match");
		free(fl);
		fl = next;
	}

	CHECK(int, 0, pthread_mutex_unlock(&iou_lock));
	CHECK(int, 0, pthread_mutex_unlock(&cleanup_lock));
}

static struct ioutil * iou_vivify(dev_t st_dev)
{
	struct ioutil lookup = { .st_dev = st_dev };
	struct ioutil *iou = hash_lookup(dev_iou, &lookup);

	if (!iou) {
		iou = xmalloc(sizeof(*iou));
		iou->st_dev = st_dev;
		iou->util[0] = '-';
		iou->util[1] = 0;
		iou->free_next = NULL;
		CHECK(int, 1, hash_insert_if_absent(dev_iou, iou, NULL));
	}
	iou->in_use = true;

	return iou;
}

void mog_iou_read(dev_t st_dev, char buf[MOG_IOUTIL_LEN])
{
	struct ioutil *iou;

	CHECK(int, 0, pthread_mutex_lock(&iou_lock));
	iou = iou_vivify(st_dev);
	memcpy(buf, iou->util, MOG_IOUTIL_LEN);
	CHECK(int, 0, pthread_mutex_unlock(&iou_lock));
}

void mog_iou_write(dev_t st_dev, const char buf[MOG_IOUTIL_LEN])
{
	struct ioutil *iou;

	CHECK(int, 0, pthread_mutex_lock(&iou_lock));
	iou = iou_vivify(st_dev);
	memcpy(iou->util, buf, MOG_IOUTIL_LEN);
	CHECK(int, 0, pthread_mutex_unlock(&iou_lock));
}

/* marks the given device as in-use */
void mog_iou_active(dev_t st_dev)
{
	CHECK(int, 0, pthread_mutex_lock(&iou_lock));
	(void)iou_vivify(st_dev);
	CHECK(int, 0, pthread_mutex_unlock(&iou_lock));
}

git clone https://yhbt.net/cmogstored.git