Commit bbff0245 authored by Kirill Smelkov's avatar Kirill Smelkov

X zodb: Polish a bit

parent 4ac3a550
...@@ -502,14 +502,19 @@ func (c *Client) Iterate(tidMin, tidMax zodb.Tid) zodb.ITxnIterator { ...@@ -502,14 +502,19 @@ func (c *Client) Iterate(tidMin, tidMax zodb.Tid) zodb.ITxnIterator {
} }
// TODO read-only support func openClientByURL(ctx context.Context, u *url.URL, opt *zodb.OpenOptions) (zodb.IStorage, error) {
func openClientByURL(ctx context.Context, u *url.URL) (zodb.IStorage, error) {
// neo://name@master1,master2,...,masterN?options // neo://name@master1,master2,...,masterN?options
if u.User == nil { if u.User == nil {
return nil, fmt.Errorf("neo: open %q: cluster name not specified") return nil, fmt.Errorf("neo: open %q: cluster name not specified")
} }
// XXX readonly stub
// XXX place = ?
if !opt.ReadOnly {
return nil, fmt.Errorf("neo: %s: TODO write mode not implemented", u)
}
// XXX check/use other url fields // XXX check/use other url fields
net := xnet.NetPlain("tcp") // TODO + TLS; not only "tcp" ? net := xnet.NetPlain("tcp") // TODO + TLS; not only "tcp" ?
......
...@@ -115,7 +115,7 @@ func main() { ...@@ -115,7 +115,7 @@ func main() {
func zhash(ctx context.Context, url string, h hasher, useprefetch bool, bench, check string) (err error) { func zhash(ctx context.Context, url string, h hasher, useprefetch bool, bench, check string) (err error) {
defer task.Running(&ctx, "zhash")(&err) defer task.Running(&ctx, "zhash")(&err)
stor, err := zodb.OpenStorageURL(ctx, url) stor, err := zodb.OpenStorage(ctx, url)
if err != nil { if err != nil {
return err return err
} }
...@@ -124,7 +124,7 @@ func zhash(ctx context.Context, url string, h hasher, useprefetch bool, bench, c ...@@ -124,7 +124,7 @@ func zhash(ctx context.Context, url string, h hasher, useprefetch bool, bench, c
err = xerr.First(err, err2) err = xerr.First(err, err2)
}() }()
// XXX always open storage with cache by zodb.OpenStorageURL // XXX always open storage with cache by zodb.OpenStorage
var cache *storage.Cache var cache *storage.Cache
if useprefetch { if useprefetch {
cache = storage.NewCache(stor, 16*1024*1024) cache = storage.NewCache(stor, 16*1024*1024)
......
...@@ -40,7 +40,7 @@ type Buf struct { ...@@ -40,7 +40,7 @@ type Buf struct {
// reference counter. // reference counter.
// //
// NOTE to allow both Bufs created via BufAlloc and via std new Buf is // NOTE to allow both Bufs created via BufAlloc and via std new, Buf is
// created with refcnt=0. The real number of references to Buf is thus .refcnt+1 // created with refcnt=0. The real number of references to Buf is thus .refcnt+1
refcnt int32 refcnt int32
} }
...@@ -68,6 +68,7 @@ func BufAlloc(size int) *Buf { ...@@ -68,6 +68,7 @@ func BufAlloc(size int) *Buf {
return BufAlloc64(int64(size)) return BufAlloc64(int64(size))
} }
// BufAlloc64 is same as BufAlloc but accepts int64 for size.
func BufAlloc64(size int64) *Buf { func BufAlloc64(size int64) *Buf {
if size < 0 { if size < 0 {
panic("invalid size") panic("invalid size")
...@@ -76,22 +77,17 @@ func BufAlloc64(size int64) *Buf { ...@@ -76,22 +77,17 @@ func BufAlloc64(size int64) *Buf {
// order = min i: 2^i >= size // order = min i: 2^i >= size
order := xmath.CeilLog2(uint64(size)) order := xmath.CeilLog2(uint64(size))
//println("alloc", size, "order:", order)
order -= order0 order -= order0
if order < 0 { if order < 0 {
order = 0 order = 0
} }
//println("\t->", order)
// if too big - allocate straightly from heap // if too big - allocate straightly from heap
if order >= len(bufPoolv) { if order >= len(bufPoolv) {
return &Buf{Data: make([]byte, size)} return &Buf{Data: make([]byte, size)}
} }
buf := bufPoolv[order].Get().(*Buf) buf := bufPoolv[order].Get().(*Buf)
//println("\tlen:", len(buf.Data), "cap:", cap(buf.Data))
buf.Data = buf.Data[:size] // leaving cap as is = 2^i buf.Data = buf.Data[:size] // leaving cap as is = 2^i
buf.refcnt = 0 buf.refcnt = 0
return buf return buf
......
...@@ -27,8 +27,13 @@ import ( ...@@ -27,8 +27,13 @@ import (
"strings" "strings"
) )
// OpenOptions describes options for OpenStorage
type OpenOptions struct {
ReadOnly bool // whether to open storage as read-only
}
// StorageOpener is a function to open a storage // StorageOpener is a function to open a storage
type StorageOpener func (ctx context.Context, u *url.URL) (IStorage, error) type StorageOpener func (ctx context.Context, u *url.URL, opt *OpenOptions) (IStorage, error)
// {} scheme -> StorageOpener // {} scheme -> StorageOpener
var storageRegistry = map[string]StorageOpener{} var storageRegistry = map[string]StorageOpener{}
...@@ -51,8 +56,7 @@ func RegisterStorage(scheme string, opener StorageOpener) { ...@@ -51,8 +56,7 @@ func RegisterStorage(scheme string, opener StorageOpener) {
// Storage authors should register their storages with RegisterStorage. // Storage authors should register their storages with RegisterStorage.
// //
// TODO automatically wrap a storage with Cache. // TODO automatically wrap a storage with Cache.
// TODO readonly func OpenStorage(ctx context.Context, storageURL string, opt *OpenOptions) (IStorage, error) {
func OpenStorageURL(ctx context.Context, storageURL string) (IStorage, error) {
// no scheme -> file:// // no scheme -> file://
if !strings.Contains(storageURL, "://") { if !strings.Contains(storageURL, "://") {
storageURL = "file://" + storageURL storageURL = "file://" + storageURL
...@@ -63,10 +67,13 @@ func OpenStorageURL(ctx context.Context, storageURL string) (IStorage, error) { ...@@ -63,10 +67,13 @@ func OpenStorageURL(ctx context.Context, storageURL string) (IStorage, error) {
return nil, err return nil, err
} }
// XXX commonly handle some options from url -> opt?
// (e.g. ?readonly=1 -> opt.ReadOnly=true + remove ?readonly=1 from URL)
opener, ok := storageRegistry[u.Scheme] opener, ok := storageRegistry[u.Scheme]
if !ok { if !ok {
return nil, fmt.Errorf("zodb: URL scheme \"%s://\" not supported", u.Scheme) return nil, fmt.Errorf("zodb: URL scheme \"%s://\" not supported", u.Scheme)
} }
return opener(ctx, u) return opener(ctx, u, opt)
} }
...@@ -53,7 +53,7 @@ ...@@ -53,7 +53,7 @@
// //
// Unless one is doing something FileStorage-specific, it is advices not to use // Unless one is doing something FileStorage-specific, it is advices not to use
// fs1 package directly, and instead link-in lab.nexedi.com/kirr/neo/go/zodb/wks, // fs1 package directly, and instead link-in lab.nexedi.com/kirr/neo/go/zodb/wks,
// open storage by zodb.OpenStorageURL and use it by way of zodb.IStorage interface. // open storage by zodb.OpenStorage and use it by way of zodb.IStorage interface.
// //
// The fs1 package exposes all FileStorage data format details and most of // The fs1 package exposes all FileStorage data format details and most of
// internal workings so that it is possible to implement FileStorage-specific // internal workings so that it is possible to implement FileStorage-specific
......
...@@ -22,16 +22,24 @@ package fs1 ...@@ -22,16 +22,24 @@ package fs1
import ( import (
"context" "context"
"fmt"
"net/url" "net/url"
"lab.nexedi.com/kirr/neo/go/zodb" "lab.nexedi.com/kirr/neo/go/zodb"
) )
// TODO read-only support func openByURL(ctx context.Context, u *url.URL, opt *zodb.OpenOptions) (zodb.IStorage, error) {
func openByURL(ctx context.Context, u *url.URL) (zodb.IStorage, error) {
// TODO handle query // TODO handle query
// XXX u.Path is not always raw path - recheck and fix // XXX u.Path is not always raw path - recheck and fix
return Open(ctx, u.Host + u.Path) path := u.Host + u.Path
// XXX readonly stub
// XXX place = ?
if !opt.ReadOnly {
return nil, fmt.Errorf("fs1: %s: TODO write mode not implemented", path)
}
return Open(ctx, path)
} }
func init() { func init() {
......
// 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 mem implements in-memory ZODB storage
package mem
// XXX partly based on code from ZODB ?
// XXX not yet really needed
/*
import (
"../../../zodb"
)
// Storage is a ZODB storage which stores data in RAM.
type Storage struct {
}
var _ zodb.IStorage = (*Storage)(nil)
*/
...@@ -29,10 +29,24 @@ import ( ...@@ -29,10 +29,24 @@ import (
"lab.nexedi.com/kirr/go123/xstrings" "lab.nexedi.com/kirr/go123/xstrings"
) )
// String converts tid to string.
//
// Default tid string representation is 16-character hex string, e.g.:
//
// 0285cbac258bf266
//
// See also: ParseTid.
func (tid Tid) String() string { func (tid Tid) String() string {
return string(tid.XFmtString(nil)) return string(tid.XFmtString(nil))
} }
// String converts oid to string.
//
// Default oid string representation is 16-character hex string, e.g.:
//
// 0000000000000001
//
// See also: ParseOid.
func (oid Oid) String() string { func (oid Oid) String() string {
return string(oid.XFmtString(nil)) return string(oid.XFmtString(nil))
} }
...@@ -47,8 +61,9 @@ func (oid Oid) XFmtString(b []byte) []byte { ...@@ -47,8 +61,9 @@ func (oid Oid) XFmtString(b []byte) []byte {
return xfmt.AppendHex016(b, uint64(oid)) return xfmt.AppendHex016(b, uint64(oid))
} }
// XXX move me out of here // bint converts bool to int with true => 1; false => 0.
// bint converts bool to int with true => 1; false => 0 //
// XXX place = ?
func bint(b bool) int { func bint(b bool) int {
if b { if b {
return 1 return 1
...@@ -57,11 +72,38 @@ func bint(b bool) int { ...@@ -57,11 +72,38 @@ func bint(b bool) int {
} }
} }
// String converts xtid to string.
//
// Default xtid string representation is:
//
// - "=" or "<" character depending on whether xtid represents exact or "tid before" query
// - tid
//
// e.g.
//
// =0285cbac258bf266 - exactly 0285cbac258bf266
// <0285cbac258bf266 - before 0285cbac258bf266
//
// See also: ParseXTid.
func (xtid XTid) String() string { func (xtid XTid) String() string {
// XXX also print "tid:" prefix ? // XXX also print "tid:" prefix ?
return fmt.Sprintf("%c%v", "=<"[bint(xtid.TidBefore)], xtid.Tid) return fmt.Sprintf("%c%v", "=<"[bint(xtid.TidBefore)], xtid.Tid)
} }
// String converts xid to string.
//
// Default xid string representation is:
//
// - string of xtid
// - ":"
// - string of oid
//
// e.g.
//
// =0285cbac258bf266:0000000000000001 - oid 1 at exactly 0285cbac258bf266 transaction
// <0285cbac258bf266:0000000000000001 - oid 1 at first newest transaction changing it with tid < 0285cbac258bf266
//
// See also: ParseXid.
func (xid Xid) String() string { func (xid Xid) String() string {
return xid.XTid.String() + ":" + xid.Oid.String() return xid.XTid.String() + ":" + xid.Oid.String()
} }
...@@ -93,16 +135,25 @@ func parseHex64(subj, s string) (uint64, error) { ...@@ -93,16 +135,25 @@ func parseHex64(subj, s string) (uint64, error) {
return binary.BigEndian.Uint64(b[:]), nil return binary.BigEndian.Uint64(b[:]), nil
} }
// ParseTid parses tid from string.
//
// See also: Tid.String .
func ParseTid(s string) (Tid, error) { func ParseTid(s string) (Tid, error) {
x, err := parseHex64("tid", s) x, err := parseHex64("tid", s)
return Tid(x), err return Tid(x), err
} }
// ParseOid parses oid from string.
//
// See also: Oid.String .
func ParseOid(s string) (Oid, error) { func ParseOid(s string) (Oid, error) {
x, err := parseHex64("oid", s) x, err := parseHex64("oid", s)
return Oid(x), err return Oid(x), err
} }
// ParseXTid parses xtid from string.
//
// See also: XTid.String .
func ParseXTid(s string) (XTid, error) { func ParseXTid(s string) (XTid, error) {
if len(s) < 1 { if len(s) < 1 {
goto Error goto Error
...@@ -132,6 +183,9 @@ Error: ...@@ -132,6 +183,9 @@ Error:
return XTid{}, fmt.Errorf("xtid %q invalid", s) return XTid{}, fmt.Errorf("xtid %q invalid", s)
} }
// ParseXid parses xid from string.
//
// See also: Xid.String .
func ParseXid(s string) (Xid, error) { func ParseXid(s string) (Xid, error) {
xtids, oids, err := xstrings.Split2(s, ":") xtids, oids, err := xstrings.Split2(s, ":")
if err != nil { if err != nil {
......
...@@ -76,5 +76,4 @@ func (tid Tid) Time() TimeStamp { ...@@ -76,5 +76,4 @@ func (tid Tid) Time() TimeStamp {
// TODO TidFromTime() // TODO TidFromTime()
// TODO TidFromTimeStamp() // TODO TidFromTimeStamp()
// TODO TidForNow() ? // TODO TidForNow() ?
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
package wks package wks
import ( import (
_ "lab.nexedi.com/kirr/neo/go/zodb/storage/mem"
_ "lab.nexedi.com/kirr/neo/go/zodb/storage/fs1" _ "lab.nexedi.com/kirr/neo/go/zodb/storage/fs1"
_ "lab.nexedi.com/kirr/neo/go/neo/client" _ "lab.nexedi.com/kirr/neo/go/neo/client"
) )
...@@ -34,7 +34,7 @@ import ( ...@@ -34,7 +34,7 @@ import (
// Tid is transaction identifier. // Tid is transaction identifier.
// //
// In ZODB transaction identifiers are unique 64-bit integer connected to time // In ZODB transaction identifiers are unique 64-bit integers connected to time
// when corresponding transaction was created. // when corresponding transaction was created.
// //
// See also: XTid. // See also: XTid.
...@@ -42,7 +42,7 @@ type Tid uint64 ...@@ -42,7 +42,7 @@ type Tid uint64
// ZODB/py defines maxtid to be max signed int64 since Jun 7 2016: // ZODB/py defines maxtid to be max signed int64 since Jun 7 2016:
// https://github.com/zopefoundation/ZODB/commit/baee84a6 // https://github.com/zopefoundation/ZODB/commit/baee84a6
// (XXX in neo/py: SQLite does not accept numbers above 2^63-1) // (same in neo/py with "SQLite does not accept numbers above 2^63-1" comment)
const TidMax Tid = 1<<63 - 1 // 0x7fffffffffffffff const TidMax Tid = 1<<63 - 1 // 0x7fffffffffffffff
......
...@@ -124,7 +124,7 @@ func catobjMain(argv []string) { ...@@ -124,7 +124,7 @@ func catobjMain(argv []string) {
ctx := context.Background() ctx := context.Background()
stor, err := zodb.OpenStorageURL(ctx, storUrl) // TODO read-only stor, err := zodb.OpenStorage(ctx, storUrl, &zodb.OpenOptions{ReadOnly: true})
if err != nil { if err != nil {
prog.Fatal(err) prog.Fatal(err)
} }
......
...@@ -270,7 +270,7 @@ func dumpMain(argv []string) { ...@@ -270,7 +270,7 @@ func dumpMain(argv []string) {
prog.Fatal(err) prog.Fatal(err)
} }
stor, err := zodb.OpenStorageURL(context.Background(), storUrl) // TODO read-only stor, err := zodb.OpenStorage(context.Background(), storUrl, &zodb.OpenOptions{ReadOnly: true})
if err != nil { if err != nil {
prog.Fatal(err) prog.Fatal(err)
} }
......
...@@ -123,7 +123,7 @@ func infoMain(argv []string) { ...@@ -123,7 +123,7 @@ func infoMain(argv []string) {
ctx := context.Background() ctx := context.Background()
stor, err := zodb.OpenStorageURL(ctx, storUrl) // TODO read-only stor, err := zodb.OpenStorage(ctx, storUrl, &zodb.OpenOptions{ReadOnly: true})
if err != nil { if err != nil {
prog.Fatal(err) prog.Fatal(err)
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment