[389-devel] Please review: Entry USN

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



First cut for implementing Entry USN.
See http://directory.fedoraproject.org/wiki/Entry_USN for the design details.
This change includes a bug fix for "db2ldif -r"; event queue system was not
shutdown before the plugins are closed, which could have crashed the command
line utility.

Thanks,
--noriko
From 454c03cf4f5462e0b215b6a5af86cd9a4d58bb50 Mon Sep 17 00:00:00 2001
From: Noriko Hosoi <nhosoi@xxxxxxxxxx>
Date: Mon, 20 Jul 2009 13:45:42 -0700
Subject: [PATCH] Entry USN
 First cut for implementing Entry USN.
 See http://directory.fedoraproject.org/wiki/Entry_USN for the design details.
 This change includes a bug fix for "db2ldif -r"; event queue system was not
 shutdown before the plugins are closed, which could have crashed the command
 line utility.

---
 Makefile.am                                        |   18 +-
 Makefile.in                                        |  105 +++-
 .../scripts/template-usn-tombstone-cleanup.pl.in   |  180 ++++++
 ldap/ldif/template-dse.ldif.in                     |   19 +
 ldap/servers/plugins/usn/usn.c                     |  570 ++++++++++++++++++++
 ldap/servers/plugins/usn/usn.h                     |   57 ++
 ldap/servers/plugins/usn/usn_cleanup.c             |  326 +++++++++++
 ldap/servers/slapd/back-ldbm/back-ldbm.h           |    1 +
 ldap/servers/slapd/back-ldbm/import.c              |    3 +
 ldap/servers/slapd/back-ldbm/init.c                |    4 +
 ldap/servers/slapd/back-ldbm/ldbm_add.c            |    3 +
 ldap/servers/slapd/back-ldbm/ldbm_delete.c         |  228 +++++++--
 .../servers/slapd/back-ldbm/ldbm_instance_config.c |    6 +
 ldap/servers/slapd/back-ldbm/ldbm_modify.c         |    1 +
 ldap/servers/slapd/back-ldbm/ldbm_usn.c            |  196 +++++++
 ldap/servers/slapd/back-ldbm/misc.c                |    8 +-
 ldap/servers/slapd/back-ldbm/proto-back-ldbm.h     |    9 +
 ldap/servers/slapd/back-ldbm/start.c               |    3 +
 ldap/servers/slapd/backend.c                       |    2 +-
 ldap/servers/slapd/main.c                          |    2 +
 ldap/servers/slapd/pblock.c                        |    8 +
 ldap/servers/slapd/plugin.c                        |   68 ++-
 ldap/servers/slapd/slap.h                          |    3 +
 ldap/servers/slapd/slapi-plugin.h                  |    6 +-
 ldap/servers/slapd/slapi-private.h                 |    3 +
 25 files changed, 1748 insertions(+), 81 deletions(-)
 mode change 100755 => 100644 Makefile.in
 mode change 100755 => 100644 aclocal.m4
 mode change 100755 => 100644 config.h.in
 create mode 100644 ldap/admin/src/scripts/template-usn-tombstone-cleanup.pl.in
 create mode 100644 ldap/servers/plugins/usn/usn.c
 create mode 100644 ldap/servers/plugins/usn/usn.h
 create mode 100644 ldap/servers/plugins/usn/usn_cleanup.c
 create mode 100644 ldap/servers/slapd/back-ldbm/ldbm_usn.c
 mode change 100755 => 100644 ltmain.sh

diff --git a/Makefile.am b/Makefile.am
index 05cb356..5ce6ccb 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -157,9 +157,10 @@ serverplugin_LTLIBRARIES = libacl-plugin.la libattr-unique-plugin.la \
 	libhttp-client-plugin.la liblinkedattrs-plugin.la \
 	libmemberof-plugin.la libpassthru-plugin.la libpwdstorage-plugin.la \
 	libreferint-plugin.la libreplication-plugin.la libretrocl-plugin.la \
-	libroles-plugin.la libschemareload-plugin.la libstatechange-plugin.la \
-	libsyntax-plugin.la libviews-plugin.la $(LIBPAM_PASSTHRU_PLUGIN) \
-	$(LIBDNA_PLUGIN) $(LIBBITWISE_PLUGIN) $(LIBPRESENCE_PLUGIN)
+	libroles-plugin.la libstatechange-plugin.la libsyntax-plugin.la \
+	libviews-plugin.la libschemareload-plugin.la libusn-plugin.la \
+	$(LIBPAM_PASSTHRU_PLUGIN) $(LIBDNA_PLUGIN) \
+	$(LIBBITWISE_PLUGIN) $(LIBPRESENCE_PLUGIN)
 
 nodist_property_DATA = ns-slapd.properties
 
@@ -314,6 +315,7 @@ task_SCRIPTS = ldap/admin/src/scripts/template-bak2db \
 	ldap/admin/src/scripts/template-ns-newpwpolicy.pl \
 	ldap/admin/src/scripts/template-schema-reload.pl \
 	ldap/admin/src/scripts/template-syntax-validate.pl \
+	ldap/admin/src/scripts/template-usn-tombstone-cleanup.pl \
 	ldap/admin/src/scripts/template-verify-db.pl \
 	ldap/admin/src/scripts/template-dbverify
 
@@ -617,6 +619,7 @@ libback_ldbm_la_SOURCES = ldap/servers/slapd/back-ldbm/ancestorid.c \
 	ldap/servers/slapd/back-ldbm/ldbm_modrdn.c \
 	ldap/servers/slapd/back-ldbm/ldbm_search.c \
 	ldap/servers/slapd/back-ldbm/ldbm_unbind.c \
+	ldap/servers/slapd/back-ldbm/ldbm_usn.c \
 	ldap/servers/slapd/back-ldbm/ldif2ldbm.c \
 	ldap/servers/slapd/back-ldbm/dbverify.c \
 	ldap/servers/slapd/back-ldbm/matchrule.c \
@@ -968,6 +971,15 @@ libsyntax_plugin_la_CPPFLAGS = $(PLUGIN_CPPFLAGS)
 libsyntax_plugin_la_LDFLAGS = -avoid-version
 
 #------------------------
+# libusn-plugin
+#------------------------
+libusn_plugin_la_SOURCES = ldap/servers/plugins/usn/usn.c \
+                           ldap/servers/plugins/usn/usn_cleanup.c
+
+libusn_plugin_la_CPPFLAGS = $(PLUGIN_CPPFLAGS)
+libusn_plugin_la_LDFLAGS = -avoid-version
+
+#------------------------
 # libviews-plugin
 #------------------------
 libviews_plugin_la_SOURCES = ldap/servers/plugins/views/views.c
diff --git a/Makefile.in b/Makefile.in
old mode 100755
new mode 100644
index 9f3208a..865a7db
--- a/Makefile.in
+++ b/Makefile.in
@@ -173,6 +173,7 @@ am_libback_ldbm_la_OBJECTS =  \
 	ldap/servers/slapd/back-ldbm/libback_ldbm_la-ldbm_modrdn.lo \
 	ldap/servers/slapd/back-ldbm/libback_ldbm_la-ldbm_search.lo \
 	ldap/servers/slapd/back-ldbm/libback_ldbm_la-ldbm_unbind.lo \
+	ldap/servers/slapd/back-ldbm/libback_ldbm_la-ldbm_usn.lo \
 	ldap/servers/slapd/back-ldbm/libback_ldbm_la-ldif2ldbm.lo \
 	ldap/servers/slapd/back-ldbm/libback_ldbm_la-dbverify.lo \
 	ldap/servers/slapd/back-ldbm/libback_ldbm_la-matchrule.lo \
@@ -688,6 +689,14 @@ libsyntax_plugin_la_OBJECTS = $(am_libsyntax_plugin_la_OBJECTS)
 libsyntax_plugin_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
 	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
 	$(libsyntax_plugin_la_LDFLAGS) $(LDFLAGS) -o $@
+libusn_plugin_la_LIBADD =
+am_libusn_plugin_la_OBJECTS =  \
+	ldap/servers/plugins/usn/libusn_plugin_la-usn.lo \
+	ldap/servers/plugins/usn/libusn_plugin_la-usn_cleanup.lo
+libusn_plugin_la_OBJECTS = $(am_libusn_plugin_la_OBJECTS)
+libusn_plugin_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(libusn_plugin_la_LDFLAGS) $(LDFLAGS) -o $@
 libviews_plugin_la_LIBADD =
 am_libviews_plugin_la_OBJECTS =  \
 	ldap/servers/plugins/views/libviews_plugin_la-views.lo
@@ -899,10 +908,11 @@ SOURCES = $(libavl_a_SOURCES) $(libldaputil_a_SOURCES) \
 	$(libretrocl_plugin_la_SOURCES) $(libroles_plugin_la_SOURCES) \
 	$(libschemareload_plugin_la_SOURCES) $(libslapd_la_SOURCES) \
 	$(libstatechange_plugin_la_SOURCES) \
-	$(libsyntax_plugin_la_SOURCES) $(libviews_plugin_la_SOURCES) \
-	$(dbscan_bin_SOURCES) $(dsktune_bin_SOURCES) \
-	$(infadd_bin_SOURCES) $(ldap_agent_bin_SOURCES) \
-	$(ldclt_bin_SOURCES) $(ldif_bin_SOURCES) $(makstrdb_SOURCES) \
+	$(libsyntax_plugin_la_SOURCES) $(libusn_plugin_la_SOURCES) \
+	$(libviews_plugin_la_SOURCES) $(dbscan_bin_SOURCES) \
+	$(dsktune_bin_SOURCES) $(infadd_bin_SOURCES) \
+	$(ldap_agent_bin_SOURCES) $(ldclt_bin_SOURCES) \
+	$(ldif_bin_SOURCES) $(makstrdb_SOURCES) \
 	$(migratecred_bin_SOURCES) $(mmldif_bin_SOURCES) \
 	$(ns_slapd_SOURCES) $(pwdhash_bin_SOURCES) \
 	$(rsearch_bin_SOURCES)
@@ -927,13 +937,14 @@ DIST_SOURCES = $(libavl_a_SOURCES) $(libldaputil_a_SOURCES) \
 	$(libschemareload_plugin_la_SOURCES) \
 	$(am__libslapd_la_SOURCES_DIST) \
 	$(libstatechange_plugin_la_SOURCES) \
-	$(libsyntax_plugin_la_SOURCES) $(libviews_plugin_la_SOURCES) \
-	$(dbscan_bin_SOURCES) $(dsktune_bin_SOURCES) \
-	$(infadd_bin_SOURCES) $(ldap_agent_bin_SOURCES) \
-	$(am__ldclt_bin_SOURCES_DIST) $(ldif_bin_SOURCES) \
-	$(makstrdb_SOURCES) $(migratecred_bin_SOURCES) \
-	$(mmldif_bin_SOURCES) $(am__ns_slapd_SOURCES_DIST) \
-	$(pwdhash_bin_SOURCES) $(rsearch_bin_SOURCES)
+	$(libsyntax_plugin_la_SOURCES) $(libusn_plugin_la_SOURCES) \
+	$(libviews_plugin_la_SOURCES) $(dbscan_bin_SOURCES) \
+	$(dsktune_bin_SOURCES) $(infadd_bin_SOURCES) \
+	$(ldap_agent_bin_SOURCES) $(am__ldclt_bin_SOURCES_DIST) \
+	$(ldif_bin_SOURCES) $(makstrdb_SOURCES) \
+	$(migratecred_bin_SOURCES) $(mmldif_bin_SOURCES) \
+	$(am__ns_slapd_SOURCES_DIST) $(pwdhash_bin_SOURCES) \
+	$(rsearch_bin_SOURCES)
 man1dir = $(mandir)/man1
 man8dir = $(mandir)/man8
 NROFF = nroff
@@ -1252,9 +1263,10 @@ serverplugin_LTLIBRARIES = libacl-plugin.la libattr-unique-plugin.la \
 	libhttp-client-plugin.la liblinkedattrs-plugin.la \
 	libmemberof-plugin.la libpassthru-plugin.la libpwdstorage-plugin.la \
 	libreferint-plugin.la libreplication-plugin.la libretrocl-plugin.la \
-	libroles-plugin.la libschemareload-plugin.la libstatechange-plugin.la \
-	libsyntax-plugin.la libviews-plugin.la $(LIBPAM_PASSTHRU_PLUGIN) \
-	$(LIBDNA_PLUGIN) $(LIBBITWISE_PLUGIN) $(LIBPRESENCE_PLUGIN)
+	libroles-plugin.la libstatechange-plugin.la libsyntax-plugin.la \
+	libviews-plugin.la libschemareload-plugin.la libusn-plugin.la \
+	$(LIBPAM_PASSTHRU_PLUGIN) $(LIBDNA_PLUGIN) \
+	$(LIBBITWISE_PLUGIN) $(LIBPRESENCE_PLUGIN)
 
 nodist_property_DATA = ns-slapd.properties
 noinst_LIBRARIES = libavl.a libldaputil.a
@@ -1408,6 +1420,7 @@ task_SCRIPTS = ldap/admin/src/scripts/template-bak2db \
 	ldap/admin/src/scripts/template-ns-newpwpolicy.pl \
 	ldap/admin/src/scripts/template-schema-reload.pl \
 	ldap/admin/src/scripts/template-syntax-validate.pl \
+	ldap/admin/src/scripts/template-usn-tombstone-cleanup.pl \
 	ldap/admin/src/scripts/template-verify-db.pl \
 	ldap/admin/src/scripts/template-dbverify
 
@@ -1657,6 +1670,7 @@ libback_ldbm_la_SOURCES = ldap/servers/slapd/back-ldbm/ancestorid.c \
 	ldap/servers/slapd/back-ldbm/ldbm_modrdn.c \
 	ldap/servers/slapd/back-ldbm/ldbm_search.c \
 	ldap/servers/slapd/back-ldbm/ldbm_unbind.c \
+	ldap/servers/slapd/back-ldbm/ldbm_usn.c \
 	ldap/servers/slapd/back-ldbm/ldif2ldbm.c \
 	ldap/servers/slapd/back-ldbm/dbverify.c \
 	ldap/servers/slapd/back-ldbm/matchrule.c \
@@ -2001,6 +2015,15 @@ libsyntax_plugin_la_CPPFLAGS = $(PLUGIN_CPPFLAGS)
 libsyntax_plugin_la_LDFLAGS = -avoid-version
 
 #------------------------
+# libusn-plugin
+#------------------------
+libusn_plugin_la_SOURCES = ldap/servers/plugins/usn/usn.c \
+                           ldap/servers/plugins/usn/usn_cleanup.c
+
+libusn_plugin_la_CPPFLAGS = $(PLUGIN_CPPFLAGS)
+libusn_plugin_la_LDFLAGS = -avoid-version
+
+#------------------------
 # libviews-plugin
 #------------------------
 libviews_plugin_la_SOURCES = ldap/servers/plugins/views/views.c
@@ -2626,6 +2649,9 @@ ldap/servers/slapd/back-ldbm/libback_ldbm_la-ldbm_search.lo:  \
 ldap/servers/slapd/back-ldbm/libback_ldbm_la-ldbm_unbind.lo:  \
 	ldap/servers/slapd/back-ldbm/$(am__dirstamp) \
 	ldap/servers/slapd/back-ldbm/$(DEPDIR)/$(am__dirstamp)
+ldap/servers/slapd/back-ldbm/libback_ldbm_la-ldbm_usn.lo:  \
+	ldap/servers/slapd/back-ldbm/$(am__dirstamp) \
+	ldap/servers/slapd/back-ldbm/$(DEPDIR)/$(am__dirstamp)
 ldap/servers/slapd/back-ldbm/libback_ldbm_la-ldif2ldbm.lo:  \
 	ldap/servers/slapd/back-ldbm/$(am__dirstamp) \
 	ldap/servers/slapd/back-ldbm/$(DEPDIR)/$(am__dirstamp)
@@ -3747,6 +3773,20 @@ ldap/servers/plugins/syntaxes/libsyntax_plugin_la-value.lo:  \
 	ldap/servers/plugins/syntaxes/$(DEPDIR)/$(am__dirstamp)
 libsyntax-plugin.la: $(libsyntax_plugin_la_OBJECTS) $(libsyntax_plugin_la_DEPENDENCIES) 
 	$(libsyntax_plugin_la_LINK) -rpath $(serverplugindir) $(libsyntax_plugin_la_OBJECTS) $(libsyntax_plugin_la_LIBADD) $(LIBS)
