From 5162c4477b9b53872a236dafbd761bf347afd0ec Mon Sep 17 00:00:00 2001
From: Jong Hyuk Choi <jongchoi@openldap.org>
Date: Tue, 14 Dec 2004 17:25:35 +0000
Subject: [PATCH] adaptive caching code

---
 servers/slapd/entry.c      | 12 ++++++
 servers/slapd/proto-slap.h | 32 +++++++++++++++-
 servers/slapd/slap.h       | 13 +++++++
 servers/slapd/zn_malloc.c  | 76 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 132 insertions(+), 1 deletion(-)

diff --git a/servers/slapd/entry.c b/servers/slapd/entry.c
index 5d238d0328..13fee4fc28 100644
--- a/servers/slapd/entry.c
+++ b/servers/slapd/entry.c
@@ -596,7 +596,11 @@ int entry_encode(Entry *e, struct berval *bv)
  * you can not free individual attributes or names from this
  * structure. Attempting to do so will likely corrupt memory.
  */
+#ifdef SLAP_ZONE_ALLOC
+int entry_decode(struct berval *bv, Entry **e, void *ctx)
+#else
 int entry_decode(struct berval *bv, Entry **e)
+#endif
 {
 	int i, j, count;
 	int rc;
@@ -613,7 +617,15 @@ int entry_decode(struct berval *bv, Entry **e)
 			"entry_decode: entry length was zero\n", 0, 0, 0);
 		return LDAP_OTHER;
 	}
+#ifdef SLAP_ZONE_ALLOC
+	x = slap_zn_calloc(1, i + bv->bv_len, ctx);
+	AC_MEMCPY((char*)x + i, bv->bv_val, bv->bv_len);
+	bv->bv_val = (char*)x + i;
+	ptr = (unsigned char *)bv->bv_val;
+	i = entry_getlen(&ptr);
+#else
 	x = ch_calloc(1, i);
+#endif
 	i = entry_getlen(&ptr);
 	x->e_name.bv_val = (char *) ptr;
 	x->e_name.bv_len = i;
diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h
index 1aeab3f09c..9237cc7629 100644
--- a/servers/slapd/proto-slap.h
+++ b/servers/slapd/proto-slap.h
@@ -620,7 +620,13 @@ LDAP_SLAPD_F (char *) entry2str LDAP_P(( Entry *e, int *len ));
 
 LDAP_SLAPD_F (void) entry_flatsize LDAP_P((
 	Entry *e, ber_len_t *siz, ber_len_t *len, int norm ));
-LDAP_SLAPD_F (int) entry_decode LDAP_P(( struct berval *bv, Entry **e ));
+#ifdef SLAP_ZONE_ALLOC
+LDAP_SLAPD_F (int) entry_decode LDAP_P((
+						struct berval *bv, Entry **e, void *ctx ));
+#else
+LDAP_SLAPD_F (int) entry_decode LDAP_P((
+						struct berval *bv, Entry **e ));
+#endif
 LDAP_SLAPD_F (int) entry_encode LDAP_P(( Entry *e, struct berval *bv ));
 
 LDAP_SLAPD_F (void) entry_clean LDAP_P(( Entry *e ));
