github.com/matrixorigin/matrixone@v0.7.0/pkg/config/configuration.go (about)

     1  // Copyright 2021 Matrix Origin
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package config
    16  
    17  import (
    18  	"context"
    19  	"os"
    20  	"path/filepath"
    21  	"time"
    22  
    23  	"github.com/matrixorigin/matrixone/pkg/fileservice"
    24  	"github.com/matrixorigin/matrixone/pkg/logutil"
    25  	"github.com/matrixorigin/matrixone/pkg/txn/client"
    26  	"github.com/matrixorigin/matrixone/pkg/util/toml"
    27  	"github.com/matrixorigin/matrixone/pkg/vm/engine"
    28  )
    29  
    30  type ConfigurationKeyType int
    31  
    32  const (
    33  	ParameterUnitKey ConfigurationKeyType = 1
    34  )
    35  
    36  var (
    37  	//root name
    38  	defaultRootName = "root"
    39  
    40  	//root password
    41  	defaultRootPassword = ""
    42  
    43  	//dump user name
    44  	defaultDumpUser = "dump"
    45  
    46  	//dump user password
    47  	defaultDumpPassword = "111"
    48  
    49  	//port defines which port the mo-server listens on and clients connect to
    50  	defaultPort = 6001
    51  
    52  	//listening ip
    53  	defaultHost = "0.0.0.0"
    54  
    55  	//listening unix domain socket
    56  	defaultUnixAddr = "/tmp/mysql.sock"
    57  
    58  	//guest mmu limitation.  1 << 40 = 1099511627776
    59  	defaultGuestMmuLimitation = 1099511627776
    60  
    61  	//mempool maxsize.  1 << 40 = 1099511627776
    62  	defaultMempoolMaxSize = 1099511627776
    63  
    64  	//mempool factor.
    65  	defaultMempoolFactor = 8
    66  
    67  	//process.Limitation.Size.  10 << 32 = 42949672960
    68  	defaultProcessLimitationSize = 42949672960
    69  
    70  	//process.Limitation.BatchRows.  10 << 32 = 42949672960
    71  	defaultProcessLimitationBatchRows = 42949672960
    72  
    73  	//process.Limitation.PartitionRows.  10 << 32 = 42949672960
    74  	defaultProcessLimitationPartitionRows = 42949672960
    75  
    76  	//the root directory of the storage
    77  	defaultStorePath = "./store"
    78  
    79  	defaultServerVersionPrefix = "8.0.30-MatrixOne-v"
    80  
    81  	//the length of query printed into console. -1, complete string. 0, empty string. >0 , length of characters at the header of the string.
    82  	defaultLengthOfQueryPrinted = 200000
    83  
    84  	//the count of rows in vector of batch in load data
    85  	defaultBatchSizeInLoadData = 40000
    86  
    87  	//initial value is 4. The count of go routine writing batch into the storage.
    88  	defaultLoadDataConcurrencyCount = 4
    89  
    90  	//KB. When the number of bytes in the outbuffer exceeds the it,the outbuffer will be flushed.
    91  	defaultMaxBytesInOutbufToFlush = 1024
    92  
    93  	//printLog Interval is 10s.
    94  	defaultPrintLogInterVal = 10
    95  
    96  	//export data to csv file default flush size
    97  	defaultExportDataDefaultFlushSize = 1
    98  
    99  	//port defines which port the rpc server listens on
   100  	defaultPortOfRpcServerInComputationEngine = 20000
   101  
   102  	//statusPort defines which port the mo status server (for metric etc.) listens on and clients connect to
   103  	defaultStatusPort = 7001
   104  
   105  	// defaultBatchProcessor default is FileService. if InternalExecutor, use internal sql executor, FileService will implement soon.
   106  	defaultBatchProcessor = "FileService"
   107  
   108  	// defaultTraceExportInterval default: 15 sec.
   109  	defaultTraceExportInterval = 15
   110  
   111  	// defaultMetricExportInterval default: 15 sec.
   112  	defaultMetricExportInterval = 15
   113  
   114  	// defaultLogShardID default: 1
   115  	defaultLogShardID = 1
   116  
   117  	// defaultDNReplicaID default: 1
   118  	defaultDNReplicaID = 1
   119  	// defaultMetricGatherInterval default: 15 sec.
   120  	defaultMetricGatherInterval = 15
   121  
   122  	// defaultMetricUpdateStorageUsageInterval default: 15 min.
   123  	defaultMetricUpdateStorageUsageInterval = 15 * time.Minute
   124  
   125  	// defaultMergeCycle default: 4 hours
   126  	defaultMergeCycle = 4 * time.Hour
   127  
   128  	// defaultMaxFileSize default: 128 MB
   129  	defaultMaxFileSize = 128
   130  
   131  	// defaultPathBuilder, val in [DBTable, AccountDate]
   132  	defaultPathBuilder = "AccountDate"
   133  
   134  	// defaultSessionTimeout default: 10 minutes
   135  	defaultSessionTimeout = 24 * time.Hour
   136  
   137  	// defaultLogsExtension default: tae. Support val in [csv, tae]
   138  	defaultLogsExtension = "tae"
   139  
   140  	// defaultMergedExtension default: tae. Support val in [csv, tae]
   141  	defaultMergedExtension = "tae"
   142  )
   143  
   144  // FrontendParameters of the frontend
   145  type FrontendParameters struct {
   146  	MoVersion string
   147  
   148  	//root name
   149  	RootName string `toml:"rootname"`
   150  
   151  	//root password
   152  	RootPassword string `toml:"rootpassword"`
   153  
   154  	DumpUser string `toml:"dumpuser"`
   155  
   156  	DumpPassword string `toml:"dumppassword"`
   157  
   158  	//dump database
   159  	DumpDatabase string `toml:"dumpdatabase"`
   160  
   161  	//port defines which port the mo-server listens on and clients connect to
   162  	Port int64 `toml:"port"`
   163  
   164  	//listening ip
   165  	Host string `toml:"host"`
   166  
   167  	// UnixSocketAddress listening unix domain socket
   168  	UnixSocketAddress string `toml:"unix-socket"`
   169  
   170  	//guest mmu limitation. default: 1 << 40 = 1099511627776
   171  	GuestMmuLimitation int64 `toml:"guestMmuLimitation"`
   172  
   173  	//mempool maxsize. default: 1 << 40 = 1099511627776
   174  	MempoolMaxSize int64 `toml:"mempoolMaxSize"`
   175  
   176  	//mempool factor. default: 8
   177  	MempoolFactor int64 `toml:"mempoolFactor"`
   178  
   179  	//process.Limitation.Size. default: 10 << 32 = 42949672960
   180  	ProcessLimitationSize int64 `toml:"processLimitationSize"`
   181  
   182  	//process.Limitation.BatchRows. default: 10 << 32 = 42949672960
   183  	ProcessLimitationBatchRows int64 `toml:"processLimitationBatchRows"`
   184  
   185  	//process.Limitation.BatchSize. default: 0
   186  	ProcessLimitationBatchSize int64 `toml:"processLimitationBatchSize"`
   187  
   188  	//process.Limitation.PartitionRows. default: 10 << 32 = 42949672960
   189  	ProcessLimitationPartitionRows int64 `toml:"processLimitationPartitionRows"`
   190  
   191  	//the root directory of the storage and matrixcube's data. The actual dir is cubeDirPrefix + nodeID
   192  	StorePath string `toml:"storePath"`
   193  
   194  	//the root directory of the storage and matrixcube's data. The actual dir is cubeDirPrefix + nodeID
   195  	ServerVersionPrefix string `toml:"serverVersionPrefix"`
   196  
   197  	//the length of query printed into console. -1, complete string. 0, empty string. >0 , length of characters at the header of the string.
   198  	LengthOfQueryPrinted int64 `toml:"lengthOfQueryPrinted"`
   199  
   200  	//the count of rows in vector of batch in load data
   201  	BatchSizeInLoadData int64 `toml:"batchSizeInLoadData"`
   202  
   203  	//default is 4. The count of go routine writing batch into the storage.
   204  	LoadDataConcurrencyCount int64 `toml:"loadDataConcurrencyCount"`
   205  
   206  	//default is false. Skip writing batch into the storage
   207  	LoadDataSkipWritingBatch bool `toml:"loadDataSkipWritingBatch"`
   208  
   209  	//KB. When the number of bytes in the outbuffer exceeds it,the outbuffer will be flushed.
   210  	MaxBytesInOutbufToFlush int64 `toml:"maxBytesInOutbufToFlush"`
   211  
   212  	//default printLog Interval is 10s.
   213  	PrintLogInterVal int64 `toml:"printLogInterVal"`
   214  
   215  	//export data to csv file default flush size
   216  	ExportDataDefaultFlushSize int64 `toml:"exportDataDefaultFlushSize"`
   217  
   218  	//port defines which port the rpc server listens on
   219  	PortOfRpcServerInComputationEngine int64 `toml:"portOfRpcServerInComputationEngine"`
   220  
   221  	//default is false. false : one txn for an independent batch true : only one txn during loading data
   222  	DisableOneTxnPerBatchDuringLoad bool `toml:"DisableOneTxnPerBatchDuringLoad"`
   223  
   224  	//default is 'debug'. the level of log.
   225  	LogLevel string `toml:"logLevel"`
   226  
   227  	//default is 'json'. the format of log.
   228  	LogFormat string `toml:"logFormat"`
   229  
   230  	//default is ''. the file
   231  	LogFilename string `toml:"logFilename"`
   232  
   233  	//default is 512MB. the maximum of log file size
   234  	LogMaxSize int64 `toml:"logMaxSize"`
   235  
   236  	//default is 0. the maximum days of log file to be kept
   237  	LogMaxDays int64 `toml:"logMaxDays"`
   238  
   239  	//default is 0. the maximum numbers of log file to be retained
   240  	LogMaxBackups int64 `toml:"logMaxBackups"`
   241  
   242  	//default is false. With true. Server will support tls
   243  	EnableTls bool `toml:"enableTls"`
   244  
   245  	//default is ''. Path of file that contains list of trusted SSL CAs for client
   246  	TlsCaFile string `toml:"tlsCaFile"`
   247  
   248  	//default is ''. Path of file that contains X509 certificate in PEM format for client
   249  	TlsCertFile string `toml:"tlsCertFile"`
   250  
   251  	//default is ''. Path of file that contains X509 key in PEM format for client
   252  	TlsKeyFile string `toml:"tlsKeyFile"`
   253  
   254  	//default is 1
   255  	LogShardID uint64 `toml:"logshardid"`
   256  
   257  	//default is 1
   258  	DNReplicaID uint64 `toml:"dnreplicalid"`
   259  
   260  	EnableDoComQueryInProgress bool `toml:"comQueryInProgress"`
   261  
   262  	//timeout of the session. the default is 10minutes
   263  	SessionTimeout toml.Duration `toml:"sessionTimeout"`
   264  
   265  	// MaxMessageSize max size for read messages from dn. Default is 10M
   266  	MaxMessageSize uint64 `toml:"max-message-size"`
   267  
   268  	// default off
   269  	SaveQueryResult string `toml:"saveQueryResult"`
   270  
   271  	// default 24 (h)
   272  	QueryResultTimeout uint64 `toml:"queryResultTimeout"`
   273  
   274  	// default 100 (MB)
   275  	QueryResultMaxsize uint64 `toml:"queryResultMaxsize"`
   276  
   277  	AutoIncrCacheSize uint64 `toml:"autoIncrCacheSize"`
   278  }
   279  
   280  func (fp *FrontendParameters) SetDefaultValues() {
   281  	if fp.RootName == "" {
   282  		fp.RootName = defaultRootName
   283  	}
   284  
   285  	if fp.RootPassword == "" {
   286  		fp.RootPassword = defaultRootPassword
   287  	}
   288  
   289  	if fp.DumpUser == "" {
   290  		fp.DumpUser = defaultDumpUser
   291  	}
   292  
   293  	if fp.DumpPassword == "" {
   294  		fp.DumpPassword = defaultDumpPassword
   295  	}
   296  
   297  	if fp.Port == 0 {
   298  		fp.Port = int64(defaultPort)
   299  	}
   300  
   301  	if fp.Host == "" {
   302  		fp.Host = defaultHost
   303  	}
   304  
   305  	if fp.UnixSocketAddress == "" {
   306  		fp.UnixSocketAddress = defaultUnixAddr
   307  	}
   308  
   309  	if fp.GuestMmuLimitation == 0 {
   310  		fp.GuestMmuLimitation = int64(toml.ByteSize(defaultGuestMmuLimitation))
   311  	}
   312  
   313  	if fp.MempoolMaxSize == 0 {
   314  		fp.MempoolMaxSize = int64(toml.ByteSize(defaultMempoolMaxSize))
   315  	}
   316  
   317  	if fp.MempoolFactor == 0 {
   318  		fp.MempoolFactor = int64(defaultMempoolFactor)
   319  	}
   320  
   321  	if fp.ProcessLimitationSize == 0 {
   322  		fp.ProcessLimitationSize = int64(toml.ByteSize(defaultProcessLimitationSize))
   323  	}
   324  
   325  	if fp.ProcessLimitationBatchRows == 0 {
   326  		fp.ProcessLimitationBatchRows = int64(toml.ByteSize(defaultProcessLimitationBatchRows))
   327  	}
   328  
   329  	if fp.ProcessLimitationPartitionRows == 0 {
   330  		fp.ProcessLimitationPartitionRows = int64(toml.ByteSize(defaultProcessLimitationPartitionRows))
   331  	}
   332  
   333  	if fp.StorePath == "" {
   334  		fp.StorePath = defaultStorePath
   335  	}
   336  
   337  	if fp.ServerVersionPrefix == "" {
   338  		fp.ServerVersionPrefix = defaultServerVersionPrefix
   339  	}
   340  
   341  	if fp.LengthOfQueryPrinted == 0 {
   342  		fp.LengthOfQueryPrinted = int64(defaultLengthOfQueryPrinted)
   343  	}
   344  
   345  	if fp.BatchSizeInLoadData == 0 {
   346  		fp.BatchSizeInLoadData = int64(defaultBatchSizeInLoadData)
   347  	}
   348  
   349  	if fp.LoadDataConcurrencyCount == 0 {
   350  		fp.LoadDataConcurrencyCount = int64(defaultLoadDataConcurrencyCount)
   351  	}
   352  
   353  	if fp.MaxBytesInOutbufToFlush == 0 {
   354  		fp.MaxBytesInOutbufToFlush = int64(defaultMaxBytesInOutbufToFlush)
   355  	}
   356  
   357  	if fp.PrintLogInterVal == 0 {
   358  		fp.PrintLogInterVal = int64(defaultPrintLogInterVal)
   359  	}
   360  
   361  	if fp.ExportDataDefaultFlushSize == 0 {
   362  		fp.ExportDataDefaultFlushSize = int64(defaultExportDataDefaultFlushSize)
   363  	}
   364  
   365  	if fp.PortOfRpcServerInComputationEngine == 0 {
   366  		fp.PortOfRpcServerInComputationEngine = int64(defaultPortOfRpcServerInComputationEngine)
   367  	}
   368  
   369  	if fp.DNReplicaID == 0 {
   370  		fp.DNReplicaID = uint64(defaultDNReplicaID)
   371  	}
   372  
   373  	if fp.LogShardID == 0 {
   374  		fp.LogShardID = uint64(defaultLogShardID)
   375  	}
   376  
   377  	if fp.SessionTimeout.Duration == 0 {
   378  		fp.SessionTimeout.Duration = defaultSessionTimeout
   379  	}
   380  
   381  	if fp.SaveQueryResult == "" {
   382  		fp.SaveQueryResult = "off"
   383  	}
   384  
   385  	if fp.QueryResultTimeout == 0 {
   386  		fp.QueryResultTimeout = 24
   387  	}
   388  
   389  	if fp.QueryResultMaxsize == 0 {
   390  		fp.QueryResultMaxsize = 100
   391  	}
   392  
   393  	if fp.AutoIncrCacheSize == 0 {
   394  		fp.AutoIncrCacheSize = 3000
   395  	}
   396  }
   397  
   398  func (fp *FrontendParameters) SetMaxMessageSize(size uint64) {
   399  	fp.MaxMessageSize = size
   400  }
   401  
   402  func (fp *FrontendParameters) SetLogAndVersion(log *logutil.LogConfig, version string) {
   403  	fp.LogLevel = log.Level
   404  	fp.LogFormat = log.Format
   405  	fp.LogFilename = log.Filename
   406  	fp.LogMaxSize = int64(log.MaxSize)
   407  	fp.LogMaxDays = int64(log.MaxDays)
   408  	fp.LogMaxBackups = int64(log.MaxBackups)
   409  	fp.MoVersion = version
   410  }
   411  
   412  func (fp *FrontendParameters) GetUnixSocketAddress() string {
   413  	if fp.UnixSocketAddress == "" {
   414  		return ""
   415  	}
   416  	ok, err := isFileExist(fp.UnixSocketAddress)
   417  	if err != nil || ok {
   418  		return ""
   419  	}
   420  
   421  	canCreate := func() string {
   422  		f, err := os.Create(fp.UnixSocketAddress)
   423  		if err != nil {
   424  			return ""
   425  		}
   426  		if err := f.Close(); err != nil {
   427  			panic(err)
   428  		}
   429  		if err := os.Remove(fp.UnixSocketAddress); err != nil {
   430  			panic(err)
   431  		}
   432  		return fp.UnixSocketAddress
   433  	}
   434  
   435  	rootPath := filepath.Dir(fp.UnixSocketAddress)
   436  	f, err := os.Open(rootPath)
   437  	if os.IsNotExist(err) {
   438  		err := os.MkdirAll(rootPath, 0755)
   439  		if err != nil {
   440  			return ""
   441  		}
   442  		return canCreate()
   443  	} else if err != nil {
   444  		return ""
   445  	}
   446  	if err := f.Close(); err != nil {
   447  		panic(err)
   448  	}
   449  	return canCreate()
   450  }
   451  
   452  func isFileExist(file string) (bool, error) {
   453  	f, err := os.Open(file)
   454  	if err == nil {
   455  		return true, f.Close()
   456  	}
   457  	if os.IsNotExist(err) {
   458  		return false, nil
   459  	}
   460  	return false, err
   461  }
   462  
   463  // ObservabilityParameters hold metric/trace switch
   464  type ObservabilityParameters struct {
   465  	// MoVersion, see SetDefaultValues
   466  	MoVersion string
   467  
   468  	// Host listening ip. normally same as FrontendParameters.Host
   469  	Host string `toml:"host"`
   470  
   471  	// StatusPort defines which port the mo status server (for metric etc.) listens on and clients connect to
   472  	// Start listen with EnableMetricToProm is true.
   473  	StatusPort int64 `toml:"statusPort"`
   474  
   475  	// EnableMetricToProm default is false. if true, metrics can be scraped through host:status/metrics endpoint
   476  	EnableMetricToProm bool `toml:"enableMetricToProm"`
   477  
   478  	// DisableMetric default is false. if false, enable metric at booting
   479  	DisableMetric bool `toml:"disableMetric"`
   480  
   481  	// DisableTrace default is false. if false, enable trace at booting
   482  	DisableTrace bool `toml:"disableTrace"`
   483  
   484  	// EnableTraceDebug default is FileService. if InternalExecutor, use internal sql executor, FileService will implement soon.
   485  	BatchProcessor string `toml:"batchProcessor"`
   486  
   487  	// EnableTraceDebug default is false. With true, system will check all the children span is ended, which belong to the closing span.
   488  	EnableTraceDebug bool `toml:"enableTraceDebug"`
   489  
   490  	// TraceExportInterval default is 15s.
   491  	TraceExportInterval int `toml:"traceExportInterval"`
   492  
   493  	// LongQueryTime default is 0.0 sec. if 0.0f, record every query. Record with exec time longer than LongQueryTime.
   494  	LongQueryTime float64 `toml:"longQueryTime"`
   495  
   496  	// MetricMultiTable default is false. With true, save all metric data in one table.
   497  	MetricMultiTable bool `toml:"metricMultiTable"`
   498  
   499  	// MetricExportInterval default is 15 sec.
   500  	MetricExportInterval int `toml:"metricExportInterval"`
   501  
   502  	// MetricGatherInterval default is 15 sec.
   503  	MetricGatherInterval int `toml:"metricGatherInterval"`
   504  
   505  	// MetricUpdateStorageUsageInterval, default: 30 min
   506  	MetricUpdateStorageUsageInterval toml.Duration `toml:"metricUpdateStorageUsageInterval"`
   507  
   508  	// MergeCycle default: 14400 sec (4 hours).
   509  	// PS: only used while MO init.
   510  	MergeCycle toml.Duration `toml:"mergeCycle"`
   511  
   512  	// MergeMaxFileSize default: 128 (MB)
   513  	MergeMaxFileSize int `toml:"mergeMaxFileSize"`
   514  
   515  	// PathBuilder default: DBTable. Support val in [DBTable, AccountDate]
   516  	PathBuilder string `toml:"pathBuilder"`
   517  
   518  	// LogsExtension default: tae. Support val in [csv, tae]
   519  	LogsExtension string `toml:"logsExtension"`
   520  
   521  	// MergedExtension default: tae. Support val in [csv, tae]
   522  	MergedExtension string `toml:"mergedExtension"`
   523  }
   524  
   525  func (op *ObservabilityParameters) SetDefaultValues(version string) {
   526  	op.MoVersion = version
   527  
   528  	if op.Host == "" {
   529  		op.Host = defaultHost
   530  	}
   531  
   532  	if op.StatusPort == 0 {
   533  		op.StatusPort = int64(defaultStatusPort)
   534  	}
   535  
   536  	if op.BatchProcessor == "" {
   537  		op.BatchProcessor = defaultBatchProcessor
   538  	}
   539  
   540  	if op.TraceExportInterval <= 0 {
   541  		op.TraceExportInterval = defaultTraceExportInterval
   542  	}
   543  
   544  	if op.MetricExportInterval <= 0 {
   545  		op.MetricExportInterval = defaultMetricExportInterval
   546  	}
   547  
   548  	if op.MetricGatherInterval <= 0 {
   549  		op.MetricGatherInterval = defaultMetricGatherInterval
   550  	}
   551  
   552  	if op.MetricUpdateStorageUsageInterval.Duration <= 0 {
   553  		op.MetricUpdateStorageUsageInterval.Duration = defaultMetricUpdateStorageUsageInterval
   554  	}
   555  
   556  	if op.MergeCycle.Duration <= 0 {
   557  		op.MergeCycle.Duration = defaultMergeCycle
   558  	}
   559  
   560  	if op.PathBuilder == "" {
   561  		op.PathBuilder = defaultPathBuilder
   562  	}
   563  
   564  	if op.MergeMaxFileSize <= 0 {
   565  		op.MergeMaxFileSize = defaultMaxFileSize
   566  	}
   567  
   568  	if op.LogsExtension == "" {
   569  		op.LogsExtension = defaultLogsExtension
   570  	}
   571  
   572  	if op.MergedExtension == "" {
   573  		op.MergedExtension = defaultMergedExtension
   574  	}
   575  }
   576  
   577  type ParameterUnit struct {
   578  	SV *FrontendParameters
   579  
   580  	//Storage Engine
   581  	StorageEngine engine.Engine
   582  
   583  	//TxnClient
   584  	TxnClient client.TxnClient
   585  
   586  	//Cluster Nodes
   587  	ClusterNodes engine.Nodes
   588  
   589  	// FileService
   590  	FileService fileservice.FileService
   591  
   592  	// GetClusterDetails
   593  	GetClusterDetails engine.GetClusterDetailsFunc
   594  }
   595  
   596  func NewParameterUnit(
   597  	sv *FrontendParameters,
   598  	storageEngine engine.Engine,
   599  	txnClient client.TxnClient,
   600  	clusterNodes engine.Nodes,
   601  	getClusterDetails engine.GetClusterDetailsFunc,
   602  ) *ParameterUnit {
   603  	return &ParameterUnit{
   604  		SV:                sv,
   605  		StorageEngine:     storageEngine,
   606  		TxnClient:         txnClient,
   607  		ClusterNodes:      clusterNodes,
   608  		GetClusterDetails: getClusterDetails,
   609  	}
   610  }
   611  
   612  // GetParameterUnit gets the configuration from the context.
   613  func GetParameterUnit(ctx context.Context) *ParameterUnit {
   614  	pu := ctx.Value(ParameterUnitKey).(*ParameterUnit)
   615  	if pu == nil {
   616  		panic("parameter unit is invalid")
   617  	}
   618  	return pu
   619  }