+ldap/servers/plugins/usn/$(am__dirstamp):
+	@$(MKDIR_P) ldap/servers/plugins/usn
+	@: > ldap/servers/plugins/usn/$(am__dirstamp)
+ldap/servers/plugins/usn/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) ldap/servers/plugins/usn/$(DEPDIR)
+	@: > ldap/servers/plugins/usn/$(DEPDIR)/$(am__dirstamp)
+ldap/servers/plugins/usn/libusn_plugin_la-usn.lo:  \
+	ldap/servers/plugins/usn/$(am__dirstamp) \
+	ldap/servers/plugins/usn/$(DEPDIR)/$(am__dirstamp)
+ldap/servers/plugins/usn/libusn_plugin_la-usn_cleanup.lo:  \
+	ldap/servers/plugins/usn/$(am__dirstamp) \
+	ldap/servers/plugins/usn/$(DEPDIR)/$(am__dirstamp)
+libusn-plugin.la: $(libusn_plugin_la_OBJECTS) $(libusn_plugin_la_DEPENDENCIES) 
+	$(libusn_plugin_la_LINK) -rpath $(serverplugindir) $(libusn_plugin_la_OBJECTS) $(libusn_plugin_la_LIBADD) $(LIBS)
 ldap/servers/plugins/views/$(am__dirstamp):
 	@$(MKDIR_P) ldap/servers/plugins/views
 	@: > ldap/servers/plugins/views/$(am__dirstamp)
@@ -4484,6 +4524,10 @@ mostlyclean-compile:
 	-rm -f ldap/servers/plugins/uiduniq/libattr_unique_plugin_la-7bit.lo
 	-rm -f ldap/servers/plugins/uiduniq/libattr_unique_plugin_la-uid.$(OBJEXT)
 	-rm -f ldap/servers/plugins/uiduniq/libattr_unique_plugin_la-uid.lo
+	-rm -f ldap/servers/plugins/usn/libusn_plugin_la-usn.$(OBJEXT)
+	-rm -f ldap/servers/plugins/usn/libusn_plugin_la-usn.lo
+	-rm -f ldap/servers/plugins/usn/libusn_plugin_la-usn_cleanup.$(OBJEXT)
+	-rm -f ldap/servers/plugins/usn/libusn_plugin_la-usn_cleanup.lo
 	-rm -f ldap/servers/plugins/views/libviews_plugin_la-views.$(OBJEXT)
 	-rm -f ldap/servers/plugins/views/libviews_plugin_la-views.lo
 	-rm -f ldap/servers/slapd/back-ldbm/libback_ldbm_la-ancestorid.$(OBJEXT)
@@ -4572,6 +4616,8 @@ mostlyclean-compile:
 	-rm -f ldap/servers/slapd/back-ldbm/libback_ldbm_la-ldbm_search.lo
 	-rm -f ldap/servers/slapd/back-ldbm/libback_ldbm_la-ldbm_unbind.$(OBJEXT)
 	-rm -f ldap/servers/slapd/back-ldbm/libback_ldbm_la-ldbm_unbind.lo
+	-rm -f ldap/servers/slapd/back-ldbm/libback_ldbm_la-ldbm_usn.$(OBJEXT)
+	-rm -f ldap/servers/slapd/back-ldbm/libback_ldbm_la-ldbm_usn.lo
 	-rm -f ldap/servers/slapd/back-ldbm/libback_ldbm_la-ldif2ldbm.$(OBJEXT)
 	-rm -f ldap/servers/slapd/back-ldbm/libback_ldbm_la-ldif2ldbm.lo
 	-rm -f ldap/servers/slapd/back-ldbm/libback_ldbm_la-matchrule.$(OBJEXT)
@@ -5144,6 +5190,8 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/plugins/syntaxes/$(DEPDIR)/libsyntax_plugin_la-value.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/plugins/uiduniq/$(DEPDIR)/libattr_unique_plugin_la-7bit.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/plugins/uiduniq/$(DEPDIR)/libattr_unique_plugin_la-uid.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/plugins/usn/$(DEPDIR)/libusn_plugin_la-usn.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/plugins/usn/$(DEPDIR)/libusn_plugin_la-usn_cleanup.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/plugins/views/$(DEPDIR)/libviews_plugin_la-views.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/slapd/$(DEPDIR)/ldap_agent_bin-agtmmap.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/slapd/$(DEPDIR)/libslapd_la-add.Plo@am__quote@
@@ -5316,6 +5364,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/slapd/back-ldbm/$(DEPDIR)/libback_ldbm_la-ldbm_modrdn.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/slapd/back-ldbm/$(DEPDIR)/libback_ldbm_la-ldbm_search.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/slapd/back-ldbm/$(DEPDIR)/libback_ldbm_la-ldbm_unbind.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/slapd/back-ldbm/$(DEPDIR)/libback_ldbm_la-ldbm_usn.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/slapd/back-ldbm/$(DEPDIR)/libback_ldbm_la-ldif2ldbm.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/slapd/back-ldbm/$(DEPDIR)/libback_ldbm_la-matchrule.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/slapd/back-ldbm/$(DEPDIR)/libback_ldbm_la-misc.Plo@am__quote@
@@ -5994,6 +6043,13 @@ ldap/servers/slapd/back-ldbm/libback_ldbm_la-ldbm_unbind.lo: ldap/servers/slapd/
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libback_ldbm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ldap/servers/slapd/back-ldbm/libback_ldbm_la-ldbm_unbind.lo `test -f 'ldap/servers/slapd/back-ldbm/ldbm_unbind.c' || echo '$(srcdir)/'`ldap/servers/slapd/back-ldbm/ldbm_unbind.c
 
