## 3 File Access Patterns
### File Access Patterns  
A sequence of file requests can exhibit various access patterns, which we organize into four major groups: (i) _temporal_, (ii) _spatial_, (iii) _length_, and (iv) _frequency_ patterns. For every new file request, we extract the required information and compute each listed pattern along with how frequently each access pattern appears. The _temporal pattern_ represents the frequency in which a file receives read/write I/O requests over time. Files can be accessed based on an _intense_ frequency (i.e., each request is submitted almost immediately after the previous one) or a _mild_ frequency (i.e., there is some small delay between request submissions). The temporal pattern requires storing the last \(n\) request times per file to be calculated. Consider \(\mathbb{T}_{f}\) as the set of \(n\) previous request times for a file \(f\). Thus, the temporal pattern is given by:  
\[\delta(f)= \begin{cases}\text{intense,}&\forall t_{i}\in\mathbb{T}_{f}:|t_{i}-t _{i-1}|\leq\Delta,\Delta>0\\ \text{mild,}&\text{otherwise}\end{cases}  \tag{1}\]  
where \(\Delta\) is a configurable length gap between consecutive requests. Whenever \(|\mathbb{T}|\) reaches the size of \(n\), we remove the last item of \(\mathbb{T}\). The _spatial pattern_ represents the order in which the data are accessed in a file. Files can receive _sequential_ and _non-sequential_ (or _random_) I/O requests over their data. A sequential spatial pattern represents a file that has its data accessed contiguously, without any gap in the accessed data requested between file requests. Consider \(\mathbb{H}_{f}\) as the access history of file \(f\), containing the pairs \((o,l)\), where \(o\) is an offset and \(l\) is a length. Also consider \(n\) as the size of \(H\). The spatial pattern of \(f\) is given by:  
\[\omega(f)= \begin{cases}\text{sequential,}&\forall(o_{i},l_{i})\in\mathbb{H}_{ f}:o_{i}=o_{i-1}+l_{i-1}\\ \text{random,}&\text{otherwise}\end{cases}  \tag{2}\]  
When \(|\mathbb{H}|\)'s size reaches \(n\), the last (oldest) pair in \(\mathbb{H}\) is removed. The _length pattern_ represents the variability of the length size requested to be read from or written to a file. This pattern determines whether or not requests over a file are accessing equal-sized blocks of data. Thus, it can be of _uniform_ length size or _variable_ length size. \(\mathbb{H}_{f}\) holds the history of the previous accessed _offset_ (\(o\)) and _length_ (\(l\)) of each file. The length interval is given by:  
\[\lambda(f)= \begin{cases}\text{uniform,}&\forall(o_{i},l_{i})\in\mathbb{H}_{f}: |l_{i}-l_{i-1}|=0\\ \text{variable,}&\text{otherwise}\end{cases}  \tag{3}\]  
The _frequency patterns_ provide an estimate of the number of times a file \(f\) has been accessed. We differentiate between two forms of frequency patterns. The first form is the _file access frequency_, represented by a number between 0 and 1, amortized by a logarithmic function. It requires storing a counter \(c_{f}\) per file \(f\) to count the number of times the file is open for reading and is given by:  
\[\rho_{1}(f)=1-\left(\frac{1}{\log_{2}\left(c_{f}+2\right)}\right) \tag{4}\]  
The intuition for \(\rho_{1}(f)\) is to have the shape of a logarithmic function that starts from point \((0,0)\), increases quickly for small \(c_{f}\), and then converges to the value 1 as \(c_{f}\) goes to infinity. The second form is the _fully read frequency_ metric, which calculates an approximation of how many times this file was fully read, normalized by the size of the file. It requires the total number of bytes accessed from a file (\(b_{f}\)) and the file size (\(s_{f}\)), calculated by:\[\rho_{2}(f)=\left\lfloor\frac{b_{f}}{s_{f}}\right\rfloor \tag{5}\]  
We aggregate these file access patterns into two additional sets of patterns to provide a greater context to the learning models. We aggregate by files under the same _directory_ and by files with the same _file format_ (e.g., text, audio, image, video, compression, executable, scientific, source code, etc.).