View Javadoc

1   /*
2   Copyright (c) 2007 Health Market Science, Inc.
3   
4   This library is free software; you can redistribute it and/or
5   modify it under the terms of the GNU Lesser General Public
6   License as published by the Free Software Foundation; either
7   version 2.1 of the License, or (at your option) any later version.
8   
9   This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  Lesser General Public License for more details.
13  
14  You should have received a copy of the GNU Lesser General Public
15  License along with this library; if not, write to the Free Software
16  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
17  USA
18  
19  You can contact Health Market Science at info@healthmarketscience.com
20  or at the following address:
21  
22  Health Market Science
23  2700 Horizon Drive
24  Suite 200
25  King of Prussia, PA 19406
26  */
27  
28  package com.healthmarketscience.jackcess;
29  
30  import java.io.IOException;
31  import java.nio.ByteBuffer;
32  
33  /**
34   * Manages a reference to a page buffer.
35   *
36   * @author James Ahlborn
37   */
38  public final class TempPageHolder {
39  
40    private int _pageNumber = PageChannel.INVALID_PAGE_NUMBER;
41    private final TempBufferHolder _buffer;
42    /** the last "modification" count of the buffer that this holder observed.
43        this is tracked so that the page data can be re-read if the underlying
44        buffer has been discarded since the last page read */
45    private int _bufferModCount;
46    
47    private TempPageHolder(TempBufferHolder.Type type) {
48      _buffer = TempBufferHolder.newHolder(type, false);
49      _bufferModCount = _buffer.getModCount();
50    }
51  
52    /**
53     * Creates a new TempPageHolder.
54     * @param type the type of reference desired for any create page buffers
55     */
56    public static TempPageHolder newHolder(TempBufferHolder.Type type) {
57      return new TempPageHolder(type);
58    }
59  
60    /**
61     * @return the currently set page number
62     */
63    public int getPageNumber() {
64      return _pageNumber;
65    }
66  
67    /**
68     * @return the page for the current page number, reading as necessary,
69     *         position and limit are unchanged
70     */
71    public ByteBuffer getPage(PageChannel pageChannel)
72      throws IOException
73    {
74      return setPage(pageChannel, _pageNumber, false);
75    }
76    
77    /**
78     * Sets the current page number and returns that page
79     * @return the page for the new page number, reading as necessary, resets
80     *         position
81     */
82    public ByteBuffer setPage(PageChannel pageChannel, int pageNumber)
83      throws IOException
84    {
85      return setPage(pageChannel, pageNumber, true);
86    }
87  
88    private ByteBuffer setPage(PageChannel pageChannel, int pageNumber,
89                               boolean rewind)
90      throws IOException
91    {
92      ByteBuffer buffer = _buffer.getPageBuffer(pageChannel);
93      int modCount = _buffer.getModCount();
94      if((pageNumber != _pageNumber) || (_bufferModCount != modCount)) {
95        _pageNumber = pageNumber;
96        _bufferModCount = modCount;
97        pageChannel.readPage(buffer, _pageNumber);
98      } else if(rewind) {
99        buffer.rewind();
100     }
101     
102     return buffer;
103   }
104 
105   /**
106    * Allocates a new buffer in the database (with undefined data) and returns
107    * a new empty buffer.
108    */
109   public ByteBuffer setNewPage(PageChannel pageChannel)
110     throws IOException
111   {
112     // ditch any current data
113     clear();
114     // allocate a new page in the database
115     _pageNumber = pageChannel.allocateNewPage();
116     // return a new buffer
117     return _buffer.getPageBuffer(pageChannel);
118   }
119 
120   /**
121    * Forces any current page data to be disregarded (any
122    * <code>getPage</code>/<code>setPage</code> call must reload page data).
123    * Does not necessarily release any memory.
124    */
125   public void invalidate() {
126     possiblyInvalidate(_pageNumber, null);
127   }
128   
129   /**
130    * Forces any current page data to be disregarded if it matches the given
131    * page number (any <code>getPage</code>/<code>setPage</code> call must
132    * reload page data) and is not the given buffer.  Does not necessarily
133    * release any memory.
134    */
135   public void possiblyInvalidate(int modifiedPageNumber,
136                                  ByteBuffer modifiedBuffer) {
137     if(modifiedBuffer == _buffer.getExistingBuffer()) {
138       // no worries, our buffer was the one modified (or is null, either way
139       // we'll need to reload)
140       return;
141     }
142     if(modifiedPageNumber == _pageNumber) {
143       _pageNumber = PageChannel.INVALID_PAGE_NUMBER;
144     }
145   }
146 
147   /**
148    * Forces any current page data to be disregarded (any
149    * <code>getPage</code>/<code>setPage</code> call must reload page data) and
150    * releases any referenced memory.
151    */
152   public void clear() {
153     invalidate();
154     _buffer.clear();
155   }
156 
157 }