Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
N
neo
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
2
Merge Requests
2
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Jobs
Commits
Open sidebar
Kirill Smelkov
neo
Commits
d56fe396
Commit
d56fe396
authored
Aug 25, 2017
by
Kirill Smelkov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
X move to zodb/storage.Cache & xcontainer/list
parent
1e40e46d
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
68 additions
and
38 deletions
+68
-38
go/xcommon/xcontainer/list/list.go
go/xcommon/xcontainer/list/list.go
+11
-8
go/zodb/storage/cache.go
go/zodb/storage/cache.go
+31
-25
go/zodb/storage/cache_test.go
go/zodb/storage/cache_test.go
+3
-3
go/zodb/storage/doc.go
go/zodb/storage/doc.go
+21
-0
go/zodb/storage/ztrace.go
go/zodb/storage/ztrace.go
+2
-2
No files found.
go/
neo/clien
t/list.go
→
go/
xcommon/xcontainer/lis
t/list.go
View file @
d56fe396
...
...
@@ -17,27 +17,30 @@
// See COPYING file for full licensing terms.
// See https://www.nexedi.com/licensing for rationale and options.
package
client
// base for intrusiv
e list
// Package list provides intrusive double-linked lists.
packag
e
list
//
list
Head is a list head entry for an element in an intrusive doubly-linked list.
// Head is a list head entry for an element in an intrusive doubly-linked list.
//
// XXX doc how to get to container of this list head via unsafe.OffsetOf
//
// always call Init() to initialize a head before using it.
type
list
Head
struct
{
type
Head
struct
{
// XXX needs to be created with .next = .prev = self
next
,
prev
*
list
Head
next
,
prev
*
Head
}
func
(
h
*
Head
)
Next
()
*
Head
{
return
h
.
next
}
func
(
h
*
Head
)
Prev
()
*
Head
{
return
h
.
prev
}
// Init initializes a head making it point to itself via .next and .prev
func
(
h
*
list
Head
)
Init
()
{
func
(
h
*
Head
)
Init
()
{
h
.
next
=
h
h
.
prev
=
h
}
// Delete deletes h from its list
func
(
h
*
list
Head
)
Delete
()
{
func
(
h
*
Head
)
Delete
()
{
h
.
next
.
prev
=
h
.
prev
h
.
prev
.
next
=
h
.
next
h
.
Init
()
...
...
@@ -45,7 +48,7 @@ func (h *listHead) Delete() {
// MoveBefore moves a to be before b
// XXX ok to move if a was not previously on the list?
func
(
a
*
listHead
)
MoveBefore
(
b
*
list
Head
)
{
func
(
a
*
Head
)
MoveBefore
(
b
*
Head
)
{
a
.
Delete
()
a
.
next
=
b
...
...
go/
neo/client
/cache.go
→
go/
zodb/storage
/cache.go
View file @
d56fe396
...
...
@@ -17,7 +17,7 @@
// See COPYING file for full licensing terms.
// See https://www.nexedi.com/licensing for rationale and options.
package
client
package
storage
// cache management
// XXX gotrace ... -> gotrace gen ...
...
...
@@ -29,19 +29,16 @@ import (
"sync"
"unsafe"
// "github.com/kylelemons/godebug/pretty"
"lab.nexedi.com/kirr/neo/go/zodb"
"lab.nexedi.com/kirr/neo/go/xcommon/xcontainer/list"
)
// storLoader represents loading part of a storage
// XXX -> zodb?
type
storLoader
interface
{
Load
(
xid
zodb
.
Xid
)
(
data
[]
byte
,
serial
zodb
.
Tid
,
err
error
)
}
// TODO maintain nhit / nmiss + way to read cache stats
// Cache adds RAM caching layer over a storage
// Cache adds RAM caching layer over a storage
.
type
Cache
struct
{
loader
s
torLoader
loader
S
torLoader
mu
sync
.
RWMutex
...
...
@@ -55,7 +52,7 @@ type Cache struct {
gcCh
chan
struct
{}
// signals gc to run
gcMu
sync
.
Mutex
lru
l
ist
Head
// revCacheEntries in LRU order
lru
l
ru
Head
// revCacheEntries in LRU order
size
int
// cached data size in bytes
sizeMax
int
// cache is allowed to occupy not more than this
...
...
@@ -80,7 +77,7 @@ type oidCacheEntry struct {
// revCacheEntry is information about 1 cached oid revision
type
revCacheEntry
struct
{
parent
*
oidCacheEntry
// oidCacheEntry holding us
inLRU
l
ist
Head
// in Cache.lru; protected by Cache.gcMu
inLRU
l
ru
Head
// in Cache.lru; protected by Cache.gcMu
// we know that loadBefore(oid, .before) will give this .serial:oid.
//
...
...
@@ -107,16 +104,20 @@ type revCacheEntry struct {
accounted
bool
// whether rce size accounted in cache size; protected by .parent's lock
}
// StorLoader represents loading part of a storage.
// XXX -> zodb?
type
StorLoader
interface
{
Load
(
xid
zodb
.
Xid
)
(
data
[]
byte
,
serial
zodb
.
Tid
,
err
error
)
}
// lock order: Cache.mu > oidCacheEntry
// Cache.gcMu > oidCacheEntry
// XXX maintain nhit / nmiss?
// NewCache creates new cache backed up by loader.
//
// The cache will use not more than ~ sizeMax bytes of RAM for cached data.
func
NewCache
(
loader
s
torLoader
,
sizeMax
int
)
*
Cache
{
func
NewCache
(
loader
S
torLoader
,
sizeMax
int
)
*
Cache
{
c
:=
&
Cache
{
loader
:
loader
,
entryMap
:
make
(
map
[
zodb
.
Oid
]
*
oidCacheEntry
),
...
...
@@ -146,7 +147,7 @@ func (c *Cache) SetSizeMax(sizeMax int) {
// Load loads data from database via cache.
//
// If data is already in cache cached content is returned.
// If data is already in cache
-
cached content is returned.
func
(
c
*
Cache
)
Load
(
xid
zodb
.
Xid
)
(
data
[]
byte
,
serial
zodb
.
Tid
,
err
error
)
{
rce
,
rceNew
:=
c
.
lookupRCE
(
xid
)
...
...
@@ -154,7 +155,7 @@ func (c *Cache) Load(xid zodb.Xid) (data []byte, serial zodb.Tid, err error) {
if
!
rceNew
{
<-
rce
.
ready
c
.
gcMu
.
Lock
()
rce
.
inLRU
.
MoveBefore
(
&
c
.
lru
)
rce
.
inLRU
.
MoveBefore
(
&
c
.
lru
.
Head
)
c
.
gcMu
.
Unlock
()
// rce is not in cache - this goroutine becomes responsible for loading it
...
...
@@ -366,23 +367,19 @@ func (c *Cache) loadRCE(rce *revCacheEntry, oid zodb.Oid) {
// update lru & cache size
gcrun
:=
false
c
.
gcMu
.
Lock
()
//xv1 := map[string]interface{}{"lru": &c.lru, "rce": &rce.inLRU}
//fmt.Printf("aaa:\n%s\n", pretty.Sprint(xv1))
if
rcePrevDropped
!=
nil
{
rcePrevDropped
.
inLRU
.
Delete
()
}
if
!
rceDropped
{
rce
.
inLRU
.
MoveBefore
(
&
c
.
lru
)
rce
.
inLRU
.
MoveBefore
(
&
c
.
lru
.
Head
)
}
//xv2 := map[string]interface{}{"lru": &c.lru, "rce": &rce.inLRU}
//fmt.Printf("\n--------\n%s\n\n\n", pretty.Sprint(xv2))
c
.
size
+=
δsize
if
c
.
size
>
c
.
sizeMax
{
gcrun
=
true
}
c
.
gcMu
.
Unlock
()
c
.
gcMu
.
Unlock
()
if
gcrun
{
c
.
gcsignal
()
}
...
...
@@ -495,7 +492,7 @@ func (c *Cache) gc() {
}
// kill 1 least-used rce
h
:=
c
.
lru
.
next
h
:=
c
.
lru
.
Next
()
if
h
==
&
c
.
lru
{
panic
(
"cache: gc: empty .lru but .size > .sizeMax"
)
}
...
...
@@ -608,8 +605,17 @@ func (rce *revCacheEntry) userErr(xid zodb.Xid) error {
return
rce
.
err
}
// list head that knows it is in revCacheEntry.inLRU
type
lruHead
struct
{
list
.
Head
}
// XXX vvv strictly speaking -unsafe.Offsetof(h.Head)
func
(
h
*
lruHead
)
Next
()
*
lruHead
{
return
(
*
lruHead
)(
unsafe
.
Pointer
(
h
.
Head
.
Next
()))
}
func
(
h
*
lruHead
)
Prev
()
*
lruHead
{
return
(
*
lruHead
)(
unsafe
.
Pointer
(
h
.
Head
.
Prev
()))
}
// revCacheEntry: .inLRU -> .
func
(
h
*
l
ist
Head
)
rceFromInLRU
()
(
rce
*
revCacheEntry
)
{
func
(
h
*
l
ru
Head
)
rceFromInLRU
()
(
rce
*
revCacheEntry
)
{
urce
:=
unsafe
.
Pointer
(
uintptr
(
unsafe
.
Pointer
(
h
))
-
unsafe
.
Offsetof
(
rce
.
inLRU
))
return
(
*
revCacheEntry
)(
urce
)
}
...
...
go/
neo/client
/cache_test.go
→
go/
zodb/storage
/cache_test.go
View file @
d56fe396
...
...
@@ -17,7 +17,7 @@
// See COPYING file for full licensing terms.
// See https://www.nexedi.com/licensing for rationale and options.
package
client
package
storage
import
(
"bytes"
...
...
@@ -199,10 +199,10 @@ func TestCache(t *testing.T) {
t
.
Helper
()
size
:=
0
var
mruv
[]
*
revCacheEntry
for
hp
,
h
:=
&
c
.
lru
,
c
.
lru
.
prev
;
h
!=
&
c
.
lru
;
hp
,
h
=
h
,
h
.
prev
{
for
hp
,
h
:=
&
c
.
lru
,
c
.
lru
.
Prev
();
h
!=
&
c
.
lru
;
hp
,
h
=
h
,
h
.
Prev
()
{
//xv := []interface{}{&c.lru, h.rceFromInLRU()}
//debug.Print(xv) // &c.lru, h.rceFromInLRU())
if
h
.
next
!=
hp
{
if
h
.
Next
()
!=
hp
{
t
.
Fatalf
(
"LRU list .next/.prev broken for
\n
h:
\n
%s
\n\n
hp:
\n
%s
\n
"
,
debug
.
Sprint
(
h
),
debug
.
Sprint
(
hp
))
}
...
...
go/zodb/storage/doc.go
0 → 100644
View file @
d56fe396
// Copyright (C) 2017 Nexedi SA and Contributors.
// Kirill Smelkov <kirr@nexedi.com>
//
// This program is free software: you can Use, Study, Modify and Redistribute
// it under the terms of the GNU General Public License version 3, or (at your
// option) any later version, as published by the Free Software Foundation.
//
// You can also Link and Combine this program with other software covered by
// the terms of any of the Free Software licenses or any of the Open Source
// Initiative approved licenses and Convey the resulting work. Corresponding
// source of such a combination shall include the source code for all other
// software used.
//
// This program is distributed WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// See COPYING file for full licensing terms.
// See https://www.nexedi.com/licensing for rationale and options.
// Package storage provides common bits related to ZODB storages. XXX text
package
storage
go/
neo/client
/ztrace.go
→
go/
zodb/storage
/ztrace.go
View file @
d56fe396
// Code generated by lab.nexedi.com/kirr/go123/tracing/cmd/gotrace; DO NOT EDIT.
package
client
package
storage
// code generated for tracepoints
import
(
...
...
@@ -63,4 +63,4 @@ func traceCacheGCStart_Attach(pg *tracing.ProbeGroup, probe func(c *Cache)) *tra
}
// trace export signature
func
_trace_exporthash_
624de1c8d179b91f695f79fec7f7cdb7386501f4
()
{}
func
_trace_exporthash_
46a80e8af5056736069c296a95ad4c94388ab850
()
{}
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