+ldap/servers/slapd/back-ldbm/libback_ldbm_la-ldbm_usn.lo: ldap/servers/slapd/back-ldbm/ldbm_usn.c
+@am__fastdepCC_TRUE@	$(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libback_ldbm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ldap/servers/slapd/back-ldbm/libback_ldbm_la-ldbm_usn.lo -MD -MP -MF ldap/servers/slapd/back-ldbm/$(DEPDIR)/libback_ldbm_la-ldbm_usn.Tpo -c -o ldap/servers/slapd/back-ldbm/libback_ldbm_la-ldbm_usn.lo `test -f 'ldap/servers/slapd/back-ldbm/ldbm_usn.c' || echo '$(srcdir)/'`ldap/servers/slapd/back-ldbm/ldbm_usn.c
+@am__fastdepCC_TRUE@	mv -f ldap/servers/slapd/back-ldbm/$(DEPDIR)/libback_ldbm_la-ldbm_usn.Tpo ldap/servers/slapd/back-ldbm/$(DEPDIR)/libback_ldbm_la-ldbm_usn.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='ldap/servers/slapd/back-ldbm/ldbm_usn.c' object='ldap/servers/slapd/back-ldbm/libback_ldbm_la-ldbm_usn.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libback_ldbm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ldap/servers/slapd/back-ldbm/libback_ldbm_la-ldbm_usn.lo `test -f 'ldap/servers/slapd/back-ldbm/ldbm_usn.c' || echo '$(srcdir)/'`ldap/servers/slapd/back-ldbm/ldbm_usn.c
+
 ldap/servers/slapd/back-ldbm/libback_ldbm_la-ldif2ldbm.lo: ldap/servers/slapd/back-ldbm/ldif2ldbm.c
 @am__fastdepCC_TRUE@	$(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libback_ldbm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ldap/servers/slapd/back-ldbm/libback_ldbm_la-ldif2ldbm.lo -MD -MP -MF ldap/servers/slapd/back-ldbm/$(DEPDIR)/libback_ldbm_la-ldif2ldbm.Tpo -c -o ldap/servers/slapd/back-ldbm/libback_ldbm_la-ldif2ldbm.lo `test -f 'ldap/servers/slapd/back-ldbm/ldif2ldbm.c' || echo '$(srcdir)/'`ldap/servers/slapd/back-ldbm/ldif2ldbm.c
 @am__fastdepCC_TRUE@	mv -f ldap/servers/slapd/back-ldbm/$(DEPDIR)/libback_ldbm_la-ldif2ldbm.Tpo ldap/servers/slapd/back-ldbm/$(DEPDIR)/libback_ldbm_la-ldif2ldbm.Plo
@@ -7912,6 +7968,20 @@ ldap/servers/plugins/syntaxes/libsyntax_plugin_la-value.lo: ldap/servers/plugins
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsyntax_plugin_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ldap/servers/plugins/syntaxes/libsyntax_plugin_la-value.lo `test -f 'ldap/servers/plugins/syntaxes/value.c' || echo '$(srcdir)/'`ldap/servers/plugins/syntaxes/value.c
 
+ldap/servers/plugins/usn/libusn_plugin_la-usn.lo: ldap/servers/plugins/usn/usn.c
+@am__fastdepCC_TRUE@	$(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libusn_plugin_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ldap/servers/plugins/usn/libusn_plugin_la-usn.lo -MD -MP -MF ldap/servers/plugins/usn/$(DEPDIR)/libusn_plugin_la-usn.Tpo -c -o ldap/servers/plugins/usn/libusn_plugin_la-usn.lo `test -f 'ldap/servers/plugins/usn/usn.c' || echo '$(srcdir)/'`ldap/servers/plugins/usn/usn.c
+@am__fastdepCC_TRUE@	mv -f ldap/servers/plugins/usn/$(DEPDIR)/libusn_plugin_la-usn.Tpo ldap/servers/plugins/usn/$(DEPDIR)/libusn_plugin_la-usn.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='ldap/servers/plugins/usn/usn.c' object='ldap/servers/plugins/usn/libusn_plugin_la-usn.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libusn_plugin_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ldap/servers/plugins/usn/libusn_plugin_la-usn.lo `test -f 'ldap/servers/plugins/usn/usn.c' || echo '$(srcdir)/'`ldap/servers/plugins/usn/usn.c
+
+ldap/servers/plugins/usn/libusn_plugin_la-usn_cleanup.lo: ldap/servers/plugins/usn/usn_cleanup.c
+@am__fastdepCC_TRUE@	$(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libusn_plugin_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ldap/servers/plugins/usn/libusn_plugin_la-usn_cleanup.lo -MD -MP -MF ldap/servers/plugins/usn/$(DEPDIR)/libusn_plugin_la-usn_cleanup.Tpo -c -o ldap/servers/plugins/usn/libusn_plugin_la-usn_cleanup.lo `test -f 'ldap/servers/plugins/usn/usn_cleanup.c' || echo '$(srcdir)/'`ldap/servers/plugins/usn/usn_cleanup.c
+@am__fastdepCC_TRUE@	mv -f ldap/servers/plugins/usn/$(DEPDIR)/libusn_plugin_la-usn_cleanup.Tpo ldap/servers/plugins/usn/$(DEPDIR)/libusn_plugin_la-usn_cleanup.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='ldap/servers/plugins/usn/usn_cleanup.c' object='ldap/servers/plugins/usn/libusn_plugin_la-usn_cleanup.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libusn_plugin_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ldap/servers/plugins/usn/libusn_plugin_la-usn_cleanup.lo `test -f 'ldap/servers/plugins/usn/usn_cleanup.c' || echo '$(srcdir)/'`ldap/servers/plugins/usn/usn_cleanup.c
+
 ldap/servers/plugins/views/libviews_plugin_la-views.lo: ldap/servers/plugins/views/views.c
 @am__fastdepCC_TRUE@	$(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libviews_plugin_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ldap/servers/plugins/views/libviews_plugin_la-views.lo -MD -MP -MF ldap/servers/plugins/views/$(DEPDIR)/libviews_plugin_la-views.Tpo -c -o ldap/servers/plugins/views/libviews_plugin_la-views.lo `test -f 'ldap/servers/plugins/views/views.c' || echo '$(srcdir)/'`ldap/servers/plugins/views/views.c
 @am__fastdepCC_TRUE@	mv -f ldap/servers/plugins/views/$(DEPDIR)/libviews_plugin_la-views.Tpo ldap/servers/plugins/views/$(DEPDIR)/libviews_plugin_la-views.Plo
@@ -9128,6 +9198,7 @@ clean-libtool:
 	-rm -rf ldap/servers/plugins/statechange/.libs ldap/servers/plugins/statechange/_libs
 	-rm -rf ldap/servers/plugins/syntaxes/.libs ldap/servers/plugins/syntaxes/_libs
 	-rm -rf ldap/servers/plugins/uiduniq/.libs ldap/servers/plugins/uiduniq/_libs
+	-rm -rf ldap/servers/plugins/usn/.libs ldap/servers/plugins/usn/_libs
 	-rm -rf ldap/servers/plugins/views/.libs ldap/servers/plugins/views/_libs
 	-rm -rf ldap/servers/slapd/.libs ldap/servers/slapd/_libs
 	-rm -rf ldap/servers/slapd/back-ldbm/.libs ldap/servers/slapd/back-ldbm/_libs
@@ -9642,6 +9713,8 @@ distclean-generic:
 	-rm -f ldap/servers/plugins/syntaxes/$(am__dirstamp)
 	-rm -f ldap/servers/plugins/uiduniq/$(DEPDIR)/$(am__dirstamp)
 	-rm -f ldap/servers/plugins/uiduniq/$(am__dirstamp)
+	-rm -f ldap/servers/plugins/usn/$(DEPDIR)/$(am__dirstamp)
+	-rm -f ldap/servers/plugins/usn/$(am__dirstamp)
 	-rm -f ldap/servers/plugins/views/$(DEPDIR)/$(am__dirstamp)
 	-rm -f ldap/servers/plugins/views/$(am__dirstamp)
 	-rm -f ldap/servers/slapd/$(DEPDIR)/$(am__dirstamp)
@@ -9682,7 +9755,7 @@ clean-am: clean-binPROGRAMS clean-generic clean-libtool \
 
 distclean: distclean-am
 	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
-	-rm -rf ldap/libraries/libavl/$(DEPDIR) ldap/servers/plugins/acl/$(DEPDIR) ldap/servers/plugins/bitwise/$(DEPDIR) ldap/servers/plugins/chainingdb/$(DEPDIR) ldap/servers/plugins/collation/$(DEPDIR) ldap/servers/plugins/cos/$(DEPDIR) ldap/servers/plugins/distrib/$(DEPDIR) ldap/servers/plugins/dna/$(DEPDIR) ldap/servers/plugins/http/$(DEPDIR) ldap/servers/plugins/linkedattrs/$(DEPDIR) ldap/servers/plugins/memberof/$(DEPDIR) ldap/servers/plugins/pam_passthru/$(DEPDIR) ldap/servers/plugins/passthru/$(DEPDIR) ldap/servers/plugins/presence/$(DEPDIR) ldap/servers/plugins/pwdstorage/$(DEPDIR) ldap/servers/plugins/referint/$(DEPDIR) ldap/servers/plugins/replication/$(DEPDIR) ldap/servers/plugins/retrocl/$(DEPDIR) ldap/servers/plugins/rever/$(DEPDIR) ldap/servers/plugins/roles/$(DEPDIR) ldap/servers/plugins/schema_reload/$(DEPDIR) ldap/servers/plugins/shared/$(DEPDIR) ldap/servers/plugins/statechange/$(DEPDIR) ldap/servers/plugins/syntaxes/$(DEPDIR) ldap/servers/plugins/uiduniq/$(DEPDIR) ldap/servers/plugins/views/$(DEPDIR) ldap/servers/slapd/$(DEPDIR) ldap/servers/slapd/back-ldbm/$(DEPDIR) ldap/servers/slapd/tools/$(DEPDIR) ldap/servers/slapd/tools/ldclt/$(DEPDIR) ldap/servers/slapd/tools/rsearch/$(DEPDIR) ldap/servers/snmp/$(DEPDIR) ldap/systools/$(DEPDIR) lib/base/$(DEPDIR) lib/ldaputil/$(DEPDIR) lib/libaccess/$(DEPDIR) lib/libadmin/$(DEPDIR) lib/libsi18n/$(DEPDIR)
+	-rm -rf ldap/libraries/libavl/$(DEPDIR) ldap/servers/plugins/acl/$(DEPDIR) ldap/servers/plugins/bitwise/$(DEPDIR) ldap/servers/plugins/chainingdb/$(DEPDIR) ldap/servers/plugins/collation/$(DEPDIR) ldap/servers/plugins/cos/$(DEPDIR) ldap/servers/plugins/distrib/$(DEPDIR) ldap/servers/plugins/dna/$(DEPDIR) ldap/servers/plugins/http/$(DEPDIR) ldap/servers/plugins/linkedattrs/$(DEPDIR) ldap/servers/plugins/memberof/$(DEPDIR) ldap/servers/plugins/pam_passthru/$(DEPDIR) ldap/servers/plugins/passthru/$(DEPDIR) ldap/servers/plugins/presence/$(DEPDIR) ldap/servers/plugins/pwdstorage/$(DEPDIR) ldap/servers/plugins/referint/$(DEPDIR) ldap/servers/plugins/replication/$(DEPDIR) ldap/servers/plugins/retrocl/$(DEPDIR) ldap/servers/plugins/rever/$(DEPDIR) ldap/servers/plugins/roles/$(DEPDIR) ldap/servers/plugins/schema_reload/$(DEPDIR) ldap/servers/plugins/shared/$(DEPDIR) ldap/servers/plugins/statechange/$(DEPDIR) ldap/servers/plugins/syntaxes/$(DEPDIR) ldap/servers/plugins/uiduniq/$(DEPDIR) ldap/servers/plugins/usn/$(DEPDIR) ldap/servers/plugins/views/$(DEPDIR) ldap/servers/slapd/$(DEPDIR) ldap/servers/slapd/back-ldbm/$(DEPDIR) ldap/servers/slapd/tools/$(DEPDIR) ldap/servers/slapd/tools/ldclt/$(DEPDIR) ldap/servers/slapd/tools/rsearch/$(DEPDIR) ldap/servers/snmp/$(DEPDIR) ldap/systools/$(DEPDIR) lib/base/$(DEPDIR) lib/ldaputil/$(DEPDIR) lib/libaccess/$(DEPDIR) lib/libadmin/$(DEPDIR) lib/libsi18n/$(DEPDIR)
 	-rm -f Makefile
 distclean-am: clean-am distclean-compile distclean-generic \
 	distclean-hdr distclean-libtool distclean-tags
@@ -9724,7 +9797,7 @@ installcheck-am:
 maintainer-clean: maintainer-clean-am
 	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
 	-rm -rf $(top_srcdir)/autom4te.cache
-	-rm -rf ldap/libraries/libavl/$(DEPDIR) ldap/servers/plugins/acl/$(DEPDIR) ldap/servers/plugins/bitwise/$(DEPDIR) ldap/servers/plugins/chainingdb/$(DEPDIR) ldap/servers/plugins/collation/$(DEPDIR) ldap/servers/plugins/cos/$(DEPDIR) ldap/servers/plugins/distrib/$(DEPDIR) ldap/servers/plugins/dna/$(DEPDIR) ldap/servers/plugins/http/$(DEPDIR) ldap/servers/plugins/linkedattrs/$(DEPDIR) ldap/servers/plugins/memberof/$(DEPDIR) ldap/servers/plugins/pam_passthru/$(DEPDIR) ldap/servers/plugins/passthru/$(DEPDIR) ldap/servers/plugins/presence/$(DEPDIR) ldap/servers/plugins/pwdstorage/$(DEPDIR) ldap/servers/plugins/referint/$(DEPDIR) ldap/servers/plugins/replication/$(DEPDIR) ldap/servers/plugins/retrocl/$(DEPDIR) ldap/servers/plugins/rever/$(DEPDIR) ldap/servers/plugins/roles/$(DEPDIR) ldap/servers/plugins/schema_reload/$(DEPDIR) ldap/servers/plugins/shared/$(DEPDIR) ldap/servers/plugins/statechange/$(DEPDIR) ldap/servers/plugins/syntaxes/$(DEPDIR) ldap/servers/plugins/uiduniq/$(DEPDIR) ldap/servers/plugins/views/$(DEPDIR) ldap/servers/slapd/$(DEPDIR) ldap/servers/slapd/back-ldbm/$(DEPDIR) ldap/servers/slapd/tools/$(DEPDIR) ldap/servers/slapd/tools/ldclt/$(DEPDIR) ldap/servers/slapd/tools/rsearch/$(DEPDIR) ldap/servers/snmp/$(DEPDIR) ldap/systools/$(DEPDIR) lib/base/$(DEPDIR) lib/ldaputil/$(DEPDIR) lib/libaccess/$(DEPDIR) lib/libadmin/$(DEPDIR) lib/libsi18n/$(DEPDIR)
+	-rm -rf ldap/libraries/libavl/$(DEPDIR) ldap/servers/plugins/acl/$(DEPDIR) ldap/servers/plugins/bitwise/$(DEPDIR) ldap/servers/plugins/chainingdb/$(DEPDIR) ldap/servers/plugins/collation/$(DEPDIR) ldap/servers/plugins/cos/$(DEPDIR) ldap/servers/plugins/distrib/$(DEPDIR) ldap/servers/plugins/dna/$(DEPDIR) ldap/servers/plugins/http/$(DEPDIR) ldap/servers/plugins/linkedattrs/$(DEPDIR) ldap/servers/plugins/memberof/$(DEPDIR) ldap/servers/plugins/pam_passthru/$(DEPDIR) ldap/servers/plugins/passthru/$(DEPDIR) ldap/servers/plugins/presence/$(DEPDIR) ldap/servers/plugins/pwdstorage/$(DEPDIR) ldap/servers/plugins/referint/$(DEPDIR) ldap/servers/plugins/replication/$(DEPDIR) ldap/servers/plugins/retrocl/$(DEPDIR) ldap/servers/plugins/rever/$(DEPDIR) ldap/servers/plugins/roles/$(DEPDIR) ldap/servers/plugins/schema_reload/$(DEPDIR) ldap/servers/plugins/shared/$(DEPDIR) ldap/servers/plugins/statechange/$(DEPDIR) ldap/servers/plugins/syntaxes/$(DEPDIR) ldap/servers/plugins/uiduniq/$(DEPDIR) ldap/servers/plugins/usn/$(DEPDIR) ldap/servers/plugins/views/$(DEPDIR) ldap/servers/slapd/$(DEPDIR) ldap/servers/slapd/back-ldbm/$(DEPDIR) ldap/servers/slapd/tools/$(DEPDIR) ldap/servers/slapd/tools/ldclt/$(DEPDIR) ldap/servers/slapd/tools/rsearch/$(DEPDIR) ldap/servers/snmp/$(DEPDIR) ldap/systools/$(DEPDIR) lib/base/$(DEPDIR) lib/ldaputil/$(DEPDIR) lib/libaccess/$(DEPDIR) lib/libadmin/$(DEPDIR) lib/libsi18n/$(DEPDIR)
 	-rm -f Makefile
 maintainer-clean-am: distclean-am maintainer-clean-generic
 
diff --git a/aclocal.m4 b/aclocal.m4
old mode 100755
new mode 100644
diff --git a/config.h.in b/config.h.in
old mode 100755
new mode 100644
diff --git a/ldap/admin/src/scripts/template-usn-tombstone-cleanup.pl.in b/ldap/admin/src/scripts/template-usn-tombstone-cleanup.pl.in
new file mode 100644
index 0000000..1bd0925
--- /dev/null
+++ b/ldap/admin/src/scripts/template-usn-tombstone-cleanup.pl.in
@@ -0,0 +1,180 @@
+#{{PERL-EXEC}}
+#
+# BEGIN COPYRIGHT BLOCK
+# This Program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; version 2 of the License.
+# 
+# This Program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License along with
+# this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA.
+# 
+# In addition, as a special exception, Red Hat, Inc. gives You the additional
+# right to link the code of this Program with code not covered under the GNU
+# General Public License ("Non-GPL Code") and to distribute linked combinations
+# including the two, subject to the limitations in this paragraph. Non-GPL Code
+# permitted under this exception must only link to the code of this Program
+# through those well defined interfaces identified in the file named EXCEPTION
+# found in the source code files (the "Approved Interfaces"). The files of
+# Non-GPL Code may instantiate templates or use macros or inline functions from
+# the Approved Interfaces without causing the resulting work to be covered by
+# the GNU General Public License. Only Red Hat, Inc. may make changes or
+# additions to the list of Approved Interfaces. You must obey the GNU General
+# Public License in all respects for all of the Program code and other code used
+# in conjunction with the Program except the Non-GPL Code covered by this
+# exception. If you modify this file, you may extend this exception to your
+# version of the file, but you are not obligated to do so. If you do not wish to
+# provide this exception without modification, you must delete this exception
+# statement from your version and license this file solely under the GPL without
+# exception. 
+# 
+# 
+# Copyright (C) 2009 Red Hat, Inc.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+sub usage {
+    print(STDERR "Usage: $0 [-v] -D rootdn { -w password | -w - | -j filename } -s suffix | -n backend [ -m maxusn_to_delete ]\n");
+    print(STDERR " Opts: -D rootdn           - Directory Manager\n");
+    print(STDERR "     : -w password         - Directory Manager's password\n");
+    print(STDERR "     : -w -                - Prompt for Directory Manager's password\n");
+    print(STDERR "     : -j filename         - Read Directory Manager's password from file\n");
+    print(STDERR "     : -s suffix           - Suffix where USN tombstone entries are cleaned up\n");
+    print(STDERR "     : -n backend          - Backend instance in which USN tombstone entries \n");
+	print(STDERR "                             are cleaned up (alternative to suffix)\n");
+    print(STDERR "     : -m maxusn_to_delete - USN tombstones entries are deleted up to \n");
+    print(STDERR "                             the entry with maxusn_to_delete\n");
+    print(STDERR "     : -v                  - verbose\n");
+}
+
+$rootdn = "";
+$passwd = "";
+$passwdfile = "";
+$args = "";
+$suffix_arg = "";
+$backend_arg = "";
+$maxusn_arg = "";
+$verbose = 0;
+
+$prefix = "{{DS-ROOT}}";
+
+$ENV{'PATH'} = "$prefix@ldapsdk_bindir@:$prefix/usr/bin:@ldapsdk_bindir@:/usr/bin";
+$ENV{'LD_LIBRARY_PATH'} = "$prefix@nss_libdir@:$prefix/usr/lib:@nss_libdir@:/usr/lib";
+$ENV{'SHLIB_PATH'} = "$prefix@nss_libdir@:$prefix/usr/lib:@nss_libdir@:/usr/lib";
+
+$i = 0;
+while ($i <= $#ARGV) 
+{
+    if ("$ARGV[$i]" eq "-s")
+    {
+        # suffix
+        $i++; $suffix_arg = $ARGV[$i];
+    }
+    elsif ("$ARGV[$i]" eq "-n")
+    {
+        # backend
+        $i++; $backend_arg = $ARGV[$i];
+    }
+    elsif ("$ARGV[$i]" eq "-m")
+    {
+        # max usn
+        $i++; $maxusn_arg = $ARGV[$i];
+    }
+    elsif ("$ARGV[$i]" eq "-D") 
+    {    
+        # Directory Manager
+        $i++; $rootdn = $ARGV[$i];
+    }
+    elsif ("$ARGV[$i]" eq "-w") 
+    {    
+        # Directory Manager's password
+        $i++; $passwd = $ARGV[$i];
+    } 
+    elsif ("$ARGV[$i]" eq "-j")
+    {
+         # Read Directory Manager's password from a file
+        $i++; $passwdfile = $ARGV[$i];
+    }
+    elsif ("$ARGV[$i]" eq "-v") 
+    {    
+        # verbose
+        $verbose = 1;
+    }
+    else
+    {
+        &usage; exit(1);
+    }
+    $i++;
+}
+
+if ($passwdfile ne ""){
+# Open file and get the password
+    unless (open (RPASS, $passwdfile)) {
+        die "Error, cannot open password file $passwdfile\n";
+    }
+    $passwd = <RPASS>;
+    chomp($passwd);
+    close(RPASS);
+} elsif ($passwd eq "-"){
+# Read the password from terminal
+	print "Bind Password: ";
+	# Disable console echo
+	system("stty -echo");
+	# read the answer
+	$passwd = <STDIN>;
+	# Enable console echo
+	system("stty echo");
+	print "\n";
+	chop($passwd); # trim trailing newline
+}
+
+if ( $rootdn eq "" || $passwd eq "" )
+{ 
+    &usage; 
+    exit(1); 
+}
+
+$vstr = "";
+if ($verbose != 0) 
+{ 
+    $vstr = "-v"; 
+}
+
+# Use a timestamp as part of the task entry name
+($s, $m, $h, $dy, $mn, $yr, $wdy, $ydy, $r) = localtime(time);
+$mn++; $yr += 1900;
+$taskname = "usn_cleanup_${yr}_${mn}_${dy}_${h}_${m}_${s}";
+
+# Build the task entry to add
+$dn = "dn: cn=$taskname, cn=USN tombstone cleanup task, cn=tasks, cn=config\n";
+$misc = "changetype: add\nobjectclass: top\nobjectclass: extensibleObject\n";
+$cn =  "cn: $taskname\n";
+
+if ( $suffix_arg eq "" && $backend_arg eq "" )
+{
+    &usage; 
+    exit(1); 
+}
+elsif ( $suffix_arg ne "" )
+{
+    $args = "suffix: $suffix_arg\n";
+}
+else
+{
+    $args = "backend: $backend_arg\n";
+}
+
+if ( $maxusn_arg ne "" )
+{
+    $args = $args . "maxusn_to_delete: $maxusn_arg\n";
+}
+
+$entry = "${dn}${misc}${cn}${basedn}${args}";
+open(FOO, "| ldapmodify $vstr -h {{SERVER-NAME}} -p {{SERVER-PORT}} -D \"$rootdn\" -w \"$passwd\" -a" );
+print(FOO "$entry");
+close(FOO);
diff --git a/ldap/ldif/template-dse.ldif.in b/ldap/ldif/template-dse.ldif.in
index d0e2927..c2ac588 100644
--- a/ldap/ldif/template-dse.ldif.in
+++ b/ldap/ldif/template-dse.ldif.in
@@ -677,6 +677,17 @@ nsslapd-plugintype: preoperation
 nsslapd-pluginenabled: off
 nsslapd-plugin-depends-on-type: database
 
+dn: cn=USN,cn=plugins,cn=config
+objectclass: top
+objectclass: nsSlapdPlugin
+objectclass: extensibleObject
+cn: USN
+nsslapd-pluginpath: libusn-plugin
+nsslapd-plugininitfunc: usn_init
+nsslapd-plugintype: object
+nsslapd-pluginenabled: off
+nsslapd-plugin-depends-on-type: database
+
 dn: cn=ldbm database,cn=plugins,cn=config
 objectclass: top
 objectclass: nsSlapdPlugin
@@ -724,6 +735,14 @@ cn: entrydn
 nssystemindex: true
 nsindextype: eq
 
+dn: cn=entryusn,cn=default indexes, cn=config,cn=ldbm database,cn=plugins,cn=config
+objectclass: top
+objectclass: nsIndex
+cn: entryusn
+nssystemindex: true
+nsindextype: eq
+nsmatchingrule: integerOrderingMatch
+
 dn: cn=givenName,cn=default indexes, cn=config,cn=ldbm database,cn=plugins,cn=config
 objectclass: top
 objectclass: nsIndex
diff --git a/ldap/servers/plugins/usn/usn.c b/ldap/servers/plugins/usn/usn.c
new file mode 100644
index 0000000..2bb389a
--- /dev/null
+++ b/ldap/servers/plugins/usn/usn.c
@@ -0,0 +1,570 @@
+/** BEGIN COPYRIGHT BLOCK
+ * This Program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; version 2 of the License.
+ *
+ * This Program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * In addition, as a special exception, Red Hat, Inc. gives You the additional
+ * right to link the code of this Program with code not covered under the GNU
+ * General Public License ("Non-GPL Code") and to distribute linked combinations
+ * including the two, subject to the limitations in this paragraph. Non-GPL Code
+ * permitted under this exception must only link to the code of this Program
+ * through those well defined interfaces identified in the file named EXCEPTION
+ * found in the source code files (the "Approved Interfaces"). The files of
+ * Non-GPL Code may instantiate templates or use macros or inline functions from
+ * the Approved Interfaces without causing the resulting work to be covered by
+ * the GNU General Public License. Only Red Hat, Inc. may make changes or
+ * additions to the list of Approved Interfaces. You must obey the GNU General
+ * Public License in all respects for all of the Program code and other code used
+ * in conjunction with the Program except the Non-GPL Code covered by this
+ * exception. If you modify this file, you may extend this exception to your
+ * version of the file, but you are not obligated to do so. If you do not wish to
+ * provide this exception without modification, you must delete this exception
+ * statement from your version and license this file solely under the GPL without
+ * exception.
+ *
+ *
+ * Copyright (C) 2009 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "usn.h"
+
+static Slapi_PluginDesc pdesc = {
+        "USN", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT,
+        "USN (Update Sequence Number) plugin" };
+
+static CSNGen *_usn_csngen = NULL;
+
+static void *_usn_identity = NULL;
+
+static int usn_preop_init(Slapi_PBlock *pb);
+static int usn_bepreop_init(Slapi_PBlock *pb);
+static int usn_bepostop_init(Slapi_PBlock *pb);
+static int usn_rootdse_init();
+
+static int usn_preop_delete(Slapi_PBlock *pb);
+static int usn_bepreop_add(Slapi_PBlock *pb);
+static int usn_bepreop_delete(Slapi_PBlock *pb);
+static int usn_bepreop_modify(Slapi_PBlock *pb);
+static int usn_bepostop(Slapi_PBlock *pb);
+static int usn_start(Slapi_PBlock *pb);
+static int usn_close(Slapi_PBlock *pb);
+static int usn_get_attr(Slapi_PBlock *pb, const char* type, void *value);
+
+static int usn_rootdse_search(Slapi_PBlock *pb, Slapi_Entry* e,
+        Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
+
+/*
+ * Register USN plugin
+ * Note: USN counter initialization is done in the backend (ldbm_usn_init).
+ */
+int
+usn_init(Slapi_PBlock *pb)
+{
+    int rc = 0;
+    void *identity = NULL;
+    int enabled = 0;
+
+    slapi_log_error(SLAPI_LOG_TRACE, USN_PLUGIN_SUBSYSTEM,
+                    "--> usn_init\n");
+
+    slapi_pblock_get(pb, SLAPI_PLUGIN_ENABLED, &enabled);
+
+    if (!enabled) {
+        /* not enabled */
+        goto bail;
+    }
+
+    slapi_pblock_get(pb, SLAPI_PLUGIN_IDENTITY, &identity);
+
+    /* slapi_register_plugin always returns SUCCESS (0) */
+    if (slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION,
+                         SLAPI_PLUGIN_VERSION_01) != 0 ||
+        slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION,
+                         (void *)&pdesc) != 0) {
+        slapi_log_error(SLAPI_LOG_FATAL, USN_PLUGIN_SUBSYSTEM,
+                        "usn_init: failed to register version & description\n");
+        rc = -1;
+        goto bail;
+    }
+    if (slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN,
+                         (void *)usn_start) != 0 ) {
+        slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN,
+                         (void *)usn_close) != 0 ||
+        slapi_log_error(SLAPI_LOG_FATAL, USN_PLUGIN_SUBSYSTEM,
+                        "usn_init: failed to register close callback & task\n");
+        rc = -1;
+        goto bail;
+    }
+
+    rc = slapi_register_plugin("preoperation", 1 /* Enabled */,
+                               "usn_preop_init", usn_preop_init,
+                               "USN preoperation plugin", NULL, identity);
+    rc = slapi_register_plugin("bepreoperation", 1 /* Enabled */,
+                               "usn_bepreop_init", usn_bepreop_init,
+                               "USN bepreoperation plugin", NULL, identity);
+    rc = slapi_register_plugin("bepostoperation", 1 /* Enabled */,
+                               "usn_bepostop_init", usn_bepostop_init,
+                               "USN bepostoperation plugin", NULL, identity);
+   usn_set_identity(identity);
+bail:
+    slapi_log_error(SLAPI_LOG_TRACE, USN_PLUGIN_SUBSYSTEM,
+                    "<-- usn_init\n");
+    return rc;
+}
+
+static int
+usn_preop_init(Slapi_PBlock *pb)
+{
+    int rc = 0;
+
+    /* set up csn generator for tombstone */
+    _usn_csngen = csngen_new(USN_CSNGEN_ID, NULL);
+    if (NULL == _usn_csngen) {
+        slapi_log_error(SLAPI_LOG_FATAL, USN_PLUGIN_SUBSYSTEM,
+                        "usn_preop_init: csngen_new failed\n");
+        rc = -1;
+    }
+
+    if (slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_DELETE_FN,
+                                 (void *)usn_preop_delete) != 0) {
+        slapi_log_error(SLAPI_LOG_FATAL, USN_PLUGIN_SUBSYSTEM,
+                        "usn_preop_init: failed to register preop plugin\n");
+        rc = -1;
+    }
+
+    return rc;
+}
+
+static int
+usn_bepreop_init(Slapi_PBlock *pb)
+{
+    int rc = 0;
+
+    if (slapi_pblock_set(pb, SLAPI_PLUGIN_BE_PRE_ADD_FN,
+                                 (void *)usn_bepreop_add) != 0 ||
+        slapi_pblock_set(pb, SLAPI_PLUGIN_BE_PRE_DELETE_FN,
+                                 (void *)usn_bepreop_delete) != 0 ||
+        slapi_pblock_set(pb, SLAPI_PLUGIN_BE_PRE_MODIFY_FN,
+                                 (void *)usn_bepreop_modify) != 0 ||
+        slapi_pblock_set(pb, SLAPI_PLUGIN_BE_PRE_MODRDN_FN,
+                                 (void *)usn_bepreop_modify) != 0) {
+        slapi_log_error(SLAPI_LOG_FATAL, USN_PLUGIN_SUBSYSTEM,
+                    "usn_bepreop_init: failed to register bepreop plugin\n");
+        rc = -1;
+    }
+
+    return rc;
+}
+
+static int
+usn_bepostop_init(Slapi_PBlock *pb)
+{
+    int rc = 0;
+
+    if (slapi_pblock_set(pb, SLAPI_PLUGIN_BE_POST_ADD_FN,
+                                 (void *)usn_bepostop) != 0 ||
+        slapi_pblock_set(pb, SLAPI_PLUGIN_BE_POST_DELETE_FN,
+                                 (void *)usn_bepostop) != 0 ||
+        slapi_pblock_set(pb, SLAPI_PLUGIN_BE_POST_MODIFY_FN,
+                                 (void *)usn_bepostop) != 0 ||
+        slapi_pblock_set(pb, SLAPI_PLUGIN_BE_POST_MODRDN_FN,
+                                 (void *)usn_bepostop) != 0) {
+        slapi_log_error(SLAPI_LOG_FATAL, USN_PLUGIN_SUBSYSTEM,
+                    "usn_bepostop_init: failed to register bepostop plugin\n");
+        rc = -1;
+    }
+
+    return rc;
+}
+
+static int
+usn_rootdse_init()
+{
+    int rc = -1;
+
+    if (slapi_config_register_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP,
+                                        "", LDAP_SCOPE_BASE, "(objectclass=*)", 
+                                        usn_rootdse_search, NULL)) {
+        rc = 0;
+    }
+
+    return rc;
+}
+
+/*
+ * usn_start: usn_rootdse_init -- set rootdse callback to aggregate in rootDSE
+ *            usn_cleanup_start -- initialize USN tombstone cleanup task
+ */
+static int
+usn_start(Slapi_PBlock *pb)
+{
+    int rc = 0;
+
+    slapi_log_error(SLAPI_LOG_TRACE, USN_PLUGIN_SUBSYSTEM, "--> usn_start\n");
+
+    rc = usn_rootdse_init();
+    rc |= usn_cleanup_start(pb);
+
+    slapi_log_error(SLAPI_LOG_TRACE, USN_PLUGIN_SUBSYSTEM, "<-- usn_start\n");
+
+    return rc;
+}
+
+/*
+ * usn_close: release the csn generator used to convert an entry to tombstone
+ */
+static int
+usn_close(Slapi_PBlock *pb)
+{
+    slapi_log_error(SLAPI_LOG_TRACE, USN_PLUGIN_SUBSYSTEM, "--> usn_close\n");
+
+    csngen_free(&_usn_csngen);
+
+    slapi_log_error(SLAPI_LOG_TRACE, USN_PLUGIN_SUBSYSTEM, "<-- usn_close\n");
+}
+
+/* 
+ * usn_preop_delete -- set params to turn the entry to tombstone
+ */
+static int
+usn_preop_delete(Slapi_PBlock *pb)
+{
+    int rc = 0;
+    CSN *csn = NULL;
+    CSN *orig_csn = NULL;
+    Slapi_Operation *op = NULL;
+
+    slapi_log_error(SLAPI_LOG_TRACE, USN_PLUGIN_SUBSYSTEM,
+                    "--> usn_preop_delete\n");
+
+    slapi_pblock_get(pb, SLAPI_OPERATION, &op);
+    orig_csn = operation_get_csn(op);
+
+    if (NULL == orig_csn) {
+        /* 
+         * No other plugins hasn't set csn yet, so let's set USN's csn.
+         * If other plugin overrides csn and replica_attr_handler, that's fine.
+         */
+        rc = csngen_new_csn(_usn_csngen, &csn, PR_FALSE /* notify */);
+        if (CSN_SUCCESS != rc) {
+            slapi_log_error(SLAPI_LOG_FATAL, USN_PLUGIN_SUBSYSTEM,
+                            "usn_preop_delete: csngen_new failed (%d)\n", rc);
+            goto bail;
+        }
+        operation_set_csn(op, csn);
+        slapi_operation_set_replica_attr_handler(op, (void *)usn_get_attr);
+    }
+bail:
+    slapi_log_error(SLAPI_LOG_TRACE, USN_PLUGIN_SUBSYSTEM,
+                    "<-- usn_preop_delete\n");
+
+    return rc;
+}
+
+#define KEEP_PREV_USN 1
+
+static void
+_usn_add_next_usn(Slapi_Entry *e, Slapi_Backend *be, int flags)
+{
+    struct berval usn_berval = {0};
+    Slapi_Attr* attr = NULL;
+
+    if (NULL == be->be_usn_counter) {
+        /* USN plugin is not enabled */
+        return;
+    }
+
+    slapi_log_error(SLAPI_LOG_TRACE, USN_PLUGIN_SUBSYSTEM,
+                    "--> _usn_add_next_usn\n");
+
+    /* add next USN to the entry; "be" contains the usn counter */
+    usn_berval.bv_val = slapi_ch_smprintf("%" NSPRIu64, 
+                                   slapi_counter_get_value(be->be_usn_counter));
+    usn_berval.bv_len = strlen(usn_berval.bv_val);
+    slapi_entry_attr_find(e, SLAPI_ATTR_ENTRYUSN, &attr);
+    if (NULL == attr) { /* ENTRYUSN does not exist; add it */
+        Slapi_Value *usn_value = slapi_value_new_berval(&usn_berval);
+        slapi_entry_add_value(e, SLAPI_ATTR_ENTRYUSN, usn_value);
+        slapi_value_free(&usn_value);
+    } else { /* ENTRYUSN exists; replace it */
+        struct berval *new_bvals[2];
+        struct berval **prev_values = NULL;
+        if (KEEP_PREV_USN == flags) {
+            if (0 == slapi_attr_get_bervals_copy(attr, &prev_values)) {
+                slapi_entry_add_values(e,
+                                SLAPI_ATTR_ENTRYUSN_PREV, prev_values);
+                ber_bvecfree(prev_values);
+            }
+        }
+        new_bvals[0] = &usn_berval;
+        new_bvals[1] = NULL;
+        slapi_entry_attr_replace(e, SLAPI_ATTR_ENTRYUSN, new_bvals);
+    }
+    slapi_ch_free_string(&usn_berval.bv_val);
+
+    slapi_log_error(SLAPI_LOG_TRACE, USN_PLUGIN_SUBSYSTEM,
+                    "<-- _usn_add_next_usn\n");
+
+    return;
+}
+
+static int
+_usn_mod_next_usn(LDAPMod ***mods, Slapi_Backend *be)
+{
+    Slapi_Mods smods = {0};
+    struct berval *bvals[2];
+    struct berval usn_berval = {0};
+    char counter_buf[USN_COUNTER_BUF_LEN];
+
+    if (NULL == be->be_usn_counter) {
+        /* USN plugin is not enabled */
+        return LDAP_UNWILLING_TO_PERFORM;
+    }
+
+    slapi_log_error(SLAPI_LOG_TRACE, USN_PLUGIN_SUBSYSTEM,
+                    "--> _usn_mod_next_usn\n");
+
+    /* add next USN to the mods; "be" contains the usn counter */
+    usn_berval.bv_val = counter_buf;
+    PR_snprintf(usn_berval.bv_val, USN_COUNTER_BUF_LEN, "%" NSPRIu64, 
+                                   slapi_counter_get_value(be->be_usn_counter));
+    usn_berval.bv_len = strlen(usn_berval.bv_val);
+    bvals[0] = &usn_berval;
+    bvals[1] = NULL;
+
+    slapi_mods_init_byref(&smods, *mods);
+    /* bvals is duplicated by ber_bvdup in slapi_mods_add_modbvps */
+    slapi_mods_add_modbvps(&smods, LDAP_MOD_REPLACE | LDAP_MOD_BVALUES,
+                           SLAPI_ATTR_ENTRYUSN, bvals);
+
+    *mods = slapi_mods_get_ldapmods_byref(&smods);
+
+    slapi_log_error(SLAPI_LOG_TRACE, USN_PLUGIN_SUBSYSTEM,
+                    "<-- _usn_mod_next_usn\n");
+    return LDAP_SUCCESS;
+}
+
+/*
+ * usn_bepreop_add - add next USN to the entry to be added
+ */
+static int
+usn_bepreop_add(Slapi_PBlock *pb)
+{
+    Slapi_Entry *e = NULL;
+    Slapi_Backend *be = NULL;
+    int rc = LDAP_SUCCESS;
+
+    slapi_log_error(SLAPI_LOG_TRACE, USN_PLUGIN_SUBSYSTEM,
+                    "--> usn_bepreop_add\n");
+
+    /* add next USN to the entry; "be" contains the usn counter */
+    slapi_pblock_get(pb, SLAPI_ADD_ENTRY, &e);
+    if (NULL == e) {
+        rc = LDAP_NO_SUCH_OBJECT;    
+        goto bail;
+    }
+    slapi_pblock_get(pb, SLAPI_BACKEND, &be);
+    if (NULL == be) {
+        rc = LDAP_PARAM_ERROR;    
+        goto bail;
+    }
+    _usn_add_next_usn(e, be, 0);
+bail:
+    slapi_log_error(SLAPI_LOG_TRACE, USN_PLUGIN_SUBSYSTEM,
+                    "<-- usn_bepreop_add\n");
+    return rc;
+}
+
+/* 
+ * usn_bepreop_delete -- add/replace next USN to the entry
+ *                       bepreop_delete is not called if the entry is tombstone
+ */
+static int
+usn_bepreop_delete(Slapi_PBlock *pb)
+{
+    Slapi_Entry *e = NULL;
+    Slapi_Backend *be = NULL;
+    int rc = LDAP_SUCCESS;
+
+    slapi_log_error(SLAPI_LOG_TRACE, USN_PLUGIN_SUBSYSTEM,
+                    "--> usn_bepreop_delete\n");
+
+    /* add next USN to the entry; "be" contains the usn counter */
+    slapi_pblock_get(pb, SLAPI_DELETE_BEPREOP_ENTRY, &e);
+    if (NULL == e) {
+        rc = LDAP_NO_SUCH_OBJECT;    
+        goto bail;
+    }
+    slapi_pblock_get(pb, SLAPI_BACKEND, &be);
+    if (NULL == be) {
+        rc = LDAP_PARAM_ERROR;    
+        goto bail;
+    }
+    if (e->e_flags & SLAPI_ENTRY_FLAG_TOMBSTONE) {
+        Slapi_Operation *op = NULL;
+        slapi_pblock_get(pb, SLAPI_OPERATION, &op);
+        slapi_operation_set_flag(op, OP_FLAG_TOMBSTONE_ENTRY);
+    } else {
+        _usn_add_next_usn(e, be, KEEP_PREV_USN);
+    }
+bail:
+    slapi_log_error(SLAPI_LOG_TRACE, USN_PLUGIN_SUBSYSTEM,
+                    "<-- usn_bepreop_delete\n");
+    return rc;
+}
+
+/*
+ * usn_bepreop_modify - add/replace next USN to the mods; 
+ *                      shared by modify and modrdn
+ */
+static int
+usn_bepreop_modify (Slapi_PBlock *pb)
+{
+    LDAPMod **mods = NULL;
+    Slapi_Backend *be = NULL;
+    int rc = LDAP_SUCCESS;
+
+    slapi_log_error(SLAPI_LOG_TRACE, USN_PLUGIN_SUBSYSTEM,
+                    "--> usn_bepreop_modify\n");
+
+    /* add/replace next USN to the mods; "be" contains the usn counter */
+    slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
+    slapi_pblock_get(pb, SLAPI_BACKEND, &be);
+    if (NULL == be) {
+        rc = LDAP_PARAM_ERROR;    
+        goto bail;
+    }
+    if (LDAP_SUCCESS == _usn_mod_next_usn(&mods, be)) {
+        slapi_pblock_set(pb, SLAPI_MODIFY_MODS, mods);
+    }
+bail:
+    slapi_log_error(SLAPI_LOG_TRACE, USN_PLUGIN_SUBSYSTEM,
+                    "<-- usn_bepreop_modify\n");
+    return rc;
+}
+
+/* count up the counter */
+static int
+usn_bepostop (Slapi_PBlock *pb)
+{
+    int rc = -1;
+    Slapi_Backend *be = NULL;
+
+    slapi_log_error(SLAPI_LOG_TRACE, USN_PLUGIN_SUBSYSTEM,
+                    "--> usn_bepostop\n");
+
+    /* if op is not successful, don't increment the counter */
+    slapi_pblock_get(pb, SLAPI_RESULT_CODE, &rc);
+    if (LDAP_SUCCESS != rc) {
+        goto bail;
+    }
+
+    slapi_pblock_get(pb, SLAPI_BACKEND, &be);
+    if (NULL == be) {
+        rc = LDAP_PARAM_ERROR;    
+        goto bail;
+    }
+
+    if (be->be_usn_counter) {
+        slapi_counter_increment(be->be_usn_counter);
+    }
+bail:
+    slapi_log_error(SLAPI_LOG_TRACE, USN_PLUGIN_SUBSYSTEM,
+                    "<-- usn_bepostop\n");
+    return rc;
+}
+
+/* mimic replication to turn on create_tombstone_entry */
+static int
+usn_get_attr(Slapi_PBlock *pb, const char* type, void *value)
+{
+    if (0 == strcasecmp(type, "nsds5ReplicaTombstonePurgeInterval")) {
+        *(int *)value = 1;
+    } else {
+        *(int *)value = 0;
+    }
+}
+
+void
+usn_set_identity(void *identity)
+{
+    _usn_identity = identity;
+}
+
+void *
+usn_get_identity()
+{
+    return _usn_identity;
+}
+
+/*
+ * usn_rootdse_search -- callback for the search on root DSN
+ *                       add lastusn value per backend
+ *
+ * example:
+ * ldapsearch -b "" -s base "(objectclass=*)" lastusn
+ * dn:
+ * lastusn;userroot: 72
+ * lastusn;testbackend: 15
+ */
+static int
+usn_rootdse_search(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter,
+                   int *returncode, char *returntext, void *arg)
+{
+    char *cookie = NULL;
+    Slapi_Backend *be;
+    struct berval *vals[2];
+    struct berval usn_berval;
+    vals[0] = &usn_berval;
+    vals[1] = NULL;
+    char counter_buf[USN_COUNTER_BUF_LEN];
+    int attr_len = 64; /* length of lastusn;<backend_name> */
+    char *attr = (char *)slapi_ch_malloc(attr_len);
+    char *attr_subp = NULL;
+
+    slapi_log_error(SLAPI_LOG_TRACE, USN_PLUGIN_SUBSYSTEM,
+                    "--> usn_rootdse_search\n");
+
+    usn_berval.bv_val = counter_buf;
+    PR_snprintf(attr, USN_LAST_USN_ATTR_CORE_LEN+1, "%s;", USN_LAST_USN);
+    attr_subp = attr + USN_LAST_USN_ATTR_CORE_LEN;
+    for (be = slapi_get_first_backend(&cookie); be;
+         be = slapi_get_next_backend(cookie)) {
+        if (NULL == be->be_usn_counter) { /* no counter == not a db backend */
+            continue;
+        }
+        /* get a next USN counter from be_usn_counter; then minus 1 from it */
+        PR_snprintf(usn_berval.bv_val, USN_COUNTER_BUF_LEN, "%" NSPRIu64, 
+                                 slapi_counter_get_value(be->be_usn_counter)-1);
+        usn_berval.bv_len = strlen(usn_berval.bv_val);
+
+        if (USN_LAST_USN_ATTR_CORE_LEN + strlen(be->be_name) + 1 > attr_len) {
+            attr_len *= 2;
+            attr = (char *)slapi_ch_realloc(attr, attr_len);
+            attr_subp = attr + USN_LAST_USN_ATTR_CORE_LEN;
+        }
+        PR_snprintf(attr_subp, attr_len - USN_LAST_USN_ATTR_CORE_LEN,
+                                "%s", be->be_name);
+        slapi_entry_attr_replace(e, attr, vals);
+    }
+
+    slapi_ch_free_string(&cookie);
+    slapi_ch_free_string(&attr);
+
+    slapi_log_error(SLAPI_LOG_TRACE, USN_PLUGIN_SUBSYSTEM,
+                    "<-- usn_rootdse_search\n");
+    return SLAPI_DSE_CALLBACK_OK;
+}
diff --git a/ldap/servers/plugins/usn/usn.h b/ldap/servers/plugins/usn/usn.h
new file mode 100644
index 0000000..cf0cd18
--- /dev/null
+++ b/ldap/servers/plugins/usn/usn.h
@@ -0,0 +1,57 @@
+/** BEGIN COPYRIGHT BLOCK
+ * This Program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; version 2 of the License.
+ *
+ * This Program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * In addition, as a special exception, Red Hat, Inc. gives You the additional
+ * right to link the code of this Program with code not covered under the GNU
+ * General Public License ("Non-GPL Code") and to distribute linked combinations
+ * including the two, subject to the limitations in this paragraph. Non-GPL Code
+ * permitted under this exception must only link to the code of this Program
+ * through those well defined interfaces identified in the file named EXCEPTION
+ * found in the source code files (the "Approved Interfaces"). The files of
+ * Non-GPL Code may instantiate templates or use macros or inline functions from
+ * the Approved Interfaces without causing the resulting work to be covered by
+ * the GNU General Public License. Only Red Hat, Inc. may make changes or
+ * additions to the list of Approved Interfaces. You must obey the GNU General
+ * Public License in all respects for all of the Program code and other code used
+ * in conjunction with the Program except the Non-GPL Code covered by this
+ * exception. If you modify this file, you may extend this exception to your
+ * version of the file, but you are not obligated to do so. If you do not wish to
+ * provide this exception without modification, you must delete this exception
+ * statement from your version and license this file solely under the GPL without
+ * exception.
+ *
+ *
+ * Copyright (C) 2009 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include <string.h>
+#include "slap.h"
+#include "slapi-plugin.h"
+
+#define USN_PLUGIN_SUBSYSTEM      "usn-plugin"
+
+#define USN_CSNGEN_ID              65535
+
+#define USN_LAST_USN               "lastusn"
+#define USN_LAST_USN_ATTR_CORE_LEN 8 /* lastusn; */
+
+#define USN_COUNTER_BUF_LEN        32 /* enough size for 64 bit inteters */
+
+/* usn.c */
+void usn_set_identity(void *identity);
+void *usn_get_identity();
+
+/* usn_cleanup.c */
+int usn_cleanup_start(Slapi_PBlock *pb);
+
diff --git a/ldap/servers/plugins/usn/usn_cleanup.c b/ldap/servers/plugins/usn/usn_cleanup.c
new file mode 100644
index 0000000..c513629
--- /dev/null
+++ b/ldap/servers/plugins/usn/usn_cleanup.c
@@ -0,0 +1,326 @@
+/** BEGIN COPYRIGHT BLOCK
+ * This Program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; version 2 of the License.
+ *
+ * This Program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * In addition, as a special exception, Red Hat, Inc. gives You the additional
+ * right to link the code of this Program with code not covered under the GNU
+ * General Public License ("Non-GPL Code") and to distribute linked combinations
+ * including the two, subject to the limitations in this paragraph. Non-GPL Code
+ * permitted under this exception must only link to the code of this Program
+ * through those well defined interfaces identified in the file named EXCEPTION
+ * found in the source code files (the "Approved Interfaces"). The files of
+ * Non-GPL Code may instantiate templates or use macros or inline functions from
+ * the Approved Interfaces without causing the resulting work to be covered by
+ * the GNU General Public License. Only Red Hat, Inc. may make changes or
+ * additions to the list of Approved Interfaces. You must obey the GNU General
+ * Public License in all respects for all of the Program code and other code used
+ * in conjunction with the Program except the Non-GPL Code covered by this
+ * exception. If you modify this file, you may extend this exception to your
+ * version of the file, but you are not obligated to do so. If you do not wish to
+ * provide this exception without modification, you must delete this exception
+ * statement from your version and license this file solely under the GPL without
+ * exception.
+ *
+ *
+ * Copyright (C) 2009 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "usn.h"
+
+struct usn_cleanup_data {
+    char *suffix;
+    char *maxusn_to_delete;
+};
+
+
+static int usn_cleanup_add(Slapi_PBlock *pb, Slapi_Entry *e,
+            Slapi_Entry *eAfter, int *returncode, char *returntext, void *arg);
+
+int
+usn_cleanup_start(Slapi_PBlock *pb)
+{
+    int rc = slapi_task_register_handler("USN tombstone cleanup task",
+                                         usn_cleanup_add);
+    return rc;
+}
+
+/*
+ * Task thread
+ */
+static void
+usn_cleanup_thread(void *arg)
+{
+    Slapi_Task *task = (Slapi_Task *)arg;
+    int rv = 0;
+    int total_work = 2;
+    /* fetch our argument from the task */
+    struct usn_cleanup_data *cleanup_data =
+            (struct usn_cleanup_data*)slapi_task_get_data(task);
+    Slapi_PBlock *search_pb = NULL;
+    Slapi_Entry **entries = NULL, **ep = NULL;
+    Slapi_PBlock *delete_pb = NULL;
+    char *filter = "objectclass=nsTombstone";
+
+    slapi_log_error(SLAPI_LOG_TRACE, USN_PLUGIN_SUBSYSTEM,
+                    "--> usn_cleanup_thread\n");
+
+    if (NULL == usn_get_identity()) { /* plugin is not initialized */
+        slapi_task_log_notice(task, "USN plugin is not initialized\n");
+        slapi_log_error(SLAPI_LOG_FATAL, USN_PLUGIN_SUBSYSTEM,
+                      "USN tombstone cleanup: USN plugin is not initialized\n");
+        rv = -1;
+        goto bail;
+    }
+
+    /* update task state to show it's running */
+    slapi_task_begin(task, total_work);
+    if (cleanup_data->maxusn_to_delete) {
+        /* (&(objectclass=nsTombstone)(entryusn<=maxusn_to_delete)) */
+        int filter_len =
+                strlen(filter) + strlen(cleanup_data->maxusn_to_delete) + 32;
+        filter = (char *)slapi_ch_malloc(filter_len);
+        PR_snprintf(filter, filter_len,
+                    "(&(objectclass=nsTombstone)(entryusn<=%s))",
+                    cleanup_data->maxusn_to_delete);
+    }
+
+    search_pb = slapi_pblock_new();
+    slapi_search_internal_set_pb(search_pb, cleanup_data->suffix,
+            LDAP_SCOPE_SUBTREE, filter,
+            NULL, 0, NULL, NULL, usn_get_identity(), 0);
+    slapi_search_internal_pb(search_pb);
+    slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &rv);
+    if (LDAP_NO_SUCH_OBJECT == rv) {
+        slapi_task_log_notice(task,
+                    "USN tombstone cleanup: no such suffix %s.\n",
+                    cleanup_data->suffix);
+        slapi_task_log_status(task,
+                    "USN tombstone cleanup: no such suffix %s.\n",
+                    cleanup_data->suffix);
+        slapi_log_error(SLAPI_LOG_FATAL, USN_PLUGIN_SUBSYSTEM,
+                    "USN tombstone cleanup: no such suffix %s.\n",
+                    cleanup_data->suffix);
+        goto bail;
+    } else if (LDAP_SUCCESS != rv) {
+        slapi_task_log_notice(task,
+                    "USN tombstone cleanup: searching tombstone entries "
+                    "in %s failed; (%d).\n", cleanup_data->suffix, rv);
+        slapi_task_log_status(task,
+                    "USN tombstone cleanup: searching tombstone entries in "
+                    "%s failed; (%d).\n", cleanup_data->suffix, rv);
+        slapi_log_error(SLAPI_LOG_FATAL, USN_PLUGIN_SUBSYSTEM,
+                    "USN tombstone cleanup: searching tombstone entries in "
+                    "%s failed; (%d).\n", cleanup_data->suffix, rv);
+        goto bail;
+    }
+
+    slapi_task_log_notice(task,
+            "USN tombstone cleanup task starts (suffix: %s) ...\n", 
+            cleanup_data->suffix);
+    slapi_log_error(SLAPI_LOG_FATAL, USN_PLUGIN_SUBSYSTEM,
+            "USN tombstone cleanup task starts (suffix: %s) ...\n", 
+            cleanup_data->suffix);
+
+    slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+
+    delete_pb = slapi_pblock_new();
+    for (ep = entries; ep && *ep; ep++) {
+        int delrv = 0;
+        const Slapi_DN *sdn = slapi_entry_get_sdn_const(*ep);
+
+        slapi_delete_internal_set_pb(delete_pb, slapi_sdn_get_dn(sdn),
+                                     NULL, NULL, usn_get_identity(), 0);
+        slapi_delete_internal_pb(delete_pb);
+        slapi_pblock_get(delete_pb, SLAPI_PLUGIN_INTOP_RESULT, &delrv);
+        if (LDAP_SUCCESS != delrv) {
+            slapi_task_log_notice(task,
+                    "USN tombstone cleanup: deleteing %s failed; (%d).\n",
+                    slapi_sdn_get_dn(sdn), delrv);
+            slapi_task_log_status(task,
+                    "USN tombstone cleanup: deleteing %s failed; (%d).\n",
+                    slapi_sdn_get_dn(sdn), delrv);
+            slapi_log_error(SLAPI_LOG_FATAL, USN_PLUGIN_SUBSYSTEM,
+                    "USN tombstone cleanup: deleteing %s failed; (%d).\n",
+                    slapi_sdn_get_dn(sdn), delrv);
+            rv = delrv;
+        }
+
+        slapi_pblock_init(delete_pb);
+        slapi_task_inc_progress(task);
+    }
+    slapi_task_log_notice(task, "USN tombstone cleanup task finished.");
+    slapi_task_log_status(task, "USN tombstone cleanup task finished.");
+    slapi_log_error(SLAPI_LOG_FATAL, USN_PLUGIN_SUBSYSTEM,
+                    "USN tombstone cleanup task finished.\n");
+bail:
+    slapi_free_search_results_internal(search_pb);
+    slapi_pblock_destroy(search_pb);
+    slapi_pblock_destroy(delete_pb);
+    if (cleanup_data->maxusn_to_delete) {
+        slapi_ch_free_string(&filter);
+    }
+    slapi_ch_free_string(&cleanup_data->maxusn_to_delete);
+    slapi_ch_free_string(&cleanup_data->suffix);
+    slapi_ch_free((void **)&cleanup_data);
+
+    /* this will queue the destruction of the task */
+    slapi_task_finish(task, rv);
+
+    slapi_log_error(SLAPI_LOG_TRACE, USN_PLUGIN_SUBSYSTEM,
+                    "<-- usn_cleanup_thread\n");
+}
+
+#define MAPPING_TREE_BASE_DN "cn=mapping tree,cn=config"
+
+static int
+_usn_cleanup_is_mmr_enabled(const char *suffix)
+{
+    Slapi_PBlock *search_pb = NULL;
+    Slapi_Entry **entries = NULL;
+    char *base_dn = NULL;
+    int rc = 0; /* disabled, by default */
+
+    base_dn = slapi_ch_smprintf("cn=replica,cn=\"%s\",%s",
+                                suffix, MAPPING_TREE_BASE_DN);
+    search_pb = slapi_pblock_new();
+    slapi_search_internal_set_pb(search_pb, base_dn, LDAP_SCOPE_ONELEVEL,
+                                 "objectclass=nsDS5ReplicationAgreement",
+                                 NULL, 0, NULL, NULL, usn_get_identity(), 0);
+    slapi_search_internal_pb(search_pb);
+    slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+    if (LDAP_SUCCESS != rc) { /* agreement is not available */
+        goto bail;
+    }
+    slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+    if (entries && *entries) {
+        rc = 1; /* At least one agreement on the suffix is found */
+    }
+bail:
+    slapi_free_search_results_internal(search_pb);
+    slapi_pblock_destroy(search_pb);
+    slapi_ch_free_string(&base_dn);
+
+    return rc;
+}
+
+static int
+usn_cleanup_add(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter,
+                int *returncode, char *returntext, void *arg)
+{
+    PRThread *thread = NULL;
+    char *cn = NULL;
+    char *suffix = NULL;
+    char *backend = NULL;
+    char *maxusn = NULL;
+    struct usn_cleanup_data *cleanup_data = NULL;
+    int rv = SLAPI_DSE_CALLBACK_OK;
+    Slapi_Task *task = NULL;
+    Slapi_Backend *be = NULL;
+    const Slapi_DN *be_suffix = NULL;
+
+    slapi_log_error(SLAPI_LOG_TRACE, USN_PLUGIN_SUBSYSTEM,
+                    "--> usn_cleanup_add\n");
+
+    *returncode = LDAP_SUCCESS;
+    cn = slapi_entry_attr_get_charptr(e, "cn");
+    if (NULL == cn) {
+        *returncode = LDAP_OBJECT_CLASS_VIOLATION;
+        rv = SLAPI_DSE_CALLBACK_ERROR;
+        goto bail;
+    }
+
+    /* get args */
+    suffix = slapi_entry_attr_get_charptr(e, "suffix");
+    backend = slapi_entry_attr_get_charptr(e, "backend");
+    maxusn = slapi_entry_attr_get_charptr(e, "maxusn_to_delete");
+
+    if (NULL == suffix && NULL == backend) {
+        slapi_log_error(SLAPI_LOG_FATAL, USN_PLUGIN_SUBSYSTEM,
+            "USN tombstone cleanup: Both suffix and backend are missing.\n");
+        *returncode = LDAP_PARAM_ERROR;
+        rv = SLAPI_DSE_CALLBACK_ERROR;
+        goto bail;
+    }
+
+    /* suffix is not given, but backend is; get the suffix */
+    if (NULL == suffix && NULL != backend) {
+        be = slapi_be_select_by_instance_name(backend);
+        be_suffix = slapi_be_getsuffix(be, 0);
+        if (be_suffix) {
+            suffix = slapi_ch_strdup(slapi_sdn_get_ndn(be_suffix));
+        } else {
+            slapi_log_error(SLAPI_LOG_FATAL, USN_PLUGIN_SUBSYSTEM,
+                "USN tombstone cleanup: Backend %s is invalid.\n", backend);
+            *returncode = LDAP_PARAM_ERROR;
+            rv = SLAPI_DSE_CALLBACK_ERROR;
+            goto bail;
+        }
+    }
+
+    /* The suffix is the target of replication, 
+     * we don't want to clean up tombstones used by MMR */
+    if (_usn_cleanup_is_mmr_enabled(suffix)) {
+        slapi_log_error(SLAPI_LOG_FATAL, USN_PLUGIN_SUBSYSTEM,
+            "USN tombstone cleanup: Suffix %s is replicated. Unwilling to "
+            "perform cleaning up tombstones.\n", suffix);
+        *returncode = LDAP_UNWILLING_TO_PERFORM;
+        rv = SLAPI_DSE_CALLBACK_ERROR;
+        goto bail;
+    }
+
+    cleanup_data =
+      (struct usn_cleanup_data *)slapi_ch_malloc(sizeof(struct usn_cleanup_data));
+    cleanup_data->suffix = slapi_ch_strdup(suffix);
+    cleanup_data->maxusn_to_delete = slapi_ch_strdup(maxusn);
+
+    /* allocate new task now */
+    task = slapi_new_task(slapi_entry_get_ndn(e));
+    if (task == NULL) {
+        slapi_log_error(SLAPI_LOG_FATAL, USN_PLUGIN_SUBSYSTEM,
+            "USN tombstone cleanup: unable to allocate new task.\n");
+        *returncode = LDAP_OPERATIONS_ERROR;
+        rv = SLAPI_DSE_CALLBACK_ERROR;
+        goto bail;
+    }
+
+    /* Stash our argument in the task for use by the task thread */
+    slapi_task_set_data(task, cleanup_data);
+
+    /* start the USN tombstone cleanup task as a separate thread */
+    thread = PR_CreateThread(PR_USER_THREAD, usn_cleanup_thread,
+                          (void *)task, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+                          PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE);
+    if (thread == NULL) {
+        slapi_log_error(SLAPI_LOG_FATAL, USN_PLUGIN_SUBSYSTEM,
+                "USN tombstone cleanup: unable to create task thread.\n");
+        *returncode = LDAP_OPERATIONS_ERROR;
+        rv = SLAPI_DSE_CALLBACK_ERROR;
+        slapi_task_finish(task, *returncode);
+    } else {
+        /* thread successful */
+        rv = SLAPI_DSE_CALLBACK_OK;
+    }
+bail:
+    slapi_ch_free_string(&cn);
+    slapi_ch_free_string(&suffix);
+    slapi_ch_free_string(&backend);
+    slapi_ch_free_string(&maxusn);
+    slapi_log_error(SLAPI_LOG_TRACE, USN_PLUGIN_SUBSYSTEM,
+                    "<-- usn_cleanup_add\n");
+    return rv;
+}
+
diff --git a/ldap/servers/slapd/back-ldbm/back-ldbm.h b/ldap/servers/slapd/back-ldbm/back-ldbm.h
index 1b6dda5..3036bf7 100644
--- a/ldap/servers/slapd/back-ldbm/back-ldbm.h
+++ b/ldap/servers/slapd/back-ldbm/back-ldbm.h
@@ -739,6 +739,7 @@ typedef struct _back_search_result_set
 #define LDBM_DNCOMP_OID				"2.16.840.1.113730.3.1.603"
 #define LDBM_PARENTID_OID			"2.16.840.1.113730.3.1.604"
 #define LDBM_ENTRYID_OID			"2.16.840.1.113730.3.1.605"
