mirror of https://github.com/minio/minio.git
				
				
				
			
		
			
	
	
		
			409 lines
		
	
	
		
			9.6 KiB
		
	
	
	
		
			Go
		
	
	
	
		
		
			
		
	
	
			409 lines
		
	
	
		
			9.6 KiB
		
	
	
	
		
			Go
		
	
	
	
| 
								 | 
							
								// Copyright (c) 2015-2021 MinIO, Inc.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// This file is part of MinIO Object Storage stack
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// This program is free software: you can redistribute it and/or modify
							 | 
						||
| 
								 | 
							
								// it under the terms of the GNU Affero General Public License as published by
							 | 
						||
| 
								 | 
							
								// the Free Software Foundation, either version 3 of the License, or
							 | 
						||
| 
								 | 
							
								// (at your option) any later version.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// This program is distributed in the hope that it will be useful
							 | 
						||
| 
								 | 
							
								// but WITHOUT ANY WARRANTY; without even the implied warranty of
							 | 
						||
| 
								 | 
							
								// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
							 | 
						||
| 
								 | 
							
								// GNU Affero General Public License for more details.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// You should have received a copy of the GNU Affero General Public License
							 | 
						||
| 
								 | 
							
								// along with this program.  If not, see <http://www.gnu.org/licenses/>.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								package cmd
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import (
							 | 
						||
| 
								 | 
							
									"errors"
							 | 
						||
| 
								 | 
							
									"fmt"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									"github.com/minio/minio/internal/logger"
							 | 
						||
| 
								 | 
							
									"github.com/tinylib/msgp/msgp"
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// xlMetaInlineData is serialized data in [string][]byte pairs.
							 | 
						||
| 
								 | 
							
								type xlMetaInlineData []byte
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// xlMetaInlineDataVer indicates the version of the inline data structure.
							 | 
						||
| 
								 | 
							
								const xlMetaInlineDataVer = 1
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// versionOK returns whether the version is ok.
							 | 
						||
| 
								 | 
							
								func (x xlMetaInlineData) versionOK() bool {
							 | 
						||
| 
								 | 
							
									if len(x) == 0 {
							 | 
						||
| 
								 | 
							
										return true
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return x[0] > 0 && x[0] <= xlMetaInlineDataVer
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// afterVersion returns the payload after the version, if any.
							 | 
						||
| 
								 | 
							
								func (x xlMetaInlineData) afterVersion() []byte {
							 | 
						||
| 
								 | 
							
									if len(x) == 0 {
							 | 
						||
| 
								 | 
							
										return x
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return x[1:]
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// find the data with key s.
							 | 
						||
| 
								 | 
							
								// Returns nil if not for or an error occurs.
							 | 
						||
| 
								 | 
							
								func (x xlMetaInlineData) find(key string) []byte {
							 | 
						||
| 
								 | 
							
									if len(x) == 0 || !x.versionOK() {
							 | 
						||
| 
								 | 
							
										return nil
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									sz, buf, err := msgp.ReadMapHeaderBytes(x.afterVersion())
							 | 
						||
| 
								 | 
							
									if err != nil || sz == 0 {
							 | 
						||
| 
								 | 
							
										return nil
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									for i := uint32(0); i < sz; i++ {
							 | 
						||
| 
								 | 
							
										var found []byte
							 | 
						||
| 
								 | 
							
										found, buf, err = msgp.ReadMapKeyZC(buf)
							 | 
						||
| 
								 | 
							
										if err != nil || sz == 0 {
							 | 
						||
| 
								 | 
							
											return nil
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										if string(found) == key {
							 | 
						||
| 
								 | 
							
											val, _, _ := msgp.ReadBytesZC(buf)
							 | 
						||
| 
								 | 
							
											return val
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										// Skip it
							 | 
						||
| 
								 | 
							
										_, buf, err = msgp.ReadBytesZC(buf)
							 | 
						||
| 
								 | 
							
										if err != nil {
							 | 
						||
| 
								 | 
							
											return nil
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// validate checks if the data is valid.
							 | 
						||
| 
								 | 
							
								// It does not check integrity of the stored data.
							 | 
						||
| 
								 | 
							
								func (x xlMetaInlineData) validate() error {
							 | 
						||
| 
								 | 
							
									if len(x) == 0 {
							 | 
						||
| 
								 | 
							
										return nil
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if !x.versionOK() {
							 | 
						||
| 
								 | 
							
										return fmt.Errorf("xlMetaInlineData: unknown version 0x%x", x[0])
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									sz, buf, err := msgp.ReadMapHeaderBytes(x.afterVersion())
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return fmt.Errorf("xlMetaInlineData: %w", err)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									for i := uint32(0); i < sz; i++ {
							 | 
						||
| 
								 | 
							
										var key []byte
							 | 
						||
| 
								 | 
							
										key, buf, err = msgp.ReadMapKeyZC(buf)
							 | 
						||
| 
								 | 
							
										if err != nil {
							 | 
						||
| 
								 | 
							
											return fmt.Errorf("xlMetaInlineData: %w", err)
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										if len(key) == 0 {
							 | 
						||
| 
								 | 
							
											return fmt.Errorf("xlMetaInlineData: key %d is length 0", i)
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										_, buf, err = msgp.ReadBytesZC(buf)
							 | 
						||
| 
								 | 
							
										if err != nil {
							 | 
						||
| 
								 | 
							
											return fmt.Errorf("xlMetaInlineData: %w", err)
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// repair will copy all seemingly valid data entries from a corrupted set.
							 | 
						||
| 
								 | 
							
								// This does not ensure that data is correct, but will allow all operations to complete.
							 | 
						||
| 
								 | 
							
								func (x *xlMetaInlineData) repair() {
							 | 
						||
| 
								 | 
							
									data := *x
							 | 
						||
| 
								 | 
							
									if len(data) == 0 {
							 | 
						||
| 
								 | 
							
										return
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if !data.versionOK() {
							 | 
						||
| 
								 | 
							
										*x = nil
							 | 
						||
| 
								 | 
							
										return
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									sz, buf, err := msgp.ReadMapHeaderBytes(data.afterVersion())
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										*x = nil
							 | 
						||
| 
								 | 
							
										return
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Remove all current data
							 | 
						||
| 
								 | 
							
									keys := make([][]byte, 0, sz)
							 | 
						||
| 
								 | 
							
									vals := make([][]byte, 0, sz)
							 | 
						||
| 
								 | 
							
									for i := uint32(0); i < sz; i++ {
							 | 
						||
| 
								 | 
							
										var key, val []byte
							 | 
						||
| 
								 | 
							
										key, buf, err = msgp.ReadMapKeyZC(buf)
							 | 
						||
| 
								 | 
							
										if err != nil {
							 | 
						||
| 
								 | 
							
											break
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										if len(key) == 0 {
							 | 
						||
| 
								 | 
							
											break
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										val, buf, err = msgp.ReadBytesZC(buf)
							 | 
						||
| 
								 | 
							
										if err != nil {
							 | 
						||
| 
								 | 
							
											break
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										keys = append(keys, key)
							 | 
						||
| 
								 | 
							
										vals = append(vals, val)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									x.serialize(-1, keys, vals)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// validate checks if the data is valid.
							 | 
						||
| 
								 | 
							
								// It does not check integrity of the stored data.
							 | 
						||
| 
								 | 
							
								func (x xlMetaInlineData) list() ([]string, error) {
							 | 
						||
| 
								 | 
							
									if len(x) == 0 {
							 | 
						||
| 
								 | 
							
										return nil, nil
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if !x.versionOK() {
							 | 
						||
| 
								 | 
							
										return nil, errors.New("xlMetaInlineData: unknown version")
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									sz, buf, err := msgp.ReadMapHeaderBytes(x.afterVersion())
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									keys := make([]string, 0, sz)
							 | 
						||
| 
								 | 
							
									for i := uint32(0); i < sz; i++ {
							 | 
						||
| 
								 | 
							
										var key []byte
							 | 
						||
| 
								 | 
							
										key, buf, err = msgp.ReadMapKeyZC(buf)
							 | 
						||
| 
								 | 
							
										if err != nil {
							 | 
						||
| 
								 | 
							
											return keys, err
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										if len(key) == 0 {
							 | 
						||
| 
								 | 
							
											return keys, fmt.Errorf("xlMetaInlineData: key %d is length 0", i)
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										keys = append(keys, string(key))
							 | 
						||
| 
								 | 
							
										// Skip data...
							 | 
						||
| 
								 | 
							
										_, buf, err = msgp.ReadBytesZC(buf)
							 | 
						||
| 
								 | 
							
										if err != nil {
							 | 
						||
| 
								 | 
							
											return keys, err
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return keys, nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// serialize will serialize the provided keys and values.
							 | 
						||
| 
								 | 
							
								// The function will panic if keys/value slices aren't of equal length.
							 | 
						||
| 
								 | 
							
								// Payload size can give an indication of expected payload size.
							 | 
						||
| 
								 | 
							
								// If plSize is <= 0 it will be calculated.
							 | 
						||
| 
								 | 
							
								func (x *xlMetaInlineData) serialize(plSize int, keys [][]byte, vals [][]byte) {
							 | 
						||
| 
								 | 
							
									if len(keys) != len(vals) {
							 | 
						||
| 
								 | 
							
										panic(fmt.Errorf("xlMetaInlineData.serialize: keys/value number mismatch"))
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if len(keys) == 0 {
							 | 
						||
| 
								 | 
							
										*x = nil
							 | 
						||
| 
								 | 
							
										return
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if plSize <= 0 {
							 | 
						||
| 
								 | 
							
										plSize = 1 + msgp.MapHeaderSize
							 | 
						||
| 
								 | 
							
										for i := range keys {
							 | 
						||
| 
								 | 
							
											plSize += len(keys[i]) + len(vals[i]) + msgp.StringPrefixSize + msgp.ArrayHeaderSize
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									payload := make([]byte, 1, plSize)
							 | 
						||
| 
								 | 
							
									payload[0] = xlMetaInlineDataVer
							 | 
						||
| 
								 | 
							
									payload = msgp.AppendMapHeader(payload, uint32(len(keys)))
							 | 
						||
| 
								 | 
							
									for i := range keys {
							 | 
						||
| 
								 | 
							
										payload = msgp.AppendStringFromBytes(payload, keys[i])
							 | 
						||
| 
								 | 
							
										payload = msgp.AppendBytes(payload, vals[i])
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									*x = payload
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// entries returns the number of entries in the data.
							 | 
						||
| 
								 | 
							
								func (x xlMetaInlineData) entries() int {
							 | 
						||
| 
								 | 
							
									if len(x) == 0 || !x.versionOK() {
							 | 
						||
| 
								 | 
							
										return 0
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									sz, _, _ := msgp.ReadMapHeaderBytes(x.afterVersion())
							 | 
						||
| 
								 | 
							
									return int(sz)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// replace will add or replace a key/value pair.
							 | 
						||
| 
								 | 
							
								func (x *xlMetaInlineData) replace(key string, value []byte) {
							 | 
						||
| 
								 | 
							
									in := x.afterVersion()
							 | 
						||
| 
								 | 
							
									sz, buf, _ := msgp.ReadMapHeaderBytes(in)
							 | 
						||
| 
								 | 
							
									keys := make([][]byte, 0, sz+1)
							 | 
						||
| 
								 | 
							
									vals := make([][]byte, 0, sz+1)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Version plus header...
							 | 
						||
| 
								 | 
							
									plSize := 1 + msgp.MapHeaderSize
							 | 
						||
| 
								 | 
							
									replaced := false
							 | 
						||
| 
								 | 
							
									for i := uint32(0); i < sz; i++ {
							 | 
						||
| 
								 | 
							
										var found, foundVal []byte
							 | 
						||
| 
								 | 
							
										var err error
							 | 
						||
| 
								 | 
							
										found, buf, err = msgp.ReadMapKeyZC(buf)
							 | 
						||
| 
								 | 
							
										if err != nil {
							 | 
						||
| 
								 | 
							
											break
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										foundVal, buf, err = msgp.ReadBytesZC(buf)
							 | 
						||
| 
								 | 
							
										if err != nil {
							 | 
						||
| 
								 | 
							
											break
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										plSize += len(found) + msgp.StringPrefixSize + msgp.ArrayHeaderSize
							 | 
						||
| 
								 | 
							
										keys = append(keys, found)
							 | 
						||
| 
								 | 
							
										if string(found) == key {
							 | 
						||
| 
								 | 
							
											vals = append(vals, value)
							 | 
						||
| 
								 | 
							
											plSize += len(value)
							 | 
						||
| 
								 | 
							
											replaced = true
							 | 
						||
| 
								 | 
							
										} else {
							 | 
						||
| 
								 | 
							
											vals = append(vals, foundVal)
							 | 
						||
| 
								 | 
							
											plSize += len(foundVal)
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Add one more.
							 | 
						||
| 
								 | 
							
									if !replaced {
							 | 
						||
| 
								 | 
							
										keys = append(keys, []byte(key))
							 | 
						||
| 
								 | 
							
										vals = append(vals, value)
							 | 
						||
| 
								 | 
							
										plSize += len(key) + len(value) + msgp.StringPrefixSize + msgp.ArrayHeaderSize
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Reserialize...
							 | 
						||
| 
								 | 
							
									x.serialize(plSize, keys, vals)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// rename will rename a key.
							 | 
						||
| 
								 | 
							
								// Returns whether the key was found.
							 | 
						||
| 
								 | 
							
								func (x *xlMetaInlineData) rename(oldKey, newKey string) bool {
							 | 
						||
| 
								 | 
							
									in := x.afterVersion()
							 | 
						||
| 
								 | 
							
									sz, buf, _ := msgp.ReadMapHeaderBytes(in)
							 | 
						||
| 
								 | 
							
									keys := make([][]byte, 0, sz)
							 | 
						||
| 
								 | 
							
									vals := make([][]byte, 0, sz)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Version plus header...
							 | 
						||
| 
								 | 
							
									plSize := 1 + msgp.MapHeaderSize
							 | 
						||
| 
								 | 
							
									found := false
							 | 
						||
| 
								 | 
							
									for i := uint32(0); i < sz; i++ {
							 | 
						||
| 
								 | 
							
										var foundKey, foundVal []byte
							 | 
						||
| 
								 | 
							
										var err error
							 | 
						||
| 
								 | 
							
										foundKey, buf, err = msgp.ReadMapKeyZC(buf)
							 | 
						||
| 
								 | 
							
										if err != nil {
							 | 
						||
| 
								 | 
							
											break
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										foundVal, buf, err = msgp.ReadBytesZC(buf)
							 | 
						||
| 
								 | 
							
										if err != nil {
							 | 
						||
| 
								 | 
							
											break
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										plSize += len(foundVal) + msgp.StringPrefixSize + msgp.ArrayHeaderSize
							 | 
						||
| 
								 | 
							
										vals = append(vals, foundVal)
							 | 
						||
| 
								 | 
							
										if string(foundKey) != oldKey {
							 | 
						||
| 
								 | 
							
											keys = append(keys, foundKey)
							 | 
						||
| 
								 | 
							
											plSize += len(foundKey)
							 | 
						||
| 
								 | 
							
										} else {
							 | 
						||
| 
								 | 
							
											keys = append(keys, []byte(newKey))
							 | 
						||
| 
								 | 
							
											plSize += len(newKey)
							 | 
						||
| 
								 | 
							
											found = true
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									// If not found, just return.
							 | 
						||
| 
								 | 
							
									if !found {
							 | 
						||
| 
								 | 
							
										return false
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Reserialize...
							 | 
						||
| 
								 | 
							
									x.serialize(plSize, keys, vals)
							 | 
						||
| 
								 | 
							
									return true
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// remove will remove one or more keys.
							 | 
						||
| 
								 | 
							
								// Returns true if any key was found.
							 | 
						||
| 
								 | 
							
								func (x *xlMetaInlineData) remove(keys ...string) bool {
							 | 
						||
| 
								 | 
							
									in := x.afterVersion()
							 | 
						||
| 
								 | 
							
									sz, buf, _ := msgp.ReadMapHeaderBytes(in)
							 | 
						||
| 
								 | 
							
									newKeys := make([][]byte, 0, sz)
							 | 
						||
| 
								 | 
							
									newVals := make([][]byte, 0, sz)
							 | 
						||
| 
								 | 
							
									var removeKey func(s []byte) bool
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Copy if big number of compares...
							 | 
						||
| 
								 | 
							
									if len(keys) > 5 && sz > 5 {
							 | 
						||
| 
								 | 
							
										mKeys := make(map[string]struct{}, len(keys))
							 | 
						||
| 
								 | 
							
										for _, key := range keys {
							 | 
						||
| 
								 | 
							
											mKeys[key] = struct{}{}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										removeKey = func(s []byte) bool {
							 | 
						||
| 
								 | 
							
											_, ok := mKeys[string(s)]
							 | 
						||
| 
								 | 
							
											return ok
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									} else {
							 | 
						||
| 
								 | 
							
										removeKey = func(s []byte) bool {
							 | 
						||
| 
								 | 
							
											for _, key := range keys {
							 | 
						||
| 
								 | 
							
												if key == string(s) {
							 | 
						||
| 
								 | 
							
													return true
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											return false
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Version plus header...
							 | 
						||
| 
								 | 
							
									plSize := 1 + msgp.MapHeaderSize
							 | 
						||
| 
								 | 
							
									found := false
							 | 
						||
| 
								 | 
							
									for i := uint32(0); i < sz; i++ {
							 | 
						||
| 
								 | 
							
										var foundKey, foundVal []byte
							 | 
						||
| 
								 | 
							
										var err error
							 | 
						||
| 
								 | 
							
										foundKey, buf, err = msgp.ReadMapKeyZC(buf)
							 | 
						||
| 
								 | 
							
										if err != nil {
							 | 
						||
| 
								 | 
							
											break
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										foundVal, buf, err = msgp.ReadBytesZC(buf)
							 | 
						||
| 
								 | 
							
										if err != nil {
							 | 
						||
| 
								 | 
							
											break
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										if !removeKey(foundKey) {
							 | 
						||
| 
								 | 
							
											plSize += msgp.StringPrefixSize + msgp.ArrayHeaderSize + len(foundKey) + len(foundVal)
							 | 
						||
| 
								 | 
							
											newKeys = append(newKeys, foundKey)
							 | 
						||
| 
								 | 
							
											newVals = append(newVals, foundVal)
							 | 
						||
| 
								 | 
							
										} else {
							 | 
						||
| 
								 | 
							
											found = true
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									// If not found, just return.
							 | 
						||
| 
								 | 
							
									if !found {
							 | 
						||
| 
								 | 
							
										return false
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									// If none left...
							 | 
						||
| 
								 | 
							
									if len(newKeys) == 0 {
							 | 
						||
| 
								 | 
							
										*x = nil
							 | 
						||
| 
								 | 
							
										return true
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Reserialize...
							 | 
						||
| 
								 | 
							
									x.serialize(plSize, newKeys, newVals)
							 | 
						||
| 
								 | 
							
									return true
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// xlMetaV2TrimData will trim any data from the metadata without unmarshalling it.
							 | 
						||
| 
								 | 
							
								// If any error occurs the unmodified data is returned.
							 | 
						||
| 
								 | 
							
								func xlMetaV2TrimData(buf []byte) []byte {
							 | 
						||
| 
								 | 
							
									metaBuf, min, maj, err := checkXL2V1(buf)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return buf
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if maj == 1 && min < 1 {
							 | 
						||
| 
								 | 
							
										// First version to carry data.
							 | 
						||
| 
								 | 
							
										return buf
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									// Skip header
							 | 
						||
| 
								 | 
							
									_, metaBuf, err = msgp.ReadBytesZC(metaBuf)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										logger.LogIf(GlobalContext, err)
							 | 
						||
| 
								 | 
							
										return buf
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									// Skip CRC
							 | 
						||
| 
								 | 
							
									if maj > 1 || min >= 2 {
							 | 
						||
| 
								 | 
							
										_, metaBuf, err = msgp.ReadUint32Bytes(metaBuf)
							 | 
						||
| 
								 | 
							
										logger.LogIf(GlobalContext, err)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									//   =  input - current pos
							 | 
						||
| 
								 | 
							
									ends := len(buf) - len(metaBuf)
							 | 
						||
| 
								 | 
							
									if ends > len(buf) {
							 | 
						||
| 
								 | 
							
										return buf
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return buf[:ends]
							 | 
						||
| 
								 | 
							
								}
							 |