Coder Social home page Coder Social logo

go-libzfs's People

Contributors

aslmvc avatar atykhyy avatar deitch avatar didrocks avatar fkasumovic avatar ncabatoff avatar prometherion avatar steigr avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

go-libzfs's Issues

Wrong pool status reported?

When running pool.Status():

allPools, err := zfs.PoolOpenAll()
if err != nil {
	println(err)
}

for _, pool := range allPools {
	status, err := pool.Status()
	if err != nil {
		println(err)
	}
	state, err := pool.State()
	if err != nil {
		println(err)
	}
	name, err := pool.Name()
	if err != nil {
		println(err)
	}
	fmt.Printf("Pool name: %s\n", name)
	fmt.Printf("Status: %s, State: %s\n", status, state)

}
zfs.PoolCloseAll(allPools)

I get this output:

ps@ubuntu-srv-zfs:~/go/src/testzfs$ ./testzfs
Pool name: tank2
Status: REMOVED_DEV, State: ACTIVE

REMOVED_DEV status seems wrong given that I have no issues with my pool:

ps@ubuntu-srv-zfs:~$ sudo zpool status -v
  pool: tank2
 state: ONLINE
  scan: scrub repaired 0B in 9h19m with 0 errors on Sun Dec 15 09:19:05 2019
config:

	NAME                        STATE     READ WRITE CKSUM
	tank2                       ONLINE       0     0     0
	  mirror-0                  ONLINE       0     0     0
	    wwn-0x5000c500a42a268c  ONLINE       0     0     0
	    wwn-0x5000c500afedf367  ONLINE       0     0     0
	  mirror-1                  ONLINE       0     0     0
	    wwn-0x50014ee25e4b10c8  ONLINE       0     0     0
	    wwn-0x50014ee2b76f2200  ONLINE       0     0     0

errors: No known data errors

Am I doing something wrong here? I'm expecting to get Status: OK, given my understanding of the source code in zpool.go.

System information

Type Version/Name
Distribution Name Ubuntu Server
Distribution Version 18.04.3 LTS
Linux Kernel GNU/Linux 4.15.0-72-generic
Architecture x86_64
ZFS Version 0.7.5-1ubuntu16.6
SPL Version 0.7.5-1ubuntu2
go-libzfs tag v0.2.3

zfs-2.1.x compatibility

Hello! Is it possible to update for zfs-2.1.x?

# go get github.com/bicomsystems/go-libzfs
go: downloading github.com/bicomsystems/go-libzfs v0.3.5
# github.com/bicomsystems/go-libzfs
zfs.c: In function ‘dataset_rename’:
zfs.c:136:43: error: incompatible type for argument 3 of ‘zfs_rename’
  return zfs_rename(dataset->zh, new_name, recur, force_unm);
                                           ^~~~~
In file included from zfs.c:5:
/usr/include/libzfs/libzfs.h:661:53: note: expected ‘renameflags_t’ {aka ‘struct renameflags’} but argument is of type ‘boolean_t’ {aka         ‘enum <anonymous>’}
 extern int zfs_rename(zfs_handle_t *, const char *, renameflags_t);
                                                     ^~~~~~~~~~~~~
zfs.c:136:9: error: too many arguments to function ‘zfs_rename’
  return zfs_rename(dataset->zh, new_name, recur, force_unm);
         ^~~~~~~~~~
In file included from zfs.c:5:
/usr/include/libzfs/libzfs.h:661:12: note: declared here
 extern int zfs_rename(zfs_handle_t *, const char *, renameflags_t);

ZFS:

# modinfo zfs
filename:       /lib/modules/5.4.17-2136.302.7.2.el8uek.x86_64/extra/zfs.ko.xz
version:        2.1.2-1

Go:

# go version
go version go1.17.6 linux/amd64

ZPool properties are not parsable

I noticed a difference between values provided by zfs.Dataset properties and zfs.Pool ones: basically, on ZPool instances, quantity resources like space allocated or space size are expressed as human-readable value, as opposed to what's happening with Dataset where I can get bytes values with ease.

I tried to dig deeper on the C implementation but hadn't luck: do you plan to fill this gap of properties presentation?

JFI ZPool allows to retrieve parsable values:

# zpool list -p
NAME     SIZE  ALLOC   FREE  CKPOINT  EXPANDSZ   FRAG    CAP  DEDUP    HEALTH  ALTROOT
mypool  1006632960  419840  1006213120        -         -      0      0   1.00    ONLINE  -

Regression 0.8 branch: creating a pool with PoolPropAltRoot (zfs 0.8/commit 8bf9664c9c35) panics in the go code.

When creating a pool using go-libzfs current latest master commit + zfs 0.8 (ubuntu eoan package), there is a panic in ReloadProperties:

panic: runtime error: index out of range

goroutine 1 [running]:
github.com/bicomsystems/go-libzfs.(*Pool).ReloadProperties(0xc0000a1538, 0x22011f0, 0x2200380)
	/root/go/pkg/mod/github.com/bicomsystems/[email protected]/zpool.go:518 +0x707
github.com/bicomsystems/go-libzfs.PoolOpen(0x4cf5f8, 0x5, 0x22011f0, 0xc0000aa400, 0x20, 0x20, 0x0, 0x0, 0x0)
	/root/go/pkg/mod/github.com/bicomsystems/[email protected]/zpool.go:149 +0xa8
github.com/bicomsystems/go-libzfs.PoolCreate(0x4cf5f8, 0x5, 0x4cf4a9, 0x4, 0xc000053dd0, 0x1, 0x1, 0x0, 0x0, 0x0, ...)
	/root/go/pkg/mod/github.com/bicomsystems/[email protected]/zpool.go:968 +0xbb5
main.main()
	/home/didrocks/work/zsys/main.go:23 +0x2cd
exit status 2

Note that running go test in the project fails similarly.

Here is a small reproducer:

package main

import (
	"os"

	zfs "github.com/bicomsystems/go-libzfs"
)

