Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
W
wendelin.core
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
Kirill Smelkov
wendelin.core
Commits
197f6c42
Commit
197f6c42
authored
Dec 25, 2018
by
Kirill Smelkov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
.
parent
bb8d466b
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
107 additions
and
85 deletions
+107
-85
wcfs/misc.go
wcfs/misc.go
+25
-21
wcfs/wcfs.go
wcfs/wcfs.go
+82
-64
No files found.
wcfs/misc.go
View file @
197f6c42
...
...
@@ -23,7 +23,6 @@ package main
import
(
"context"
"fmt"
"sync/atomic"
"syscall"
log
"github.com/golang/glog"
...
...
@@ -185,10 +184,13 @@ type ZConn struct {
// read-only transaction under which we access zodb.Connection data.
txnCtx
context
.
Context
// XXX -> better directly store txn
// for historic @<rev> acess the connection can be shared between several bigfiles.
/* XXX redecided to purge files and @<rev>/ on atime timeout
// for historic @<rev> access the connection can be shared between several bigfiles.
// since we want to free such connections when no longer needed we
// return zodb.Connection back to zodb.DB when refcnt drops to 0.
refcnt int32
*/
}
// zopen opens new connection to ZODB database + associated read-only transaction.
...
...
@@ -213,10 +215,11 @@ func zopen(ctx context.Context, zdb *zodb.DB, zopt *zodb.ConnOptions) (_ *ZConn,
return
&
ZConn
{
Connection
:
zconn
,
txnCtx
:
txnCtx
,
refcnt
:
1
,
//
refcnt: 1,
},
nil
}
/*
// Release decrements reference count and releases connection back to zodb.DB
// if it is no longer used.
func (zc *ZConn) Release() {
...
...
@@ -249,8 +252,8 @@ func (zc *ZConn) Incref() {
// if the connection for this @<rev> was already opened - it is shared.
func (r *Root) zopenAt(ctx context.Context, rev zodb.Tid) (_ *ZConn, err error) {
// check if zconn for @<rev> is already there
r
.
z
revMu
.
Lock
()
zconn
:=
r
.
z
revTab
[
rev
]
r.revMu.Lock()
zconn := r.revTab[rev]
if zconn != nil {
if atomic.LoadInt32(&zconn.refcnt) > 0 {
zconn.Incref()
...
...
@@ -258,43 +261,43 @@ func (r *Root) zopenAt(ctx context.Context, rev zodb.Tid) (_ *ZConn, err error)
zconn = nil // in-progress destruction
}
}
r
.
z
revMu
.
Unlock
()
r.revMu.Unlock()
if zconn != nil {
return zconn, nil
}
// not there - without
z
revMu lock proceed to open it
// not there - without revMu lock proceed to open it
zconn, err = zopen(ctx, r.zdb, &zodb.ConnOptions{At: rev})
if err != nil {
return nil, err
}
// relock
z
revTab and either register zconn, or returun another zconn2,
// that might have been opened while we were not holding
z
revMu.
r
.
z
revMu
.
Lock
()
defer
r
.
z
revMu
.
Unlock
()
// relock revTab and either register zconn, or returun another zconn2,
// that might have been opened while we were not holding revMu.
r.revMu.Lock()
defer r.revMu.Unlock()
zconn2
:=
r
.
z
revTab
[
rev
]
zconn2 := r.revTab[rev]
if zconn2 != nil {
if atomic.LoadInt32(&zconn2.refcnt) > 0 {
zconn
.
Release
()
zconn.Release()
// FIXME aborts txn -> just drop zconn
zconn2.Incref()
return zconn2, nil
}
// else it was another in-progress destruction
}
r
.
z
revTab
[
rev
]
=
zconn
r.revTab[rev] = zconn
// schedule del
z
revTab[rev] on zconn destroy
// schedule del revTab[rev] on zconn destroy
txn := transaction.Current(zconn.txnCtx)
txn.RegisterSync(&zrevTabUnregister{r, zconn})
return zconn, nil
}
// zrevTabUnregister unregisters zconn from root.
z
revTab on zconn's transaction abort.
// zrevTabUnregister unregisters zconn from root.revTab on zconn's transaction abort.
type zrevTabUnregister struct {
root *Root
zconn *ZConn
...
...
@@ -304,12 +307,13 @@ func (u *zrevTabUnregister) BeforeCompletion(txn transaction.Transaction) {}
func (u *zrevTabUnregister) AfterCompletion(txn transaction.Transaction) {
rev := u.zconn.At()
u
.
root
.
z
revMu
.
Lock
()
defer
u
.
root
.
z
revMu
.
Unlock
()
u.root.revMu.Lock()
defer u.root.revMu.Unlock()
// delete only if zconn is still registered - as another zconn2 might have
// been already registered instead while zconn was in
z
revTab with refcnt=0.
if
u
.
root
.
z
revTab
[
rev
]
==
u
.
zconn
{
delete
(
u
.
root
.
z
revTab
,
rev
)
// been already registered instead while zconn was in revTab with refcnt=0.
if u.root.revTab[rev] == u.zconn {
delete(u.root.revTab, rev)
}
}
*/
wcfs/wcfs.go
View file @
197f6c42
...
...
@@ -390,6 +390,7 @@ import (
"lab.nexedi.com/kirr/go123/xcontext"
"lab.nexedi.com/kirr/go123/xerr"
"lab.nexedi.com/kirr/neo/go/transaction"
"lab.nexedi.com/kirr/neo/go/zodb"
"lab.nexedi.com/kirr/neo/go/zodb/btree"
_
"lab.nexedi.com/kirr/neo/go/zodb/wks"
...
...
@@ -412,24 +413,23 @@ type Root struct {
// only one connection is used for head/ and only one for each @<rev>.
zdb
*
zodb
.
DB
// ZODB connection for head/
zheadMu
sync
.
RWMutex
// protects access to zhead & live _objects_ associated with it
zhead
*
ZConn
// zwatcher resyncs zhead; others only read zhead objects.
// directory + ZODB connection for head/
head
*
Head
// ZODB connections for @<rev>/
zrevMu
sync
.
Mutex
zrevTab
map
[
zodb
.
Tid
]
*
ZConn
// XXX include?
// // {} rev -> @<rev>/
// mu sync.Mutex
// revTab map[zodb.Tid]*Rev
// directories + ZODB connections for @<rev>/
revMu
sync
.
Mutex
revTab
map
[
zodb
.
Tid
]
*
Head
}
// /(head|<rev>)/ - served by Head.
XXX separate Rev?
// /(head|<rev>)/ - served by Head.
type
Head
struct
{
nodefs
.
Node
// bigfile, at, watch, etc - all implicitly linked to by fs
rev
zodb
.
Tid
// 0 for head/, !0 for @<rev>/
// bigfile/, at, watch, etc - all implicitly linked to by fs
// ZODB connection for everything under this head
zconnMu
sync
.
RWMutex
// protects access to zconn & live _objects_ associated with it
zconn
*
ZConn
// for head/ zwatcher resyncs head.zconn; others only read zconn objects.
}
// /head/watch - served by Watch.
...
...
@@ -442,6 +442,7 @@ type Watch struct {
// /(head|<rev>)/bigfile/ - served by BigFileDir.
type
BigFileDir
struct
{
nodefs
.
Node
head
*
Head
// parent head/ or @<rev>/
// {} oid -> <bigfileX>
mu
sync
.
Mutex
...
...
@@ -452,8 +453,9 @@ type BigFileDir struct {
type
BigFile
struct
{
nodefs
.
Node
// this BigFile views ZODB via zconn
zconn
*
ZConn
// this BigFile is under head; it views ZODB via head.zconn
// parent's BigFileDir.head is the same.
head
*
Head
// ZBigFile top-level object. Kept activated during lifetime of current transaction.
zbf
*
ZBigFile
...
...
@@ -629,9 +631,9 @@ func (f *BigFile) invalidateBlk(ctx context.Context, blk int64) error {
// ----------------------------------------
// /(head
/<rev>)/bigfile/ -> Lookup receives client request to create
(head|<rev>)/bigfile/<bigfileX>.
// /(head
|<rev>)/bigfile/ -> Lookup receives client request to create /
(head|<rev>)/bigfile/<bigfileX>.
func
(
bfdir
*
BigFileDir
)
Lookup
(
out
*
fuse
.
Attr
,
name
string
,
fctx
*
fuse
.
Context
)
(
*
nodefs
.
Inode
,
fuse
.
Status
)
{
f
,
err
:=
bfdir
.
lookup
(
out
,
name
,
fctx
)
// XXX reorder out?
f
,
err
:=
bfdir
.
lookup
(
out
,
name
,
fctx
)
var
inode
*
nodefs
.
Inode
if
f
!=
nil
{
inode
=
f
.
Inode
()
...
...
@@ -642,17 +644,21 @@ func (bfdir *BigFileDir) Lookup(out *fuse.Attr, name string, fctx *fuse.Context)
func
(
bfdir
*
BigFileDir
)
lookup
(
out
*
fuse
.
Attr
,
name
string
,
fctx
*
fuse
.
Context
)
(
f
*
BigFile
,
err
error
)
{
defer
xerr
.
Contextf
(
&
err
,
"/bigfile: lookup %q"
,
name
)
defer
func
()
{
if
f
!=
nil
{
f
.
getattr
(
out
)
}
}()
oid
,
err
:=
zodb
.
ParseOid
(
name
)
if
err
!=
nil
{
return
nil
,
eINVALf
(
"not oid"
)
}
bfdir
.
head
.
zconnMu
.
Lock
()
defer
bfdir
.
head
.
zconnMu
.
Unlock
()
defer
func
()
{
if
f
!=
nil
{
f
.
getattr
(
out
)
}
}()
// check to see if dir(oid) is already there
bfdir
.
mu
.
Lock
()
f
,
already
:=
bfdir
.
tab
[
oid
]
...
...
@@ -663,7 +669,7 @@ func (bfdir *BigFileDir) lookup(out *fuse.Attr, name string, fctx *fuse.Context)
}
// not there - without bfdir lock proceed to open BigFile from ZODB
f
,
err
=
b
igopen
(
asctx
(
fctx
),
groot
.
zhead
,
oid
)
// XXX zhead -> head|rev.zconn
f
,
err
=
b
fdir
.
head
.
bigopen
(
asctx
(
fctx
),
oid
)
if
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -690,6 +696,9 @@ func (bfdir *BigFileDir) lookup(out *fuse.Attr, name string, fctx *fuse.Context)
// XXX do we need to support unlink? (probably no)
// / -> Mkdir receives client request to create @<rev>/.
//
// it is not an error if @<rev>/ already exists - mkdir succeeds and EEXIST is not returned.
// in other words mkdir behaves here similarly to `mkdir -p`.
func
(
root
*
Root
)
Mkdir
(
name
string
,
mode
uint32
,
fctx
*
fuse
.
Context
)
(
*
nodefs
.
Inode
,
fuse
.
Status
)
{
inode
,
err
:=
root
.
mkdir
(
name
,
fctx
)
// XXX ok to ignore mode?
return
inode
,
err2LogStatus
(
err
)
...
...
@@ -710,51 +719,56 @@ func (root *Root) mkdir(name string, fctx *fuse.Context) (_ *nodefs.Inode, err e
}
// check to see if dir(rev) is already there
root
.
z
revMu
.
Lock
()
_
,
already
:=
root
.
z
revTab
[
rev
]
root
.
z
revMu
.
Unlock
()
root
.
revMu
.
Lock
()
_
,
already
:=
root
.
revTab
[
rev
]
root
.
revMu
.
Unlock
()
if
already
{
return
nil
,
syscall
.
EEXIST
}
// not there - without
z
revMu lock proceed to open @rev view of ZODB
// not there - without revMu lock proceed to open @rev view of ZODB
ctx
:=
asctx
(
fctx
)
zconnRev
,
err
:=
groot
.
zopenAt
(
ctx
,
rev
)
// zconnRev, err := root.zopenAt(ctx, rev)
zconnRev
,
err
:=
zopen
(
ctx
,
root
.
zdb
,
&
zodb
.
ConnOptions
{
At
:
rev
})
if
err
!=
nil
{
return
nil
,
err
}
defer
zconnRev
.
Release
()
// XXX ok?
// relock root and either mkdir or EEXIST if the directory was maybe
// simultanously created while we were not holding
z
revMu.
root
.
z
revMu
.
Lock
()
_
,
already
=
root
.
z
revTab
[
rev
]
// simultanously created while we were not holding revMu.
root
.
revMu
.
Lock
()
_
,
already
=
root
.
revTab
[
rev
]
if
already
{
root
.
zrevMu
.
Unlock
()
root
.
revMu
.
Unlock
()
// zconnRev.Release()
transaction
.
Current
(
zconnRev
.
txnCtx
)
.
Abort
()
return
nil
,
syscall
.
EEXIST
}
revDir
:=
&
Head
{
// XXX -> Rev ?
revDir
:=
&
Head
{
Node
:
nodefs
.
NewDefaultNode
(),
rev
:
rev
,
zconn
:
zconnRev
,
}
root
.
zrevTab
[
rev
]
=
zconnRev
root
.
z
revMu
.
Unlock
()
root
.
revTab
[
rev
]
=
revDir
root
.
revMu
.
Unlock
()
// mkdir takes filesystem treeLock - do it outside
z
revMu.
// mkdir takes filesystem treeLock - do it outside revMu.
mkdir
(
root
,
name
,
revDir
)
return
revDir
.
Inode
(),
nil
}
// bigopen opens BigFile corresponding to oid on zconn.
// bigopen opens BigFile corresponding to oid on
head.
zconn.
//
// A ZBigFile corresponding to oid is activated and statted.
//
// The whole result is returned as BigFile.
func
bigopen
(
ctx
context
.
Context
,
zconn
*
ZConn
,
oid
zodb
.
Oid
)
(
_
*
BigFile
,
err
error
)
{
// head.zconn must be locked.
func
(
head
*
Head
)
bigopen
(
ctx
context
.
Context
,
oid
zodb
.
Oid
)
(
_
*
BigFile
,
err
error
)
{
zconn
:=
head
.
zconn
defer
xerr
.
Contextf
(
&
err
,
"bigopen %s @%s"
,
oid
,
zconn
.
At
())
// XXX better ctx = transaction.PutIntoContext(ctx, txn)
...
...
@@ -794,10 +808,10 @@ func bigopen(ctx context.Context, zconn *ZConn, oid zodb.Oid) (_ *BigFile, err e
return
nil
,
err
}
zconn
.
Incref
()
//
zconn.Incref()
return
&
BigFile
{
Node
:
nodefs
.
NewDefaultNode
(),
zconn
:
zconn
,
head
:
head
,
zbf
:
zbf
,
zbfSize
:
zbfSize
,
...
...
@@ -809,11 +823,12 @@ func bigopen(ctx context.Context, zconn *ZConn, oid zodb.Oid) (_ *BigFile, err e
// Close release all resources of BigFile.
func
(
f
*
BigFile
)
Close
()
error
{
f
.
zbf
.
PDeactivate
()
f
.
zbf
.
PDeactivate
()
// XXX f.head.zconn must locked
f
.
zbf
=
nil
f
.
zconn
.
Release
()
f
.
zconn
=
nil
// f.zconn.Release()
// f.zconn = nil
f
.
head
=
nil
return
nil
}
...
...
@@ -842,7 +857,8 @@ func (f *BigFile) getattr(out *fuse.Attr) {
// /(head|<rev>)/bigfile/<bigfileX> -> Read serves reading bigfile data.
func
(
f
*
BigFile
)
Read
(
_
nodefs
.
File
,
dest
[]
byte
,
off
int64
,
fctx
*
fuse
.
Context
)
(
fuse
.
ReadResult
,
fuse
.
Status
)
{
// XXX locking
f
.
head
.
zconnMu
.
RLock
()
defer
f
.
head
.
zconnMu
.
RUnlock
()
zbf
:=
f
.
zbf
...
...
@@ -866,7 +882,7 @@ func (f *BigFile) Read(_ nodefs.File, dest []byte, off int64, fctx *fuse.Context
dest
=
make
([]
byte
,
aend
-
aoff
)
// ~> [aoff:aend) in file
// XXX better ctx = transaction.PutIntoContext(ctx, txn)
ctx
,
cancel
:=
xcontext
.
Merge
(
asctx
(
fctx
),
f
.
zconn
.
txnCtx
)
ctx
,
cancel
:=
xcontext
.
Merge
(
asctx
(
fctx
),
f
.
head
.
zconn
.
txnCtx
)
defer
cancel
()
// read/load all block(s) in parallel
...
...
@@ -1014,11 +1030,9 @@ func (f *BigFile) readBlk(ctx context.Context, blk int64, dest []byte) error {
// /(head|<rev>)/at -> readAt serves read.
func
(
h
*
Head
)
readAt
()
[]
byte
{
// XXX implemented only for Head, not Rev
root
:=
groot
root
.
zheadMu
.
Lock
()
defer
root
.
zheadMu
.
Unlock
()
return
[]
byte
(
root
.
zhead
.
At
()
.
String
())
h
.
zconnMu
.
Lock
()
defer
h
.
zconnMu
.
Unlock
()
return
[]
byte
(
h
.
zconn
.
At
()
.
String
())
}
...
...
@@ -1031,7 +1045,7 @@ func (h *Head) readAt() []byte {
// - Mount:
// .Root() -> root Inode of the fs
// .Connector() -> FileSystemConnector through which fs is mounted
var
groot
*
Root
//
var groot *Root
var
gfsconn
*
nodefs
.
FileSystemConnector
func
main
()
{
...
...
@@ -1070,13 +1084,19 @@ func main() {
}
zhead
.
Cache
()
.
SetControl
(
&
zodbCacheControl
{})
// XXX +locking?
// mount root
// mount root + head/
head
:=
&
Head
{
Node
:
nodefs
.
NewDefaultNode
(),
rev
:
0
,
zconn
:
zhead
,
}
root
:=
&
Root
{
Node
:
nodefs
.
NewDefaultNode
(),
zstor
:
zstor
,
zdb
:
zdb
,
zhead
:
z
head
,
zrevTab
:
make
(
map
[
zodb
.
Tid
]
*
ZConn
),
head
:
head
,
revTab
:
make
(
map
[
zodb
.
Tid
]
*
Head
),
}
opts
:=
&
fuse
.
MountOptions
{
...
...
@@ -1091,7 +1111,7 @@ func main() {
if
err
!=
nil
{
log
.
Fatal
(
err
)
}
groot
=
root
// FIXME temp workaround (see ^^^)
//
groot = root // FIXME temp workaround (see ^^^)
gfsconn
=
fsconn
// FIXME ----//----
// we require proper pagecache control (added to Linux 2.6.36 in 2010)
...
...
@@ -1102,12 +1122,10 @@ func main() {
// add entries to /
mkfile
(
root
,
".wcfs"
,
NewStaticFile
([]
byte
(
zurl
)))
head
:=
&
Head
{
Node
:
nodefs
.
NewDefaultNode
(),
}
mkdir
(
root
,
"head"
,
head
)
mkdir
(
head
,
"bigfile"
,
&
BigFileDir
{
Node
:
nodefs
.
NewDefaultNode
(),
head
:
head
,
tab
:
make
(
map
[
zodb
.
Oid
]
*
BigFile
),
})
mkfile
(
head
,
"at"
,
NewSmallFile
(
head
.
readAt
))
// TODO mtime(at) = tidtime(at)
...
...
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