+#define LDBM_ENTRYUSN_OID			"2.16.840.1.113730.3.1.606"
 
 /* Name of psuedo attribute used to track default indexes */
 #define LDBM_PSEUDO_ATTR_DEFAULT	".default"
diff --git a/ldap/servers/slapd/back-ldbm/import.c b/ldap/servers/slapd/back-ldbm/import.c
index 57c208a..48e19c8 100644
--- a/ldap/servers/slapd/back-ldbm/import.c
+++ b/ldap/servers/slapd/back-ldbm/import.c
@@ -1052,6 +1052,9 @@ static int import_all_done(ImportJob *job, int ret)
         if (ret != 0)
             return ret;
 
+        /* Reset USN slapi_counter with the last key of the entryUSN index */
+        ldbm_set_last_usn(inst->inst_be);
+
         /* bring backend online again */
         slapi_mtn_be_enable(inst->inst_be);
     }
diff --git a/ldap/servers/slapd/back-ldbm/init.c b/ldap/servers/slapd/back-ldbm/init.c
index c32f982..a4ff79c 100644
--- a/ldap/servers/slapd/back-ldbm/init.c
+++ b/ldap/servers/slapd/back-ldbm/init.c
@@ -84,6 +84,10 @@ ldbm_back_add_schema( Slapi_PBlock *pb )
 			LDBM_ENTRYID_OID, DIRSTRING_SYNTAX_OID, CASEIGNOREMATCH_NAME,
 			SLAPI_ATTR_FLAG_SINGLE );
 
