Skip to content

Instantly share code, notes, and snippets.

@redbo
Created May 26, 2015 19:05
Show Gist options
  • Save redbo/72af3537b82f73933636 to your computer and use it in GitHub Desktop.
Save redbo/72af3537b82f73933636 to your computer and use it in GitHub Desktop.
package main
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"net"
"net/http"
"net/http/httptest"
"net/url"
"os"
"os/exec"
"path/filepath"
"strconv"
"sync"
"sync/atomic"
"time"
"github.com/openstack/swift/go/hummingbird"
"github.com/openstack/swift/go/objectserver"
)
const concurrency = 4
type TestServer struct {
*httptest.Server
host string
port int
root string
}
func (t *TestServer) Close() {
t.Server.Close()
}
func makeObjectServer(driveRoot string) (*TestServer, error) {
conf, err := ioutil.TempFile("", "")
if err != nil {
return nil, err
}
defer conf.Close()
defer os.RemoveAll(conf.Name())
conf.WriteString("[app:object-server]\n")
fmt.Fprintf(conf, "devices=%s\n", driveRoot)
fmt.Fprintf(conf, "mount_check=false\n")
fmt.Fprintf(conf, "log_facility = LOG_LOCAL2\nrecon_cache_path = /var/cache/swift\neventlet_debug = true\nlog_udp_host = 127.0.0.1\n log_udp_port = 514\n")
if err := conf.Close(); err != nil {
return nil, err
}
_, _, handler, _, _ := objectserver.GetServer(conf.Name())
ts := httptest.NewServer(handler)
u, err := url.Parse(ts.URL)
if err != nil {
return nil, err
}
host, ports, err := net.SplitHostPort(u.Host)
if err != nil {
return nil, err
}
port, err := strconv.Atoi(ports)
if err != nil {
return nil, err
}
return &TestServer{Server: ts, host: host, port: port, root: driveRoot}, nil
}
func main() {
drivePath := "/srv/node/sda"
drive := filepath.Base(drivePath)
driveRoot := filepath.Dir(drivePath)
var id int64 = 0
ts, err := makeObjectServer(driveRoot)
if err != nil {
panic(fmt.Sprintf("Failed to make object server: %v", err))
}
defer ts.Close()
/* PUTs */
exec.Command("sudo", "sh", "-c", "echo 3 > /proc/sys/vm/drop_caches").Run()
fileBuffer := make([]byte, 1024*1024)
contentLength := fmt.Sprintf("%d", len(fileBuffer))
jobch := make(chan int64)
wg := sync.WaitGroup{}
putFile := func() {
wg.Add(1)
for thisId := range jobch {
timestamp := hummingbird.GetTimestamp()
req, err := http.NewRequest("PUT", fmt.Sprintf("http://%s:%d/%s/%d/a/c/o%d", ts.host, ts.port, drive, thisId%1000, thisId), bytes.NewBuffer(fileBuffer))
if err != nil {
}
req.Header.Set("Content-Type", "application/octet-stream")
req.Header.Set("Content-Length", contentLength)
req.Header.Set("X-Timestamp", timestamp)
resp, err := http.DefaultClient.Do(req)
if err != nil {
resp.Body.Close()
}
}
wg.Done()
}
for i := 0; i < concurrency; i++ {
go putFile()
}
start := time.Now()
for atomic.LoadInt64(&id) < 500000 { // ~1 TB
jobch <- atomic.AddInt64(&id, 1)
}
close(jobch)
wg.Wait()
fmt.Println("PUT", id, "objects in", time.Since(start).Seconds())
/* GETs */
exec.Command("sudo", "sh", "-c", "echo 3 > /proc/sys/vm/drop_caches").Run()
jobch = make(chan int64)
getFile := func() {
wg.Add(1)
for thisId := range jobch {
req, err := http.NewRequest("GET", fmt.Sprintf("http://%s:%d/%s/%d/a/c/o%d", ts.host, ts.port, drive, thisId%1000, thisId), nil)
if err != nil {
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
}
io.Copy(ioutil.Discard, resp.Body)
resp.Body.Close()
}
wg.Done()
}
for i := 0; i < concurrency; i++ {
go getFile()
}
start = time.Now()
for i := int64(0); i < id; i++ {
jobch <- i
}
close(jobch)
wg.Wait()
fmt.Println("GET", id, "objects in", time.Since(start).Seconds())
/* Filesystem Walk 1 */
exec.Command("sudo", "sh", "-c", "echo 3 > /proc/sys/vm/drop_caches").Run()
var walk1 func(string)
walk1 = func(path string) {
stat, err := os.Stat(path)
if err != nil {
return
}
if !stat.Mode().IsDir() {
return
}
files, err := hummingbird.ReadDirNames(path)
if err != nil {
return
}
for _, file := range files {
walk1(filepath.Join(path, file))
}
}
start = time.Now()
walk1(drivePath)
fmt.Println("Filesystem Walk 1", time.Since(start).Seconds())
/* Filesystem Walk 2 */
exec.Command("sudo", "sh", "-c", "echo 3 > /proc/sys/vm/drop_caches").Run()
var walk2 func(string)
walk2 = func(path string) {
files, err := ioutil.ReadDir(path)
if err != nil {
return
}
for _, file := range files {
if file.Mode().IsDir() {
walk2(filepath.Join(path, file.Name()))
}
}
}
start = time.Now()
walk2(drivePath)
fmt.Println("Filesystem Walk 2", time.Since(start).Seconds())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment