/* OpenLDAP WiredTiger backend */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software .
*
* Copyright 2002-2022 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* .
*/
/* ACKNOWLEDGEMENTS:
* This work was developed by HAMANO Tsukasa
* based on back-bdb for inclusion in OpenLDAP Software.
* WiredTiger is a product of MongoDB Inc.
*/
#include "portable.h"
#include
#include "back-wt.h"
#include "slap-config.h"
#include "idl.h"
static char *
mkrevdn(struct berval src){
char *dst, *p;
char *rdn;
size_t rdn_len;
p = dst = ch_malloc(src.bv_len + 2);
while(src.bv_len){
rdn = ber_bvrchr( &src, ',' );
if (rdn) {
rdn_len = src.bv_len;
src.bv_len = rdn - src.bv_val;
rdn_len -= src.bv_len + 1;
rdn++;
}else{
/* first rdn */
rdn_len = src.bv_len;
rdn = src.bv_val;
src.bv_len = 0;
}
memcpy( p, rdn, rdn_len );
p += rdn_len;
*p++ = ',';
}
*p = '\0';
return dst;
}
int
wt_dn2id_add(
Operation *op,
wt_ctx *wc,
ID pid,
Entry *e)
{
struct wt_info *wi = (struct wt_info *) op->o_bd->be_private;
int rc;
WT_SESSION *session = wc->session;
WT_CURSOR *cursor = wc->dn2id_w;
char *revdn = NULL;
Debug( LDAP_DEBUG_TRACE, "=> wt_dn2id_add 0x%lx: \"%s\"\n",
e->e_id, e->e_ndn );
assert( e->e_id != NOID );
/* make reverse dn */
revdn = mkrevdn(e->e_nname);
if(!cursor){
rc = session->open_cursor(session, WT_TABLE_DN2ID, NULL,
"overwrite=false", &cursor);
if(rc){
Debug( LDAP_DEBUG_ANY,
"wt_dn2id_add: open_cursor failed: %s (%d)\n",
wiredtiger_strerror(rc), rc );
goto done;
}
wc->dn2id_w = cursor;
}
cursor->set_key(cursor, revdn);
cursor->set_value(cursor, e->e_ndn, e->e_id, pid);
rc = cursor->insert(cursor);
if(rc){
Debug( LDAP_DEBUG_ANY,
"wt_dn2id_add: insert failed: %s (%d)\n",
wiredtiger_strerror(rc), rc );
goto done;
}
if (wi->wi_flags & WT_USE_IDLCACHE) {
wt_idlcache_clear(op, wc, &e->e_nname);
}
done:
if(revdn){
ch_free(revdn);
}
#ifdef WT_CURSOR_CACHE
if(cursor){
cursor->reset(cursor);
}
#else
if(cursor){
cursor->close(cursor);
wc->dn2id_w = NULL;
}
#endif
Debug( LDAP_DEBUG_TRACE, "<= wt_dn2id_add 0x%lx: %d\n", e->e_id, rc );
return rc;
}
int
wt_dn2id_delete(
Operation *op,
wt_ctx *wc,
struct berval *ndn)
{
struct wt_info *wi = (struct wt_info *) op->o_bd->be_private;
int rc = 0;
WT_SESSION *session = wc->session;
WT_CURSOR *cursor = wc->dn2id_w;
char *revdn = NULL;
Debug( LDAP_DEBUG_TRACE, "=> wt_dn2id_delete %s\n", ndn->bv_val );
/* make reverse dn */
revdn = mkrevdn(*ndn);
if(!cursor){
rc = session->open_cursor(session, WT_TABLE_DN2ID, NULL,
"overwrite=false", &cursor);
if ( rc ) {
Debug( LDAP_DEBUG_ANY,
"wt_dn2id_delete: open_cursor failed: %s (%d)\n",
wiredtiger_strerror(rc), rc );
goto done;
}
wc->dn2id_w = cursor;
}
cursor->set_key(cursor, revdn);
rc = cursor->remove(cursor);
if ( rc ) {
Debug( LDAP_DEBUG_ANY,
"wt_dn2id_delete: remove failed: %s (%d)\n",
wiredtiger_strerror(rc), rc );
goto done;
}
if (wi->wi_flags & WT_USE_IDLCACHE) {
wt_idlcache_clear(op, wc, ndn);
}
Debug( LDAP_DEBUG_TRACE,
"<= wt_dn2id_delete %s: %d\n", ndn->bv_val, rc );
done:
if(revdn){
ch_free(revdn);
}
#ifdef WT_CURSOR_CACHE
if(cursor){
cursor->reset(cursor);
}
#else
if(cursor){
cursor->close(cursor);
wc->dn2id_w = NULL;
}
#endif
return rc;
}
int
wt_dn2id(
Operation *op,
wt_ctx *wc,
struct berval *ndn,
ID *id)
{
WT_SESSION *session = wc->session;
WT_CURSOR *cursor = wc->dn2id_ndn;
int rc = LDAP_SUCCESS;
Debug( LDAP_DEBUG_TRACE, "=> wt_dn2id(\"%s\")\n", ndn->bv_val );
if ( ndn->bv_len == 0 ) {
*id = 0;
goto done;
}
if(!cursor){
rc = session->open_cursor(session, WT_INDEX_NDN
"(id)",
NULL, NULL, &cursor);
if( rc ){
Debug( LDAP_DEBUG_ANY,
"wt_dn2id: cursor open failed: %s (%d)\n",
wiredtiger_strerror(rc), rc );
goto done;
}
wc->dn2id_ndn = cursor;
}
cursor->set_key(cursor, ndn->bv_val);
rc = cursor->search(cursor);
switch( rc ){
case 0:
break;
case WT_NOTFOUND:
goto done;
default:
Debug( LDAP_DEBUG_ANY,
"wt_dn2id: search failed: %s (%d)\n",
wiredtiger_strerror(rc), rc );
goto done;
}
rc = cursor->get_value(cursor, id);
if( rc ){
Debug( LDAP_DEBUG_ANY,
"wt_dn2id: get_value failed: %s (%d)\n",
wiredtiger_strerror(rc), rc );
goto done;
}
done:
#ifdef WT_CURSOR_CACHE
if(cursor){
cursor->reset(cursor);
}
#else
if(cursor){
cursor->close(cursor);
wc->dn2id_ndn = NULL;
}
#endif
if( rc ) {
Debug( LDAP_DEBUG_TRACE, "<= wt_dn2id: get failed: %s (%d)\n",
wiredtiger_strerror(rc), rc );
} else {
Debug( LDAP_DEBUG_TRACE, "<= wt_dn2id: got id=0x%lx\n",
*id );
}
return rc;
}
int
wt_dn2id_has_children(
Operation *op,
wt_ctx *wc,
ID id )
{
WT_SESSION *session = wc->session;
WT_CURSOR *cursor = wc->index_pid;
int rc;
uint64_t key = id;
if(!cursor){
rc = session->open_cursor(session, WT_INDEX_PID,
NULL, NULL, &cursor);
if( rc ){
Debug( LDAP_DEBUG_ANY,
"wt_dn2id_has_children: cursor open failed: %s (%d)\n",
wiredtiger_strerror(rc), rc );
goto done;
}
wc->index_pid = cursor;
}
cursor->set_key(cursor, key);
rc = cursor->search(cursor);
done:
#ifdef WT_CURSOR_CACHE
if(cursor){
cursor->reset(cursor);
}
#else
if(cursor){
cursor->close(cursor);
wc->index_pid = NULL;
}
#endif
return rc;
}
int
wt_dn2idl_db(
Operation *op,
wt_ctx *wc,
struct berval *ndn,
Entry *e,
ID *ids,
ID *stack)
{
WT_SESSION *session = wc->session;
WT_CURSOR *cursor = wc->dn2id;
int rc;
char *revdn = NULL;
size_t revdn_len;
char *key;
ID id, pid;
Debug( LDAP_DEBUG_TRACE,
"=> wt_dn2idl(\"%s\")\n",
ndn->bv_val );
revdn = mkrevdn(*ndn);
revdn_len = strlen(revdn);
if ( !cursor ) {
rc = session->open_cursor(session, WT_TABLE_DN2ID"(id, pid)",
NULL, NULL, &cursor);
if( rc ){
Debug( LDAP_DEBUG_ANY,
"wt_dn2idl: cursor open failed: %s (%d)\n",
wiredtiger_strerror(rc), rc );
goto done;
}
wc->dn2id = cursor;
}
cursor->set_key(cursor, revdn);
rc = cursor->search(cursor);
if( rc ){
Debug( LDAP_DEBUG_ANY,
"wt_dn2idl: search failed: %s (%d)\n",
wiredtiger_strerror(rc), rc );
goto done;
}
if( op->ors_scope == LDAP_SCOPE_CHILDREN ) {
cursor->next(cursor);
}
do {
rc = cursor->get_key(cursor, &key);
if( rc ){
Debug( LDAP_DEBUG_ANY,
"wt_dn2idl: get_key failed: %s (%d)\n",
wiredtiger_strerror(rc), rc );
goto done;
}
rc = cursor->get_value(cursor, &id, &pid);
if( rc ){
Debug( LDAP_DEBUG_ANY,
"wt_dn2id: get_value failed: %s (%d)\n",
wiredtiger_strerror(rc), rc );
goto done;
}
if( strncmp(revdn, key, revdn_len) ){
break;
}
if( op->ors_scope == LDAP_SCOPE_ONELEVEL && e->e_id != pid ){
goto next;
}
wt_idl_append_one(ids, id);
next:
rc = cursor->next(cursor);
}while(rc == 0);
if (rc == WT_NOTFOUND ) {
rc = LDAP_SUCCESS;
}
wt_idl_sort(ids, stack);
Debug( LDAP_DEBUG_TRACE,
"<= wt_dn2idl_db: size=%ld first=%ld last=%ld\n",
(long) ids[0],
(long) WT_IDL_FIRST(ids),
(long) WT_IDL_LAST(ids) );
done:
if(revdn){
ch_free(revdn);
}
#ifdef WT_CURSOR_CACHE
if(cursor){
cursor->reset(cursor);
}
#else
if(cursor){
cursor->close(cursor);
wc->dn2id = NULL;
}
#endif
return rc;
}
int
wt_dn2idl(
Operation *op,
wt_ctx *wc,
struct berval *ndn,
Entry *e,
ID *ids,
ID *stack)
{
struct wt_info *wi = (struct wt_info *) op->o_bd->be_private;
int rc;
Debug( LDAP_DEBUG_TRACE,
"=> wt_dn2idl(\"%s\")\n", ndn->bv_val );
if(op->ors_scope != LDAP_SCOPE_ONELEVEL &&
be_issuffix( op->o_bd, &e->e_nname )){
WT_IDL_ALL(wi, ids);
return 0;
}
if (wi->wi_flags & WT_USE_IDLCACHE) {
rc = wt_idlcache_get(wc, ndn, op->ors_scope, ids);
if (rc == 0) {
/* cache hit */
return rc;
}
/* cache miss */
}
if ( wi->wi_flags & WT_USE_IDLCACHE ) {
wt_idlcache_begin(wc, ndn, op->ors_scope);
}
rc = wt_dn2idl_db(op, wc, ndn, e, ids, stack);
if ( rc == 0 && wi->wi_flags & WT_USE_IDLCACHE ) {
wt_idlcache_set(wc, ndn, op->ors_scope, ids);
}
return rc;
}
/*
* Local variables:
* indent-tabs-mode: t
* tab-width: 4
* c-basic-offset: 4
* End:
*/