@@ -1342,6 +1348,30 @@ LDAP_SLAPD_F (int) value_add_one LDAP_P((
 /* assumes (x) > (y) returns 1 if true, 0 otherwise */
 #define SLAP_PTRCMP(x, y) ((x) < (y) ? -1 : (x) > (y))
 
+#ifdef SLAP_ZONE_ALLOC
+/*
+ * zn_malloc.c
+ */
+LDAP_SLAPD_F (void *) slap_zn_malloc LDAP_P((ber_len_t, void *));
+LDAP_SLAPD_F (void *) slap_zn_realloc LDAP_P((void *, ber_len_t, void *));
+LDAP_SLAPD_F (void *) slap_zn_calloc LDAP_P((ber_len_t, ber_len_t, void *));
+LDAP_SLAPD_F (void) slap_zn_free LDAP_P((void *, void *));
+
+LDAP_SLAPD_F (void *) slap_zn_mem_create LDAP_P((
+							ber_len_t, ber_len_t, ber_len_t, ber_len_t));
+LDAP_SLAPD_F (void) slap_zn_mem_destroy LDAP_P((void *));
+LDAP_SLAPD_F (int) slap_zn_validate LDAP_P((void *, void *, int));
+LDAP_SLAPD_F (int) slap_zn_invalidate LDAP_P((void *, void *));
+LDAP_SLAPD_F (int) slap_zh_rlock LDAP_P((void*));
+LDAP_SLAPD_F (int) slap_zh_runlock LDAP_P((void*));
+LDAP_SLAPD_F (int) slap_zh_wlock LDAP_P((void*));
+LDAP_SLAPD_F (int) slap_zh_wunlock LDAP_P((void*));
+LDAP_SLAPD_F (int) slap_zn_rlock LDAP_P((void*, void*));
+LDAP_SLAPD_F (int) slap_zn_runlock LDAP_P((void*, void*));
+LDAP_SLAPD_F (int) slap_zn_wlock LDAP_P((void*, void*));
+LDAP_SLAPD_F (int) slap_zn_wunlock LDAP_P((void*, void*));
+#endif
+
 /*
  * Other...
  */
diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h
index 785f72cf59..3dd62fcfdd 100644
--- a/servers/slapd/slap.h
+++ b/servers/slapd/slap.h
@@ -2860,6 +2860,7 @@ struct slab_heap {
 #define SLAP_ZONE_SIZE 0x80000		/* 512KB */
 #define SLAP_ZONE_SHIFT 19
 #define SLAP_ZONE_INITSIZE 0x800000 /* 8MB */
+#define SLAP_ZONE_MAXSIZE 0x80000000/* 2GB */
 #define SLAP_ZONE_DELTA 0x800000	/* 8MB */
 #define SLAP_ZONE_ZOBLOCK 256
 
@@ -2871,6 +2872,11 @@ struct zone_object {
 	LDAP_LIST_ENTRY(zone_object) zo_link;
 };
 
+struct zone_latency_history {
+	double zlh_latency;
+	LDAP_STAILQ_ENTRY(zone_latency_history) zlh_next;
+};
+
 struct zone_heap {
 	int zh_fd;
 	int zh_zonesize;
@@ -2887,6 +2893,13 @@ struct zone_heap {
 	LDAP_LIST_HEAD( zh_so, zone_object ) zh_zopool;
 	ldap_pvt_thread_mutex_t zh_mutex;
 	ldap_pvt_thread_rdwr_t zh_lock;
+	double zh_ema_latency;
+	unsigned long zh_ema_samples;
+	LDAP_STAILQ_HEAD( zh_latency_history, zone_latency_history )
+				zh_latency_history_queue;
+	int zh_latency_history_qlen;
+	int zh_latency_jump;
+	int zh_swapping;
 };
 #endif
 
diff --git a/servers/slapd/zn_malloc.c b/servers/slapd/zn_malloc.c
index c2e8d20f96..328616d19b 100644
--- a/servers/slapd/zn_malloc.c
+++ b/servers/slapd/zn_malloc.c
@@ -220,6 +220,7 @@ slap_zn_mem_create(
 		ldap_pvt_thread_rdwr_init(&zh->zh_znlock[i]);
 	}
 
+	LDAP_STAILQ_INIT(&zh->zh_latency_history_queue);
 	ldap_pvt_thread_mutex_init(&zh->zh_mutex);
 	ldap_pvt_thread_rdwr_init(&zh->zh_lock);
 
@@ -892,4 +893,79 @@ int slap_zn_wunlock(
 	}
 }
 
+#define T_SEC_IN_USEC 1000000
+
+static int
+slap_timediff(struct timeval *tv_begin, struct timeval *tv_end)
+{
+	uint64_t t_begin, t_end, t_diff;
+
+	t_begin = T_SEC_IN_USEC * tv_begin->tv_sec + tv_begin->tv_usec;
+	t_end  = T_SEC_IN_USEC * tv_end->tv_sec  + tv_end->tv_usec;
+	t_diff  = t_end - t_begin;
+	
+	if ( t_diff < 0 )
+		t_diff = 0;
+
+	return (int)t_diff;
+}
+
+void
+slap_set_timing(struct timeval *tv_set)
+{
+	gettimeofday(tv_set, (struct timezone *)NULL);
+}
+
+int
+slap_measure_timing(struct timeval *tv_set, struct timeval *tv_measure)
+{
+	gettimeofday(tv_measure, (struct timezone *)NULL);
+	return(slap_timediff(tv_set, tv_measure));
+}
+
+#define EMA_WEIGHT 0.999000
+#define SLAP_ZN_LATENCY_HISTORY_QLEN 500
+int
+slap_zn_latency_history(void* ctx, int ea_latency)
+{
+/* TODO: monitor /proc/swap as well */
+	struct zone_heap* zh = ctx;
+	double t_diff = 0.0;
+
+	zh->zh_ema_latency = (double)ea_latency * (1.0 - EMA_WEIGHT)
+					+ zh->zh_ema_latency * EMA_WEIGHT;
+	if (!zh->zh_swapping && zh->zh_ema_samples++ % 100 == 99) {
+		struct zone_latency_history *zlh_entry;
+		zlh_entry = ch_calloc(1, sizeof(struct zone_latency_history));
+		zlh_entry->zlh_latency = zh->zh_ema_latency;
+		LDAP_STAILQ_INSERT_TAIL(
+				&zh->zh_latency_history_queue, zlh_entry, zlh_next);
+		zh->zh_latency_history_qlen++;
+		while (zh->zh_latency_history_qlen > SLAP_ZN_LATENCY_HISTORY_QLEN) {
+			struct zone_latency_history *zlh;
+			zlh = LDAP_STAILQ_FIRST(&zh->zh_latency_history_queue);
+			LDAP_STAILQ_REMOVE_HEAD(
+					&zh->zh_latency_history_queue, zlh_next);
+			zh->zh_latency_history_qlen--;
+			ch_free(zlh);
+		}
+		if (zh->zh_latency_history_qlen == SLAP_ZN_LATENCY_HISTORY_QLEN) {
+			struct zone_latency_history *zlh_first, *zlh_last;
+			zlh_first = LDAP_STAILQ_FIRST(&zh->zh_latency_history_queue);
+			zlh_last = LDAP_STAILQ_LAST(&zh->zh_latency_history_queue,
+						zone_latency_history, zlh_next);
+			t_diff = zlh_last->zlh_latency - zlh_first->zlh_latency;
+		}
+		if (t_diff >= 2000) {
+			zh->zh_latency_jump++;
+		} else {
+			zh->zh_latency_jump = 0;
+		}
+		if (zh->zh_latency_jump > 3) {
+			zh->zh_latency_jump = 0;
+			zh->zh_swapping = 1;
+		}
+	}
+	return zh->zh_swapping;
+}
 #endif /* SLAP_ZONE_ALLOC */
-- 
GitLab