[389-devel] Entry USN (additional changes)

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

 



Regarding the first question from Andrey:

   The USNs seem to be unique within a suffix/backend. Should we enable
   the uniqueness plug-in for them? If not can we be sure that a manual
   change of entryUSN will not interfere with the correct functioning
   of the plug-in?

Nathan suggested to set SLAPI_ATTR_FLAG_NOUSERMOD to the attribute entryusn as follows.

   diff --git a/ldap/servers/slapd/back-ldbm/init.c
   b/ldap/servers/slapd/back-ldbm/
   index a4ff79c..be9c114 100644
   --- a/ldap/servers/slapd/back-ldbm/init.c
   +++ b/ldap/servers/slapd/back-ldbm/init.c
   @@ -86,7 +86,7 @@ ldbm_back_add_schema( Slapi_PBlock *pb )
rc |= add_ldbm_internal_attr_syntax( "entryusn",
                           LDBM_ENTRYUSN_OID, INTEGER_SYNTAX_OID,
   INTFIRSTCOMPMATCH
   -                       SLAPI_ATTR_FLAG_SINGLE );
+ SLAPI_ATTR_FLAG_SINGLE|SLAPI_ATTR_FLAG_NOUSERMOD ); return rc;
    }

The flag nicely prevents the manual update on EntryUSN.

   ldapmodify -D "cn=Directory Manager" -w /password/
   dn: uid=tuserX,dc=example,dc=com
   changetype: modify
   replace: entryusn
   entryusn: 100

   modifying entry uid=tuserX,dc=example,dc=com
   ldap_modify: DSA is unwilling to perform
   ldap_modify: additional info: no modifiable attributes specified

Nathan also pointed out several typos as well as an issue of internal deletion. Currently, if the delete is initiated internally, the entry is not converted to a tombstone unless the backend is replicated. I'm adding this issue to ToDo list for now.
Attached patch includes the above diff and typo fixes.

Thanks so much to Nathan for his reviews and suggestions.
--noriko

Noriko Hosoi wrote:
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
------------------------------------------------------------------------

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

From a0c08fa9d2ef39d682425d58fc97bb4600bbf08d Mon Sep 17 00:00:00 2001
From: Noriko Hosoi <nhosoi@xxxxxxxxxx>
Date: Tue, 21 Jul 2009 12:59:38 -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..bd8c257
--- /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 tombstone 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..bf13073
--- /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: deleting %s failed; (%d).\n",
+                    slapi_sdn_get_dn(sdn), delrv);
+            slapi_task_log_status(task,
+                    "USN tombstone cleanup: deleting %s failed; (%d).\n",
+                    slapi_sdn_get_dn(sdn), delrv);
+            slapi_log_error(SLAPI_LOG_FATAL, USN_PLUGIN_SUBSYSTEM,
+                    "USN tombstone cleanup: deleting %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..be9c114 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|SLAPI_ATTR_FLAG_NOUSERMOD );
+
 	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