func main() {
	p := "/tmp/tempPoolFile"
	f, _ := os.Create(p)
	f.Truncate(100 * 1024 * 1024)
	f.Close()

	vdev := zfs.VDevTree{
		Type:    zfs.VDevTypeFile,
		Path:    p,
		Devices: []zfs.VDevTree{{Type: zfs.VDevTypeFile, Path: p}},
	}
	features := make(map[string]string)
	props := make(map[zfs.Prop]string)
	fsprops := make(map[zfs.Prop]string)
	zfs.PoolCreate("rpool", vdev, features, props, fsprops)
}

Note that this code used to work with zfs 0.7 and v0.2.3 release.

random panic on DS close after deletion

I'm using this package to provide a sort of HTTP APIs to manage ZFS dataset.

So far so good, but we started seeing some random panic crashes with the following stack:

fatal error: unexpected signal during runtime execution                                                                                                                                                                                       
[signal SIGSEGV: segmentation violation code=0x80 addr=0x0 pc=0x7f76f734a1e5]                                                                                                                                                                 
                                                                                                                                                                                                                                              
runtime stack:                                                                                                                                                                                                                                
runtime.throw(0xcd90ea, 0x2a)                                                                                                                                                                                                                 
        /usr/local/go/src/runtime/panic.go:774 +0x72                                                                                                                                                                                          
runtime.sigpanic()                                                                                                                                                                                                                            
        /usr/local/go/src/runtime/signal_unix.go:378 +0x47c                                                                                                                                                                                   
                                                                                                                                                                                                                                              
goroutine 1524 [syscall]:                                                                                                                                                                                                                     
runtime.cgocall(0xb12a80, 0xc000165310, 0x300000002)                                                                                                                                                                                          
        /usr/local/go/src/runtime/cgocall.go:128 +0x5b fp=0xc0001652e0 sp=0xc0001652a8 pc=0x40992b                                                                                                                                            
github.com/bicomsystems/go-libzfs._Cfunc_dataset_list_close(0x7f76f6fa4fe0)                                                                                                                                                                   
        _cgo_gotypes.go:483 +0x41 fp=0xc000165310 sp=0xc0001652e0 pc=0xa4f901                                                                                                                                                                 
github.com/bicomsystems/go-libzfs.(*Dataset).Close.func1(0xc000165410)                                                                                                                                                                        
        /go/pkg/mod/github.com/bicomsystems/[email protected]/zfs.go:187 +0x5e fp=0xc000165350 sp=0xc000165310 pc=0xa5e63e                                                                                                                     
github.com/bicomsystems/go-libzfs.(*Dataset).Close(0xc000165410)                                                                                                                                                                              
        /go/pkg/mod/github.com/bicomsystems/[email protected]/zfs.go:187 +0x5d fp=0xc0001653e8 sp=0xc000165350 pc=0xa5483d                                                                                                                     
github.com/bicomsystems/go-libzfs.(*Dataset).Close(0xc000165510)                                                                                                                                                                              
        /go/pkg/mod/github.com/bicomsystems/[email protected]/zfs.go:191 +0x10b fp=0xc000165480 sp=0xc0001653e8 pc=0xa548eb                                                                                                                    
cloud.team/zfs-api/pkg/zfs/dataset.Delete(0xc0001b0736, 0x1d, 0x0, 0xc00012a1a0, 0xc00015b390, 0xcc00d0, 0xa, 0xc00049a0ae, 0xa, 0xc00003a1c0, ...)                                                                                           
        /etc/zfs_api/pkg/zfs/dataset/delete.go:29 +0x1f2 fp=0xc000165580 sp=0xc000165480 pc=0xa67c92                                                                                                                                          
cloud.team/zfs-api/pkg/webserver/v1beta1.DeleteDataset(0xc0003fa160)                                                                                                                                                                          
        /etc/zfs_api/pkg/webserver/v1beta1/delete_dataset.go:40 +0x2ef fp=0xc0001656d0 sp=0xc000165580 pc=0xa6f4ef                                                                                                                            
github.com/gin-gonic/gin.(*Context).Next(0xc0003fa160)                                                                                                                                                                                        
        /go/pkg/mod/github.com/gin-gonic/[email protected]/context.go:124 +0x3b fp=0xc0001656f0 sp=0xc0001656d0 pc=0xa3a36b                                                                                                                          
cloud.team/zfs-api/pkg/webserver/utility.DatasetDeleteDefault.func1(0xc0003fa160)                                                                                                                                                             
        /etc/zfs_api/pkg/webserver/utility/middleware.go:56 +0x118 fp=0xc000165750 sp=0xc0001656f0 pc=0xa644e8                                                                                                                                
github.com/gin-gonic/gin.(*Context).Next(0xc0003fa160)                                                                                                                                                                                        
        /go/pkg/mod/github.com/gin-gonic/[email protected]/context.go:124 +0x3b fp=0xc000165770 sp=0xc000165750 pc=0xa3a36b                                                                                                                          
cloud.team/zfs-api/pkg/webserver/utility.DatasetPathByQueryString.func1(0xc0003fa160)                                                                                                                                                         
        /etc/zfs_api/pkg/webserver/utility/middleware.go:115 +0x118 fp=0xc0001657d0 sp=0xc000165770 pc=0xa64eb8                                                                                                                               
github.com/gin-gonic/gin.(*Context).Next(0xc0003fa160)                                                                                                                                                                                        
        /go/pkg/mod/github.com/gin-gonic/[email protected]/context.go:124 +0x3b fp=0xc0001657f0 sp=0xc0001657d0 pc=0xa3a36b                                                                                                                          
github.com/gin-gonic/gin.RecoveryWithWriter.func1(0xc0003fa160)                                                                                                                                                                               
        /go/pkg/mod/github.com/gin-gonic/[email protected]/recovery.go:83 +0x64 fp=0xc000165850 sp=0xc0001657f0 pc=0xa4d274                                                                                                                          
github.com/gin-gonic/gin.(*Context).Next(0xc0003fa160)                                                                                                                                                                                        
        /go/pkg/mod/github.com/gin-gonic/[email protected]/context.go:124 +0x3b fp=0xc000165870 sp=0xc000165850 pc=0xa3a36b                                                                                                                          
