Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
libvmod-file
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
uplex-varnish
libvmod-file
Commits
aef58778
Commit
aef58778
authored
Sep 20, 2019
by
Geoff Simmons
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactor to check files asynchrously using POSIX timers.
parent
101c810d
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
192 additions
and
87 deletions
+192
-87
Makefile.am
src/Makefile.am
+1
-1
get.vtc
src/tests/get.vtc
+1
-1
vmod_file.c
src/vmod_file.c
+190
-85
No files found.
src/Makefile.am
View file @
aef58778
AUTOMAKE_OPTIONS
=
subdir-objects
AUTOMAKE_OPTIONS
=
subdir-objects
AM_CFLAGS
=
$(VARNISHAPI_CFLAGS)
-Wall
-Werror
-Wextra
-std
=
c99
AM_CFLAGS
=
$(VARNISHAPI_CFLAGS)
-Wall
-Werror
-Wextra
-std
=
c99
AM_LDFLAGS
=
$(VARNISHAPI_LIBS)
-ldl
AM_LDFLAGS
=
$(VARNISHAPI_LIBS)
-ldl
-lrt
vmod_LTLIBRARIES
=
libvmod_file.la
vmod_LTLIBRARIES
=
libvmod_file.la
...
...
src/tests/get.vtc
View file @
aef58778
...
@@ -2,7 +2,7 @@
...
@@ -2,7 +2,7 @@
varnishtest "reader constructor and .get()"
varnishtest "reader constructor and .get()"
shell {echo "foo bar baz quux" > ${tmpdir}/file}
shell {echo
-n
"foo bar baz quux" > ${tmpdir}/file}
varnish v1 -vcl+backend {
varnish v1 -vcl+backend {
import ${vmod_file};
import ${vmod_file};
...
...
src/vmod_file.c
View file @
aef58778
...
@@ -26,7 +26,7 @@
...
@@ -26,7 +26,7 @@
* SUCH DAMAGE.
* SUCH DAMAGE.
*/
*/
/* for strdup() */
/* for strdup()
and timer_*
*/
#define _POSIX_C_SOURCE 200809L
#define _POSIX_C_SOURCE 200809L
#include "config.h"
#include "config.h"
...
@@ -38,103 +38,149 @@
...
@@ -38,103 +38,149 @@
#include <fcntl.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdlib.h>
#include <string.h>
#include <string.h>
#include <signal.h>
#include <stdio.h>
#include "cache/cache.h"
#include "cache/cache.h"
#include "vcl.h"
#include "vcl.h"
#include "vtim.h"
#include "vcc_if.h"
#include "vcc_if.h"
#define FAIL(ctx, msg) \
VRT_fail((ctx), "vmod file failure: " msg)
#define VFAIL(ctx, fmt, ...) \
#define VFAIL(ctx, fmt, ...) \
VRT_fail((ctx), "vmod file failure: " fmt, __VA_ARGS__)
VRT_fail((ctx), "vmod file failure: " fmt, __VA_ARGS__)
#define VERRMSG(rdr, fmt, ...) \
snprintf((rdr)->errbuf, (rdr)->errlen, "vmod file failure: " fmt, \
__VA_ARGS__)
#define INIT_SLEEP_INTERVAL 0.001
#define ERRMSG_LEN 128
#define NO_ERR ("No error")
struct
file_info
{
struct
file_info
{
unsigned
magic
;
unsigned
magic
;
#define FILE_INFO_MAGIC 0x46ebec3d
#define FILE_INFO_MAGIC 0x46ebec3d
struct
timespec
mtime
;
struct
timespec
mtime
;
char
*
path
;
size_t
len
;
dev_t
dev
;
dev_t
dev
;
ino_t
ino
;
ino_t
ino
;
};
};
#define RDR_INITIALIZED (1 << 0)
#define RDR_ERROR (1 << 1)
#define RDR_MAPPED (1 << 2)
#define RDR_TIMER_INIT (1 << 3)
struct
VPFX
(
file_reader
)
{
struct
VPFX
(
file_reader
)
{
unsigned
magic
;
unsigned
magic
;
#define FILE_READER_MAGIC 0x08d18e5b
#define FILE_READER_MAGIC 0x08d18e5b
timer_t
timerid
;
struct
file_info
*
info
;
struct
file_info
*
info
;
char
*
vcl_name
;
char
*
vcl_name
;
char
*
path
;
char
*
addr
;
char
*
addr
;
size_t
len
;
char
*
errbuf
;
VCL_DURATION
ttl
;
size_t
errlen
;
VCL_TIME
t_expire
;
int
flags
;
};
};
static
inline
int
static
void
do_stat
(
VRT_CTX
,
struct
VPFX
(
file_reader
)
*
rdr
,
struct
stat
*
st
,
check
(
union
sigval
val
)
const
char
*
method
)
{
{
CHECK_OBJ_NOTNULL
(
ctx
,
VRT_CTX_MAGIC
);
struct
VPFX
(
file_reader
)
*
rdr
;
CHECK_OBJ_NOTNULL
(
rdr
,
FILE_READER_MAGIC
);
struct
file_info
*
info
;
AN
(
st
);
struct
stat
st
;
int
fd
;
void
*
addr
;
CAST_OBJ_NOTNULL
(
rdr
,
val
.
sival_ptr
,
FILE_READER_MAGIC
);
CHECK_OBJ_NOTNULL
(
rdr
->
info
,
FILE_INFO_MAGIC
);
info
=
rdr
->
info
;
AN
(
rdr
->
vcl_name
);
AN
(
rdr
->
errbuf
);
AN
(
info
->
path
);
errno
=
0
;
errno
=
0
;
if
(
stat
(
rdr
->
path
,
st
)
!=
0
)
{
if
(
stat
(
info
->
path
,
&
st
)
!=
0
)
{
VFAIL
(
ctx
,
"%s.%s(): cannot read info about %s: %s"
,
VERRMSG
(
rdr
,
"%s: cannot read info about %s: %s"
,
rdr
->
vcl_name
,
rdr
->
vcl_name
,
method
,
rdr
->
path
,
vstrerror
(
errno
));
info
->
path
,
vstrerror
(
errno
));
return
(
-
1
);
VSL
(
SLT_Error
,
0
,
rdr
->
errbuf
);
rdr
->
flags
|=
RDR_ERROR
;
return
;
}
}
if
(
!
S_ISREG
(
st
->
st_mode
))
{
if
(
!
S_ISREG
(
st
.
st_mode
))
{
VFAIL
(
ctx
,
"%s.%s(): %s is not a regular file"
,
rdr
->
vcl_name
,
VERRMSG
(
rdr
,
"%s: %s is not a regular file"
,
rdr
->
vcl_name
,
method
,
rdr
->
path
);
info
->
path
);
return
(
-
1
);
VSL
(
SLT_Error
,
0
,
rdr
->
errbuf
);
rdr
->
flags
|=
RDR_ERROR
;
return
;
}
}
return
(
0
);
}
static
int
if
((
rdr
->
flags
&
(
RDR_INITIALIZED
|
RDR_MAPPED
))
update_map
(
VRT_CTX
,
struct
VPFX
(
file_reader
)
*
rdr
,
struct
stat
*
st
,
&&
info
->
mtime
.
tv_sec
==
st
.
st_mtim
.
tv_sec
const
char
*
method
)
&&
info
->
mtime
.
tv_nsec
==
st
.
st_mtim
.
tv_nsec
{
&&
info
->
dev
==
st
.
st_dev
&&
info
->
ino
==
st
.
st_ino
)
{
struct
file_info
*
info
;
AN
(
rdr
->
addr
)
;
int
fd
;
return
;
void
*
addr
;
}
CHECK_OBJ_NOTNULL
(
ctx
,
VRT_CTX_MAGIC
);
if
(
rdr
->
flags
&
RDR_MAPPED
)
{
CHECK_OBJ_NOTNULL
(
rdr
,
FILE_READER_MAGIC
);
AN
(
rdr
->
addr
);
CHECK_OBJ_NOTNULL
(
rdr
->
info
,
FILE_INFO_MAGIC
);
if
(
munmap
(
rdr
->
addr
,
info
->
len
)
!=
0
)
{
AN
(
st
);
VERRMSG
(
rdr
,
"%s: unmap failed: %s"
,
rdr
->
vcl_name
,
info
=
rdr
->
info
;
vstrerror
(
errno
));
VSL
(
SLT_Error
,
0
,
rdr
->
errbuf
);
rdr
->
flags
|=
RDR_ERROR
;
return
;
}
}
rdr
->
flags
&=
~
RDR_MAPPED
;
errno
=
0
;
errno
=
0
;
if
((
fd
=
open
(
rdr
->
path
,
O_RDWR
))
<
0
)
{
if
((
fd
=
open
(
info
->
path
,
O_RDWR
))
<
0
)
{
VFAIL
(
ctx
,
"%s.%s(): cannot open %s: %s"
,
rdr
->
vcl_name
,
method
,
VERRMSG
(
rdr
,
"%s: cannot open %s: %s"
,
rdr
->
vcl_name
,
rdr
->
path
,
vstrerror
(
errno
));
info
->
path
,
vstrerror
(
errno
));
return
(
-
1
);
VSL
(
SLT_Error
,
0
,
rdr
->
errbuf
);
rdr
->
flags
|=
RDR_ERROR
;
return
;
}
}
errno
=
0
;
errno
=
0
;
if
((
addr
=
mmap
(
NULL
,
st
->
st_size
+
1
,
PROT_READ
|
PROT_WRITE
,
if
((
addr
=
mmap
(
NULL
,
st
.
st_size
+
1
,
PROT_READ
|
PROT_WRITE
,
MAP_PRIVATE
,
fd
,
0
))
==
MAP_FAILED
)
{
MAP_PRIVATE
,
fd
,
0
))
==
MAP_FAILED
)
{
VFAIL
(
ctx
,
"%s.%s(): could not map %s: %s"
,
rdr
->
vcl_name
,
VERRMSG
(
rdr
,
"%s: could not map %s: %s"
,
rdr
->
vcl_name
,
method
,
rdr
->
path
,
vstrerror
(
errno
));
info
->
path
,
vstrerror
(
errno
));
VSL
(
SLT_Error
,
0
,
rdr
->
errbuf
);
rdr
->
flags
|=
RDR_ERROR
;
closefd
(
&
fd
);
closefd
(
&
fd
);
return
(
-
1
)
;
return
;
}
}
closefd
(
&
fd
);
closefd
(
&
fd
);
AN
(
addr
);
rdr
->
flags
|=
RDR_MAPPED
;
/*
/*
* Add a terminating null byte, so that the mapped file can be
* Add a terminating null byte, so that the mapped file can be
* used as a VCL_STRING or a C string.
* used as a VCL_STRING or a C string.
*/
*/
*
((
char
*
)(
addr
+
st
->
st_size
))
=
'\0'
;
*
((
char
*
)(
addr
+
st
.
st_size
))
=
'\0'
;
info
->
mtime
.
tv_sec
=
st
->
st_mtim
.
tv_sec
;
info
->
mtime
.
tv_sec
=
st
.
st_mtim
.
tv_sec
;
info
->
mtime
.
tv_nsec
=
st
->
st_mtim
.
tv_nsec
;
info
->
mtime
.
tv_nsec
=
st
.
st_mtim
.
tv_nsec
;
info
->
dev
=
st
->
st_dev
;
info
->
dev
=
st
.
st_dev
;
info
->
ino
=
st
->
st_ino
;
info
->
ino
=
st
.
st_ino
;
info
->
len
=
st
.
st_size
+
1
;
rdr
->
addr
=
addr
;
rdr
->
addr
=
addr
;
rdr
->
len
=
st
->
st_size
+
1
;
rdr
->
flags
&=
~
RDR_ERROR
;
return
(
0
);
strcpy
(
rdr
->
errbuf
,
NO_ERR
);
rdr
->
flags
|=
RDR_INITIALIZED
;
return
;
}
}
VCL_VOID
VCL_VOID
...
@@ -144,7 +190,9 @@ vmod_reader__init(VRT_CTX, struct VPFX(file_reader) **rdrp,
...
@@ -144,7 +190,9 @@ vmod_reader__init(VRT_CTX, struct VPFX(file_reader) **rdrp,
{
{
struct
VPFX
(
file_reader
)
*
rdr
;
struct
VPFX
(
file_reader
)
*
rdr
;
struct
file_info
*
info
;
struct
file_info
*
info
;
struct
stat
st
;
struct
sigevent
sigev
;
timer_t
timerid
;
struct
itimerspec
timerspec
;
CHECK_OBJ_NOTNULL
(
ctx
,
VRT_CTX_MAGIC
);
CHECK_OBJ_NOTNULL
(
ctx
,
VRT_CTX_MAGIC
);
AN
(
rdrp
);
AN
(
rdrp
);
...
@@ -156,6 +204,10 @@ vmod_reader__init(VRT_CTX, struct VPFX(file_reader) **rdrp,
...
@@ -156,6 +204,10 @@ vmod_reader__init(VRT_CTX, struct VPFX(file_reader) **rdrp,
VFAIL
(
ctx
,
"new %s: name is NULL"
,
vcl_name
);
VFAIL
(
ctx
,
"new %s: name is NULL"
,
vcl_name
);
return
;
return
;
}
}
if
(
*
name
==
'\0'
)
{
VFAIL
(
ctx
,
"new %s: name is empty"
,
vcl_name
);
return
;
}
if
(
ttl
<=
0
)
{
if
(
ttl
<=
0
)
{
VFAIL
(
ctx
,
"new %s: ttl %.03f must be > 0"
,
vcl_name
,
ttl
);
VFAIL
(
ctx
,
"new %s: ttl %.03f must be > 0"
,
vcl_name
,
ttl
);
return
;
return
;
...
@@ -177,16 +229,66 @@ vmod_reader__init(VRT_CTX, struct VPFX(file_reader) **rdrp,
...
@@ -177,16 +229,66 @@ vmod_reader__init(VRT_CTX, struct VPFX(file_reader) **rdrp,
return
;
return
;
}
}
rdr
->
errlen
=
ERRMSG_LEN
+
strlen
(
name
)
+
strlen
(
vcl_name
);
errno
=
0
;
rdr
->
errbuf
=
malloc
(
rdr
->
errlen
);
if
(
rdr
->
errbuf
==
NULL
)
{
VFAIL
(
ctx
,
"new %s: allocating error message buffer: %s"
,
vcl_name
,
vstrerror
(
errno
));
return
;
}
rdr
->
info
=
info
;
rdr
->
info
=
info
;
rdr
->
vcl_name
=
strdup
(
vcl_name
);
rdr
->
vcl_name
=
strdup
(
vcl_name
);
rdr
->
path
=
strdup
(
name
);
info
->
path
=
strdup
(
name
);
rdr
->
ttl
=
ttl
;
rdr
->
t_expire
=
ctx
->
now
+
ttl
;
memset
(
&
sigev
,
0
,
sizeof
(
sigev
));
sigev
.
sigev_notify
=
SIGEV_THREAD
;
sigev
.
sigev_notify_function
=
check
;
sigev
.
sigev_value
.
sival_ptr
=
rdr
;
errno
=
0
;
if
(
timer_create
(
CLOCK_MONOTONIC
,
&
sigev
,
&
timerid
)
!=
0
)
{
VFAIL
(
ctx
,
"new %s: cannot create update timer: %s"
,
vcl_name
,
vstrerror
(
errno
));
return
;
}
rdr
->
timerid
=
timerid
;
if
(
do_stat
(
ctx
,
rdr
,
&
st
,
"new"
)
!=
0
)
timerspec
.
it_value
.
tv_sec
=
0
;
timerspec
.
it_value
.
tv_nsec
=
1
;
timerspec
.
it_interval
.
tv_sec
=
(
time_t
)
ttl
;
assert
(
timerspec
.
it_interval
.
tv_sec
-
ttl
<
1
.);
timerspec
.
it_interval
.
tv_nsec
=
(
long
)(
1e9
*
(
timerspec
.
it_interval
.
tv_sec
-
ttl
));
errno
=
0
;
if
(
timer_settime
(
timerid
,
0
,
&
timerspec
,
NULL
)
!=
0
)
{
VFAIL
(
ctx
,
"new %s: cannot start update timer: %s"
,
vcl_name
,
vstrerror
(
errno
));
return
;
return
;
if
(
update_map
(
ctx
,
rdr
,
&
st
,
"new"
)
!=
0
)
}
rdr
->
flags
|=
RDR_TIMER_INIT
;
AZ
(
rdr
->
addr
);
AZ
(
rdr
->
info
->
mtime
.
tv_sec
);
AZ
(
rdr
->
info
->
mtime
.
tv_nsec
);
AZ
(
rdr
->
flags
&
(
RDR_INITIALIZED
|
RDR_ERROR
));
do
{
VTIM_sleep
(
INIT_SLEEP_INTERVAL
);
}
while
((
rdr
->
flags
&
(
RDR_INITIALIZED
|
RDR_ERROR
))
==
0
);
if
(
rdr
->
flags
&
RDR_ERROR
)
{
AN
(
strcmp
(
rdr
->
errbuf
,
NO_ERR
));
VFAIL
(
ctx
,
"new %s: %s"
,
vcl_name
,
rdr
->
errbuf
);
return
;
return
;
}
AN
(
rdr
->
flags
&
RDR_MAPPED
);
AN
(
rdr
->
addr
);
AN
(
rdr
->
info
->
mtime
.
tv_sec
);
AN
(
rdr
->
info
->
mtime
.
tv_nsec
);
*
rdrp
=
rdr
;
*
rdrp
=
rdr
;
}
}
...
@@ -200,53 +302,56 @@ vmod_reader__fini(struct VPFX(file_reader) **rdrp)
...
@@ -200,53 +302,56 @@ vmod_reader__fini(struct VPFX(file_reader) **rdrp)
return
;
return
;
TAKE_OBJ_NOTNULL
(
rdr
,
rdrp
,
FILE_READER_MAGIC
);
TAKE_OBJ_NOTNULL
(
rdr
,
rdrp
,
FILE_READER_MAGIC
);
if
(
rdr
->
flags
&
RDR_TIMER_INIT
)
{
AN
(
rdr
->
vcl_name
);
errno
=
0
;
errno
=
0
;
if
(
munmap
(
rdr
->
addr
,
rdr
->
len
)
!=
0
)
if
(
timer_delete
(
rdr
->
timerid
)
!=
0
)
VSL
(
SLT_Error
,
0
,
"unmap failed in %s finalization: %s"
,
VSL
(
SLT_Error
,
0
,
"vmod file %s finalization: "
rdr
->
vcl_name
,
vstrerror
(
errno
));
"cannot delete timer: %s"
,
rdr
->
vcl_name
,
vstrerror
(
errno
));
}
if
(
rdr
->
flags
&
RDR_MAPPED
)
{
CHECK_OBJ_NOTNULL
(
rdr
->
info
,
FILE_INFO_MAGIC
);
AN
(
rdr
->
addr
);
AN
(
rdr
->
vcl_name
);
errno
=
0
;
if
(
munmap
(
rdr
->
addr
,
rdr
->
info
->
len
)
!=
0
)
VSL
(
SLT_Error
,
0
,
"vmod file %s finalization: "
"unmap failed: %s"
,
rdr
->
vcl_name
,
vstrerror
(
errno
));
}
if
(
rdr
->
info
!=
NULL
)
{
if
(
rdr
->
info
!=
NULL
)
{
CHECK_OBJ
(
rdr
->
info
,
FILE_INFO_MAGIC
);
CHECK_OBJ
(
rdr
->
info
,
FILE_INFO_MAGIC
);
if
(
rdr
->
info
->
path
!=
NULL
)
free
(
rdr
->
info
->
path
);
FREE_OBJ
(
rdr
->
info
);
FREE_OBJ
(
rdr
->
info
);
}
}
if
(
rdr
->
vcl_name
!=
NULL
)
if
(
rdr
->
vcl_name
!=
NULL
)
free
(
rdr
->
vcl_name
);
free
(
rdr
->
vcl_name
);
if
(
rdr
->
path
!=
NULL
)
if
(
rdr
->
errbuf
!=
NULL
)
free
(
rdr
->
path
);
free
(
rdr
->
errbuf
);
FREE_OBJ
(
rdr
);
FREE_OBJ
(
rdr
);
}
}
VCL_STRING
VCL_STRING
vmod_reader_get
(
VRT_CTX
,
struct
VPFX
(
file_reader
)
*
rdr
)
vmod_reader_get
(
VRT_CTX
,
struct
VPFX
(
file_reader
)
*
rdr
)
{
{
struct
file_info
*
info
;
struct
stat
st
;
double
intervals
,
whole
,
frac
;
CHECK_OBJ_NOTNULL
(
ctx
,
VRT_CTX_MAGIC
);
CHECK_OBJ_NOTNULL
(
ctx
,
VRT_CTX_MAGIC
);
CHECK_OBJ_NOTNULL
(
rdr
,
FILE_READER_MAGIC
);
CHECK_OBJ_NOTNULL
(
rdr
,
FILE_READER_MAGIC
);
CHECK_OBJ_NOTNULL
(
rdr
->
info
,
FILE_INFO_MAGIC
);
AN
(
rdr
->
addr
);
info
=
rdr
->
info
;
if
(
ctx
->
now
<=
rdr
->
t_expire
)
return
(
rdr
->
addr
);
if
(
do_stat
(
ctx
,
rdr
,
&
st
,
"get"
)
!=
0
)
return
(
NULL
);
if
(
info
->
mtime
.
tv_sec
==
st
.
st_mtim
.
tv_sec
if
(
(
rdr
->
flags
&
RDR_ERROR
)
==
0
)
{
&&
info
->
mtime
.
tv_nsec
==
st
.
st_mtim
.
tv_nsec
AN
(
rdr
->
addr
);
&&
info
->
dev
==
st
.
st_dev
&&
info
->
ino
==
st
.
st_ino
)
AN
(
rdr
->
flags
&
RDR_MAPPED
);
return
(
rdr
->
addr
);
return
(
rdr
->
addr
);
}
if
(
update_map
(
ctx
,
rdr
,
&
st
,
"get"
)
!=
0
)
AN
(
strcmp
(
rdr
->
errbuf
,
NO_ERR
));
VFAIL
(
ctx
,
"%s.get(): %s"
,
rdr
->
vcl_name
,
rdr
->
errbuf
);
return
(
NULL
);
return
(
NULL
);
intervals
=
(
ctx
->
now
-
rdr
->
t_expire
)
/
rdr
->
ttl
;
frac
=
modf
(
intervals
,
&
whole
);
rdr
->
t_expire
=
ctx
->
now
+
(
rdr
->
ttl
*
(
1
.
-
frac
));
return
(
rdr
->
addr
);
}
}
VCL_STRING
VCL_STRING
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment