mirror of
https://github.com/aptly-dev/aptly.git
synced 2026-06-08 05:50:47 +00:00
Merge pull request #300 from vincentbernat/fix/api-serve-lock
Add a flag to unlock database after each API request
This commit is contained in:
+50
-3
@@ -22,17 +22,36 @@ func apiVersion(c *gin.Context) {
|
|||||||
c.JSON(200, gin.H{"Version": aptly.Version})
|
c.JSON(200, gin.H{"Version": aptly.Version})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Periodically flushes CollectionFactory to free up memory used by collections,
|
const (
|
||||||
// flushing caches.
|
ACQUIREDB = iota
|
||||||
|
RELEASEDB
|
||||||
|
)
|
||||||
|
|
||||||
|
// Periodically flushes CollectionFactory to free up memory used by
|
||||||
|
// collections, flushing caches. If the two channels are provided,
|
||||||
|
// they are used to acquire and release the database.
|
||||||
//
|
//
|
||||||
// Should be run in goroutine!
|
// Should be run in goroutine!
|
||||||
func cacheFlusher() {
|
func cacheFlusher(requests chan int, acks chan error) {
|
||||||
ticker := time.Tick(15 * time.Minute)
|
ticker := time.Tick(15 * time.Minute)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
<-ticker
|
<-ticker
|
||||||
|
|
||||||
func() {
|
func() {
|
||||||
|
// lock database if needed
|
||||||
|
if requests != nil {
|
||||||
|
requests <- ACQUIREDB
|
||||||
|
err := <-acks
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
requests <- RELEASEDB
|
||||||
|
<-acks
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
// lock everything to eliminate in-progress calls
|
// lock everything to eliminate in-progress calls
|
||||||
r := context.CollectionFactory().RemoteRepoCollection()
|
r := context.CollectionFactory().RemoteRepoCollection()
|
||||||
r.Lock()
|
r.Lock()
|
||||||
@@ -56,6 +75,34 @@ func cacheFlusher() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Acquire database lock and release it when not needed anymore. Two
|
||||||
|
// channels must be provided. The first one is to receive requests to
|
||||||
|
// acquire/release the database and the second one is to send acks.
|
||||||
|
//
|
||||||
|
// Should be run in a goroutine!
|
||||||
|
func acquireDatabase(requests chan int, acks chan error) {
|
||||||
|
clients := 0
|
||||||
|
for {
|
||||||
|
request := <-requests
|
||||||
|
switch request {
|
||||||
|
case ACQUIREDB:
|
||||||
|
if clients == 0 {
|
||||||
|
acks <- context.ReOpenDatabase()
|
||||||
|
} else {
|
||||||
|
acks <- nil
|
||||||
|
}
|
||||||
|
clients++
|
||||||
|
case RELEASEDB:
|
||||||
|
clients--
|
||||||
|
if clients == 0 {
|
||||||
|
acks <- context.CloseDatabase()
|
||||||
|
} else {
|
||||||
|
acks <- nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Common piece of code to show list of packages,
|
// Common piece of code to show list of packages,
|
||||||
// with searching & details if requested
|
// with searching & details if requested
|
||||||
func showPackages(c *gin.Context, reflist *deb.PackageRefList) {
|
func showPackages(c *gin.Context, reflist *deb.PackageRefList) {
|
||||||
|
|||||||
+32
-2
@@ -12,11 +12,41 @@ var context *ctx.AptlyContext
|
|||||||
func Router(c *ctx.AptlyContext) http.Handler {
|
func Router(c *ctx.AptlyContext) http.Handler {
|
||||||
context = c
|
context = c
|
||||||
|
|
||||||
go cacheFlusher()
|
|
||||||
|
|
||||||
router := gin.Default()
|
router := gin.Default()
|
||||||
router.Use(gin.ErrorLogger())
|
router.Use(gin.ErrorLogger())
|
||||||
|
|
||||||
|
if context.Flags().Lookup("no-lock").Value.Get().(bool) {
|
||||||
|
// We use a goroutine to count the number of
|
||||||
|
// concurrent requests. When no more requests are
|
||||||
|
// running, we close the database to free the lock.
|
||||||
|
requests := make(chan int)
|
||||||
|
acks := make(chan error)
|
||||||
|
|
||||||
|
go acquireDatabase(requests, acks)
|
||||||
|
go cacheFlusher(requests, acks)
|
||||||
|
|
||||||
|
router.Use(func(c *gin.Context) {
|
||||||
|
requests <- ACQUIREDB
|
||||||
|
err := <-acks
|
||||||
|
if err != nil {
|
||||||
|
c.Fail(500, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
requests <- RELEASEDB
|
||||||
|
err = <-acks
|
||||||
|
if err != nil {
|
||||||
|
c.Fail(500, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
c.Next()
|
||||||
|
})
|
||||||
|
|
||||||
|
} else {
|
||||||
|
go cacheFlusher(nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
root := router.Group("/api")
|
root := router.Group("/api")
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ Example:
|
|||||||
}
|
}
|
||||||
|
|
||||||
cmd.Flag.String("listen", ":8080", "host:port for HTTP listening")
|
cmd.Flag.String("listen", ":8080", "host:port for HTTP listening")
|
||||||
|
cmd.Flag.Bool("no-lock", false, "don't lock the database")
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
|
|
||||||
|
|||||||
@@ -1658,6 +1658,10 @@ Options:
|
|||||||
\-\fBlisten\fR=:8080
|
\-\fBlisten\fR=:8080
|
||||||
host:port for HTTP listening
|
host:port for HTTP listening
|
||||||
.
|
.
|
||||||
|
.TP
|
||||||
|
\-\fBno-lock\fR
|
||||||
|
don't lock the database and allow one to still use the command-line client
|
||||||
|
.
|
||||||
.SH "RENDER GRAPH OF RELATIONSHIPS"
|
.SH "RENDER GRAPH OF RELATIONSHIPS"
|
||||||
\fBaptly\fR \fBgraph\fR
|
\fBaptly\fR \fBgraph\fR
|
||||||
.
|
.
|
||||||
|
|||||||
Reference in New Issue
Block a user