1 #include <tdb_compat.h>
3 /* Note: for the moment, we only need this file for TDB2, so we can
6 TDB_DATA tdb_null
= { NULL
, 0 };
8 /* Proxy which sets waitflag to false so we never block. */
9 static int lock_nonblock(int fd
, int rw
, off_t off
, off_t len
, bool waitflag
,
12 struct tdb_attribute_flock
*orig
= _orig
;
14 return orig
->lock(fd
, rw
, off
, len
, false, orig
->data
);
17 enum TDB_ERROR
tdb_transaction_start_nonblock(struct tdb_context
*tdb
)
19 union tdb_attribute locking
, orig
;
22 orig
.base
.attr
= TDB_ATTRIBUTE_FLOCK
;
23 ecode
= tdb_get_attribute(tdb
, &orig
);
24 if (ecode
!= TDB_SUCCESS
)
27 /* Replace locking function with our own. */
29 locking
.flock
.data
= &orig
;
30 locking
.flock
.lock
= lock_nonblock
;
32 ecode
= tdb_set_attribute(tdb
, &locking
);
33 if (ecode
!= TDB_SUCCESS
)
36 ecode
= tdb_transaction_start(tdb
);
37 tdb_unset_attribute(tdb
, TDB_ATTRIBUTE_FLOCK
);
41 /* For TDB1 tdbs, read traverse vs normal matters: write traverse
42 locks the entire thing! */
43 int64_t tdb_traverse_read_(struct tdb_context
*tdb
,
44 int (*fn
)(struct tdb_context
*,
51 if (tdb_get_flags(tdb
) & TDB_RDONLY
) {
52 return tdb_traverse(tdb
, fn
, p
);
55 tdb_add_flag(tdb
, TDB_RDONLY
);
56 ret
= tdb_traverse(tdb
, fn
, p
);
57 tdb_remove_flag(tdb
, TDB_RDONLY
);
62 * This handles TDB_CLEAR_IF_FIRST.
64 static enum TDB_ERROR
clear_if_first(int fd
, void *unused
)
66 /* We hold a lock offset 4 always, so we can tell if anyone else is. */
70 fl
.l_whence
= SEEK_SET
;
71 fl
.l_start
= 4; /* ACTIVE_LOCK */
74 if (fcntl(fd
, F_SETLK
, &fl
) == 0) {
75 /* We must be first ones to open it w/ TDB_CLEAR_IF_FIRST! */
76 if (ftruncate(fd
, 0) != 0) {
81 if (fcntl(fd
, F_SETLKW
, &fl
) != 0) {
88 tdb_open_compat_(const char *name
, int hash_size
,
89 int tdb_flags
, int open_flags
, mode_t mode
,
90 void (*log_fn
)(struct tdb_context
*,
97 union tdb_attribute cif
, log
, hash
, max_dead
, hsize
, *attr
= NULL
;
99 if (!getenv("TDB_COMPAT_USE_TDB2")) {
100 tdb_flags
|= TDB_VERSION1
;
104 log
.log
.base
.attr
= TDB_ATTRIBUTE_LOG
;
105 log
.log
.base
.next
= NULL
;
107 log
.log
.data
= log_data
;
111 if (tdb_flags
& TDB_CLEAR_IF_FIRST
) {
112 cif
.openhook
.base
.attr
= TDB_ATTRIBUTE_OPENHOOK
;
113 cif
.openhook
.base
.next
= attr
;
114 cif
.openhook
.fn
= clear_if_first
;
116 tdb_flags
&= ~TDB_CLEAR_IF_FIRST
;
119 if (tdb_flags
& TDB_INCOMPATIBLE_HASH
) {
120 if (tdb_flags
& TDB_VERSION1
) {
121 hash
.hash
.base
.attr
= TDB_ATTRIBUTE_HASH
;
122 hash
.hash
.base
.next
= attr
;
123 hash
.hash
.fn
= tdb1_incompatible_hash
;
126 tdb_flags
&= ~TDB_INCOMPATIBLE_HASH
;
129 if (tdb_flags
& TDB_VOLATILE
) {
130 if (tdb_flags
& TDB_VERSION1
) {
131 max_dead
.base
.attr
= TDB_ATTRIBUTE_TDB1_MAX_DEAD
;
132 max_dead
.base
.next
= attr
;
133 max_dead
.tdb1_max_dead
.max_dead
= 5;
136 tdb_flags
&= ~TDB_VOLATILE
;
139 if (hash_size
&& (tdb_flags
& TDB_VERSION1
) && (open_flags
& O_CREAT
)) {
140 hsize
.base
.attr
= TDB_ATTRIBUTE_TDB1_HASHSIZE
;
141 hsize
.base
.next
= attr
;
142 hsize
.tdb1_hashsize
.hsize
= hash_size
;
146 /* Testsuite uses this to speed things up. */
147 if (getenv("TDB_NO_FSYNC")) {
148 tdb_flags
|= TDB_NOSYNC
;
151 return tdb_open(name
, tdb_flags
|TDB_ALLOW_NESTING
, open_flags
, mode
,
155 /* We only need these for the CLEAR_IF_FIRST lock. */
156 static int reacquire_cif_lock(struct tdb_context
*tdb
, bool *fail
)
159 union tdb_attribute cif
;
161 cif
.openhook
.base
.attr
= TDB_ATTRIBUTE_OPENHOOK
;
162 cif
.openhook
.base
.next
= NULL
;
164 if (tdb_get_attribute(tdb
, &cif
) != TDB_SUCCESS
165 || cif
.openhook
.fn
!= clear_if_first
) {
169 /* We hold a lock offset 4 always, so we can tell if anyone else is. */
171 fl
.l_whence
= SEEK_SET
;
172 fl
.l_start
= 4; /* ACTIVE_LOCK */
174 if (fcntl(tdb_fd(tdb
), F_SETLKW
, &fl
) != 0) {
181 int tdb_reopen(struct tdb_context
*tdb
)
184 return reacquire_cif_lock(tdb
, &unused
);
187 int tdb_reopen_all(int parent_longlived
)
191 if (parent_longlived
) {
195 tdb_foreach(reacquire_cif_lock
, &fail
);