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
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Joshua
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
Hide 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 ?
Node
:
nodefs
.
NewDefaultNode
(),
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
),
Node
:
nodefs
.
NewDefaultNode
(),
zstor
:
zstor
,
zdb
:
zdb
,
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