summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2010-01-09 13:11:27 +1100
committerAndrew Tridgell <tridge@samba.org>2010-01-09 13:11:27 +1100
commit349f7ba09c4cda14eea4df69bd6dcb082fc23c8d (patch)
tree9ff4e1dd1a914053aada408d6cb5c96f7bf4612c
parentb0090d01e061220d9b70a14e5a88b683949fe6a5 (diff)
downloadsamba-349f7ba09c4cda14eea4df69bd6dcb082fc23c8d.tar.gz
samba-349f7ba09c4cda14eea4df69bd6dcb082fc23c8d.tar.bz2
samba-349f7ba09c4cda14eea4df69bd6dcb082fc23c8d.zip
s4-drs: added filtering by udv in getncchanges
When a client supplied an uptodateness_vector, we can use it to filter what objects we return. This greatly reduces the amount of replication traffic between DCs.
-rw-r--r--source4/dsdb/common/util.c6
-rw-r--r--source4/rpc_server/drsuapi/getncchanges.c66
2 files changed, 63 insertions, 9 deletions
diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c
index 70750ca141..632025da54 100644
--- a/source4/dsdb/common/util.c
+++ b/source4/dsdb/common/util.c
@@ -2810,6 +2810,12 @@ int drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1,
return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
}
+int drsuapi_DsReplicaCursor_compare(const struct drsuapi_DsReplicaCursor *c1,
+ const struct drsuapi_DsReplicaCursor *c2)
+{
+ return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
+}
+
/*
see if we are a RODC
diff --git a/source4/rpc_server/drsuapi/getncchanges.c b/source4/rpc_server/drsuapi/getncchanges.c
index d0ce8198b8..46996c7426 100644
--- a/source4/rpc_server/drsuapi/getncchanges.c
+++ b/source4/rpc_server/drsuapi/getncchanges.c
@@ -30,6 +30,7 @@
#include "rpc_server/dcerpc_server_proto.h"
#include "../libcli/drsuapi/drsuapi.h"
#include "libcli/security/security.h"
+#include "lib/util/binsearch.h"
/*
build a DsReplicaObjectIdentifier from a ldb msg
@@ -57,6 +58,29 @@ static struct drsuapi_DsReplicaObjectIdentifier *get_object_identifier(TALLOC_CT
return identifier;
}
+static int udv_compare(const struct GUID *guid1, struct GUID guid2)
+{
+ return GUID_compare(guid1, &guid2);
+}
+
+/*
+ see if we can filter an attribute using the uptodateness_vector
+ */
+static bool udv_filter(const struct drsuapi_DsReplicaCursorCtrEx *udv,
+ const struct GUID *originating_invocation_id,
+ uint64_t originating_usn)
+{
+ const struct drsuapi_DsReplicaCursor *c;
+ if (udv == NULL) return false;
+ BINARY_ARRAY_SEARCH(udv->cursors, udv->count, source_dsa_invocation_id,
+ originating_invocation_id, udv_compare, c);
+ if (c && originating_usn <= c->highest_usn) {
+ return true;
+ }
+ return false;
+
+}
+
/*
drsuapi_DsGetNCChanges for one object
*/
@@ -67,7 +91,8 @@ static WERROR get_nc_changes_build_object(struct drsuapi_DsReplicaObjectListItem
struct dsdb_schema *schema,
DATA_BLOB *session_key,
uint64_t highest_usn,
- uint32_t replica_flags)
+ uint32_t replica_flags,
+ struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector)
{
const struct ldb_val *md_value;
int i, n;
@@ -156,6 +181,14 @@ static WERROR get_nc_changes_build_object(struct drsuapi_DsReplicaObjectListItem
}
}
+ /* filter by uptodateness_vector */
+ if (md.ctr.ctr1.array[i].attid != DRSUAPI_ATTRIBUTE_instanceType &&
+ udv_filter(uptodateness_vector,
+ &md.ctr.ctr1.array[i].originating_invocation_id,
+ md.ctr.ctr1.array[i].originating_usn)) {
+ continue;
+ }
+
obj->meta_data_ctr->meta_data[n].originating_change_time = md.ctr.ctr1.array[i].originating_change_time;
obj->meta_data_ctr->meta_data[n].version = md.ctr.ctr1.array[i].version;
obj->meta_data_ctr->meta_data[n].originating_invocation_id = md.ctr.ctr1.array[i].originating_invocation_id;
@@ -164,11 +197,15 @@ static WERROR get_nc_changes_build_object(struct drsuapi_DsReplicaObjectListItem
n++;
}
- /*
- note that if n==0 we still need to send the change, as it
- could be a rename, which changes the uSNChanged, but not any
- of the replicated attributes
- */
+ /* ignore it if its an empty change. Note that renames always
+ * change the 'name' attribute, so they won't be ignored by
+ * this */
+ if (n == 0 ||
+ (n == 1 && attids[0] == DRSUAPI_ATTRIBUTE_instanceType)) {
+ talloc_free(obj->meta_data_ctr);
+ obj->meta_data_ctr = NULL;
+ return WERR_OK;
+ }
obj->meta_data_ctr->count = n;
@@ -302,7 +339,8 @@ static WERROR get_nc_changes_add_links(struct ldb_context *sam_ctx,
uint32_t replica_flags,
struct ldb_message *msg,
struct drsuapi_DsReplicaLinkedAttribute **la_list,
- uint32_t *la_count)
+ uint32_t *la_count,
+ struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector)
{
int i;
TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
@@ -668,6 +706,7 @@ struct drsuapi_getncchanges_state {
struct ldb_dn *last_dn;
struct drsuapi_DsReplicaLinkedAttribute *la_list;
uint32_t la_count;
+ struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector;
};
/*
@@ -880,6 +919,14 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_
(comparison_fn_t)site_res_cmp_usn_order);
}
+ getnc_state->uptodateness_vector = talloc_steal(getnc_state, req8->uptodateness_vector);
+ if (getnc_state->uptodateness_vector) {
+ /* make sure its sorted */
+ qsort(getnc_state->uptodateness_vector->cursors,
+ getnc_state->uptodateness_vector->count,
+ sizeof(getnc_state->uptodateness_vector->cursors[0]),
+ (comparison_fn_t)drsuapi_DsReplicaCursor_compare);
+ }
}
/* Prefix mapping */
@@ -935,7 +982,7 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_
werr = get_nc_changes_build_object(obj, msg,
b_state->sam_ctx, getnc_state->ncRoot_dn,
schema, &session_key, getnc_state->min_usn,
- req8->replica_flags);
+ req8->replica_flags, getnc_state->uptodateness_vector);
if (!W_ERROR_IS_OK(werr)) {
return werr;
}
@@ -946,7 +993,8 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_
req8->replica_flags,
msg,
&getnc_state->la_list,
- &getnc_state->la_count);
+ &getnc_state->la_count,
+ getnc_state->uptodateness_vector);
if (!W_ERROR_IS_OK(werr)) {
return werr;
}