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
Hide 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
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
...
...
src/tests/get.vtc
View file @
aef58778
...
...
@@ -2,7 +2,7 @@
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 {
import ${vmod_file};
...
...
src/vmod_file.c
View file @
aef58778
...
...
@@ -26,7 +26,7 @@
* SUCH DAMAGE.
*/
/* for strdup() */
/* for strdup()
and timer_*
*/
#define _POSIX_C_SOURCE 200809L
#include "config.h"
...
...
@@ -38,103 +38,149 @@
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <stdio.h>
#include "cache/cache.h"
#include "vcl.h"
#include "vtim.h"
#include "vcc_if.h"
#define VFAIL(ctx, fmt, ...) \
#define FAIL(ctx, msg) \
VRT_fail((ctx), "vmod file failure: " msg)
#define VFAIL(ctx, fmt, ...) \
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
{
unsigned
magic
;
#define FILE_INFO_MAGIC 0x46ebec3d
struct
timespec
mtime
;
char
*
path
;
size_t
len
;
dev_t
dev
;
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
)
{
unsigned
magic
;
#define FILE_READER_MAGIC 0x08d18e5b
timer_t
timerid
;
struct
file_info
*
info
;
char
*
vcl_name
;
char
*
path
;
char
*
addr
;
size_t
len
;
VCL_DURATION
ttl
;
VCL_TIME
t_expire
;
char
*
errbuf
;
size_t
errlen
;
int
flags
;
};
static
inline
int
do_stat
(
VRT_CTX
,
struct
VPFX
(
file_reader
)
*
rdr
,
struct
stat
*
st
,
const
char
*
method
)
{
CHECK_OBJ_NOTNULL
(
ctx
,
VRT_CTX_MAGIC
);
CHECK_OBJ_NOTNULL
(
rdr
,
FILE_READER_MAGIC
);
AN
(
st
);
errno
=
0
;
if
(
stat
(
rdr
->
path
,
st
)
!=
0
)
{
VFAIL
(
ctx
,
"%s.%s(): cannot read info about %s: %s"
,
rdr
->
vcl_name
,
method
,
rdr
->
path
,
vstrerror
(
errno
));
return
(
-
1
);
}
if
(
!
S_ISREG
(
st
->
st_mode
))
{
VFAIL
(
ctx
,
"%s.%s(): %s is not a regular file"
,
rdr
->
vcl_name
,
method
,
rdr
->
path
);
return
(
-
1
);
}
return
(
0
);
}
static
int
update_map
(
VRT_CTX
,
struct
VPFX
(
file_reader
)
*
rdr
,
struct
stat
*
st
,
const
char
*
method
)
static
void
check
(
union
sigval
val
)
{
struct
VPFX
(
file_reader
)
*
rdr
;
struct
file_info
*
info
;
struct
stat
st
;
int
fd
;
void
*
addr
;
CHECK_OBJ_NOTNULL
(
ctx
,
VRT_CTX_MAGIC
);
CHECK_OBJ_NOTNULL
(
rdr
,
FILE_READER_MAGIC
);
CAST_OBJ_NOTNULL
(
rdr
,
val
.
sival_ptr
,
FILE_READER_MAGIC
);
CHECK_OBJ_NOTNULL
(
rdr
->
info
,
FILE_INFO_MAGIC
);
AN
(
st
);
info
=
rdr
->
info
;
AN
(
rdr
->
vcl_name
);
AN
(
rdr
->
errbuf
);
AN
(
info
->
path
);
errno
=
0
;
if
(
stat
(
info
->
path
,
&
st
)
!=
0
)
{
VERRMSG
(
rdr
,
"%s: cannot read info about %s: %s"
,
rdr
->
vcl_name
,
info
->
path
,
vstrerror
(
errno
));
VSL
(
SLT_Error
,
0
,
rdr
->
errbuf
);
rdr
->
flags
|=
RDR_ERROR
;
return
;
}
if
(
!
S_ISREG
(
st
.
st_mode
))
{
VERRMSG
(
rdr
,
"%s: %s is not a regular file"
,
rdr
->
vcl_name
,
info
->
path
);
VSL
(
SLT_Error
,
0
,
rdr
->
errbuf
);
rdr
->
flags
|=
RDR_ERROR
;
return
;
}
if
((
rdr
->
flags
&
(
RDR_INITIALIZED
|
RDR_MAPPED
))
&&
info
->
mtime
.
tv_sec
==
st
.
st_mtim
.
tv_sec
&&
info
->
mtime
.
tv_nsec
==
st
.
st_mtim
.
tv_nsec
&&
info
->
dev
==
st
.
st_dev
&&
info
->
ino
==
st
.
st_ino
)
{
AN
(
rdr
->
addr
);
return
;
}
if
(
rdr
->
flags
&
RDR_MAPPED
)
{
AN
(
rdr
->
addr
);
if
(
munmap
(
rdr
->
addr
,
info
->
len
)
!=
0
)
{
VERRMSG
(
rdr
,
"%s: unmap failed: %s"
,
rdr
->
vcl_name
,
vstrerror
(
errno
));
VSL
(
SLT_Error
,
0
,
rdr
->
errbuf
);
rdr
->
flags
|=
RDR_ERROR
;
return
;
}
}
rdr
->
flags
&=
~
RDR_MAPPED
;
errno
=
0
;
if
((
fd
=
open
(
rdr
->
path
,
O_RDWR
))
<
0
)
{
VFAIL
(
ctx
,
"%s.%s(): cannot open %s: %s"
,
rdr
->
vcl_name
,
method
,
rdr
->
path
,
vstrerror
(
errno
));
return
(
-
1
);
if
((
fd
=
open
(
info
->
path
,
O_RDWR
))
<
0
)
{
VERRMSG
(
rdr
,
"%s: cannot open %s: %s"
,
rdr
->
vcl_name
,
info
->
path
,
vstrerror
(
errno
));
VSL
(
SLT_Error
,
0
,
rdr
->
errbuf
);
rdr
->
flags
|=
RDR_ERROR
;
return
;
}
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
)
{
VFAIL
(
ctx
,
"%s.%s(): could not map %s: %s"
,
rdr
->
vcl_name
,
method
,
rdr
->
path
,
vstrerror
(
errno
));
VERRMSG
(
rdr
,
"%s: could not map %s: %s"
,
rdr
->
vcl_name
,
info
->
path
,
vstrerror
(
errno
));
VSL
(
SLT_Error
,
0
,
rdr
->
errbuf
);
rdr
->
flags
|=
RDR_ERROR
;
closefd
(
&
fd
);
return
(
-
1
)
;
return
;
}
closefd
(
&
fd
);
AN
(
addr
);
rdr
->
flags
|=
RDR_MAPPED
;
/*
* Add a terminating null byte, so that the mapped file can be
* 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_nsec
=
st
->
st_mtim
.
tv_nsec
;
info
->
dev
=
st
->
st_dev
;
info
->
ino
=
st
->
st_ino
;
info
->
mtime
.
tv_sec
=
st
.
st_mtim
.
tv_sec
;
info
->
mtime
.
tv_nsec
=
st
.
st_mtim
.
tv_nsec
;
info
->
dev
=
st
.
st_dev
;
info
->
ino
=
st
.
st_ino
;
info
->
len
=
st
.
st_size
+
1
;
rdr
->
addr
=
addr
;
rdr
->
len
=
st
->
st_size
+
1
;
return
(
0
);
rdr
->
flags
&=
~
RDR_ERROR
;
strcpy
(
rdr
->
errbuf
,
NO_ERR
);
rdr
->
flags
|=
RDR_INITIALIZED
;
return
;
}
VCL_VOID
...
...
@@ -144,7 +190,9 @@ vmod_reader__init(VRT_CTX, struct VPFX(file_reader) **rdrp,
{
struct
VPFX
(
file_reader
)
*
rdr
;
struct
file_info
*
info
;
struct
stat
st
;
struct
sigevent
sigev
;
timer_t
timerid
;
struct
itimerspec
timerspec
;
CHECK_OBJ_NOTNULL
(
ctx
,
VRT_CTX_MAGIC
);
AN
(
rdrp
);
...
...
@@ -156,6 +204,10 @@ vmod_reader__init(VRT_CTX, struct VPFX(file_reader) **rdrp,
VFAIL
(
ctx
,
"new %s: name is NULL"
,
vcl_name
);
return
;
}
if
(
*
name
==
'\0'
)
{
VFAIL
(
ctx
,
"new %s: name is empty"
,
vcl_name
);
return
;
}
if
(
ttl
<=
0
)
{
VFAIL
(
ctx
,
"new %s: ttl %.03f must be > 0"
,
vcl_name
,
ttl
);
return
;
...
...
@@ -177,16 +229,66 @@ vmod_reader__init(VRT_CTX, struct VPFX(file_reader) **rdrp,
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
->
vcl_name
=
strdup
(
vcl_name
);
rdr
->
path
=
strdup
(
name
);
rdr
->
ttl
=
ttl
;
rdr
->
t_expire
=
ctx
->
now
+
ttl
;
info
->
path
=
strdup
(
name
);
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
;
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
;
}
AN
(
rdr
->
flags
&
RDR_MAPPED
);
AN
(
rdr
->
addr
);
AN
(
rdr
->
info
->
mtime
.
tv_sec
);
AN
(
rdr
->
info
->
mtime
.
tv_nsec
);
*
rdrp
=
rdr
;
}
...
...
@@ -200,53 +302,56 @@ vmod_reader__fini(struct VPFX(file_reader) **rdrp)
return
;
TAKE_OBJ_NOTNULL
(
rdr
,
rdrp
,
FILE_READER_MAGIC
);
errno
=
0
;
if
(
munmap
(
rdr
->
addr
,
rdr
->
len
)
!=
0
)
VSL
(
SLT_Error
,
0
,
"unmap failed in %s finalization: %s"
,
rdr
->
vcl_name
,
vstrerror
(
errno
));
if
(
rdr
->
flags
&
RDR_TIMER_INIT
)
{
AN
(
rdr
->
vcl_name
);
errno
=
0
;
if
(
timer_delete
(
rdr
->
timerid
)
!=
0
)
VSL
(
SLT_Error
,
0
,
"vmod file %s finalization: "
"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
)
{
CHECK_OBJ
(
rdr
->
info
,
FILE_INFO_MAGIC
);
if
(
rdr
->
info
->
path
!=
NULL
)
free
(
rdr
->
info
->
path
);
FREE_OBJ
(
rdr
->
info
);
}
if
(
rdr
->
vcl_name
!=
NULL
)
free
(
rdr
->
vcl_name
);
if
(
rdr
->
path
!=
NULL
)
free
(
rdr
->
path
);
if
(
rdr
->
errbuf
!=
NULL
)
free
(
rdr
->
errbuf
);
FREE_OBJ
(
rdr
);
}
VCL_STRING
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
(
rdr
,
FILE_READER_MAGIC
);
CHECK_OBJ_NOTNULL
(
rdr
->
info
,
FILE_INFO_MAGIC
);
AN
(
rdr
->
addr
);
info
=
rdr
->
info
;
if
(
ctx
->
now
<=
rdr
->
t_expire
)
if
((
rdr
->
flags
&
RDR_ERROR
)
==
0
)
{
AN
(
rdr
->
addr
);
AN
(
rdr
->
flags
&
RDR_MAPPED
);
return
(
rdr
->
addr
);
}
if
(
do_stat
(
ctx
,
rdr
,
&
st
,
"get"
)
!=
0
)
return
(
NULL
);
if
(
info
->
mtime
.
tv_sec
==
st
.
st_mtim
.
tv_sec
&&
info
->
mtime
.
tv_nsec
==
st
.
st_mtim
.
tv_nsec
&&
info
->
dev
==
st
.
st_dev
&&
info
->
ino
==
st
.
st_ino
)
return
(
rdr
->
addr
);
if
(
update_map
(
ctx
,
rdr
,
&
st
,
"get"
)
!=
0
)
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
);
AN
(
strcmp
(
rdr
->
errbuf
,
NO_ERR
));
VFAIL
(
ctx
,
"%s.get(): %s"
,
rdr
->
vcl_name
,
rdr
->
errbuf
);
return
(
NULL
);
}
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