4 * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC")
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
19 /* Id: ecdb.c,v 1.4 2009/11/06 04:19:28 marka Exp */
23 #include <isc/result.h>
25 #include <isc/mutex.h>
30 #include <dns/rdata.h>
31 #include <dns/rdataset.h>
32 #include <dns/rdatasetiter.h>
33 #include <dns/rdataslab.h>
35 #define ECDB_MAGIC ISC_MAGIC('E', 'C', 'D', 'B')
36 #define VALID_ECDB(db) ((db) != NULL && \
37 (db)->common.impmagic == ECDB_MAGIC)
39 #define ECDBNODE_MAGIC ISC_MAGIC('E', 'C', 'D', 'N')
40 #define VALID_ECDBNODE(ecdbn) ISC_MAGIC_VALID(ecdbn, ECDBNODE_MAGIC)
42 #if DNS_RDATASET_FIXED
43 #error "Fixed rdataset isn't supported in this implementation"
47 * The 'ephemeral' cache DB (ecdb) implementation. An ecdb just provides
48 * temporary storage for ongoing name resolution with the common DB interfaces.
49 * It actually doesn't cache anything. The implementation expects any stored
50 * data is released within a short period, and does not care about the
51 * scalability in terms of the number of nodes.
54 typedef struct dns_ecdb
{
60 unsigned int references
;
61 ISC_LIST(struct dns_ecdbnode
) nodes
;
64 typedef struct dns_ecdbnode
{
70 ISC_LINK(struct dns_ecdbnode
) link
;
73 ISC_LIST(struct rdatasetheader
) rdatasets
;
74 unsigned int references
;
77 typedef struct rdatasetheader
{
81 dns_rdatatype_t covers
;
82 unsigned int attributes
;
84 ISC_LINK(struct rdatasetheader
) link
;
87 /* Copied from rbtdb.c */
88 #define RDATASET_ATTR_NXDOMAIN 0x0010
89 #define NXDOMAIN(header) \
90 (((header)->attributes & RDATASET_ATTR_NXDOMAIN) != 0)
92 static isc_result_t
dns_ecdb_create(isc_mem_t
*mctx
, dns_name_t
*origin
,
94 dns_rdataclass_t rdclass
,
95 unsigned int argc
, char *argv
[],
96 void *driverarg
, dns_db_t
**dbp
);
98 static void rdataset_disassociate(dns_rdataset_t
*rdataset
);
99 static isc_result_t
rdataset_first(dns_rdataset_t
*rdataset
);
100 static isc_result_t
rdataset_next(dns_rdataset_t
*rdataset
);
101 static void rdataset_current(dns_rdataset_t
*rdataset
, dns_rdata_t
*rdata
);
102 static void rdataset_clone(dns_rdataset_t
*source
, dns_rdataset_t
*target
);
103 static unsigned int rdataset_count(dns_rdataset_t
*rdataset
);
105 static dns_rdatasetmethods_t rdataset_methods
= {
106 rdataset_disassociate
,
112 NULL
, /* addnoqname */
113 NULL
, /* getnoqname */
114 NULL
, /* addclosest */
115 NULL
, /* getclosest */
116 NULL
, /* getadditional */
117 NULL
, /* setadditional */
118 NULL
/* putadditional */
121 typedef struct ecdb_rdatasetiter
{
122 dns_rdatasetiter_t common
;
123 rdatasetheader_t
*current
;
124 } ecdb_rdatasetiter_t
;
126 static void rdatasetiter_destroy(dns_rdatasetiter_t
**iteratorp
);
127 static isc_result_t
rdatasetiter_first(dns_rdatasetiter_t
*iterator
);
128 static isc_result_t
rdatasetiter_next(dns_rdatasetiter_t
*iterator
);
129 static void rdatasetiter_current(dns_rdatasetiter_t
*iterator
,
130 dns_rdataset_t
*rdataset
);
132 static dns_rdatasetitermethods_t rdatasetiter_methods
= {
133 rdatasetiter_destroy
,
140 dns_ecdb_register(isc_mem_t
*mctx
, dns_dbimplementation_t
**dbimp
) {
141 REQUIRE(mctx
!= NULL
);
142 REQUIRE(dbimp
!= NULL
&& *dbimp
== NULL
);
144 return (dns_db_register("ecdb", dns_ecdb_create
, NULL
, mctx
, dbimp
));
148 dns_ecdb_unregister(dns_dbimplementation_t
**dbimp
) {
149 REQUIRE(dbimp
!= NULL
&& *dbimp
!= NULL
);
151 dns_db_unregister(dbimp
);
159 attach(dns_db_t
*source
, dns_db_t
**targetp
) {
160 dns_ecdb_t
*ecdb
= (dns_ecdb_t
*)source
;
162 REQUIRE(VALID_ECDB(ecdb
));
163 REQUIRE(targetp
!= NULL
&& *targetp
== NULL
);
173 destroy_ecdb(dns_ecdb_t
**ecdbp
) {
174 dns_ecdb_t
*ecdb
= *ecdbp
;
175 isc_mem_t
*mctx
= ecdb
->common
.mctx
;
177 if (dns_name_dynamic(&ecdb
->common
.origin
))
178 dns_name_free(&ecdb
->common
.origin
, mctx
);
180 DESTROYLOCK(&ecdb
->lock
);
182 ecdb
->common
.impmagic
= 0;
183 ecdb
->common
.magic
= 0;
185 isc_mem_putanddetach(&mctx
, ecdb
, sizeof(*ecdb
));
191 detach(dns_db_t
**dbp
) {
193 isc_boolean_t need_destroy
= ISC_FALSE
;
195 REQUIRE(dbp
!= NULL
);
196 ecdb
= (dns_ecdb_t
*)*dbp
;
197 REQUIRE(VALID_ECDB(ecdb
));
201 if (ecdb
->references
== 0 && ISC_LIST_EMPTY(ecdb
->nodes
))
202 need_destroy
= ISC_TRUE
;
212 attachnode(dns_db_t
*db
, dns_dbnode_t
*source
, dns_dbnode_t
**targetp
) {
213 dns_ecdb_t
*ecdb
= (dns_ecdb_t
*)db
;
214 dns_ecdbnode_t
*node
= (dns_ecdbnode_t
*)source
;
216 REQUIRE(VALID_ECDB(ecdb
));
217 REQUIRE(VALID_ECDBNODE(node
));
218 REQUIRE(targetp
!= NULL
&& *targetp
== NULL
);
221 INSIST(node
->references
> 0);
223 INSIST(node
->references
!= 0); /* Catch overflow. */
230 destroynode(dns_ecdbnode_t
*node
) {
232 dns_ecdb_t
*ecdb
= node
->ecdb
;
233 isc_boolean_t need_destroydb
= ISC_FALSE
;
234 rdatasetheader_t
*header
;
236 mctx
= ecdb
->common
.mctx
;
239 ISC_LIST_UNLINK(ecdb
->nodes
, node
, link
);
240 if (ecdb
->references
== 0 && ISC_LIST_EMPTY(ecdb
->nodes
))
241 need_destroydb
= ISC_TRUE
;
244 dns_name_free(&node
->name
, mctx
);
246 while ((header
= ISC_LIST_HEAD(node
->rdatasets
)) != NULL
) {
247 unsigned int headersize
;
249 ISC_LIST_UNLINK(node
->rdatasets
, header
, link
);
251 dns_rdataslab_size((unsigned char *)header
,
253 isc_mem_put(mctx
, header
, headersize
);
256 DESTROYLOCK(&node
->lock
);
259 isc_mem_put(mctx
, node
, sizeof(*node
));
266 detachnode(dns_db_t
*db
, dns_dbnode_t
**nodep
) {
267 dns_ecdb_t
*ecdb
= (dns_ecdb_t
*)db
;
268 dns_ecdbnode_t
*node
;
269 isc_boolean_t need_destroy
= ISC_FALSE
;
271 REQUIRE(VALID_ECDB(ecdb
));
272 REQUIRE(nodep
!= NULL
);
273 node
= (dns_ecdbnode_t
*)*nodep
;
274 REQUIRE(VALID_ECDBNODE(node
));
276 UNUSED(ecdb
); /* in case REQUIRE() is empty */
279 INSIST(node
->references
> 0);
281 if (node
->references
== 0)
282 need_destroy
= ISC_TRUE
;
292 find(dns_db_t
*db
, dns_name_t
*name
, dns_dbversion_t
*version
,
293 dns_rdatatype_t type
, unsigned int options
, isc_stdtime_t now
,
294 dns_dbnode_t
**nodep
, dns_name_t
*foundname
, dns_rdataset_t
*rdataset
,
295 dns_rdataset_t
*sigrdataset
)
297 dns_ecdb_t
*ecdb
= (dns_ecdb_t
*)db
;
299 REQUIRE(VALID_ECDB(ecdb
));
311 return (ISC_R_NOTFOUND
);
315 findzonecut(dns_db_t
*db
, dns_name_t
*name
,
316 unsigned int options
, isc_stdtime_t now
,
317 dns_dbnode_t
**nodep
, dns_name_t
*foundname
,
318 dns_rdataset_t
*rdataset
, dns_rdataset_t
*sigrdataset
)
320 dns_ecdb_t
*ecdb
= (dns_ecdb_t
*)db
;
322 REQUIRE(VALID_ECDB(ecdb
));
332 return (ISC_R_NOTFOUND
);
336 findnode(dns_db_t
*db
, dns_name_t
*name
, isc_boolean_t create
,
337 dns_dbnode_t
**nodep
)
339 dns_ecdb_t
*ecdb
= (dns_ecdb_t
*)db
;
341 dns_ecdbnode_t
*node
;
344 REQUIRE(VALID_ECDB(ecdb
));
345 REQUIRE(nodep
!= NULL
&& *nodep
== NULL
);
349 if (create
!= ISC_TRUE
) {
350 /* an 'ephemeral' node is never reused. */
351 return (ISC_R_NOTFOUND
);
354 mctx
= ecdb
->common
.mctx
;
355 node
= isc_mem_get(mctx
, sizeof(*node
));
357 return (ISC_R_NOMEMORY
);
359 result
= isc_mutex_init(&node
->lock
);
360 if (result
!= ISC_R_SUCCESS
) {
361 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
362 "isc_mutex_init() failed: %s",
363 isc_result_totext(result
));
364 isc_mem_put(mctx
, node
, sizeof(*node
));
365 return (ISC_R_UNEXPECTED
);
368 dns_name_init(&node
->name
, NULL
);
369 result
= dns_name_dup(name
, mctx
, &node
->name
);
370 if (result
!= ISC_R_SUCCESS
) {
371 DESTROYLOCK(&node
->lock
);
372 isc_mem_put(mctx
, node
, sizeof(*node
));
376 node
->references
= 1;
377 ISC_LIST_INIT(node
->rdatasets
);
379 ISC_LINK_INIT(node
, link
);
382 ISC_LIST_APPEND(ecdb
->nodes
, node
, link
);
385 node
->magic
= ECDBNODE_MAGIC
;
389 return (ISC_R_SUCCESS
);
393 bind_rdataset(dns_ecdb_t
*ecdb
, dns_ecdbnode_t
*node
,
394 rdatasetheader_t
*header
, dns_rdataset_t
*rdataset
)
399 * Caller must be holding the node lock.
402 REQUIRE(!dns_rdataset_isassociated(rdataset
));
404 rdataset
->methods
= &rdataset_methods
;
405 rdataset
->rdclass
= ecdb
->common
.rdclass
;
406 rdataset
->type
= header
->type
;
407 rdataset
->covers
= header
->covers
;
408 rdataset
->ttl
= header
->ttl
;
409 rdataset
->trust
= header
->trust
;
410 if (NXDOMAIN(header
))
411 rdataset
->attributes
|= DNS_RDATASETATTR_NXDOMAIN
;
413 rdataset
->private1
= ecdb
;
414 rdataset
->private2
= node
;
415 raw
= (unsigned char *)header
+ sizeof(*header
);
416 rdataset
->private3
= raw
;
420 * Reset iterator state.
422 rdataset
->privateuint4
= 0;
423 rdataset
->private5
= NULL
;
425 INSIST(node
->references
> 0);
430 addrdataset(dns_db_t
*db
, dns_dbnode_t
*node
, dns_dbversion_t
*version
,
431 isc_stdtime_t now
, dns_rdataset_t
*rdataset
, unsigned int options
,
432 dns_rdataset_t
*addedrdataset
)
434 dns_ecdb_t
*ecdb
= (dns_ecdb_t
*)db
;
436 isc_result_t result
= ISC_R_SUCCESS
;
438 dns_ecdbnode_t
*ecdbnode
= (dns_ecdbnode_t
*)node
;
439 rdatasetheader_t
*header
;
441 REQUIRE(VALID_ECDB(ecdb
));
442 REQUIRE(VALID_ECDBNODE(ecdbnode
));
448 mctx
= ecdb
->common
.mctx
;
450 LOCK(&ecdbnode
->lock
);
453 * Sanity check: this implementation does not allow overriding an
454 * existing rdataset of the same type.
456 for (header
= ISC_LIST_HEAD(ecdbnode
->rdatasets
); header
!= NULL
;
457 header
= ISC_LIST_NEXT(header
, link
)) {
458 INSIST(header
->type
!= rdataset
->type
||
459 header
->covers
!= rdataset
->covers
);
462 result
= dns_rdataslab_fromrdataset(rdataset
, mctx
,
463 &r
, sizeof(rdatasetheader_t
));
464 if (result
!= ISC_R_SUCCESS
)
467 header
= (rdatasetheader_t
*)r
.base
;
468 header
->type
= rdataset
->type
;
469 header
->ttl
= rdataset
->ttl
;
470 header
->trust
= rdataset
->trust
;
471 header
->covers
= rdataset
->covers
;
472 header
->attributes
= 0;
473 if ((rdataset
->attributes
& DNS_RDATASETATTR_NXDOMAIN
) != 0)
474 header
->attributes
|= RDATASET_ATTR_NXDOMAIN
;
475 ISC_LINK_INIT(header
, link
);
476 ISC_LIST_APPEND(ecdbnode
->rdatasets
, header
, link
);
478 if (addedrdataset
== NULL
)
481 bind_rdataset(ecdb
, ecdbnode
, header
, addedrdataset
);
484 UNLOCK(&ecdbnode
->lock
);
490 deleterdataset(dns_db_t
*db
, dns_dbnode_t
*node
, dns_dbversion_t
*version
,
491 dns_rdatatype_t type
, dns_rdatatype_t covers
)
499 return (ISC_R_NOTIMPLEMENTED
);
503 createiterator(dns_db_t
*db
, unsigned int options
,
504 dns_dbiterator_t
**iteratorp
)
510 return (ISC_R_NOTIMPLEMENTED
);
514 allrdatasets(dns_db_t
*db
, dns_dbnode_t
*node
, dns_dbversion_t
*version
,
515 isc_stdtime_t now
, dns_rdatasetiter_t
**iteratorp
)
517 dns_ecdb_t
*ecdb
= (dns_ecdb_t
*)db
;
518 dns_ecdbnode_t
*ecdbnode
= (dns_ecdbnode_t
*)node
;
520 ecdb_rdatasetiter_t
*iterator
;
522 REQUIRE(VALID_ECDB(ecdb
));
523 REQUIRE(VALID_ECDBNODE(ecdbnode
));
525 mctx
= ecdb
->common
.mctx
;
527 iterator
= isc_mem_get(mctx
, sizeof(ecdb_rdatasetiter_t
));
528 if (iterator
== NULL
)
529 return (ISC_R_NOMEMORY
);
531 iterator
->common
.magic
= DNS_RDATASETITER_MAGIC
;
532 iterator
->common
.methods
= &rdatasetiter_methods
;
533 iterator
->common
.db
= db
;
534 iterator
->common
.node
= NULL
;
535 attachnode(db
, node
, &iterator
->common
.node
);
536 iterator
->common
.version
= version
;
537 iterator
->common
.now
= now
;
539 *iteratorp
= (dns_rdatasetiter_t
*)iterator
;
541 return (ISC_R_SUCCESS
);
544 static dns_dbmethods_t ecdb_methods
= {
547 NULL
, /* beginload */
550 NULL
, /* currentversion */
551 NULL
, /* newversion */
552 NULL
, /* attachversion */
553 NULL
, /* closeversion */
559 NULL
, /* expirenode */
560 NULL
, /* printnode */
561 createiterator
, /* createiterator */
562 NULL
, /* findrdataset */
565 NULL
, /* subtractrdataset */
568 NULL
, /* nodecount */
569 NULL
, /* ispersistent */
572 NULL
, /* getoriginnode */
573 NULL
, /* transfernode */
574 NULL
, /* getnsec3parameters */
575 NULL
, /* findnsec3node */
576 NULL
, /* setsigningtime */
577 NULL
, /* getsigningtime */
580 NULL
/* getrrsetstats */
584 dns_ecdb_create(isc_mem_t
*mctx
, dns_name_t
*origin
, dns_dbtype_t type
,
585 dns_rdataclass_t rdclass
, unsigned int argc
, char *argv
[],
586 void *driverarg
, dns_db_t
**dbp
)
591 REQUIRE(mctx
!= NULL
);
592 REQUIRE(origin
== dns_rootname
);
593 REQUIRE(type
== dns_dbtype_cache
);
594 REQUIRE(dbp
!= NULL
&& *dbp
== NULL
);
600 ecdb
= isc_mem_get(mctx
, sizeof(*ecdb
));
602 return (ISC_R_NOMEMORY
);
604 ecdb
->common
.attributes
= DNS_DBATTR_CACHE
;
605 ecdb
->common
.rdclass
= rdclass
;
606 ecdb
->common
.methods
= &ecdb_methods
;
607 dns_name_init(&ecdb
->common
.origin
, NULL
);
608 result
= dns_name_dupwithoffsets(origin
, mctx
, &ecdb
->common
.origin
);
609 if (result
!= ISC_R_SUCCESS
) {
610 isc_mem_put(mctx
, ecdb
, sizeof(*ecdb
));
614 result
= isc_mutex_init(&ecdb
->lock
);
615 if (result
!= ISC_R_SUCCESS
) {
616 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
617 "isc_mutex_init() failed: %s",
618 isc_result_totext(result
));
619 if (dns_name_dynamic(&ecdb
->common
.origin
))
620 dns_name_free(&ecdb
->common
.origin
, mctx
);
621 isc_mem_put(mctx
, ecdb
, sizeof(*ecdb
));
622 return (ISC_R_UNEXPECTED
);
625 ecdb
->references
= 1;
626 ISC_LIST_INIT(ecdb
->nodes
);
628 ecdb
->common
.mctx
= NULL
;
629 isc_mem_attach(mctx
, &ecdb
->common
.mctx
);
630 ecdb
->common
.impmagic
= ECDB_MAGIC
;
631 ecdb
->common
.magic
= DNS_DB_MAGIC
;
633 *dbp
= (dns_db_t
*)ecdb
;
635 return (ISC_R_SUCCESS
);
643 rdataset_disassociate(dns_rdataset_t
*rdataset
) {
644 dns_db_t
*db
= rdataset
->private1
;
645 dns_dbnode_t
*node
= rdataset
->private2
;
647 dns_db_detachnode(db
, &node
);
651 rdataset_first(dns_rdataset_t
*rdataset
) {
652 unsigned char *raw
= rdataset
->private3
;
655 count
= raw
[0] * 256 + raw
[1];
657 rdataset
->private5
= NULL
;
658 return (ISC_R_NOMORE
);
662 * The privateuint4 field is the number of rdata beyond the cursor
663 * position, so we decrement the total count by one before storing
667 rdataset
->privateuint4
= count
;
668 rdataset
->private5
= raw
;
670 return (ISC_R_SUCCESS
);
674 rdataset_next(dns_rdataset_t
*rdataset
) {
679 count
= rdataset
->privateuint4
;
681 return (ISC_R_NOMORE
);
683 rdataset
->privateuint4
= count
;
684 raw
= rdataset
->private5
;
685 length
= raw
[0] * 256 + raw
[1];
687 rdataset
->private5
= raw
;
689 return (ISC_R_SUCCESS
);
693 rdataset_current(dns_rdataset_t
*rdataset
, dns_rdata_t
*rdata
) {
694 unsigned char *raw
= rdataset
->private5
;
697 unsigned int flags
= 0;
699 REQUIRE(raw
!= NULL
);
701 length
= raw
[0] * 256 + raw
[1];
703 if (rdataset
->type
== dns_rdatatype_rrsig
) {
704 if (*raw
& DNS_RDATASLAB_OFFLINE
)
705 flags
|= DNS_RDATA_OFFLINE
;
711 dns_rdata_fromregion(rdata
, rdataset
->rdclass
, rdataset
->type
, &r
);
712 rdata
->flags
|= flags
;
716 rdataset_clone(dns_rdataset_t
*source
, dns_rdataset_t
*target
) {
717 dns_db_t
*db
= source
->private1
;
718 dns_dbnode_t
*node
= source
->private2
;
719 dns_dbnode_t
*cloned_node
= NULL
;
721 attachnode(db
, node
, &cloned_node
);
725 * Reset iterator state.
727 target
->privateuint4
= 0;
728 target
->private5
= NULL
;
732 rdataset_count(dns_rdataset_t
*rdataset
) {
733 unsigned char *raw
= rdataset
->private3
;
736 count
= raw
[0] * 256 + raw
[1];
742 * Rdataset Iterator Methods
746 rdatasetiter_destroy(dns_rdatasetiter_t
**iteratorp
) {
747 ecdb_rdatasetiter_t
*ecdbiterator
;
750 REQUIRE(iteratorp
!= NULL
);
751 ecdbiterator
= (ecdb_rdatasetiter_t
*)*iteratorp
;
752 REQUIRE(DNS_RDATASETITER_VALID(&ecdbiterator
->common
));
754 mctx
= ecdbiterator
->common
.db
->mctx
;
756 ecdbiterator
->common
.magic
= 0;
758 dns_db_detachnode(ecdbiterator
->common
.db
, &ecdbiterator
->common
.node
);
759 isc_mem_put(mctx
, ecdbiterator
, sizeof(ecdb_rdatasetiter_t
));
765 rdatasetiter_first(dns_rdatasetiter_t
*iterator
) {
766 ecdb_rdatasetiter_t
*ecdbiterator
= (ecdb_rdatasetiter_t
*)iterator
;
767 dns_ecdbnode_t
*ecdbnode
= (dns_ecdbnode_t
*)iterator
->node
;
769 REQUIRE(DNS_RDATASETITER_VALID(iterator
));
771 if (ISC_LIST_EMPTY(ecdbnode
->rdatasets
))
772 return (ISC_R_NOMORE
);
773 ecdbiterator
->current
= ISC_LIST_HEAD(ecdbnode
->rdatasets
);
774 return (ISC_R_SUCCESS
);
778 rdatasetiter_next(dns_rdatasetiter_t
*iterator
) {
779 ecdb_rdatasetiter_t
*ecdbiterator
= (ecdb_rdatasetiter_t
*)iterator
;
781 REQUIRE(DNS_RDATASETITER_VALID(iterator
));
783 ecdbiterator
->current
= ISC_LIST_NEXT(ecdbiterator
->current
, link
);
784 if (ecdbiterator
->current
== NULL
)
785 return (ISC_R_NOMORE
);
787 return (ISC_R_SUCCESS
);
791 rdatasetiter_current(dns_rdatasetiter_t
*iterator
, dns_rdataset_t
*rdataset
) {
792 ecdb_rdatasetiter_t
*ecdbiterator
= (ecdb_rdatasetiter_t
*)iterator
;
795 ecdb
= (dns_ecdb_t
*)iterator
->db
;
796 REQUIRE(VALID_ECDB(ecdb
));
798 bind_rdataset(ecdb
, iterator
->node
, ecdbiterator
->current
, rdataset
);