// Copyright 2020 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package procfs

import (
	
	
	
	
	
	

	
)

var (
	slabSpace  = regexp.MustCompile(`\s+`)
	slabVer    = regexp.MustCompile(`slabinfo -`)
	slabHeader = regexp.MustCompile(`# name`)
)

// Slab represents a slab pool in the kernel.
type Slab struct {
	Name         string
	ObjActive    int64
	ObjNum       int64
	ObjSize      int64
	ObjPerSlab   int64
	PagesPerSlab int64
	// tunables
	Limit        int64
	Batch        int64
	SharedFactor int64
	SlabActive   int64
	SlabNum      int64
	SharedAvail  int64
}

// SlabInfo represents info for all slabs.
type SlabInfo struct {
	Slabs []*Slab
}

func shouldParseSlab( string) bool {
	if slabVer.MatchString() {
		return false
	}
	if slabHeader.MatchString() {
		return false
	}
	return true
}

// parseV21SlabEntry is used to parse a line from /proc/slabinfo version 2.1.
func parseV21SlabEntry( string) (*Slab, error) {
	// First cleanup whitespace.
	 := slabSpace.ReplaceAllString(, " ")
	 := strings.Split(, " ")
	if len() != 16 {
		return nil, fmt.Errorf("%w: unable to parse: %q", ErrFileParse, )
	}
	var  error
	 := &Slab{Name: [0]}
	.ObjActive,  = strconv.ParseInt([1], 10, 64)
	if  != nil {
		return nil, 
	}
	.ObjNum,  = strconv.ParseInt([2], 10, 64)
	if  != nil {
		return nil, 
	}
	.ObjSize,  = strconv.ParseInt([3], 10, 64)
	if  != nil {
		return nil, 
	}
	.ObjPerSlab,  = strconv.ParseInt([4], 10, 64)
	if  != nil {
		return nil, 
	}
	.PagesPerSlab,  = strconv.ParseInt([5], 10, 64)
	if  != nil {
		return nil, 
	}
	.Limit,  = strconv.ParseInt([8], 10, 64)
	if  != nil {
		return nil, 
	}
	.Batch,  = strconv.ParseInt([9], 10, 64)
	if  != nil {
		return nil, 
	}
	.SharedFactor,  = strconv.ParseInt([10], 10, 64)
	if  != nil {
		return nil, 
	}
	.SlabActive,  = strconv.ParseInt([13], 10, 64)
	if  != nil {
		return nil, 
	}
	.SlabNum,  = strconv.ParseInt([14], 10, 64)
	if  != nil {
		return nil, 
	}
	.SharedAvail,  = strconv.ParseInt([15], 10, 64)
	if  != nil {
		return nil, 
	}
	return , nil
}

// parseSlabInfo21 is used to parse a slabinfo 2.1 file.
func parseSlabInfo21( *bytes.Reader) (SlabInfo, error) {
	 := bufio.NewScanner()
	 := SlabInfo{Slabs: []*Slab{}}
	for .Scan() {
		 := .Text()
		if !shouldParseSlab() {
			continue
		}
		,  := parseV21SlabEntry()
		if  != nil {
			return , 
		}
		.Slabs = append(.Slabs, )
	}
	return , nil
}

// SlabInfo reads data from `/proc/slabinfo`.
func ( FS) () (SlabInfo, error) {
	// TODO: Consider passing options to allow for parsing different
	// slabinfo versions. However, slabinfo 2.1 has been stable since
	// kernel 2.6.10 and later.
	,  := util.ReadFileNoStat(.proc.Path("slabinfo"))
	if  != nil {
		return SlabInfo{}, 
	}

	return parseSlabInfo21(bytes.NewReader())
}