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 enum TDB_ERROR
tdb_chainlock_nonblock(struct tdb_context
*tdb
, TDB_DATA key
)
43 union tdb_attribute locking
, orig
;
46 orig
.base
.attr
= TDB_ATTRIBUTE_FLOCK
;
47 ecode
= tdb_get_attribute(tdb
, &orig
);
48 if (ecode
!= TDB_SUCCESS
)
51 /* Replace locking function with our own. */
53 locking
.flock
.data
= &orig
;
54 locking
.flock
.lock
= lock_nonblock
;
56 ecode
= tdb_set_attribute(tdb
, &locking
);
57 if (ecode
!= TDB_SUCCESS
)
60 ecode
= tdb_chainlock(tdb
, key
);
61 tdb_unset_attribute(tdb
, TDB_ATTRIBUTE_FLOCK
);
65 /* For TDB1 tdbs, read traverse vs normal matters: write traverse
66 locks the entire thing! */
67 int64_t tdb_traverse_read_(struct tdb_context
*tdb
,
68 int (*fn
)(struct tdb_context
*,
75 if (tdb_get_flags(tdb
) & TDB_RDONLY
) {
76 return tdb_traverse(tdb
, fn
, p
);
79 tdb_add_flag(tdb
, TDB_RDONLY
);
80 ret
= tdb_traverse(tdb
, fn
, p
);
81 tdb_remove_flag(tdb
, TDB_RDONLY
);
86 * This handles TDB_CLEAR_IF_FIRST.
88 static enum TDB_ERROR
clear_if_first(int fd
, void *unused
)
90 /* We hold a lock offset 4 always, so we can tell if anyone else is. */
94 fl
.l_whence
= SEEK_SET
;
95 fl
.l_start
= 4; /* ACTIVE_LOCK */
98 if (fcntl(fd
, F_SETLK
, &fl
) == 0) {
99 /* We must be first ones to open it w/ TDB_CLEAR_IF_FIRST! */
100 if (ftruncate(fd
, 0) != 0) {
105 if (fcntl(fd
, F_SETLKW
, &fl
) != 0) {
112 tdb_open_compat_(const char *name
, int hash_size
,
113 int tdb_flags
, int open_flags
, mode_t mode
,
114 void (*log_fn
)(struct tdb_context
*,
121 union tdb_attribute cif
, log
, hash
, max_dead
, hsize
, *attr
= NULL
;
123 if (!getenv("TDB_COMPAT_USE_TDB2")) {
124 tdb_flags
|= TDB_VERSION1
;
128 log
.log
.base
.attr
= TDB_ATTRIBUTE_LOG
;
129 log
.log
.base
.next
= NULL
;
131 log
.log
.data
= log_data
;
135 if (tdb_flags
& TDB_CLEAR_IF_FIRST
) {
136 cif
.openhook
.base
.attr
= TDB_ATTRIBUTE_OPENHOOK
;
137 cif
.openhook
.base
.next
= attr
;
138 cif
.openhook
.fn
= clear_if_first
;
140 tdb_flags
&= ~TDB_CLEAR_IF_FIRST
;
143 if (tdb_flags
& TDB_INCOMPATIBLE_HASH
) {
144 if (tdb_flags
& TDB_VERSION1
) {
145 hash
.hash
.base
.attr
= TDB_ATTRIBUTE_HASH
;
146 hash
.hash
.base
.next
= attr
;
147 hash
.hash
.fn
= tdb1_incompatible_hash
;
150 tdb_flags
&= ~TDB_INCOMPATIBLE_HASH
;
153 if (tdb_flags
& TDB_VOLATILE
) {
154 if (tdb_flags
& TDB_VERSION1
) {
155 max_dead
.base
.attr
= TDB_ATTRIBUTE_TDB1_MAX_DEAD
;
156 max_dead
.base
.next
= attr
;
157 max_dead
.tdb1_max_dead
.max_dead
= 5;
160 tdb_flags
&= ~TDB_VOLATILE
;
163 if (hash_size
&& (tdb_flags
& TDB_VERSION1
) && (open_flags
& O_CREAT
)) {
164 hsize
.base
.attr
= TDB_ATTRIBUTE_TDB1_HASHSIZE
;
165 hsize
.base
.next
= attr
;
166 hsize
.tdb1_hashsize
.hsize
= hash_size
;
170 /* Testsuite uses this to speed things up. */
171 if (getenv("TDB_NO_FSYNC")) {
172 tdb_flags
|= TDB_NOSYNC
;
175 return tdb_open(name
, tdb_flags
|TDB_ALLOW_NESTING
, open_flags
, mode
,
179 /* We only need these for the CLEAR_IF_FIRST lock. */
180 static int reacquire_cif_lock(struct tdb_context
*tdb
, bool *fail
)
183 union tdb_attribute cif
;
185 cif
.openhook
.base
.attr
= TDB_ATTRIBUTE_OPENHOOK
;
186 cif
.openhook
.base
.next
= NULL
;
188 if (tdb_get_attribute(tdb
, &cif
) != TDB_SUCCESS
189 || cif
.openhook
.fn
!= clear_if_first
) {
193 /* We hold a lock offset 4 always, so we can tell if anyone else is. */
195 fl
.l_whence
= SEEK_SET
;
196 fl
.l_start
= 4; /* ACTIVE_LOCK */
198 if (fcntl(tdb_fd(tdb
), F_SETLKW
, &fl
) != 0) {
205 int tdb_reopen(struct tdb_context
*tdb
)
208 return reacquire_cif_lock(tdb
, &unused
);
211 int tdb_reopen_all(int parent_longlived
)
215 if (parent_longlived
) {
219 tdb_foreach(reacquire_cif_lock
, &fail
);