github.com/Depado/ginprom.(*Prometheus).Instrument.func1(0xc0003fa160)                                                                                                                                                                        
        /go/pkg/mod/github.com/!depado/[email protected]/prom.go:285 +0x115 fp=0xc000165918 sp=0xc000165870 pc=0xadbaa5                                                                                                                          
github.com/gin-gonic/gin.(*Context).Next(0xc0003fa160)                                                                                                                                                                                        
        /go/pkg/mod/github.com/gin-gonic/[email protected]/context.go:124 +0x3b fp=0xc000165938 sp=0xc000165918 pc=0xa3a36b                                                                                                                          
github.com/gin-gonic/gin.LoggerWithConfig.func1(0xc0003fa160)                                                                                                                                                                                 
        /go/pkg/mod/github.com/gin-gonic/[email protected]/logger.go:240 +0xe1 fp=0xc000165ad8 sp=0xc000165938 pc=0xa4c321                                                                                                                           
github.com/gin-gonic/gin.(*Context).Next(0xc0003fa160)                                                                                                                                                                                        
        /go/pkg/mod/github.com/gin-gonic/[email protected]/context.go:124 +0x3b fp=0xc000165af8 sp=0xc000165ad8 pc=0xa3a36b                                                                                                                          
github.com/gin-gonic/gin.(*Engine).handleHTTPRequest(0xc0000e4000, 0xc0003fa160)                                                                                                                                                              
        /go/pkg/mod/github.com/gin-gonic/[email protected]/gin.go:389 +0x5b2 fp=0xc000165be0 sp=0xc000165af8 pc=0xa438f2                                                                                                                             
github.com/gin-gonic/gin.(*Engine).ServeHTTP(0xc0000e4000, 0xdf83e0, 0xc00014c7e0, 0xc000248600)                                                                                                                                              
        /go/pkg/mod/github.com/gin-gonic/[email protected]/gin.go:351 +0x134 fp=0xc000165c18 sp=0xc000165be0 pc=0xa43124                                                                                                                             
net/http.serverHandler.ServeHTTP(0xc0000160e0, 0xdf83e0, 0xc00014c7e0, 0xc000248600)                                                                                                                                                          
        /usr/local/go/src/net/http/server.go:2802 +0xa4 fp=0xc000165c48 sp=0xc000165c18 pc=0x76d044                                                                                                                                           
net/http.(*conn).serve(0xc000150fa0, 0xdfb4e0, 0xc000f254c0)                                                                                                                                                                                  
        /usr/local/go/src/net/http/server.go:1890 +0x875 fp=0xc000165fc8 sp=0xc000165c48 pc=0x7688e5
runtime.goexit()
        /usr/local/go/src/runtime/asm_amd64.s:1357 +0x1 fp=0xc000165fd0 sp=0xc000165fc8 pc=0x465681                                                                                                                                           
created by net/http.(*Server).Serve                                                                                                                                                                                                           
        /usr/local/go/src/net/http/server.go:2928 +0x384                                                                                                                                                                                      

goroutine 1 [IO wait]:
internal/poll.runtime_pollWait(0x7f76f47afdd8, 0x72, 0x0)
        /usr/local/go/src/runtime/netpoll.go:184 +0x55
internal/poll.(*pollDesc).wait(0xc00048c298, 0x72, 0x0, 0x0, 0xcbd32b)
        /usr/local/go/src/internal/poll/fd_poll_runtime.go:87 +0x45
internal/poll.(*pollDesc).waitRead(...)
        /usr/local/go/src/internal/poll/fd_poll_runtime.go:92