+	rc |= add_ldbm_internal_attr_syntax( "entryusn",
+			LDBM_ENTRYUSN_OID, INTEGER_SYNTAX_OID, INTFIRSTCOMPMATCH_NAME,
+			SLAPI_ATTR_FLAG_SINGLE );
+
 	return rc;
 }
 
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_add.c b/ldap/servers/slapd/back-ldbm/ldbm_add.c
index b9f573a..fa53e05 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_add.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_add.c
@@ -159,6 +159,7 @@ ldbm_back_add( Slapi_PBlock *pb )
 		operation->o_status = SLAPI_OP_STATUS_WILL_COMPLETE;
 	}
 	if ( slapi_op_abandoned( pb ) ) {
+		ldap_result_code = -1; /* needs to distinguish from "success" */
 		goto error_return;
 	}
 
@@ -847,6 +848,8 @@ common_return:
 	{
 		cache_return( &inst->inst_cache, &addingentry );
 	}
+	/* bepost op needs to know this result */
+	slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ldap_result_code);
 	/* JCMREPL - The bepostop is called even if the operation fails. */
 	plugin_call_plugins (pb, SLAPI_PLUGIN_BE_POST_ADD_FN);
 
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_delete.c b/ldap/servers/slapd/back-ldbm/ldbm_delete.c
index fe02b20..74d8de8 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_delete.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_delete.c
@@ -82,6 +82,9 @@ ldbm_back_delete( Slapi_PBlock *pb )
 	int tombstone_in_cache = 0;
 	entry_address *addr;
 	int addordel_flags = 0; /* passed to index_addordel */
+	char *entryusn_str = NULL;
+	char *prev_entryusn_str = NULL;
+	Slapi_Entry *orig_entry = NULL;
 
 	slapi_pblock_get( pb, SLAPI_BACKEND, &be);
 	slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
@@ -133,6 +136,23 @@ ldbm_back_delete( Slapi_PBlock *pb )
 		goto error_return;
 	}
 
+	/* find and lock the entry we are about to modify */
+	if ( (e = find_entry2modify( pb, be, addr, NULL )) == NULL )
+	{
+    	ldap_result_code= -1; 
+		goto error_return; /* error result sent by find_entry2modify() */
+	}
+
+	if ( slapi_entry_has_children( e->ep_entry ) )
+	{
+		ldap_result_code= LDAP_NOT_ALLOWED_ON_NONLEAF;
+		goto error_return;
+	}
+
+	/* set entry in case be-preop plugins need to work on it (e.g., USN) */
+	slapi_pblock_get( pb, SLAPI_DELETE_BEPREOP_ENTRY, &orig_entry );
+	slapi_pblock_set( pb, SLAPI_DELETE_BEPREOP_ENTRY, e->ep_entry );
+
 	/* Don't call pre-op for Tombstone entries */
 	if (!delete_tombstone_entry)
 	{
@@ -141,7 +161,8 @@ ldbm_back_delete( Slapi_PBlock *pb )
 		 * backend pre-op plugin. To ensure a consistent snapshot of this state
 		 * we wrap the reading of the entry with the dblock.
 		 */
-		ldap_result_code= get_copy_of_entry(pb, addr, &txn, SLAPI_DELETE_EXISTING_ENTRY, !is_replicated_operation);
+		ldap_result_code= get_copy_of_entry(pb, addr, &txn,
+						SLAPI_DELETE_EXISTING_ENTRY, !is_replicated_operation);
 		slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ldap_result_code);
 		if(plugin_call_plugins(pb, SLAPI_PLUGIN_BE_PRE_DELETE_FN)==-1)
 		{
@@ -152,21 +173,12 @@ ldbm_back_delete( Slapi_PBlock *pb )
 			slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code);
 			goto error_return;
 		}
-	}
-	
-
-	/* find and lock the entry we are about to modify */
-	if ( (e = find_entry2modify( pb, be, addr, NULL )) == NULL )
-	{
-    	ldap_result_code= -1; 
-		goto error_return; /* error result sent by find_entry2modify() */
+		/* the flag could be set in a preop plugin (e.g., USN) */
+		delete_tombstone_entry = operation_is_flag_set(operation,
+									OP_FLAG_TOMBSTONE_ENTRY);
 	}
 
-	if ( slapi_entry_has_children( e->ep_entry ) )
-	{
-		ldap_result_code= LDAP_NOT_ALLOWED_ON_NONLEAF;
-		goto error_return;
-	}
+	slapi_pblock_set( pb, SLAPI_DELETE_BEPREOP_ENTRY, orig_entry );
 
 	/*
 	 * Sanity check to avoid to delete a non-tombstone or to tombstone again
@@ -196,8 +208,12 @@ ldbm_back_delete( Slapi_PBlock *pb )
 	opcsn = operation_get_csn (operation);
 	if (!delete_tombstone_entry)
 	{
-		if (opcsn == NULL && !is_fixup_operation && operation->o_csngen_handler)
+		/* If both USN and replication is enabled, csn set by replication 
+		 * should be honored. */
+		if ((opcsn == NULL || ldbm_usn_enabled(be)) &&
+						!is_fixup_operation && operation->o_csngen_handler)
 		{
+			csn_free(&opcsn); /* free opcsn set by USN plugin, if any */
 			/*
 			 * Current op is a user request. Opcsn will be assigned
 			 * by entry_assign_operation_csn() if the dn is in an
@@ -338,6 +354,20 @@ ldbm_back_delete( Slapi_PBlock *pb )
 		slapi_entry_add_value(tombstone->ep_entry, SLAPI_ATTR_OBJECTCLASS, tomb_value);
 		slapi_value_free(&tomb_value);
 		
+		/* retrieve previous entry usn value, if any */
+		prev_entryusn_str = slapi_entry_attr_get_charptr(tombstone->ep_entry,
+												SLAPI_ATTR_ENTRYUSN_PREV);
+		if (prev_entryusn_str) {
+			/* discard the previous value from the tombstone entry */
+		    retval = slapi_entry_delete_string(tombstone->ep_entry,
+							SLAPI_ATTR_ENTRYUSN_PREV, prev_entryusn_str);
+			if (0 != retval) {
+				LDAPDebug( LDAP_DEBUG_TRACE,
+							"delete (deleting %s) failed, err=%d\n",
+							SLAPI_ATTR_ENTRYUSN, retval, 0) ;
+			}
+		}
+
 		/* XXXggood above used to be: slapi_entry_add_string(tombstone->ep_entry, SLAPI_ATTR_OBJECTCLASS, SLAPI_ATTR_VALUE_TOMBSTONE); */
 		/* JCMREPL - Add a description of what's going on? */
 	}
@@ -432,45 +462,110 @@ ldbm_back_delete( Slapi_PBlock *pb )
 			 * above, but we want it to remain in the nsUniqueID and nscpEntryDN indexes
 			 * and for objectclass=tombstone.
 			 */
