Compare commits
13 Commits
main
...
json-debug
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7dddc97bbc | ||
|
|
8a7e607474 | ||
|
|
e3dbbc546a | ||
|
|
e02cbfdb73 | ||
|
|
0e74d15259 | ||
|
|
fb08c2374e | ||
|
|
7f91344fda | ||
|
|
62bfed94d6 | ||
|
|
dddbd36969 | ||
|
|
2bc40b4a39 | ||
|
|
f1b65c9f8b | ||
|
|
4316136de8 | ||
|
|
f00970493d |
33
src/cmd/jsondebug/arrayread/read.go
Normal file
33
src/cmd/jsondebug/arrayread/read.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/alcionai/corso/src/cmd/jsondebug/common"
|
||||||
|
"github.com/alcionai/corso/src/cmd/jsondebug/decoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
readData()
|
||||||
|
}
|
||||||
|
|
||||||
|
func readData() {
|
||||||
|
f, err := os.Open(common.FileName)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error opening input file: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
output, err := decoder.DecodeFooArray(f)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error decoding input: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
common.PrintMemUsage()
|
||||||
|
|
||||||
|
fmt.Printf("got array with %d items\n", len(output.Entries))
|
||||||
|
}
|
||||||
9
src/cmd/jsondebug/arrayread/read_test.go
Normal file
9
src/cmd/jsondebug/arrayread/read_test.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func Benchmark_readData(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
readData()
|
||||||
|
}
|
||||||
|
}
|
||||||
115
src/cmd/jsondebug/common/helpers.go
Normal file
115
src/cmd/jsondebug/common/helpers.go
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"runtime"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
NumItems = 300000
|
||||||
|
ItemSize = 1024
|
||||||
|
GzipSuffix = ".gz"
|
||||||
|
FileName = "input.json"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ManifestFileName = fmt.Sprintf("manifest-input.%d.json", NumItems)
|
||||||
|
|
||||||
|
type FooArray struct {
|
||||||
|
Entries []*Foo `json:"entries"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Foo struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Labels map[string]string `json:"labels"`
|
||||||
|
ModTime time.Time `json:"modified"`
|
||||||
|
Deleted bool `json:"deleted,omitempty"`
|
||||||
|
Content json.RawMessage `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Content struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Data []byte `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Manifest struct {
|
||||||
|
Entries []*ManifestEntry `json:"entries"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ManifestEntry struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Labels map[string]string `json:"labels"`
|
||||||
|
ModTime time.Time `json:"modified"`
|
||||||
|
Deleted bool `json:"deleted,omitempty"`
|
||||||
|
Content json.RawMessage `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SnapManifest struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Source SourceInfo `json:"source"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
StartTime int64 `json:"startTime"`
|
||||||
|
EndTime int64 `json:"endTime"`
|
||||||
|
Stats StatsS `json:"stats,omitempty"`
|
||||||
|
IncompleteReason string `json:"incomplete,omitempty"`
|
||||||
|
RootEntry *DirEntry `json:"rootEntry"`
|
||||||
|
Tags map[string]string `json:"tags,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SourceInfo struct {
|
||||||
|
Host string `json:"host"`
|
||||||
|
UserName string `json:"userName"`
|
||||||
|
Path string `json:"path"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type StatsS struct {
|
||||||
|
TotalFileSize int64 `json:"totalSize"`
|
||||||
|
ExcludedTotalFileSize int64 `json:"excludedTotalSize"`
|
||||||
|
TotalFileCount int32 `json:"fileCount"`
|
||||||
|
CachedFiles int32 `json:"cachedFiles"`
|
||||||
|
NonCachedFiles int32 `json:"nonCachedFiles"`
|
||||||
|
TotalDirectoryCount int32 `json:"dirCount"`
|
||||||
|
ExcludedFileCount int32 `json:"excludedFileCount"`
|
||||||
|
ExcludedDirCount int32 `json:"excludedDirCount"`
|
||||||
|
IgnoredErrorCount int32 `json:"ignoredErrorCount"`
|
||||||
|
ErrorCount int32 `json:"errorCount"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DirEntry struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
EntryType string `json:"type,omitempty"`
|
||||||
|
Permissions int `json:"mode,omitempty"`
|
||||||
|
FileSize int64 `json:"size,omitempty"`
|
||||||
|
ModTime int64 `json:"mtime,omitempty"`
|
||||||
|
UserID int32 `json:"uid,omitempty"`
|
||||||
|
GroupID int32 `json:"gid,omitempty"`
|
||||||
|
ObjectID string `json:"obj,omitempty"`
|
||||||
|
DirSummary *DirectorySummary `json:"summ,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DirectorySummary struct {
|
||||||
|
TotalFileSize int64 `json:"size"`
|
||||||
|
TotalFileCount int64 `json:"files"`
|
||||||
|
TotalSymlinkCount int64 `json:"symlinks"`
|
||||||
|
TotalDirCount int64 `json:"dirs"`
|
||||||
|
MaxModTime int64 `json:"maxTime"`
|
||||||
|
IncompleteReason string `json:"incomplete,omitempty"`
|
||||||
|
FatalErrorCount int `json:"numFailed"`
|
||||||
|
IgnoredErrorCount int `json:"numIgnoredErrors,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func PrintMemUsage() {
|
||||||
|
var m runtime.MemStats
|
||||||
|
|
||||||
|
runtime.ReadMemStats(&m)
|
||||||
|
// For info on each, see: https://golang.org/pkg/runtime/#MemStats
|
||||||
|
fmt.Printf("Alloc = %v MiB", bToMb(m.Alloc))
|
||||||
|
fmt.Printf("\tTotalAlloc = %v MiB", bToMb(m.TotalAlloc))
|
||||||
|
fmt.Printf("\tSys = %v MiB", bToMb(m.Sys))
|
||||||
|
fmt.Printf("\tNumGC = %v\n", m.NumGC)
|
||||||
|
}
|
||||||
|
|
||||||
|
func bToMb(b uint64) uint64 {
|
||||||
|
return b / 1024 / 1024
|
||||||
|
}
|
||||||
131
src/cmd/jsondebug/decoder/decoder.go
Normal file
131
src/cmd/jsondebug/decoder/decoder.go
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
package decoder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
|
"github.com/alcionai/corso/src/cmd/jsondebug/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
objectOpen = "{"
|
||||||
|
objectClose = "}"
|
||||||
|
arrayOpen = "["
|
||||||
|
arrayClose = "]"
|
||||||
|
)
|
||||||
|
|
||||||
|
var errEOF = errors.New("unexpected end of input")
|
||||||
|
|
||||||
|
func expectDelimToken(dec *json.Decoder, expectedToken string) error {
|
||||||
|
t, err := dec.Token()
|
||||||
|
if err == io.EOF {
|
||||||
|
return errors.WithStack(errEOF)
|
||||||
|
} else if err != nil {
|
||||||
|
return errors.Wrap(err, "reading JSON token")
|
||||||
|
}
|
||||||
|
|
||||||
|
d, ok := t.(json.Delim)
|
||||||
|
if !ok {
|
||||||
|
return errors.Errorf("unexpected token: (%T) %v", t, t)
|
||||||
|
} else if d.String() != expectedToken {
|
||||||
|
return errors.Errorf(
|
||||||
|
"unexpected token; wanted %s, got %s",
|
||||||
|
expectedToken,
|
||||||
|
d,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func stringToken(dec *json.Decoder) (string, error) {
|
||||||
|
t, err := dec.Token()
|
||||||
|
if errors.Is(err, io.EOF) {
|
||||||
|
return "", errors.WithStack(errEOF)
|
||||||
|
} else if err != nil {
|
||||||
|
return "", errors.Wrap(err, "reading JSON token")
|
||||||
|
}
|
||||||
|
|
||||||
|
l, ok := t.(string)
|
||||||
|
if !ok {
|
||||||
|
return "", errors.Errorf("unexpected token (%T) %v; wanted field name", t, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
return l, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DecodeFooArray(r io.Reader) (common.FooArray, error) {
|
||||||
|
var (
|
||||||
|
dec = json.NewDecoder(r)
|
||||||
|
res = common.FooArray{}
|
||||||
|
)
|
||||||
|
|
||||||
|
if err := expectDelimToken(dec, objectOpen); err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Need to manually decode fields here since we can't reuse the stdlib
|
||||||
|
// decoder due to memory issues.
|
||||||
|
if err := parseFields(dec, &res); err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Consumes closing object curly brace after we're done. Don't need to check
|
||||||
|
// for EOF because json.Decode only guarantees decoding the next JSON item in
|
||||||
|
// the stream so this follows that.
|
||||||
|
return res, expectDelimToken(dec, objectClose)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseFields(dec *json.Decoder, res *common.FooArray) error {
|
||||||
|
for dec.More() {
|
||||||
|
t, err := dec.Token()
|
||||||
|
if err == io.EOF {
|
||||||
|
return errors.WithStack(errEOF)
|
||||||
|
} else if err != nil {
|
||||||
|
return errors.Wrap(err, "reading JSON token")
|
||||||
|
}
|
||||||
|
|
||||||
|
l, ok := t.(string)
|
||||||
|
if !ok {
|
||||||
|
return errors.Errorf(
|
||||||
|
"unexpected token (%T) %v; wanted field name",
|
||||||
|
t,
|
||||||
|
t,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only have `entries` field right now. Needs to match the JSON tag for the
|
||||||
|
// struct.
|
||||||
|
if l != "entries" {
|
||||||
|
return errors.Errorf("unexpected field name %s", l)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = decodeArray(dec, &res.Entries); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeArray[T any](dec *json.Decoder, output *[]T) error {
|
||||||
|
// Consume starting bracket.
|
||||||
|
if err := expectDelimToken(dec, arrayOpen); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read elements.
|
||||||
|
for dec.More() {
|
||||||
|
tmp := *new(T)
|
||||||
|
if err := dec.Decode(&tmp); err != nil {
|
||||||
|
return errors.Wrap(err, "decoding array element")
|
||||||
|
}
|
||||||
|
|
||||||
|
*output = append(*output, tmp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Consume ending bracket.
|
||||||
|
return expectDelimToken(dec, arrayClose)
|
||||||
|
}
|
||||||
59
src/cmd/jsondebug/decoder/manifst_decoder.go
Normal file
59
src/cmd/jsondebug/decoder/manifst_decoder.go
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
package decoder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
|
"github.com/alcionai/corso/src/cmd/jsondebug/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
func DecodeManifestArray(r io.Reader) (common.Manifest, error) {
|
||||||
|
var (
|
||||||
|
dec = json.NewDecoder(r)
|
||||||
|
res = common.Manifest{}
|
||||||
|
)
|
||||||
|
|
||||||
|
if err := expectDelimToken(dec, objectOpen); err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Need to manually decode fields here since we can't reuse the stdlib
|
||||||
|
// decoder due to memory issues.
|
||||||
|
if err := parseManifestFields(dec, &res); err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Consumes closing object curly brace after we're done. Don't need to check
|
||||||
|
// for EOF because json.Decode only guarantees decoding the next JSON item in
|
||||||
|
// the stream so this follows that.
|
||||||
|
return res, expectDelimToken(dec, objectClose)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseManifestFields(dec *json.Decoder, res *common.Manifest) error {
|
||||||
|
var seen bool
|
||||||
|
|
||||||
|
for dec.More() {
|
||||||
|
l, err := stringToken(dec)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only have `entries` field right now. This is stricter than the current
|
||||||
|
// JSON decoder in the stdlib.
|
||||||
|
if l != "entries" {
|
||||||
|
return errors.Errorf("unexpected field name %s", l)
|
||||||
|
} else if seen {
|
||||||
|
return errors.New("repeated Entries field")
|
||||||
|
}
|
||||||
|
|
||||||
|
seen = true
|
||||||
|
|
||||||
|
if err := decodeArray(dec, &res.Entries); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
61
src/cmd/jsondebug/gen/gen.go
Normal file
61
src/cmd/jsondebug/gen/gen.go
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/alcionai/corso/src/cmd/jsondebug/common"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
buf := make([]byte, common.ItemSize)
|
||||||
|
data := &common.FooArray{
|
||||||
|
Entries: make([]*common.Foo, 0, common.NumItems),
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < common.NumItems; i++ {
|
||||||
|
n, err := rand.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error reading random data: %v\n", err)
|
||||||
|
return
|
||||||
|
} else if n != common.ItemSize {
|
||||||
|
fmt.Printf(
|
||||||
|
"Short read for item data: wanted %d, got %d\n",
|
||||||
|
common.ItemSize,
|
||||||
|
n,
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
content := common.Content{
|
||||||
|
ID: uuid.NewString(),
|
||||||
|
Data: buf,
|
||||||
|
}
|
||||||
|
payload, _ := json.Marshal(content)
|
||||||
|
|
||||||
|
item := common.Foo{
|
||||||
|
ID: uuid.NewString(),
|
||||||
|
Labels: map[string]string{"foo": "bar"},
|
||||||
|
ModTime: time.Now(),
|
||||||
|
Content: payload,
|
||||||
|
}
|
||||||
|
data.Entries = append(data.Entries, &item)
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.Create(common.FileName)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error making output file: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
enc := json.NewEncoder(f)
|
||||||
|
if err := enc.Encode(data); err != nil {
|
||||||
|
fmt.Printf("Error writing json to file: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
34
src/cmd/jsondebug/goread/read.go
Normal file
34
src/cmd/jsondebug/goread/read.go
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/alcionai/corso/src/cmd/jsondebug/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
readData()
|
||||||
|
}
|
||||||
|
|
||||||
|
func readData() {
|
||||||
|
f, err := os.Open(common.FileName)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error opening input file: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
dec := json.NewDecoder(f)
|
||||||
|
|
||||||
|
output := common.FooArray{}
|
||||||
|
|
||||||
|
if err := dec.Decode(&output); err != nil {
|
||||||
|
fmt.Printf("Error decoding input: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
common.PrintMemUsage()
|
||||||
|
}
|
||||||
9
src/cmd/jsondebug/goread/read_test.go
Normal file
9
src/cmd/jsondebug/goread/read_test.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func Benchmark_readData(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
readData()
|
||||||
|
}
|
||||||
|
}
|
||||||
117
src/cmd/jsondebug/jsonparser/read.go
Normal file
117
src/cmd/jsondebug/jsonparser/read.go
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"runtime/pprof"
|
||||||
|
|
||||||
|
"github.com/alcionai/corso/src/cmd/jsondebug/common"
|
||||||
|
"github.com/buger/jsonparser"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
defer func() {
|
||||||
|
common.PrintMemUsage()
|
||||||
|
f, err := os.Create("mem.prof")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Print("could not create memory profile: ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer f.Close() // error handling omitted for example
|
||||||
|
runtime.GC() // get up-to-date statistics
|
||||||
|
if err := pprof.WriteHeapProfile(f); err != nil {
|
||||||
|
fmt.Print("could not write memory profile: ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
d, err := readFile()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
parseData(d)
|
||||||
|
}
|
||||||
|
|
||||||
|
func readFile() ([]byte, error) {
|
||||||
|
common.PrintMemUsage()
|
||||||
|
|
||||||
|
data, err := ioutil.ReadFile(common.FileName)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error reading file: %v\n", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseData(data []byte) {
|
||||||
|
|
||||||
|
common.PrintMemUsage()
|
||||||
|
|
||||||
|
output := common.FooArray{
|
||||||
|
Entries: []*common.Foo{},
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = output
|
||||||
|
|
||||||
|
// var handler func([]byte, []byte, jsonparser.ValueType, int) error
|
||||||
|
// handler := func(key []byte, value []byte, dataType jsonparser.ValueType, offset int) error {
|
||||||
|
// fmt.Printf("Key: '%s'\n Value: '%s'\n Type: %s\n", string(key), string(value), dataType)
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
|
||||||
|
jsonparser.ArrayEach(data, func(value []byte, dataType jsonparser.ValueType, offset int, err error) {
|
||||||
|
|
||||||
|
e, errInner := getEntry(value)
|
||||||
|
if errInner != nil {
|
||||||
|
fmt.Printf("Error decoding input2: %v\n", errInner)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
output.Entries = append(output.Entries, e)
|
||||||
|
|
||||||
|
}, "entries")
|
||||||
|
|
||||||
|
common.PrintMemUsage()
|
||||||
|
|
||||||
|
fmt.Printf("Decoded %d entries\n", len(output.Entries))
|
||||||
|
}
|
||||||
|
|
||||||
|
func getEntry(data []byte) (*common.Foo, error) {
|
||||||
|
e := &common.Foo{}
|
||||||
|
|
||||||
|
jsonparser.ObjectEach(data, func(key []byte, value []byte, dataType jsonparser.ValueType, offset int) error {
|
||||||
|
switch string(key) {
|
||||||
|
case "id":
|
||||||
|
e.ID = string(value)
|
||||||
|
case "labels":
|
||||||
|
err := json.Unmarshal(value, &e.Labels)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unmarshalling labels: %w", err)
|
||||||
|
}
|
||||||
|
case "modified":
|
||||||
|
err := json.Unmarshal(value, &e.ModTime)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unmarshalling modtime: %w", err)
|
||||||
|
}
|
||||||
|
case "deleted":
|
||||||
|
err := json.Unmarshal(value, &e.Deleted)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unmarshalling deleted: %w", err)
|
||||||
|
}
|
||||||
|
case "data":
|
||||||
|
cpBuf := make([]byte, len(value))
|
||||||
|
_ = copy(cpBuf, value)
|
||||||
|
e.Content = cpBuf
|
||||||
|
default:
|
||||||
|
fmt.Printf("Unexpected Input: %v\n", key)
|
||||||
|
return errors.New("Unexpected Input: " + string(key))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
return e, nil
|
||||||
|
}
|
||||||
14
src/cmd/jsondebug/jsonparser/read_test.go
Normal file
14
src/cmd/jsondebug/jsonparser/read_test.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func Benchmark_parseData(b *testing.B) {
|
||||||
|
d, err := readFile()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
parseData(d)
|
||||||
|
}
|
||||||
|
}
|
||||||
177
src/cmd/jsondebug/manifestgen/gen.go
Normal file
177
src/cmd/jsondebug/manifestgen/gen.go
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"compress/gzip"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"golang.org/x/exp/maps"
|
||||||
|
|
||||||
|
"github.com/alcionai/corso/src/cmd/jsondebug/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
hostName = "host-name"
|
||||||
|
userName = "user-name"
|
||||||
|
)
|
||||||
|
|
||||||
|
func generateManifestEntry() (*common.ManifestEntry, error) {
|
||||||
|
snapMan := generateSnapManifest()
|
||||||
|
|
||||||
|
// Base tag set for all snapshots.
|
||||||
|
tags := map[string]string{
|
||||||
|
"type": "snapshot",
|
||||||
|
"hostname": snapMan.Source.Host,
|
||||||
|
"username": snapMan.Source.UserName,
|
||||||
|
"path": snapMan.Source.Path,
|
||||||
|
}
|
||||||
|
|
||||||
|
maps.Copy(tags, snapMan.Tags)
|
||||||
|
|
||||||
|
serializedSnapMan, err := json.Marshal(snapMan)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "serializing inner struct")
|
||||||
|
}
|
||||||
|
|
||||||
|
res := &common.ManifestEntry{
|
||||||
|
ID: randStringLen(32),
|
||||||
|
ModTime: time.Now(),
|
||||||
|
Deleted: rand.Uint32()&1 != 0,
|
||||||
|
Labels: tags,
|
||||||
|
Content: serializedSnapMan,
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateSnapManifest() common.SnapManifest {
|
||||||
|
var incomplete string
|
||||||
|
|
||||||
|
// Roughly 1/4 incomplete.
|
||||||
|
if rand.Intn(100) < 25 {
|
||||||
|
incomplete = "checkpoint"
|
||||||
|
}
|
||||||
|
|
||||||
|
path := randString()
|
||||||
|
|
||||||
|
res := common.SnapManifest{
|
||||||
|
Source: common.SourceInfo{
|
||||||
|
Host: hostName,
|
||||||
|
UserName: userName,
|
||||||
|
Path: path,
|
||||||
|
},
|
||||||
|
StartTime: rand.Int63(),
|
||||||
|
EndTime: rand.Int63(),
|
||||||
|
Stats: common.StatsS{
|
||||||
|
TotalFileSize: rand.Int63(),
|
||||||
|
ExcludedTotalFileSize: int64(rand.Uint32()),
|
||||||
|
TotalFileCount: rand.Int31(),
|
||||||
|
CachedFiles: rand.Int31(),
|
||||||
|
NonCachedFiles: rand.Int31(),
|
||||||
|
TotalDirectoryCount: rand.Int31(),
|
||||||
|
ExcludedFileCount: rand.Int31(),
|
||||||
|
ExcludedDirCount: rand.Int31(),
|
||||||
|
IgnoredErrorCount: rand.Int31(),
|
||||||
|
ErrorCount: rand.Int31(),
|
||||||
|
},
|
||||||
|
IncompleteReason: incomplete,
|
||||||
|
RootEntry: &common.DirEntry{
|
||||||
|
Name: path,
|
||||||
|
EntryType: randStringLen(1),
|
||||||
|
Permissions: rand.Intn(512),
|
||||||
|
FileSize: rand.Int63(),
|
||||||
|
ModTime: rand.Int63(),
|
||||||
|
UserID: rand.Int31(),
|
||||||
|
GroupID: rand.Int31(),
|
||||||
|
ObjectID: randStringLen(32),
|
||||||
|
DirSummary: &common.DirectorySummary{
|
||||||
|
TotalFileSize: rand.Int63(),
|
||||||
|
TotalFileCount: rand.Int63(),
|
||||||
|
TotalSymlinkCount: rand.Int63(),
|
||||||
|
TotalDirCount: rand.Int63(),
|
||||||
|
MaxModTime: rand.Int63(),
|
||||||
|
IncompleteReason: incomplete,
|
||||||
|
FatalErrorCount: rand.Int(),
|
||||||
|
IgnoredErrorCount: rand.Int(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Tags: map[string]string{
|
||||||
|
// User stand-in.
|
||||||
|
"tag:" + randStringLen(40): "0",
|
||||||
|
"tag:backup-id": randStringLen(36),
|
||||||
|
"tag:is-canon-backup": "0",
|
||||||
|
// Service/data type stand-in.
|
||||||
|
"tag:" + randStringLen(20): "0",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
var charSet = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789")
|
||||||
|
|
||||||
|
func randString() string {
|
||||||
|
// String lengths between [10, 128] bytes.
|
||||||
|
return randStringLen(rand.Intn(119) + 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
func randStringLen(length int) string {
|
||||||
|
res := make([]rune, length)
|
||||||
|
|
||||||
|
for i := range res {
|
||||||
|
res[i] = charSet[rand.Intn(len(charSet))]
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
data := &common.Manifest{
|
||||||
|
Entries: make([]*common.ManifestEntry, 0, common.NumItems),
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < common.NumItems; i++ {
|
||||||
|
entry, err := generateManifestEntry()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error generating random entry: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
data.Entries = append(data.Entries, entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.Create(common.ManifestFileName)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error making regular output file: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
enc := json.NewEncoder(f)
|
||||||
|
if err := enc.Encode(data); err != nil {
|
||||||
|
fmt.Printf("Error writing json to regular file: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fgz, err := os.Create(common.ManifestFileName + common.GzipSuffix)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error making gzip output file: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer fgz.Close()
|
||||||
|
|
||||||
|
gz := gzip.NewWriter(fgz)
|
||||||
|
defer gz.Close()
|
||||||
|
|
||||||
|
enc = json.NewEncoder(gz)
|
||||||
|
if err := enc.Encode(data); err != nil {
|
||||||
|
fmt.Printf("Error writing json to regular file: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -38,6 +38,7 @@ require (
|
|||||||
github.com/VividCortex/ewma v1.2.0 // indirect
|
github.com/VividCortex/ewma v1.2.0 // indirect
|
||||||
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
|
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
|
||||||
github.com/andybalholm/brotli v1.0.4 // indirect
|
github.com/andybalholm/brotli v1.0.4 // indirect
|
||||||
|
github.com/buger/jsonparser v1.1.1 // indirect
|
||||||
github.com/dnaeon/go-vcr v1.2.0 // indirect
|
github.com/dnaeon/go-vcr v1.2.0 // indirect
|
||||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||||
|
|||||||
@ -66,6 +66,8 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
|||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
|
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
|
||||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
||||||
|
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
|
||||||
|
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
||||||
github.com/cenkalti/backoff/v4 v4.2.0 h1:HN5dHm3WBOgndBH6E8V0q2jIYIR3s9yglV8k/+MN3u4=
|
github.com/cenkalti/backoff/v4 v4.2.0 h1:HN5dHm3WBOgndBH6E8V0q2jIYIR3s9yglV8k/+MN3u4=
|
||||||
github.com/cenkalti/backoff/v4 v4.2.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
github.com/cenkalti/backoff/v4 v4.2.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user