View Javadoc
1   /*
2   Copyright (c) 2007 Health Market Science, Inc.
3   
4   Licensed under the Apache License, Version 2.0 (the "License");
5   you may not use this file except in compliance with the License.
6   You may obtain a copy of the License at
7   
8       http://www.apache.org/licenses/LICENSE-2.0
9   
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15  */
16  
17  package com.healthmarketscience.jackcess.impl;
18  
19  import java.io.IOException;
20  import java.nio.ByteBuffer;
21  
22  /**
23   * Manages a reference to a page buffer.
24   *
25   * @author James Ahlborn
26   */
27  public final class TempPageHolder {
28  
29    private int _pageNumber = PageChannel.INVALID_PAGE_NUMBER;
30    private final TempBufferHolder _buffer;
31    /** the last "modification" count of the buffer that this holder observed.
32        this is tracked so that the page data can be re-read if the underlying
33        buffer has been discarded since the last page read */
34    private int _bufferModCount;
35    
36    private TempPageHolder(TempBufferHolder.Type type) {
37      _buffer = TempBufferHolder.newHolder(type, false);
38      _bufferModCount = _buffer.getModCount();
39    }
40  
41    /**
42     * Creates a new TempPageHolder.
43     * @param type the type of reference desired for any create page buffers
44     */
45    public static TempPageHolder newHolder(TempBufferHolder.Type type) {
46      return new TempPageHolder(type);
47    }
48  
49    /**
50     * @return the currently set page number
51     */
52    public int getPageNumber() {
53      return _pageNumber;
54    }
55  
56    /**
57     * @return the page for the current page number, reading as necessary,
58     *         position and limit are unchanged
59     */
60    public ByteBuffer getPage(PageChannel pageChannel)
61      throws IOException
62    {
63      return setPage(pageChannel, _pageNumber, false);
64    }
65    
66    /**
67     * Sets the current page number and returns that page
68     * @return the page for the new page number, reading as necessary, resets
69     *         position
70     */
71    public ByteBuffer setPage(PageChannel pageChannel, int pageNumber)
72      throws IOException
73    {
74      return setPage(pageChannel, pageNumber, true);
75    }
76  
77    private ByteBuffer setPage(PageChannel pageChannel, int pageNumber,
78                               boolean rewind)
79      throws IOException
80    {
81      ByteBuffer buffer = _buffer.getPageBuffer(pageChannel);
82      int modCount = _buffer.getModCount();
83      if((pageNumber != _pageNumber) || (_bufferModCount != modCount)) {
84        _pageNumber = pageNumber;
85        _bufferModCount = modCount;
86        pageChannel.readPage(buffer, _pageNumber);
87      } else if(rewind) {
88        buffer.rewind();
89      }
90      
91      return buffer;
92    }
93  
94    /**
95     * Allocates a new buffer in the database (with undefined data) and returns
96     * a new empty buffer.
97     */
98    public ByteBuffer setNewPage(PageChannel pageChannel)
99      throws IOException
100   {
101     // ditch any current data
102     clear();
103     // allocate a new page in the database
104     _pageNumber = pageChannel.allocateNewPage();
105     // return a new buffer
106     return _buffer.getPageBuffer(pageChannel);
107   }
108 
109   /**
110    * Forces any current page data to be disregarded (any
111    * <code>getPage</code>/<code>setPage</code> call must reload page data).
112    * Does not necessarily release any memory.
113    */
114   public void invalidate() {
115     possiblyInvalidate(_pageNumber, null);
116   }
117   
118   /**
119    * Forces any current page data to be disregarded if it matches the given
120    * page number (any <code>getPage</code>/<code>setPage</code> call must
121    * reload page data) and is not the given buffer.  Does not necessarily
122    * release any memory.
123    */
124   public void possiblyInvalidate(int modifiedPageNumber,
125                                  ByteBuffer modifiedBuffer) {
126     if(modifiedBuffer == _buffer.getExistingBuffer()) {
127       // no worries, our buffer was the one modified (or is null, either way
128       // we'll need to reload)
129       return;
130     }
131     if(modifiedPageNumber == _pageNumber) {
132       _pageNumber = PageChannel.INVALID_PAGE_NUMBER;
133     }
134   }
135 
136   /**
137    * Forces any current page data to be disregarded (any
138    * <code>getPage</code>/<code>setPage</code> call must reload page data) and
139    * releases any referenced memory.
140    */
141   public void clear() {
142     invalidate();
143     _buffer.clear();
144   }
145 
146 }