-			retval = index_addordel_string(be,SLAPI_ATTR_OBJECTCLASS,SLAPI_ATTR_VALUE_TOMBSTONE,tombstone->ep_id,BE_INDEX_ADD,&txn);
+			retval = index_addordel_string(be, SLAPI_ATTR_OBJECTCLASS, 
+							SLAPI_ATTR_VALUE_TOMBSTONE,
+							tombstone->ep_id,BE_INDEX_ADD, &txn);
 			if (DB_LOCK_DEADLOCK == retval) {
-				LDAPDebug( LDAP_DEBUG_ARGS, "delete 4 DB_LOCK_DEADLOCK\n", 0, 0, 0 );
+				LDAPDebug( LDAP_DEBUG_ARGS,
+							"delete (adding %s) DB_LOCK_DEADLOCK\n",
+							SLAPI_ATTR_VALUE_TOMBSTONE, 0, 0 );
 				/* Retry txn */
 				continue;
 			}
 			if (0 != retval) {
-				LDAPDebug( LDAP_DEBUG_TRACE, "delete 1 BAD, err=%d %s\n",
-					   retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
+				LDAPDebug( LDAP_DEBUG_TRACE,
+							"delete (adding %s) failed, err=%d %s\n",
+							SLAPI_ATTR_VALUE_TOMBSTONE, retval,
+							(msg = dblayer_strerror( retval )) ? msg : "" );
 				if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
-    			ldap_result_code= LDAP_OPERATIONS_ERROR;
+				ldap_result_code= LDAP_OPERATIONS_ERROR;
 				goto error_return;
 			}
-			retval = index_addordel_string(be,SLAPI_ATTR_UNIQUEID,slapi_entry_get_uniqueid(tombstone->ep_entry),tombstone->ep_id,BE_INDEX_ADD,&txn);
+			retval = index_addordel_string(be, SLAPI_ATTR_UNIQUEID,
+							slapi_entry_get_uniqueid(tombstone->ep_entry),
+							tombstone->ep_id,BE_INDEX_ADD,&txn);
 			if (DB_LOCK_DEADLOCK == retval) {
-				LDAPDebug( LDAP_DEBUG_ARGS, "delete 5 DB_LOCK_DEADLOCK\n", 0, 0, 0 );
+				LDAPDebug( LDAP_DEBUG_ARGS,
+							"delete (adding %s) DB_LOCK_DEADLOCK\n",
+							SLAPI_ATTR_UNIQUEID, 0, 0 );
 				/* Retry txn */
 				continue;
 			}
 			if (0 != retval) {
-				LDAPDebug( LDAP_DEBUG_TRACE, "delete 2 BAD, err=%d %s\n",
-					   retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
+				LDAPDebug( LDAP_DEBUG_TRACE,
+							"delete (adding %s) failed, err=%d %s\n",
+							SLAPI_ATTR_UNIQUEID, retval,
+							(msg = dblayer_strerror( retval )) ? msg : "" );
 				if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
-    			ldap_result_code= LDAP_OPERATIONS_ERROR;
+				ldap_result_code= LDAP_OPERATIONS_ERROR;
 				goto error_return;
 			}
-			retval = index_addordel_string(be,SLAPI_ATTR_NSCP_ENTRYDN, slapi_sdn_get_ndn(nscpEntrySDN),tombstone->ep_id,BE_INDEX_ADD,&txn);
+			retval = index_addordel_string(be, SLAPI_ATTR_NSCP_ENTRYDN,
+							slapi_sdn_get_ndn(nscpEntrySDN),
+							tombstone->ep_id, BE_INDEX_ADD, &txn);
 			if (DB_LOCK_DEADLOCK == retval) {
-				LDAPDebug( LDAP_DEBUG_ARGS, "delete 6 DB_LOCK_DEADLOCK\n", 0, 0, 0 );
+				LDAPDebug( LDAP_DEBUG_ARGS,
+							"delete (adding %s) DB_LOCK_DEADLOCK\n",
+							SLAPI_ATTR_NSCP_ENTRYDN, 0, 0 );
 				/* Retry txn */
 				continue;
 			}
 			if (0 != retval) {
-				LDAPDebug( LDAP_DEBUG_TRACE, "delete 3 BAD, err=%d %s\n",
-					   retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
+				LDAPDebug( LDAP_DEBUG_TRACE, 
+							"delete (adding %s) failed, err=%d %s\n",
+							SLAPI_ATTR_NSCP_ENTRYDN, retval,
+							(msg = dblayer_strerror( retval )) ? msg : "" );
 				if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
-    			ldap_result_code= LDAP_OPERATIONS_ERROR;
+				ldap_result_code= LDAP_OPERATIONS_ERROR;
 				goto error_return;
 			}
+			/* add a new usn to the entryusn index */
+			entryusn_str = slapi_entry_attr_get_charptr(tombstone->ep_entry,
+												SLAPI_ATTR_ENTRYUSN);
+			if (entryusn_str) {
+				retval = index_addordel_string(be, SLAPI_ATTR_ENTRYUSN,
+							entryusn_str, tombstone->ep_id, BE_INDEX_ADD, &txn);
+				slapi_ch_free_string(&entryusn_str);
+				if (DB_LOCK_DEADLOCK == retval) {
+					LDAPDebug( LDAP_DEBUG_ARGS,
+								"delete (adding %s) DB_LOCK_DEADLOCK\n",
+								SLAPI_ATTR_ENTRYUSN, 0, 0 );
+					/* Retry txn */
+					continue;
+				}
+				if (0 != retval) {
+					LDAPDebug( LDAP_DEBUG_TRACE, 
+								"delete (adding %s) failed, err=%d %s\n",
+								SLAPI_ATTR_ENTRYUSN, retval,
+								(msg = dblayer_strerror( retval )) ? msg : "" );
+					if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
+					ldap_result_code= LDAP_OPERATIONS_ERROR;
+					goto error_return;
+				}
+			}
+			/* delete a previous value (if it exists) from the entryusn index */
+			if (prev_entryusn_str) {
+				retval = index_addordel_string(be, SLAPI_ATTR_ENTRYUSN,
+								prev_entryusn_str, tombstone->ep_id,
+								BE_INDEX_DEL|BE_INDEX_EQUALITY, &txn);
+				slapi_ch_free_string(&prev_entryusn_str);
+				if (DB_LOCK_DEADLOCK == retval) {
+					LDAPDebug( LDAP_DEBUG_ARGS,
+								"delete (deleting %s) DB_LOCK_DEADLOCK\n",
+								SLAPI_ATTR_ENTRYUSN, 0, 0 );
+					/* Retry txn */
+					continue;
+				}
+				if (0 != retval) {
+					LDAPDebug( LDAP_DEBUG_TRACE, 
+								"delete (deleting %s) failed, err=%d %s\n",
+								SLAPI_ATTR_ENTRYUSN, retval,
+								(msg = dblayer_strerror( retval )) ? msg : "" );
+					if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
+					ldap_result_code= LDAP_OPERATIONS_ERROR;
+					goto error_return;
+				}
+			}
 		} /* create_tombstone_entry */
 		else if (delete_tombstone_entry)
 		{
@@ -480,45 +575,88 @@ ldbm_back_delete( Slapi_PBlock *pb )
 			 */
 			char *nscpedn = NULL;
 
-			retval = index_addordel_string(be,SLAPI_ATTR_OBJECTCLASS,SLAPI_ATTR_VALUE_TOMBSTONE,e->ep_id,BE_INDEX_DEL,&txn);
+			retval = index_addordel_string(be, SLAPI_ATTR_OBJECTCLASS,
+							SLAPI_ATTR_VALUE_TOMBSTONE, e->ep_id,
+							BE_INDEX_DEL, &txn);
 			if (DB_LOCK_DEADLOCK == retval) {
-				LDAPDebug( LDAP_DEBUG_ARGS, "delete 4 DB_LOCK_DEADLOCK\n", 0, 0, 0 );
+				LDAPDebug( LDAP_DEBUG_ARGS,
+							"delete (deleting %s) DB_LOCK_DEADLOCK\n",
+							SLAPI_ATTR_VALUE_TOMBSTONE, 0, 0 );
 				/* Retry txn */
 				continue;
 			}
 			if (0 != retval) {
-				LDAPDebug( LDAP_DEBUG_TRACE, "delete 1 BAD, err=%d %s\n",
-					   retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
+				LDAPDebug( LDAP_DEBUG_TRACE,
+							"delete (deleting %s) failed, err=%d %s\n",
+							SLAPI_ATTR_VALUE_TOMBSTONE, retval,
+							(msg = dblayer_strerror( retval )) ? msg : "" );
 				if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
-    			ldap_result_code= LDAP_OPERATIONS_ERROR;
+				ldap_result_code= LDAP_OPERATIONS_ERROR;
 				goto error_return;
 			}
-			retval = index_addordel_string(be,SLAPI_ATTR_UNIQUEID,slapi_entry_get_uniqueid(e->ep_entry),e->ep_id,BE_INDEX_DEL,&txn);
+			retval = index_addordel_string(be, SLAPI_ATTR_UNIQUEID,
+							slapi_entry_get_uniqueid(e->ep_entry),
+							e->ep_id, BE_INDEX_DEL, &txn);
 			if (DB_LOCK_DEADLOCK == retval) {
-				LDAPDebug( LDAP_DEBUG_ARGS, "delete 5 DB_LOCK_DEADLOCK\n", 0, 0, 0 );
+				LDAPDebug( LDAP_DEBUG_ARGS,
+							"delete (deleting %s) DB_LOCK_DEADLOCK\n",
+							SLAPI_ATTR_UNIQUEID, 0, 0 );
 				/* Retry txn */
 				continue;
 			}
 			if (0 != retval) {
-				LDAPDebug( LDAP_DEBUG_TRACE, "delete 2 BAD, err=%d %s\n",
-					   retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
+				LDAPDebug( LDAP_DEBUG_TRACE,
+							"delete (deleting %s) failed, err=%d %s\n",
+							SLAPI_ATTR_UNIQUEID, retval,
+							(msg = dblayer_strerror( retval )) ? msg : "" );
 				if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
-    			ldap_result_code= LDAP_OPERATIONS_ERROR;
+				ldap_result_code= LDAP_OPERATIONS_ERROR;
 				goto error_return;
 			}
 
-			nscpedn = slapi_entry_attr_get_charptr(e->ep_entry, SLAPI_ATTR_NSCP_ENTRYDN);
+			nscpedn = slapi_entry_attr_get_charptr(e->ep_entry,
+												SLAPI_ATTR_NSCP_ENTRYDN);
 			if (nscpedn) {
-				retval = index_addordel_string(be,SLAPI_ATTR_NSCP_ENTRYDN, nscpedn, e->ep_id,BE_INDEX_DEL,&txn);
+				retval = index_addordel_string(be, SLAPI_ATTR_NSCP_ENTRYDN,
+								nscpedn, e->ep_id, BE_INDEX_DEL, &txn);
 				slapi_ch_free((void **)&nscpedn);
 				if (DB_LOCK_DEADLOCK == retval) {
-					LDAPDebug( LDAP_DEBUG_ARGS, "delete 6 DB_LOCK_DEADLOCK\n", 0, 0, 0 );
+					LDAPDebug( LDAP_DEBUG_ARGS,
+								"delete (deleting %s) DB_LOCK_DEADLOCK\n",
+								SLAPI_ATTR_NSCP_ENTRYDN, 0, 0 );
+					/* Retry txn */
+					continue;
+				}
+				if (0 != retval) {
+					LDAPDebug( LDAP_DEBUG_TRACE,
+								"delete (deleting %s) failed, err=%d %s\n",
+								SLAPI_ATTR_NSCP_ENTRYDN, retval,
+								(msg = dblayer_strerror( retval )) ? msg : "" );
+					if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
+					ldap_result_code= LDAP_OPERATIONS_ERROR;
+					goto error_return;
+				}
+			}
+			/* delete usn from the entryusn index */
+			entryusn_str = slapi_entry_attr_get_charptr(e->ep_entry,
+												SLAPI_ATTR_ENTRYUSN);
+			if (entryusn_str) {
+				retval = index_addordel_string(be, SLAPI_ATTR_ENTRYUSN,
+							entryusn_str, e->ep_id,
+							BE_INDEX_DEL|BE_INDEX_EQUALITY, &txn);
+				slapi_ch_free_string(&entryusn_str);
+				if (DB_LOCK_DEADLOCK == retval) {
+					LDAPDebug( LDAP_DEBUG_ARGS,
+								"delete (deleting %s) DB_LOCK_DEADLOCK\n",
+								SLAPI_ATTR_ENTRYUSN, 0, 0 );
 					/* Retry txn */
 					continue;
 				}
 				if (0 != retval) {
-					LDAPDebug( LDAP_DEBUG_TRACE, "delete 3 BAD, err=%d %s\n",
-							   retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
+					LDAPDebug( LDAP_DEBUG_TRACE, 
+								"delete (deleting %s) failed, err=%d %s\n",
+								SLAPI_ATTR_ENTRYUSN, retval,
+								(msg = dblayer_strerror( retval )) ? msg : "" );
 					if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
 					ldap_result_code= LDAP_OPERATIONS_ERROR;
 					goto error_return;
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_instance_config.c b/ldap/servers/slapd/back-ldbm/ldbm_instance_config.c
index e8fc3d7..b4e4473 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_instance_config.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_instance_config.c
@@ -752,6 +752,12 @@ static int ldbm_instance_generate(struct ldbminfo *li, char *instance_name,
     ldbm_instance_config_load_dse_info(new_be->be_instance_info);
     rc = ldbm_instance_create_default_indexes(new_be);
 
+    /* if USN plugin is enabled, set slapi_counter */
+    if (plugin_enabled("USN", li->li_identity)) {
+        /* slapi_counter_new sets the initial value to 0 */
+        new_be->be_usn_counter = slapi_counter_new();
+    }
+
     if (ret_be != NULL) {
         *ret_be = new_be;
     }
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modify.c b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
index e85443d..6ae9544 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_modify.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
@@ -303,6 +303,7 @@ ldbm_back_modify( Slapi_PBlock *pb )
 		}
 		if ( !change_entry || ldap_result_code != 0 ) {
 			/* change_entry == 0 is not an error, but we need to free lock etc */
+			slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ldap_result_code);
 			goto error_return;
 		}
 	}
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_usn.c b/ldap/servers/slapd/back-ldbm/ldbm_usn.c
new file mode 100644
index 0000000..e8dd723
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/ldbm_usn.c
@@ -0,0 +1,196 @@
+/** BEGIN COPYRIGHT BLOCK
+ * This Program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; version 2 of the License.
+ *
+ * This Program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * In addition, as a special exception, Red Hat, Inc. gives You the additional
+ * right to link the code of this Program with code not covered under the GNU
+ * General Public License ("Non-GPL Code") and to distribute linked combinations
+ * including the two, subject to the limitations in this paragraph. Non-GPL Code
+ * permitted under this exception must only link to the code of this Program
+ * through those well defined interfaces identified in the file named EXCEPTION
+ * found in the source code files (the "Approved Interfaces"). The files of
+ * Non-GPL Code may instantiate templates or use macros or inline functions from
+ * the Approved Interfaces without causing the resulting work to be covered by
+ * the GNU General Public License. Only Red Hat, Inc. may make changes or
+ * additions to the list of Approved Interfaces. You must obey the GNU General
+ * Public License in all respects for all of the Program code and other code used
+ * in conjunction with the Program except the Non-GPL Code covered by this
+ * exception. If you modify this file, you may extend this exception to your
+ * version of the file, but you are not obligated to do so. If you do not wish to
+ * provide this exception without modification, you must delete this exception
+ * statement from your version and license this file solely under the GPL without
+ * exception.
+ *
+ *
+ * Copyright (C) 2009 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "back-ldbm.h"
+
+static int usn_get_last_usn(Slapi_Backend *be, PRUint64 *last_usn);
+
+/*
+ * USN counter part in the backend
+ * - If usn is enabled,
+ * -   For each backend,
+ * -     Get the last USN index key
+ * -     Initialize the slapi counter with the next USN (last USN + 1)
+ *
+ * dn: cn=entryusn,cn=default indexes,cn=config,cn=ldbm database,cn=plugins,cn=
+ *  config
+ * objectClass: top
+ * objectClass: nsIndex
+ * cn: entryusn
+ * nsSystemIndex: true
+ * nsIndexType: eq
+ */
+
+void
+ldbm_usn_init(struct ldbminfo  *li)
+{
+    Slapi_DN *sdn = NULL;
+    void *node = NULL;
+    const char *base = NULL;
+    int rc = 0;
+    Slapi_Backend *be = NULL;
+    PRUint64 last_usn = 0;
+
+    /* if USN is not enabled, return immediately */
+    if (!plugin_enabled("USN", li->li_identity)) {
+        goto bail;
+    }
+
+    /* Search each namingContext in turn */
+    for ( sdn = slapi_get_first_suffix( &node, 0 ); sdn != NULL;
+          sdn = slapi_get_next_suffix( &node, 0 )) {
+        base = slapi_sdn_get_dn( sdn );
+        be = slapi_mapping_tree_find_backend_for_sdn(sdn);
+        slapi_log_error(SLAPI_LOG_TRACE, "ldbm_usn_init",
+                        "backend: %s\n", be->be_name);
+        rc = usn_get_last_usn(be, &last_usn);
+        if (0 == rc) { /* only when the last usn is available */
+            be->be_usn_counter = slapi_counter_new();
+            slapi_counter_set_value(be->be_usn_counter, last_usn);
+            slapi_counter_increment(be->be_usn_counter); /* stores next usn */
+        }
+    }
+bail:
+    return;
+}
+
+/*
+ * usn_ge_last_usn: get the last USN from the entryusn equality index
+ */
+static int
+usn_get_last_usn(Slapi_Backend *be, PRUint64 *last_usn)
+{
+    struct attrinfo *ai = NULL;
+    struct ldbminfo *li = (struct ldbminfo *)be->be_database->plg_private;
+    int rc = -1;
+    DB *db = NULL;
+    DBC *dbc = NULL;
+    DBT key;              /* For the last usn */
+    DBT value;
+
+    if (NULL == last_usn) {
+        return rc;
+    }
+
+    memset(&key, 0, sizeof(key));
+    memset(&value, 0, sizeof(key));
+
+    *last_usn = -1; /* to start from 0 */
+
+    /* Open the entryusn index */
+    ainfo_get(be, "entryusn", &ai);
+
+    /* Open the entryusn index file */
+    rc = dblayer_get_index_file(be, ai, &db, DBOPEN_CREATE);
+    if (0 != rc) {
+        /* entryusn.db# is missing; it would be the first time. */
+        slapi_log_error(SLAPI_LOG_FATAL, "usn_get_last_usn", 
+                        "failed to open the entryusn index: %d", rc);
+        goto bail;
+    }
+
+    /* Get a cursor */
+    rc = db->cursor(db, NULL, &dbc, 0);
+    if (0 != rc) {
+        slapi_log_error(SLAPI_LOG_FATAL, "usn_get_last_usn", 
+                        "failed to create a cursor: %d", rc);
+        goto bail;
+    }
+    
+    key.flags = DB_DBT_MALLOC;
+    value.flags = DB_DBT_MALLOC;
+    rc = dbc->c_get(dbc, &key, &value, DB_LAST);
+    if ((0 == rc) && key.data) {
+        char *p = (char *)key.data;
+        while ((0 == rc) && ('=' != *p)) { /* get the last elem of equality */
+            slapi_ch_free(&(key.data));
+            slapi_ch_free(&(value.data));
+            rc = dbc->c_get(dbc, &key, &value, DB_PREV);
+            p = (char *)key.data;
+        }
+        if (0 == rc) {
+            *last_usn = strtoll(++p, (char **)NULL, 0); /* key.data: =num */
+        }
+    } else if (DB_NOTFOUND == rc) {
+        /* if empty, it's okay.  This is just a beginning. */
+        rc = 0;
+    }
+    slapi_ch_free(&(key.data));
+    slapi_ch_free(&(value.data));
+
+bail:
+    if (dbc) {
+        dbc->c_close(dbc);
+    }
+    if (db) {
+        dblayer_release_index_file(be, ai, db);
+    }
+    return rc;
+}
+
+/*
+ * Whether USN is enabled or not is checked with be_usn_counter.
+ */
+int
+ldbm_usn_enabled(Slapi_Backend *be)
+{
+    return (NULL != be->be_usn_counter);
+}
+
+/*
+ * set last usn to the USN slapi_counter in backend
+ */
+int
+ldbm_set_last_usn(Slapi_Backend *be)
+{
+    PRUint64 last_usn = 0;
+    int rc = usn_get_last_usn(be, &last_usn);
+
+    if (0 == rc) { /* only when the last usn is available */
+		/* destroy old counter, if any */
+        slapi_counter_destroy(&(be->be_usn_counter));
+        be->be_usn_counter = slapi_counter_new();
+        slapi_counter_set_value(be->be_usn_counter, last_usn);
+        slapi_counter_increment(be->be_usn_counter); /* stores next usn */
+    }
+
+    return rc;
+}
diff --git a/ldap/servers/slapd/back-ldbm/misc.c b/ldap/servers/slapd/back-ldbm/misc.c
index b4c7942..8fcb81f 100644
--- a/ldap/servers/slapd/back-ldbm/misc.c
+++ b/ldap/servers/slapd/back-ldbm/misc.c
@@ -94,17 +94,19 @@ int return_on_disk_full(struct ldbminfo  *li)
 /* System Indexes */
 
 static const char *systemIndexes[] = {
-    "entrydn",
-    "parentid",
-    "objectclass",
     "aci",
+    "entrydn",
     "numsubordinates",
+    "parentid",
+    SLAPI_ATTR_OBJECTCLASS,
     SLAPI_ATTR_UNIQUEID,
     SLAPI_ATTR_NSCP_ENTRYDN,
     ATTR_NSDS5_REPLCONFLICT,
+    SLAPI_ATTR_ENTRYUSN,
     NULL
 };
 
+
 int
 ldbm_attribute_always_indexed(const char *attrtype)
 {
diff --git a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
index 30d607e..3fc5832 100644
--- a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
+++ b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
@@ -632,3 +632,12 @@ int attrcrypt_encrypt_entry_inplace(backend *be, const struct backentry *inout);
 int attrcrypt_encrypt_entry(backend *be, const struct backentry *in, struct backentry **out);
 int attrcrypt_encrypt_index_key(backend *be, struct attrinfo	*ai, const struct berval	*in, struct berval **out);
 int attrcrypt_init(ldbm_instance *li);
+
+/*
+ * ldbm_usn.c
+ */
+void ldbm_usn_init(struct ldbminfo *li);
+int ldbm_usn_enabled(backend *be);
+int ldbm_set_last_usn(Slapi_Backend *be);
+
+
diff --git a/ldap/servers/slapd/back-ldbm/start.c b/ldap/servers/slapd/back-ldbm/start.c
index 9b517eb..6d83357 100644
--- a/ldap/servers/slapd/back-ldbm/start.c
+++ b/ldap/servers/slapd/back-ldbm/start.c
@@ -222,6 +222,9 @@ ldbm_back_start( Slapi_PBlock *pb )
     initialized = 1;
   }
 
+  /* initialize the USN counter */
+  ldbm_usn_init(li);
+
   LDAPDebug( LDAP_DEBUG_TRACE, "ldbm backend done starting\n", 0, 0, 0 );
 
   return( 0 );
diff --git a/ldap/servers/slapd/backend.c b/ldap/servers/slapd/backend.c
index c4c399f..740de29 100644
--- a/ldap/servers/slapd/backend.c
+++ b/ldap/servers/slapd/backend.c
@@ -64,7 +64,7 @@ be_init( Slapi_Backend *be, const char *type, const char *name, int isprivate, i
     /* maximum group nesting level before giving up */
     be->be_maxnestlevel = SLAPD_DEFAULT_GROUPNESTLEVEL;
     be->be_noacl= 0;
-        be->be_flags=0;
+    be->be_flags=0;
     if (( fecfg = getFrontendConfig()) != NULL )
     {
         if ( fecfg->backendconfig != NULL && fecfg->backendconfig[ 0 ] != NULL )
diff --git a/ldap/servers/slapd/main.c b/ldap/servers/slapd/main.c
index 7e59511..ed51825 100644
--- a/ldap/servers/slapd/main.c
+++ b/ldap/servers/slapd/main.c
@@ -2372,6 +2372,8 @@ slapd_exemode_db2ldif(int argc, char** argv)
 	}
 	slapi_ch_free( (void**)&myname );
     if (db2ldif_dump_replica) {
+        eq_stop();         /* event queue should be shutdown before closing
+                              all plugins (especailly, replication plugin) */
         plugin_closeall( 1 /* Close Backends */, 1 /* Close Globals */);
     }
     return( return_value );
diff --git a/ldap/servers/slapd/pblock.c b/ldap/servers/slapd/pblock.c
index 98984ad..e5751a9 100644
--- a/ldap/servers/slapd/pblock.c
+++ b/ldap/servers/slapd/pblock.c
@@ -1592,6 +1592,10 @@ slapi_pblock_get( Slapi_PBlock *pblock, int arg, void *value )
 		(*(IFP *)value) = pblock->pb_plugin->plg_entrystorefunc;
 		break;
 
+	case SLAPI_PLUGIN_ENABLED:
+		*((int *)value) =  pblock->pb_plugin_enabled;
+		break;
+
 	/* DSE add parameters */
 	case SLAPI_DSE_DONT_WRITE_WHEN_ADDING:
 		(*(int *)value) = pblock->pb_dse_dont_add_write;
@@ -2857,6 +2861,10 @@ slapi_pblock_set( Slapi_PBlock *pblock, int arg, void *value )
 			pblock->pb_plugin->plg_entrystorefunc = (IFP) value;
 		break;
 
+	case SLAPI_PLUGIN_ENABLED:
+		pblock->pb_plugin_enabled = *((int *)value);
+		break;
+
 	/* DSE add parameters */
 	case SLAPI_DSE_DONT_WRITE_WHEN_ADDING:
 		pblock->pb_dse_dont_add_write = *((int *)value);
diff --git a/ldap/servers/slapd/plugin.c b/ldap/servers/slapd/plugin.c
index 5ae6356..17730d5 100644
--- a/ldap/servers/slapd/plugin.c
+++ b/ldap/servers/slapd/plugin.c
@@ -2166,6 +2166,20 @@ plugin_setup(Slapi_Entry *plugin_entry, struct slapi_componentid *group,
 	configdir = config_get_configdir();
 	slapi_pblock_set(&pb, SLAPI_CONFIG_DIRECTORY, configdir);
 
+	/* see if the plugin is enabled or not */
+	if ((value = slapi_entry_attr_get_charptr(plugin_entry,
+											  ATTR_PLUGIN_ENABLED)) &&
+		!strcasecmp(value, "off"))
+	{
+		enabled = 0;
+	}
+	else
+	{
+		enabled = 1;
+	}
+
+	slapi_pblock_set(&pb, SLAPI_PLUGIN_ENABLED, &enabled);
+
 	if ((*initfunc)(&pb) != 0)
 	{
         LDAPDebug(LDAP_DEBUG_ANY, "Init function \"%s\" for \"%s\" plugin"
@@ -2193,18 +2207,6 @@ plugin_setup(Slapi_Entry *plugin_entry, struct slapi_componentid *group,
 		}
 	}
 
-	/* see if the plugin is enabled or not */
-	if ((value = slapi_entry_attr_get_charptr(plugin_entry,
-											  ATTR_PLUGIN_ENABLED)) &&
-		!strcasecmp(value, "off"))
-	{
-		enabled = 0;
-	}
-	else
-	{
-		enabled = 1;
-	}
-
 	if (value)
 		slapi_ch_free((void**)&value);
 
@@ -2859,3 +2861,45 @@ void plugin_print_versions(void)
 	}
 
 }
+
+/*
+ * check the spedified plugin entry and its nssladp-pluginEnabled value
+ * Return Value: 1 if the plugin is on.
+ *             : 0 otherwise.
+ */
+int
+plugin_enabled(const char *plugin_name, void *identity)
+{
+	Slapi_PBlock *search_pb = NULL;
+	Slapi_Entry **entries = NULL, **ep = NULL;
+	char *on_off = NULL;
+	char *filter = NULL;
+	int rc = 0;	/* disabled, by default */
+
+	filter = slapi_ch_smprintf("cn=%s", plugin_name);
+	search_pb = slapi_pblock_new();
+	slapi_search_internal_set_pb(search_pb, PLUGIN_BASE_DN, LDAP_SCOPE_ONELEVEL,
+								 filter, NULL, 0, NULL, NULL, identity, 0);
+	slapi_search_internal_pb(search_pb);
+	slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+	if (LDAP_SUCCESS != rc) { /* plugin is not available */
+		goto bail;
+	}
+
+	slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+	for (ep = entries; ep && *ep; ep++) {
+		on_off = slapi_entry_attr_get_charptr(*ep, "nsslapd-pluginEnabled");
+		if (on_off && (0 == strcasecmp(on_off, "on"))) {
+			rc = 1; /* plugin is on */
+			goto bail;
+		}
+	}
+
+bail:
+	slapi_ch_free_string(&on_off);
+	slapi_free_search_results_internal(search_pb);
+	slapi_pblock_destroy(search_pb);
+	slapi_ch_free_string(&filter);
+
+	return rc;
+}
diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h
index b4eb0c0..6eecd01 100644
--- a/ldap/servers/slapd/slap.h
+++ b/ldap/servers/slapd/slap.h
@@ -1115,6 +1115,7 @@ typedef struct backend {
 	PRRWLock    *be_lock;	
 	PRRWLock    *vlvSearchList_lock;
 	void        *vlvSearchList;
+	Slapi_Counter *be_usn_counter; /* USN counter; one counter per backend */
 } backend;
 
 enum
@@ -1488,6 +1489,8 @@ typedef struct slapi_pblock {
 	int		*pb_substrlens; /* user specified minimum substr search key lengths:
 							 * nsSubStrBegin, nsSubStrMiddle, nsSubStrEnd
 							 */
+	int		pb_plugin_enabled; /* nsslapd-pluginEnabled: on|off */
+							   /* used in plugin init; pb_plugin is not ready, then */
 } slapi_pblock;
 
 /* index if substrlens */
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
index e04fad9..d5efe4d 100644
--- a/ldap/servers/slapd/slapi-plugin.h
+++ b/ldap/servers/slapd/slapi-plugin.h
@@ -296,7 +296,9 @@ NSPR_API(PRUint32) PR_fprintf(struct PRFileDesc* fd, const char *fmt, ...)
 #define SLAPI_ATTR_OBJECTCLASS			"objectclass"
 #define SLAPI_ATTR_VALUE_TOMBSTONE		"nsTombstone"
 #define SLAPI_ATTR_VALUE_PARENT_UNIQUEID	"nsParentUniqueID"
-#define SLAPI_ATTR_NSCP_ENTRYDN "nscpEntryDN"
+#define SLAPI_ATTR_NSCP_ENTRYDN 		"nscpEntryDN"
+#define SLAPI_ATTR_ENTRYUSN 			"entryusn"
+#define SLAPI_ATTR_ENTRYUSN_PREV 		"preventryusn"
 
 
 /* opaque structures */
@@ -3272,6 +3274,7 @@ typedef struct slapi_plugindesc {
 /* entry fetch and entry store values */
 #define SLAPI_PLUGIN_ENTRY_FETCH_FUNC				813 
 #define SLAPI_PLUGIN_ENTRY_STORE_FUNC				814
+#define SLAPI_PLUGIN_ENABLED						815
 
 /*
  * Defined values of SLAPI_PLUGIN_SYNTAX_FLAGS:
@@ -3332,6 +3335,7 @@ typedef struct slapi_plugindesc {
 #define SLAPI_DELETE_TARGET			SLAPI_TARGET_DN
 #define SLAPI_DELETE_EXISTING_ENTRY		SLAPI_ADD_EXISTING_DN_ENTRY
 #define SLAPI_DELETE_GLUE_PARENT_ENTRY	SLAPI_ADD_PARENT_ENTRY
+#define SLAPI_DELETE_BEPREOP_ENTRY			SLAPI_ENTRY_PRE_OP
 
 /* modify arguments */
 #define SLAPI_MODIFY_TARGET			SLAPI_TARGET_DN
diff --git a/ldap/servers/slapd/slapi-private.h b/ldap/servers/slapd/slapi-private.h
index 85c4589..21b8dc4 100644
--- a/ldap/servers/slapd/slapi-private.h
+++ b/ldap/servers/slapd/slapi-private.h
@@ -1200,6 +1200,9 @@ void    DS_Sleep(PRIntervalTime ticks);
 #define PRLDAP_SET_PORT(myaddr,myport) \
     ((myaddr)->raw.family == PR_AF_INET6 ? ((myaddr)->ipv6.port = PR_htons(myport)) : ((myaddr)->inet.port = PR_htons(myport)))
 
+/* plugin.c */
+int plugin_enabled(const char *plugin_name, void *identity);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/ltmain.sh b/ltmain.sh
old mode 100755
new mode 100644
-- 
1.6.0.6

Attachment: smime.p7s
Description: S/MIME Cryptographic Signature

--
389-devel mailing list
389-devel@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/fedora-directory-devel

[Index of Archives]     [Fedora Directory Announce]     [Fedora Users]     [Older Fedora Users Mail]     [Fedora Advisory Board]     [Fedora Security]     [Fedora Devel Java]     [Fedora Desktop]     [ATA RAID]     [Fedora Marketing]     [Fedora Mentors]     [Fedora Package Review]     [Fedora Art]     [Fedora Music]     [Fedora Packaging]     [CentOS]     [Fedora SELinux]     [Big List of Linux Books]     [KDE Users]     [Fedora Art]     [Fedora Docs]

  Powered by Linux