summaryrefslogtreecommitdiff
path: root/ioreplay/src/datas/amap.c
diff options
context:
space:
mode:
Diffstat (limited to 'ioreplay/src/datas/amap.c')
-rw-r--r--ioreplay/src/datas/amap.c264
1 files changed, 264 insertions, 0 deletions
diff --git a/ioreplay/src/datas/amap.c b/ioreplay/src/datas/amap.c
new file mode 100644
index 0000000..806a3f8
--- /dev/null
+++ b/ioreplay/src/datas/amap.c
@@ -0,0 +1,264 @@
+// Copyright 2018 Mimecast Ltd.
+//
+// Licensed 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 "amap.h"
+
+/**
+ * @brief Creates a new array map
+ *
+ * @param size The array map size
+ * @param mmapped true if the memory should be mmapped
+ * @return The new amap object
+ */
+static amap_s *_amap_new(long size, bool mmapped)
+{
+ amap_s *a = NULL;
+ void ***arrays = NULL;
+
+ // Calculate a multiple of 1024, but at least in size of 'size'.
+ if (size % 1024 != 0) {
+ size = 1024*(1+(long)(size/1024));
+ }
+
+ if (size < 1) {
+ Error("Size overflow");
+ }
+
+ int num_arrays = size / AMAP_MAX_ARRAY_LENGTH;
+
+ if (mmapped) {
+ a = Mmapshared(amap_s);
+ arrays = Cmapshared(num_arrays, void**);
+ } else {
+ a = Malloc(amap_s);
+ arrays = Calloc(num_arrays, void**);
+ }
+
+ for (int i = 0; i < num_arrays; ++i) {
+ if (mmapped) {
+ //Put("%d", AMAP_MAX_ARRAY_LENGTH);
+ arrays[i] = Cmapshared(AMAP_MAX_ARRAY_LENGTH, void*);
+ } else {
+ arrays[i] = Calloc(AMAP_MAX_ARRAY_LENGTH, void*);
+ }
+ for (int j = 0; j < AMAP_MAX_ARRAY_LENGTH; ++j) {
+ arrays[i][j] = NULL;
+ }
+ }
+
+ a->arrays = arrays;
+ a->num_arrays = num_arrays;
+ a->size = size;
+ a->data_destroy = NULL;
+ a->mmapped = mmapped;
+
+ return a;
+}
+
+/**
+ * @brief Creates a new array map
+ *
+ * @param size The array map size
+ * @return The new amap object
+ */
+amap_s* amap_new(const long size)
+{
+ return _amap_new(size, false);
+}
+
+/**
+ * @brief Creates a new mmapped array map
+ *
+ * @param size The array map size
+ * @return The new amap object
+ */
+amap_s* amap_new_mmapped(const long size)
+{
+ return _amap_new(size, true);
+}
+
+/**
+ * @brief Destroys a mmap object
+ *
+ * @a The new amap object
+ */
+void amap_destroy(amap_s* a)
+{
+ if (!a) {
+ return;
+ }
+
+ // Don't bother, the mmapped version of amap will stay alive until
+ // process terminations. And after process termination everything
+ // will be cleaned up automatically by Linux.
+ if (a->mmapped) {
+ return;
+ }
+
+ for (int i = 0; i < a->num_arrays; ++i) {
+ if (a->data_destroy) {
+ for (int j = 0; j < AMAP_MAX_ARRAY_LENGTH; ++j)
+ if (a->arrays[i][j]) {
+ a->data_destroy(a->arrays[i][j]);
+ }
+ }
+ free(a->arrays[i]);
+ }
+ free(a->arrays);
+ free(a);
+}
+
+/**
+ * @brief Resets a mmap object
+ *
+ * This resets all entries to NULL.
+ *
+ * @a The new amap object
+ */
+void amap_reset(amap_s* a)
+{
+ for (int i = 0; i < a->num_arrays; ++i) {
+ for (int j = 0; j < AMAP_MAX_ARRAY_LENGTH; ++j) {
+ if (a->data_destroy) {
+ if (a->arrays[i][j]) {
+ a->data_destroy(a->arrays[i][j]);
+ }
+ }
+ a->arrays[i][j] = NULL;
+ }
+ }
+}
+
+int amap_set(amap_s *a, const long position, void* value)
+{
+ if (position >= a->size)
+ return -1;
+ int which_array = position / AMAP_MAX_ARRAY_LENGTH;
+ int array_pos = position % AMAP_MAX_ARRAY_LENGTH;
+ a->arrays[which_array][array_pos] = value;
+ return 0;
+}
+
+void* amap_get(amap_s *a, const long position)
+{
+ if (position >= a->size)
+ return NULL;
+ int which_array = position / AMAP_MAX_ARRAY_LENGTH;
+ int array_pos = position % AMAP_MAX_ARRAY_LENGTH;
+ return a->arrays[which_array][array_pos];
+}
+
+void* amap_unset(amap_s *a, const long position)
+{
+ if (position >= a->size)
+ return NULL;
+ int which_array = position / AMAP_MAX_ARRAY_LENGTH;
+ int array_pos = position % AMAP_MAX_ARRAY_LENGTH;
+ void *value = a->arrays[which_array][array_pos];
+ a->arrays[which_array][array_pos] = NULL;
+ return value;
+}
+
+void amap_run_cb(amap_s *a, void (*cb)(void *data))
+{
+ for (int i = 0; i < a->num_arrays; ++i) {
+ for (int j = 0; j < AMAP_MAX_ARRAY_LENGTH; ++j) {
+ if (a->arrays[i][j])
+ cb(a->arrays[i][j]);
+ }
+ }
+}
+
+void amap_print(amap_s* a)
+{
+ Put("amap_s (%p):", (void*)a);
+ Put("\tmmapped: %d", a->mmapped);
+ Put("\tmax_array_length: %d", AMAP_MAX_ARRAY_LENGTH);
+ Put("\tnum_arrays: %d", a->num_arrays);
+ Put("\tsize: %lu", a->size);
+ Out("\toccupied slots: ");
+ for (int i = 0; i < a->num_arrays; ++i) {
+ for (int j = 0; j < AMAP_MAX_ARRAY_LENGTH; ++j) {
+ if (a->arrays[i][j] != NULL) {
+ Out("%d:%d ", i, j);
+ }
+ }
+ }
+ Out("\n");
+}
+
+void _amap_test(amap_s *a)
+{
+ assert(0 == amap_set(a, 0, (void*)10));
+ assert(0 == amap_set(a, 1, (void*)11));
+ assert(0 == amap_set(a, 2, (void*)12));
+ assert(0 == amap_set(a, 3, (void*)a));
+ assert(10 == (long) amap_get(a, 0));
+ assert(11 == (long) amap_get(a, 1));
+ assert(12 == (long) amap_get(a, 2));
+ assert(a == amap_get(a, 3));
+
+ assert(0 == amap_set(a, AMAP_MAX_ARRAY_LENGTH-1, (void*) 23));
+ assert(23 == (long) amap_get(a, AMAP_MAX_ARRAY_LENGTH-1));
+
+ assert(0 == amap_set(a, AMAP_MAX_ARRAY_LENGTH, (void*) 42));
+ assert(42 == (long) amap_get(a, AMAP_MAX_ARRAY_LENGTH));
+
+ assert(0 == amap_set(a, AMAP_MAX_ARRAY_LENGTH*2-1, (void*) (23+42)));
+ assert(42+23 == (long) amap_get(a, AMAP_MAX_ARRAY_LENGTH*2-1));
+ assert(0 == amap_set(a, AMAP_MAX_ARRAY_LENGTH*2, (void*) 23));
+
+
+ assert(NULL == amap_get(a, 1024*1024*9-1));
+ assert(0 == amap_set(a, 1024*1024*9-1, (void*) 0x1));
+ assert(0x1 == (long) amap_get(a, 1024*1024*9-1));
+ assert(0x1 == (long) amap_unset(a, 1024*1024*9-1));
+ assert(NULL == amap_get(a, 1024*1024*9-1));
+
+ assert(0 == amap_set(a, 1024*1024*9, (void*) 100));
+ assert(100 == (long) amap_get(a, 1024*1024*9));
+
+ assert(0 == amap_set(a, 1024*1024*9+1, (void*) 101));
+ assert(101 == (long) amap_get(a, 1024*1024*9+1));
+
+ assert(0 == amap_set(a, 1024*1024*10-2, (void*) 102));
+ assert(102 == (long) amap_get(a, 1024*1024*10-2));
+
+ assert(0 == amap_set(a, 1024*1024*10-1, a));
+ assert(a == amap_get(a, 1024*1024*10-1));
+ //amap_print(a);
+
+ assert(a == amap_unset(a, 1024*1024*10-1));
+ assert(a != amap_unset(a, 1024*1024*10-1));
+ //amap_print(a);
+}
+
+void amap_test(void)
+{
+ // First test the non-mmapped version
+ amap_s* a = amap_new(1024*1024*10);
+ _amap_test(a);
+ amap_destroy(a);
+
+ // Now test the mapped version
+ a = amap_new_mmapped(1024*1024*10);
+ _amap_test(a);
+ amap_destroy(a);
+
+ // Another test with non-alligned size
+ a = amap_new(1024*1024*10+1);
+ _amap_test(a);
+ amap_destroy(a);
+}
+