func (g *GraphTool) tarCp(srcName string, tw *tar.Writer) (int64, error) { var ( src *os.File err error ) if src, err = os.Open(srcName); err != nil { return 0, err } defer src.Close() srcStat, err := src.Stat() if err != nil { g.logger.Error(err.Error()) } else if err := unix.Fadvise(int(src.Fd()), 0, srcStat.Size(), unix.MADV_SEQUENTIAL); err != nil { g.logger.Error(err.Error()) } if n, err := io.Copy(tw, src); err != nil { g.logger.Error(err.Error()) } else { return n, nil } return 0, nil }
// ClearCache syncs and then removes the file's content from the OS cache. func ClearCache(file File) error { f, ok := file.(*os.File) if !ok { panic("ClearCache called for file not *os.File") } err := f.Sync() if err != nil { return err } return unix.Fadvise(int(f.Fd()), 0, 0, _POSIX_FADV_DONTNEED) }
func (f *nonCachingFile) Read(p []byte) (int, error) { n, err := f.File.Read(p) if n > 0 { ferr := unix.Fadvise(int(f.File.Fd()), f.readOffset, int64(n), _POSIX_FADV_DONTNEED) f.readOffset += int64(n) if err == nil { err = ferr } } return n, err }
func main() { var ok int // return status outStat, err := os.Stdout.Stat() if err != nil { fatal.Fatalln(err) } outReg := outStat.Mode().IsRegular() outBsize := bsize(outStat) // catch (./cat) < /etc/group args := flag.Args() if flag.NArg() == 0 { args = []string{"-"} } var file *os.File for _, arg := range args { file = os.Stdin if arg != "-" { file, err = os.Open(arg) if err != nil { fatal.Fatalln(err) } } inStat, err := file.Stat() if err != nil { fatal.Fatalln(err) } if inStat.IsDir() { fatal.Printf("%s: is a directory\n", file.Name()) } inBsize := bsize(inStat) // prefetch! prefetch! prefetch! unix.Fadvise(int(file.Fd()), 0, 0, unix.FADV_SEQUENTIAL) // Make sure we're not catting a file to itself, // provided it's a regular file. Catting a non-reg // file to itself is cool. // e.g. cat file > file if outReg && os.SameFile(outStat, inStat) { if n, _ := file.Seek(0, os.SEEK_CUR); n < inStat.Size() { fatal.Fatalf("%s: input file is output file\n", file.Name()) } } pageSize := os.Getpagesize() if simple { // Select larger block size size := max(inBsize, outBsize) outBuf := bufio.NewWriterSize(os.Stdout, size+pageSize-1) ok ^= simpleCat(file, outBuf) // Flush because we don't have a chance to in // simpleCat() because we use io.Copy() outBuf.Flush() } else { // If you want to know why, exactly, I chose // outBsize -1 + inBsize*4 + 20, read GNU's cat // source code. The tl;dr is the 20 is the counter // buffer, inBsize*4 is from potentially prepending // the control characters (M-^), and outBsize is // due to new tests for newlines. size := outBsize - 1 + inBsize*4 + 20 outBuf := bufio.NewWriterSize(os.Stdout, size) inBuf := make([]byte, inBsize+pageSize-1) ok ^= cat(file, inBuf, outBuf) } file.Close() } os.Exit(ok) }
func wc(file *os.File, cur int64, status fstatus) int { // Our temp number of lines, words, chars, and bytes var ( lines int64 words int64 chars int64 numBytes int64 lineLength int64 buffer [bufferSize]byte // Return value. ok = 0 ) countComplicated := *printWords || *printLineLength if !*printBytes || *printChars || *printLines || countComplicated { unix.Fadvise(int(file.Fd()), 0, 0, unix.FADV_SEQUENTIAL) } // If we simply want the bytes we can ignore the overhead of // counting lines, chars, and words if *printBytes && !*printChars && !*printLines && !countComplicated { if status.failed != nil { status.stat, status.failed = file.Stat() } // For sized files, seek a block from EOF. // From GNU's source: // // "This works better for files in proc-like file systems where // the size is only approximate." if status.failed == nil && // Regular file but not stdin. ((status.stat.Mode().IsRegular() && status.stat.Mode()&os.ModeCharDevice != 0) || status.stat.Mode()&os.ModeSymlink != 0) && 0 < status.stat.Size() { numBytes = status.stat.Size() end := numBytes high := end - end%(blockSize+1) if cur < 0 { cur, _ = file.Seek(0, os.SEEK_CUR) } if 0 <= cur && cur < high { if n, _ := file.Seek(high, os.SEEK_CUR); 0 <= n { numBytes = high - cur } } } unix.Fadvise(int(file.Fd()), 0, 0, unix.FADV_SEQUENTIAL) for { n, err := file.Read(buffer[:]) if err != nil { if err != io.EOF { ok = 1 } break } numBytes += int64(n) } // Use a different loop to lower overhead if we're *only* counting // lines (or lines and bytes) } else if !*printChars && !countComplicated { for { n, err := file.Read(buffer[:]) if err != nil { if err != io.EOF { ok = 1 } break } // Go doesn't inline this sooo... for i := 0; i < n; i++ { if buffer[i] != '\n' { o := bytes.IndexByte(buffer[i:n], '\n') if o < 0 { break } i += o } lines++ } numBytes += int64(n) } } else { var ( inWord int64 linePos int64 ) for { n, err := file.Read(buffer[:]) if err != nil { if err != io.EOF { ok = 1 } break } numBytes += int64(n) for bp := 0; bp < n; { r, s := utf8.DecodeRune(buffer[bp:]) switch r { case '\n': lines++ fallthrough case '\r': fallthrough case '\f': if linePos > lineLength { lineLength = linePos } linePos = 0 words += inWord inWord = 0 case '\t': linePos += *tabWidth - (linePos % *tabWidth) words += inWord inWord = 0 case ' ': linePos++ fallthrough case '\v': words += inWord inWord = 0 default: if unicode.IsPrint(r) { linePos++ if unicode.IsSpace(r) { words += inWord inWord = 0 } inWord = 1 } } chars++ bp += s } } if linePos > lineLength { lineLength = linePos } words += inWord } writeCounts(lines, words, chars, numBytes, lineLength, file.Name()) totalBytes += numBytes totalChars += chars totalLines += lines totalWords += words if lineLength > maxLineLength { maxLineLength = lineLength } return ok }
func wc(file *os.File, cur int64, status *fstatus) int { // Our temp number of lines, words, chars, and bytes var ( lines int64 words int64 chars int64 numBytes int64 lineLength int64 linePos int64 inWord int64 buffer = make([]byte, BufferSize+1) // Return value. ok = 0 ) countComplicated := *printWords || *printLineLength if !*printBytes || *printChars || *printLines || countComplicated { unix.Fadvise(int(file.Fd()), 0, 0, unix.FADV_SEQUENTIAL) } // If we simply want the bytes we can ignore the overhead of // counting lines, chars, and words if *printBytes && !*printChars && !*printLines && !countComplicated { // Manually count bytes if Stat() failed or if we're reading from // piped input (e.g. cat file.csv | wc -c -) if status.stat == nil || status.stat.Mode()&os.ModeNamedPipe != 0 { unix.Fadvise(int(file.Fd()), 0, 0, unix.FADV_SEQUENTIAL) for { n, err := file.Read(buffer) if err != nil && err != io.EOF { ok = 1 break } numBytes += int64(n) if err == io.EOF { break } } } else { numBytes = status.stat.Size() end := numBytes high := end - end%BufferSize if cur <= 0 { cur, _ = file.Seek(0, os.SEEK_CUR) } if 0 <= cur && cur < high { if n, _ := file.Seek(high, os.SEEK_CUR); 0 <= n { numBytes = high - cur } } } // Use a different loop to lower overhead if we're *only* counting // lines (or lines and bytes) } else if !*printChars && !countComplicated { for { n, err := file.Read(buffer) if err != nil && err != io.EOF { ok = 1 break } lines += count(buffer[:n], NewLineByte) numBytes += int64(n) if err == io.EOF { break } } } else { for { n, err := file.Read(buffer) numBytes += int64(n) b := buffer[:n] for len(b) > 0 { r, s := utf8.DecodeRune(b) switch r { case NewLine: lines++ fallthrough case Return: fallthrough case FormFeed: if linePos > lineLength { lineLength = linePos } linePos = 0 words += inWord inWord = 0 case HorizTab: linePos += *tabWidth - (linePos % *tabWidth) words += inWord inWord = 0 case Space: linePos++ fallthrough case VertTab: words += inWord inWord = 0 default: if unicode.IsPrint(r) { linePos++ inWord = 1 } } chars++ b = b[s:] } if err == io.EOF { break } else if err != nil { ok = 1 break } } if linePos > lineLength { lineLength = linePos } words += inWord } writeCounts(lines, words, chars, numBytes, lineLength, file.Name()) totalBytes += numBytes totalChars += chars totalLines += lines totalWords += words if lineLength > maxLineLength { maxLineLength = lineLength } return ok }
func main() { flag.Usage = func() { fmt.Fprintf(os.Stderr, "%s", Help) os.Exit(1) } flag.Parse() if *version { fmt.Fprintf(os.Stdout, "%s", Version) os.Exit(0) } var ( ok int // return status simple bool // no non-printing ) // -vET if *all { *nonPrint = true *npTabs = true *npEnds = true } if *npEnds { *ends = true } if *blank { *number = true } if *npTabs { *tabs = true } if *all || *npEnds || *npTabs || *nonPrint { showNonPrinting = true } outStat, err := os.Stdout.Stat() if err != nil { fatal.Fatalln(err) } outReg := outStat.Mode().IsRegular() outBsize := int(outStat.Sys().(*syscall.Stat_t).Blksize) // catch (./cat) < /etc/group var args []string if flag.NArg() == 0 { args = []string{"-"} } else { args = flag.Args() } // the main loop var file *os.File for _, arg := range args { if arg == "-" { file = os.Stdin } else { file, err = os.Open(arg) if err != nil { fatal.Fatalln(err) } } inStat, err := file.Stat() if err != nil { fatal.Fatalln(err) } if inStat.IsDir() { fatal.Printf("%s: Is a directory\n", file.Name()) } inBsize := int(inStat.Sys().(*syscall.Stat_t).Blksize) // prefetch! prefetch! prefetch! unix.Fadvise(int(file.Fd()), 0, 0, unix.FADV_SEQUENTIAL) // Make sure we're not catting a file to itself, // provided it's a regular file. Catting a non-reg // file to itself is cool. // e.g. cat file > file if outReg && os.SameFile(outStat, inStat) { if n, _ := file.Seek(0, os.SEEK_CUR); n < inStat.Size() { fatal.Fatalf("%s: input file is output file\n", file.Name()) } } if simple { // Select larger block size size := max(inBsize, outBsize) outBuf := bufio.NewWriterSize(os.Stdout, size) ok ^= simpleCat(file, outBuf) // Flush because we don't have a chance to in // simpleCat() because we use io.Copy() outBuf.Flush() } else { // If you want to know why, exactly, I chose // outBsize -1 + inBsize*4 + 20, read GNU's cat // source code. The tl;dr is the 20 is the counter // buffer, inBsize*4 is from potentially prepending // the control characters (M-^), and outBsize is // due to new tests for newlines. size := outBsize - 1 + inBsize*4 + 20 outBuf := bufio.NewWriterSize(os.Stdout, size) inBuf := make([]byte, inBsize+1) ok ^= cat(file, inBuf, outBuf) } file.Close() } os.Exit(ok) }
func wc(file *os.File, cur int64, status fstatus) int { // Our temp number of lines, words, chars, and bytes var ( lines int64 words int64 chars int64 numBytes int64 lineLength int64 buffer [BufferSize + 1]byte // Return value. ok = 0 ) countComplicated := *printWords || *printLineLength if !*printBytes || *printChars || *printLines || countComplicated { unix.Fadvise(int(file.Fd()), 0, 0, unix.FADV_SEQUENTIAL) } // If we simply want the bytes we can ignore the overhead of // counting lines, chars, and words if *printBytes && !*printChars && !*printLines && !countComplicated { // Manually count bytes if Stat() failed or if we're reading from // piped input (e.g. cat file.csv | wc -c -) if status.stat == nil || status.stat.Mode()&os.ModeNamedPipe != 0 { unix.Fadvise(int(file.Fd()), 0, 0, unix.FADV_SEQUENTIAL) for { n, err := file.Read(buffer[:]) if err != nil { if err != io.EOF { ok = 1 } break } numBytes += int64(n) } } else { numBytes = status.stat.Size() end := numBytes high := end - end%BufferSize if cur < 0 { cur, _ = file.Seek(0, os.SEEK_CUR) } if 0 <= cur && cur < high { if n, _ := file.Seek(high, os.SEEK_CUR); 0 <= n { numBytes = high - cur } } } // Use a different loop to lower overhead if we're *only* counting // lines (or lines and bytes) } else if !*printChars && !countComplicated { for { n, err := file.Read(buffer[:]) if err != nil { if err != io.EOF { ok = 1 } break } // Go doesn't inline this sooo... for i := 0; i < n; i++ { if buffer[i] != '\n' { o := bytes.IndexByte(buffer[i:n], '\n') if o < 0 { break } i += o } lines++ } numBytes += int64(n) } } else { var ( inWord int64 linePos int64 ) for { n, err := file.Read(buffer[:]) if err != nil { if err != io.EOF { ok = 1 } break } numBytes += int64(n) for bp := 0; bp < n; { r, s := utf8.DecodeRune(buffer[bp:]) switch r { case '\n': lines++ fallthrough case '\r': fallthrough case '\f': if linePos > lineLength { lineLength = linePos } linePos = 0 words += inWord inWord = 0 case '\t': linePos += *tabWidth - (linePos % *tabWidth) words += inWord inWord = 0 case ' ': linePos++ fallthrough case '\v': words += inWord inWord = 0 default: if unicode.IsPrint(r) { linePos++ if unicode.IsSpace(r) { words += inWord inWord = 0 } inWord = 1 } } chars++ bp += s } } if linePos > lineLength { lineLength = linePos } words += inWord } writeCounts(lines, words, chars, numBytes, lineLength, file.Name()) totalBytes += numBytes totalChars += chars totalLines += lines totalWords += words if lineLength > maxLineLength { maxLineLength = lineLength } return ok }
func tsort(rw io.ReadWriter) int { var ( root = newItem("") j *item k *item ok int ) scanner := bufio.NewScanner(rw) scanner.Split(bufio.ScanWords) // https://talks.golang.org/2015/tricks.slide#16 if file, ok := rw.(interface { Fd() uintptr }); ok { unix.Fadvise(int(file.Fd()), 0, 0, unix.FADV_SEQUENTIAL) } for scanner.Scan() { k = root.searchItem(scanner.Text()) if j != nil { recordRelation(j, k) k = nil } j = k } if k != nil { fatal.Fatalln("input contains an odd number of tokens") } root.walkTree(countItems) for numStrings > 0 { root.walkTree(scanZeros) for head != nil { p := head.top fmt.Fprintln(rw, head.str) head.str = "" numStrings-- for p != nil { p.suc.count-- if p.suc.count == 0 { zeros.qlink = p.suc zeros = p.suc } p = p.next } head = head.qlink } if numStrings > 0 { fatal.Print("tsort: input contains a loop:") ok = 1 for { root.walkTree(detectLoop) if loop == nil { break } } } } return ok }
func tsort(file *os.File) int { root := newItem("") var ( j *item = nil k *item = nil ) ok := 0 reader := bufio.NewReader(file) scanner := bufio.NewScanner(reader) scanner.Split(bufio.ScanWords) unix.Fadvise(int(file.Fd()), 0, 0, unix.FADV_SEQUENTIAL) for scanner.Scan() { k = root.searchItem(scanner.Text()) if j != nil { recordRelation(j, k) k = nil } j = k } if k != nil { fatal.Fatalln("input contains an odd number of tokens") } root.walkTree(countItems) for numStrings > 0 { root.walkTree(scanZeros) for head != nil { p := head.top fmt.Println(head.str) head.str = "" numStrings-- for p != nil { p.suc.count-- if p.suc.count == 0 { zeros.qlink = p.suc zeros = p.suc } p = p.next } head = head.qlink } if numStrings > 0 { fatal.Print("input contains a loop:") ok = 1 for { root.walkTree(detectLoop) if loop == nil { break } } } } return ok }