internal/poll.(*FD).Accept(0xc00048c280, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
        /usr/local/go/src/internal/poll/fd_unix.go:384 +0x1f8
net.(*netFD).accept(0xc00048c280, 0xc0001679d8, 0x76dfd4, 0xc000016180)
        /usr/local/go/src/net/fd_unix.go:238 +0x42
net.(*TCPListener).accept(0xc000414e60, 0x5ec77374, 0xc0001679d8, 0x4ca926)
        /usr/local/go/src/net/tcpsock_posix.go:139 +0x32
net.(*TCPListener).Accept(0xc000414e60, 0xc000167a28, 0x18, 0xc000000180, 0x76d504)
        /usr/local/go/src/net/tcpsock.go:261 +0x47
net/http.(*Server).Serve(0xc0000160e0, 0xdf8120, 0xc000414e60, 0x0, 0x0)
        /usr/local/go/src/net/http/server.go:2896 +0x280
net/http.(*Server).ListenAndServe(0xc0000160e0, 0xc0000160e0, 0xc000171c50)
        /usr/local/go/src/net/http/server.go:2825 +0xb7
net/http.ListenAndServe(...)
        /usr/local/go/src/net/http/server.go:3081
github.com/gin-gonic/gin.(*Engine).Run(0xc0000e4000, 0xc000171cb8, 0x1, 0x1, 0x0, 0x0)
        /go/pkg/mod/github.com/gin-gonic/[email protected]/gin.go:294 +0x16d
cloud.team/zfs-api/pkg/webserver.(*WebServer).Start(0xc0003f0f50)
        /etc/zfs_api/pkg/webserver/webserver.go:28 +0xcf
cloud.team/zfs-api/cmd.glob..func2(0x12dc7a0, 0x1c31b48, 0x0, 0x0)
        /etc/zfs_api/cmd/root.go:34 +0x166
github.com/spf13/cobra.(*Command).execute(0x12dc7a0, 0xc0000321d0, 0x0, 0x0, 0x12dc7a0, 0xc0000321d0)
        /go/pkg/mod/github.com/spf13/[email protected]/command.go:830 +0x2aa
github.com/spf13/cobra.(*Command).ExecuteC(0x12dc7a0, 0x443cfa, 0x12ebaa0, 0xc000000180)
        /go/pkg/mod/github.com/spf13/[email protected]/command.go:914 +0x2fb
github.com/spf13/cobra.(*Command).Execute(...)
        /go/pkg/mod/github.com/spf13/[email protected]/command.go:864
cloud.team/zfs-api/cmd.Execute()
        /etc/zfs_api/cmd/root.go:54 +0x31
main.main()
        /etc/zfs_api/main.go:6 +0x20

goroutine 12 [IO wait, 28 minutes]:
internal/poll.runtime_pollWait(0x7f76f47afea8, 0x72, 0x0)
        /usr/local/go/src/runtime/netpoll.go:184 +0x55
internal/poll.(*pollDesc).wait(0xc0004a4018, 0x72, 0x0, 0x0, 0xcbd32b)
        /usr/local/go/src/internal/poll/fd_poll_runtime.go:87 +0x45
internal/poll.(*pollDesc).waitRead(...)
        /usr/local/go/src/internal/poll/fd_poll_runtime.go:92
internal/poll.(*FD).Accept(0xc0004a4000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
        /usr/local/go/src/internal/poll/fd_unix.go:384 +0x1f8
net.(*netFD).accept(0xc0004a4000, 0xc000075d80, 0xc000476000, 0x7f76f6dd3b28)
        /usr/local/go/src/net/fd_unix.go:238 +0x42
net.(*TCPListener).accept(0xc000304000, 0xc000075db0, 0x4134c8, 0x30)
        /usr/local/go/src/net/tcpsock_posix.go:139 +0x32
net.(*TCPListener).Accept(0xc000304000, 0xc46b80, 0xc0003ca180, 0xbc4760, 0x12d1f60)
        /usr/local/go/src/net/tcpsock.go:261 +0x47
net/http.(*Server).Serve(0xc000018000, 0xdf8120, 0xc000304000, 0x0, 0x0)
        /usr/local/go/src/net/http/server.go:2896 +0x280
net/http.(*Server).ListenAndServe(0xc000018000, 0xc000018000, 0x0)
        /usr/local/go/src/net/http/server.go:2825 +0xb7
net/http.ListenAndServe(...)
        /usr/local/go/src/net/http/server.go:3081
cloud.team/zfs-api/pkg/webserver.NewWebServer.func1()
        /etc/zfs_api/pkg/webserver/webserver.go:40 +0x73
created by cloud.team/zfs-api/pkg/webserver.NewWebServer
        /etc/zfs_api/pkg/webserver/webserver.go:39 +0xb7

goroutine 39 [IO wait]:
internal/poll.runtime_pollWait(0x7f76f47afd08, 0x72, 0xffffffffffffffff)
        /usr/local/go/src/runtime/netpoll.go:184 +0x55
internal/poll.(*pollDesc).wait(0xc000412018, 0x72, 0x1000, 0x1000, 0xffffffffffffffff)
        /usr/local/go/src/internal/poll/fd_poll_runtime.go:87 +0x45
internal/poll.(*pollDesc).waitRead(...)
        /usr/local/go/src/internal/poll/fd_poll_runtime.go:92
internal/poll.(*FD).Read(0xc000412000, 0xc000198000, 0x1000, 0x1000, 0x0, 0x0, 0x0)
        /usr/local/go/src/internal/poll/fd_unix.go:169 +0x1cf
net.(*netFD).Read(0xc000412000, 0xc000198000, 0x1000, 0x1000, 0xc00016e6c0, 0x86, 0x120)
        /usr/local/go/src/net/fd_unix.go:202 +0x4f
net.(*conn).Read(0xc00012a010, 0xc000198000, 0x1000, 0x1000, 0x0, 0x0, 0x0)
        /usr/local/go/src/net/net.go:184 +0x68
net/http.(*connReader).Read(0xc000386090, 0xc000198000, 0x1000, 0x1000, 0xc0004a4e80, 0x0, 0x2200000000)
        /usr/local/go/src/net/http/server.go:785 +0xf4
bufio.(*Reader).fill(0xc00017a000)
        /usr/local/go/src/bufio/bufio.go:100 +0x103
bufio.(*Reader).ReadSlice(0xc00017a000, 0xc0013d4c0a, 0x7f76f4aaebf8, 0xc0010259a8, 0x412c56, 0xc000248200, 0x100)
        /usr/local/go/src/bufio/bufio.go:359 +0x3d
bufio.(*Reader).ReadLine(0xc00017a000, 0xc0010259b0, 0x1c14a20, 0x7f76f6dd3b28, 0x0, 0xc7c020, 0xc000291290)
        /usr/local/go/src/bufio/bufio.go:388 +0x34
net/textproto.(*Reader).readLineSlice(0xc000291290, 0xc000248200, 0xc000412000, 0x0, 0x0, 0x437dec)
        /usr/local/go/src/net/textproto/reader.go:57 +0x6c
net/textproto.(*Reader).ReadLine(...)
        /usr/local/go/src/net/textproto/reader.go:38
net/http.readRequest(0xc00017a000, 0x0, 0xc000248200, 0x0, 0x0)
        /usr/local/go/src/net/http/request.go:1012 +0x92
net/http.(*conn).readRequest(0xc0000c2b40, 0xdfb4e0, 0xc00013a000, 0x0, 0x0, 0x0)
        /usr/local/go/src/net/http/server.go:965 +0x15f
net/http.(*conn).serve(0xc0000c2b40, 0xdfb4e0, 0xc00013a000)
        /usr/local/go/src/net/http/server.go:1817 +0x6d4
created by net/http.(*Server).Serve
        /usr/local/go/src/net/http/server.go:2928 +0x384

goroutine 44 [IO wait]:
internal/poll.runtime_pollWait(0x7f76f47afb68, 0x72, 0xffffffffffffffff)
        /usr/local/go/src/runtime/netpoll.go:184 +0x55
internal/poll.(*pollDesc).wait(0xc00048c818, 0x72, 0x1000, 0x1000, 0xffffffffffffffff)
        /usr/local/go/src/internal/poll/fd_poll_runtime.go:87 +0x45
internal/poll.(*pollDesc).waitRead(...)
        /usr/local/go/src/internal/poll/fd_poll_runtime.go:92
internal/poll.(*FD).Read(0xc00048c800, 0xc00021f000, 0x1000, 0x1000, 0x0, 0x0, 0x0)
        /usr/local/go/src/internal/poll/fd_unix.go:169 +0x1cf
net.(*netFD).Read(0xc00048c800, 0xc00021f000, 0x1000, 0x1000, 0xc000e54370, 0x87, 0xb0)
        /usr/local/go/src/net/fd_unix.go:202 +0x4f
net.(*conn).Read(0xc00012a068, 0xc00021f000, 0x1000, 0x1000, 0x0, 0x0, 0x0)
        /usr/local/go/src/net/net.go:184 +0x68
net/http.(*connReader).Read(0xc00031aa50, 0xc00021f000, 0x1000, 0x1000, 0x48227c, 0x12d4f80, 0x22000000b0)
        /usr/local/go/src/net/http/server.go:785 +0xf4
bufio.(*Reader).fill(0xc000042d80)
        /usr/local/go/src/bufio/bufio.go:100 +0x103
bufio.(*Reader).ReadSlice(0xc000042d80, 0xa, 0x7f76f6ddc6e0, 0xc0001699a8, 0x412c56, 0xc0000c4900, 0x100)
        /usr/local/go/src/bufio/bufio.go:359 +0x3d
bufio.(*Reader).ReadLine(0xc000042d80, 0xc0001699b0, 0xc000096700, 0x7f76f6dd2008, 0x0, 0x0, 0xc0001699f0)
        /usr/local/go/src/bufio/bufio.go:388 +0x34
net/textproto.(*Reader).readLineSlice(0xc0003a0db0, 0xc0000c4900, 0xc00048c800, 0x0, 0x0, 0x437dec)
        /usr/local/go/src/net/textproto/reader.go:57 +0x6c
net/textproto.(*Reader).ReadLine(...)
        /usr/local/go/src/net/textproto/reader.go:38
net/http.readRequest(0xc000042d80, 0x0, 0xc0000c4900, 0x0, 0x0)
        /usr/local/go/src/net/http/request.go:1012 +0x92
net/http.(*conn).readRequest(0xc000366000, 0xdfb4e0, 0xc00013a240, 0x0, 0x0, 0x0)
        /usr/local/go/src/net/http/server.go:965 +0x15f
net/http.(*conn).serve(0xc000366000, 0xdfb4e0, 0xc00013a240)
        /usr/local/go/src/net/http/server.go:1817 +0x6d4
created by net/http.(*Server).Serve
        /usr/local/go/src/net/http/server.go:2928 +0x384

goroutine 1024 [IO wait, 2 minutes]:
internal/poll.runtime_pollWait(0x7f76f47af9c8, 0x72, 0xffffffffffffffff)
        /usr/local/go/src/runtime/netpoll.go:184 +0x55
internal/poll.(*pollDesc).wait(0xc00034a998, 0x72, 0x1000, 0x1000, 0xffffffffffffffff)
        /usr/local/go/src/internal/poll/fd_poll_runtime.go:87 +0x45
internal/poll.(*pollDesc).waitRead(...)
        /usr/local/go/src/internal/poll/fd_poll_runtime.go:92
internal/poll.(*FD).Read(0xc00034a980, 0xc000f18000, 0x1000, 0x1000, 0x0, 0x0, 0x0)
        /usr/local/go/src/internal/poll/fd_unix.go:169 +0x1cf
net.(*netFD).Read(0xc00034a980, 0xc000f18000, 0x1000, 0x1000, 0x0, 0x3030320000000000, 0xed6596a22)
        /usr/local/go/src/net/fd_unix.go:202 +0x4f
net.(*conn).Read(0xc000010030, 0xc000f18000, 0x1000, 0x1000, 0x0, 0x0, 0x0)
        /usr/local/go/src/net/net.go:184 +0x68
net/http.(*connReader).Read(0xc00012c450, 0xc000f18000, 0x1000, 0x1000, 0xc00008c640, 0x12e38a8, 0x2)
        /usr/local/go/src/net/http/server.go:785 +0xf4
bufio.(*Reader).fill(0xc0013f4480)
        /usr/local/go/src/bufio/bufio.go:100 +0x103
bufio.(*Reader).ReadSlice(0xc0013f4480, 0xa, 0xc001029b28, 0xc0010299a8, 0x412c56, 0xc00046c400, 0x100)
        /usr/local/go/src/bufio/bufio.go:359 +0x3d
bufio.(*Reader).ReadLine(0xc0013f4480, 0xc0010299b0, 0xc0000e9180, 0x7f76f6dd3b28, 0x0, 0x4, 0xc0010299f0)
        /usr/local/go/src/bufio/bufio.go:388 +0x34
net/textproto.(*Reader).readLineSlice(0xc000409c80, 0xc00046c400, 0xc00034a980, 0x0, 0x0, 0x437dec)
        /usr/local/go/src/net/textproto/reader.go:57 +0x6c
net/textproto.(*Reader).ReadLine(...)
        /usr/local/go/src/net/textproto/reader.go:38
net/http.readRequest(0xc0013f4480, 0x0, 0xc00046c400, 0x0, 0x0)
        /usr/local/go/src/net/http/request.go:1012 +0x92
net/http.(*conn).readRequest(0xc0000c3720, 0xdfb4e0, 0xc00013a340, 0x0, 0x0, 0x0)
        /usr/local/go/src/net/http/server.go:965 +0x15f
net/http.(*conn).serve(0xc0000c3720, 0xdfb4e0, 0xc00013a340)
        /usr/local/go/src/net/http/server.go:1817 +0x6d4
created by net/http.(*Server).Serve
        /usr/local/go/src/net/http/server.go:2928 +0x384

goroutine 1394 [IO wait, 2 minutes]:
internal/poll.runtime_pollWait(0x7f76f47afc38, 0x72, 0xffffffffffffffff)
        /usr/local/go/src/runtime/netpoll.go:184 +0x55
internal/poll.(*pollDesc).wait(0xc000413b98, 0x72, 0x1000, 0x1000, 0xffffffffffffffff)
        /usr/local/go/src/internal/poll/fd_poll_runtime.go:87 +0x45
internal/poll.(*pollDesc).waitRead(...)
        /usr/local/go/src/internal/poll/fd_poll_runtime.go:92
internal/poll.(*FD).Read(0xc000413b80, 0xc000da8000, 0x1000, 0x1000, 0x0, 0x0, 0x0)
        /usr/local/go/src/internal/poll/fd_unix.go:169 +0x1cf
net.(*netFD).Read(0xc000413b80, 0xc000da8000, 0x1000, 0x1000, 0x0, 0x3030320000000000, 0xed6596a1f)
        /usr/local/go/src/net/fd_unix.go:202 +0x4f
net.(*conn).Read(0xc000010b20, 0xc000da8000, 0x1000, 0x1000, 0x0, 0x0, 0x0)
        /usr/local/go/src/net/net.go:184 +0x68
net/http.(*connReader).Read(0xc0001cdbc0, 0xc000da8000, 0x1000, 0x1000, 0xc001358240, 0x12e38a8, 0x2)
        /usr/local/go/src/net/http/server.go:785 +0xf4
bufio.(*Reader).fill(0xc00017a4e0)
        /usr/local/go/src/bufio/bufio.go:100 +0x103
bufio.(*Reader).ReadSlice(0xc00017a4e0, 0xa, 0xc001023b28, 0xc0010239a8, 0x412c56, 0xc000248800, 0x100)
        /usr/local/go/src/bufio/bufio.go:359 +0x3d
bufio.(*Reader).ReadLine(0xc00017a4e0, 0xc0010239b0, 0xc0000e9180, 0x7f76f6dd3460, 0x0, 0x3, 0xc0010239f0)
        /usr/local/go/src/bufio/bufio.go:388 +0x34
net/textproto.(*Reader).readLineSlice(0xc00024f920, 0xc000248800, 0xc000413b80, 0x0, 0x0, 0x437dec)
        /usr/local/go/src/net/textproto/reader.go:57 +0x6c
net/textproto.(*Reader).ReadLine(...)
        /usr/local/go/src/net/textproto/reader.go:38
net/http.readRequest(0xc00017a4e0, 0x0, 0xc000248800, 0x0, 0x0)
        /usr/local/go/src/net/http/request.go:1012 +0x92
net/http.(*conn).readRequest(0xc0003668c0, 0xdfb4e0, 0xc000f25900, 0x0, 0x0, 0x0)
        /usr/local/go/src/net/http/server.go:965 +0x15f
net/http.(*conn).serve(0xc0003668c0, 0xdfb4e0, 0xc000f25900)
        /usr/local/go/src/net/http/server.go:1817 +0x6d4
created by net/http.(*Server).Serve
        /usr/local/go/src/net/http/server.go:2928 +0x384

goroutine 1525 [IO wait]:
internal/poll.runtime_pollWait(0x7f76f47afa98, 0x72, 0xffffffffffffffff)
        /usr/local/go/src/runtime/netpoll.go:184 +0x55
internal/poll.(*pollDesc).wait(0xc0004a5498, 0x72, 0x0, 0x1, 0xffffffffffffffff)
        /usr/local/go/src/internal/poll/fd_poll_runtime.go:87 +0x45
internal/poll.(*pollDesc).waitRead(...)
        /usr/local/go/src/internal/poll/fd_poll_runtime.go:92
internal/poll.(*FD).Read(0xc0004a5480, 0xc0002ddd51, 0x1, 0x1, 0x0, 0x0, 0x0)
        /usr/local/go/src/internal/poll/fd_unix.go:169 +0x1cf
net.(*netFD).Read(0xc0004a5480, 0xc0002ddd51, 0x1, 0x1, 0xc000f25458, 0xc00041e768, 0x48007c)
        /usr/local/go/src/net/fd_unix.go:202 +0x4f
net.(*conn).Read(0xc0001ec138, 0xc0002ddd51, 0x1, 0x1, 0x0, 0x0, 0x0)
        /usr/local/go/src/net/net.go:184 +0x68
net/http.(*connReader).backgroundRead(0xc0002ddd40)
        /usr/local/go/src/net/http/server.go:677 +0x58
created by net/http.(*connReader).startBackgroundRead
        /usr/local/go/src/net/http/server.go:673 +0xd4

Just providing the pkg/zfs/dataset/delete.go content for getting aligned with the stack trace:

func Delete(pool string, dataset schemas.Dataset, mode schemas.DatasetDestroyMode) errors.Error {
	ds, dsErr := zfs.DatasetOpen(NewName(pool, dataset.Path, nil).String())
	if dsErr != nil {
		return errors.ComposeError(dsErr)
	}
	defer ds.Close()

	// A dataset mounted cannot be deleted unless it's not mounted,
	// so we replicate the same behavior of zfs destroy, or unmounting
	// and deleting.
	if ok, _ := ds.IsMounted(); ok {
		if err := mount(&ds, false); err != nil {
			return errors.ComposeError(err)
		}
	}

	err := zfsapi.Destroy(ds, mode)
	if err != nil {
		return errors.ComposeError(err) # <<< delete.go:29
	}

	return nil
}

func ComposeError(err error) Error {
	if strings.Contains(err.Error(), "no such pool") {
		return NewPoolNotFound(err)
	}
	if strings.Contains(err.Error(), "dataset does not exist") {
		return NewDatasetNotFound(err)
	}
	if err.Error() == "dataset already exists" {
		return NewDatasetConflict(err)
	}
	return NewGenericError(err)
}

As you can see, the panic starts at delete.go:29 but I guess it's the deferred function ds.Close().

(different) go error (1.6, Fedora 24)

This might be related to cmosetick's issue, or it may not:

$ go get github.com/bicomsystems/go-libzfs
# github.com/bicomsystems/go-libzfs
could not determine kind of name for C.boolean_t
could not determine kind of name for C.clear_last_error
could not determine kind of name for C.libzfs_errno
could not determine kind of name for C.libzfs_error_description
could not determine kind of name for C.libzfs_handle_ptr
could not determine kind of name for C.libzfs_init

and in cloned git repo:

$ go test
# github.com/bicomsystems/go-libzfs
could not determine kind of name for C.boolean_t
could not determine kind of name for C.clear_last_error
could not determine kind of name for C.libzfs_errno
could not determine kind of name for C.libzfs_error_description
could not determine kind of name for C.libzfs_handle_ptr
could not determine kind of name for C.libzfs_init
FAIL github.com/bicomsystems/go-libzfs [build failed]

My system:
Fedora 24, kernel 4.10.11
go-1.6.4 (can't downgrade via package management system to 1.4, so probably not the way to go)
zfs-0.7.0-rc3 and libzfs2 installed and source dir linked to gopath

Am I missing something? Or might something not work with newest versions of some softwares?

go get error with go 1.6

Just tried go get with this on go 1.6:

go get github.com/bicomsystems/go-libzfs
# github.com/bicomsystems/go-libzfs
src/gocode/src/github.com/bicomsystems/go-libzfs/common.go:16:10: fatal error: 'libzfs.h' file not found
#include <libzfs.h>
         ^
1 error generated.

Platform
OS X 10.11.3
go version go1.6 darwin/amd64
Open ZFS version:
brew cask info openzfs
$ openzfs: 1.4.5

Help understanding zpool state

Hello, when I run zpool status I see

root@pve-1:~# zpool status -v
  pool: data
 state: ONLINE
  scan: none requested
config:

	NAME                      STATE     READ WRITE CKSUM
	data                      ONLINE       0     0     0
	  scsi-35002538e402d9b06  ONLINE       0     0     0
	  scsi-350025388a05aeb61  ONLINE       0     0     0

When I call call pool.Status() I see "state: ACTIVE".

func check() error {
    globalPools, err := zfs.PoolOpenAll()
    defer zfs.PoolCloseAll(globalPools)
    if err != nil {
        return err
    }

    for _, pool := range globalPools {
        state, err := pool.State()
        if err != nil {
            return err
        }
        fmt.Println("pool state:", state)
    }

    return nil
}
pool state: ACTIVE

I would expect to see pool state "ONLINE", not "ACTIVE". Am I doing this incorrectly?

ZFS 2.0 support

I have a project that depends on go-libzfs. I am currently refreshing it, and was hoping to build against the latest openzfs but I seem to get some errors:

Step 10/14 : RUN GOOS=linux GOARCH=amd64 go test ./...
 ---> Running in d1570b2a8acc
...
/root/go/pkg/mod/github.com/bicomsystems/[email protected]/zpool.go:1108:39: could not determine kind of name for C.pool_initialize_func_t
/root/go/pkg/mod/github.com/bicomsystems/[email protected]/zpool.go:1108:5: could not determine kind of name for C.zpool_initialize

I can build against an older version, but am wondering if 2.0 is on the roadmap? If contributors are needed, please let me know. I am not at all experienced with C but I do have plenty of Go experience and access to systems running OpenZFS on Linux and FreeBSD. I am happy to deploy test systems.

Status strings?

The zpool status command returns not only the status code, but also some fairly standard text describing the issue and recovery options.

Would you consider including those texts as const string in the library, so that a consumer of the library using pool.Status() can have those strings? I would be happy to open a PR for it.

The strings are all here.

Granted, this is a library and not a CLI, which would need to report those, but the strings are useful for anyone building on this.

libzfs is not a stable interface

libzfs is explicitly not a stable interface; libzfs_core (formerly libzfs2) is intended to provide one when it is complete. The zfs(1M) and zpool(1M) userspace tools actually have a stability commitment.

zfs 2.2 compat: zpool.c:513:17: error: too many arguments to function ‘zpool_search_import’


In file included from zpool.c:7:
/usr/include/libzfs/libzutil.h:93:43: note: expected ‘libpc_handle_t *’ {aka ‘struct libpc_handle *’} but argument is of type ‘libzfs_handle_ptr’ {aka ‘struct libzfs_handle *’}
   93 | _LIBZUTIL_H nvlist_t *zpool_search_import(libpc_handle_t *, importargs_t *);
      |                                           ^~~~~~~~~~~~~~~~
zpool.c:513:17: error: too many arguments to function ‘zpool_search_import’
  513 |         pools = zpool_search_import(zfsh, &idata, &libzfs_config_ops);
      |                 ^~~~~~~~~~~~~~~~~~~
/usr/include/libzfs/libzutil.h:93:23: note: declared here
   93 | _LIBZUTIL_H nvlist_t *zpool_search_import(libpc_handle_t *, importargs_t *);
      |                       ^~~~~~~~~~~~~~~~~~~
make: *** [Makefile:23: bin/kr-fs] Error 1

ZFS 2.2.2 Compatibility

I have some changes developed to get go-libzfs compiling against the latest libzfs from OpenZFS 2.2.2 and I'd like to work towards getting these changes upstreamed into here if possible. Currently I have changes which apply to both master and v0.4.0. Can I have some help getting in contact with someone who can give me some recommended next steps on a process or should I just go directly towards submitting PRs?

Appreciate the help, thanks.

Hang on zfs.DatasetOpenAll()

I'm just trying to run one of the example functions and it hangs on the zfs.DatasetOpenAll() call. Am I missing something?

package main

import (
    "fmt"


    "github.com/bicomsystems/go-libzfs"


)



func ExampleDatasetOpenAll() {

  fmt.Printf("hello\n");
  datasets, err := zfs.DatasetOpenAll()
  if err != nil {
          fmt.Printf("aaaaaaaaaaaaa\n");
    panic(err.Error())
  }
          fmt.Printf("bbbbbbbbbbbbbb\n");
  defer zfs.DatasetCloseAll(datasets)

  // Print out path and type of root datasets
  for _, d := range datasets {
    path, err := d.Path()
    if err != nil {
      panic(err.Error())
    }
    p, err := d.GetProperty(zfs.DatasetPropType)
    if err != nil {
      panic(err.Error())
    }
    fmt.Printf("%30s | %10s\n", path, p.Value)
  }

}



func main() {

  ExampleDatasetOpenAll();

}

Output:

hello

And program hangs there...

error running go get

Go version: 1.17.1 linux/amd64
Ubuntu 20.04

$ go get github.com/bicomsystems/go-libzfs
# github.com/bicomsystems/go-libzfs
zfs.c: In function ‘dataset_rename’:
zfs.c:136:2: error: unknown type name ‘renameflags_t’; did you mean ‘recvflags_t’?
  136 |  renameflags_t flags = {recur,nounmount,force_unm};
      |  ^~~~~~~~~~~~~
      |  recvflags_t
zfs.c:136:31: warning: excess elements in scalar initializer
  136 |  renameflags_t flags = {recur,nounmount,force_unm};
      |                               ^~~~~~~~~
zfs.c:136:31: note: (near initialization for ‘flags’)
zfs.c:136:41: warning: excess elements in scalar initializer
  136 |  renameflags_t flags = {recur,nounmount,force_unm};
      |                                         ^~~~~~~~~
zfs.c:136:41: note: (near initialization for ‘flags’)
zfs.c:137:9: error: too few arguments to function ‘zfs_rename’
  137 |  return zfs_rename(dataset->zh, new_name, flags);
      |         ^~~~~~~~~~
In file included from zfs.c:5:
/usr/include/libzfs/libzfs.h:626:12: note: declared here
  626 | extern int zfs_rename(zfs_handle_t *, const char *, boolean_t, boolean_t);
      | 

hoping someone has run into this or knows what's up. Thanks.

Dataset created in a loop use the wrong pool

For a test suite we create a zpool and a set of dataset. Since the test suite runs several tests with similar layouts, a new pool is created for each test in a separate directory and a dataset created on this new pool.
If the name of the dataset is the same across the tests, it uses the wrong pool even if the pool doesn't exist anymore.
A workaround is to name the pool differently for each test.

The test case below demonstrates this behaviour by creating in a loop different zpools and the same dataset name on the zpool.

The output of the run is:

Iteration 1
PoolCreate guid: 7919659312967739317
PoolOpen guid: 7919659312967739317
dataset GUID:5048587912320756274
pool from dataset guid: 7919659312967739317
before datasetclose
before export
before close
Iteration 2
PoolCreate guid: 13613222439384922873
PoolOpen guid: 13613222439384922873
dataset GUID:14116188184690862102
pool from dataset guid: 7919659312967739317
before datasetclose
before export
before close
Iteration 3
PoolCreate guid: 8252255210940518902
PoolOpen guid: 8252255210940518902
dataset GUID:14785461561331967018
pool from dataset guid: 7919659312967739317
before datasetclose
before export
before close

It shows that the GUID of the zpool is different on each iteration but the GUID of the zpool of the newly created dataset is always the value of the first zpool that have been created.

package main

import (
	"fmt"
	"log"
	"os"
    "path/filepath"

	zfs "github.com/bicomsystems/go-libzfs"
)

const mB = 1024 * 1024

func main() {
	for _, i := range []string{"1", "2", "3"} {
		func() {
			fmt.Printf("Iteration %s\n", i)

			p := "/tmp/testzfs" + i + "/disk" + "." + i
			if err := os.MkdirAll(filepath.Dir(p), 0755); err != nil {
				log.Fatalf("can't create destination directory for: %q: %v", p, err)
			}
			f, err := os.Create(p)
			if err != nil {
				log.Fatal("couldn't create device file on disk", err)
			}
			if err = f.Truncate(100 * mB); err != nil {
				f.Close()
				log.Fatal("couldn't initializing device size on disk", err)
			}
			f.Close()

			vdev := zfs.VDevTree{
				Type:    zfs.VDevTypeFile,
				Path:    p,
				Devices: []zfs.VDevTree{{Type: zfs.VDevTypeFile, Path: p}},
			}

			features := make(map[string]string)
			props := make(map[zfs.Prop]string)
			fsprops := make(map[zfs.Prop]string)
			pool, err := zfs.PoolCreate("rpool", vdev, features, props, fsprops)
			if err != nil {
				log.Fatal("couldn't create pool", err)
			}
			defer pool.Close()
			defer fmt.Println("before close")
			defer pool.Export(true, "blabla")
			defer fmt.Println("before export")

			val, _ := pool.GetProperty(zfs.PoolPropGUID)
			fmt.Println("PoolCreate guid:", val.Value)

			pool1, err := zfs.PoolOpen("rpool")
			if err != nil {
				log.Fatal("Error:", err)
			}

			val, _ = pool1.GetProperty(zfs.PoolPropGUID)
			fmt.Println("PoolOpen guid:", val.Value)

			dprops := make(map[zfs.Prop]zfs.Property)
			d, err := zfs.DatasetCreate("rpool/first", zfs.DatasetTypeFilesystem, dprops)
			if err != nil {
				log.Fatal("couldn't create dataset", err)
			}
			defer d.Close()
			defer fmt.Println("before datasetclose")
			val, _ = d.GetProperty(zfs.DatasetPropGUID)
			fmt.Println("dataset GUID:" + val.Value)

			pool2, err := d.Pool()
			if err != nil {
				fmt.Println(err)
			}
			val, _ = pool2.GetProperty(zfs.PoolPropGUID)
			fmt.Println("pool from dataset guid:", val.Value)
		}()
	}
}

This is tested on Ubuntu Eoan (development releases) with zfs-linux 0.7.12-1ubuntu5 also tested with 0.7.13 from debian and 0.8 from upstream. The result is the same.

Fails to build on musl/alpine: unknown type name '__uint64_t'

Error:

# github.com/bicomsystems/go-libzfs
In file included from root/go/src/github.com/bicomsystems/go-libzfs/common.go:18:0:
./zpool.h:82:1: error: unknown type name '__uint64_t'
 __uint64_t set_zpool_vdev_online(zpool_list_t *pool, const char *path, int flags);
 ^~~~~~~~~~

Reproduce with:

docker run -ti --rm alpine sh
apk --no-cache add go git gcc musl-dev zfs-dev
go get -u github.com/bicomsystems/go-libzfs

VDevTree.Stat.Ops and .Bytes always zero

It looks like Pool.VDevTree() always returns a VDevTree with every element of Stat.Ops and Stat.Bytes set to zero, though the other members of the structure are set correctly. Running zpool iostat shows that there is in fact activity on my zpools.

Cannot delete dataset (v0.4.0)

Hello! I cannot delete dataset, both ds.Destroy and ds.DestroyRecursive returns "dataset is busy", however I can delete it with "zfs destroy"

zfs-2.1.0

What am I missing?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.