tdbPCache.c 8.3 KB
Newer Older
H
refact  
Hongze Cheng 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/*
 * Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
 *
 * This program is free software: you can use, redistribute, and/or modify
 * it under the terms of the GNU Affero General Public License, version 3
 * or later ("AGPL"), as published by the Free Software Foundation.
 *
 * 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.
 *
 * 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/>.
 */
H
Hongze Cheng 已提交
15 16
#include "tdbInt.h"

H
more  
Hongze Cheng 已提交
17
struct SPCache {
H
Hongze Cheng 已提交
18 19 20
  int         pageSize;
  int         cacheSize;
  tdb_mutex_t mutex;
H
Hongze Cheng 已提交
21
  SPage      *pList;
H
Hongze Cheng 已提交
22 23 24 25 26 27 28
  int         nFree;
  SPage      *pFree;
  int         nPage;
  int         nHash;
  SPage     **pgHash;
  int         nRecyclable;
  SPage       lru;
H
Hongze Cheng 已提交
29 30
};

wafwerar's avatar
wafwerar 已提交
31 32 33
static inline uint32_t tdbPCachePageHash(const SPgid *pPgid) {
  uint32_t *t = (uint32_t *)((pPgid)->fileid);
  return (uint32_t)(t[0] + t[1] + t[2] + t[3] + t[4] + t[5] + (pPgid)->pgno);
wafwerar's avatar
wafwerar 已提交
34
}
H
more  
Hongze Cheng 已提交
35
#define PAGE_IS_PINNED(pPage) ((pPage)->pLruNext == NULL)
H
Hongze Cheng 已提交
36

H
refact  
Hongze Cheng 已提交
37
static int    tdbPCacheOpenImpl(SPCache *pCache);
H
Hongze Cheng 已提交
38
static SPage *tdbPCacheFetchImpl(SPCache *pCache, const SPgid *pPgid, TXN *pTxn);
H
Hongze Cheng 已提交
39 40 41 42
static void   tdbPCachePinPage(SPCache *pCache, SPage *pPage);
static void   tdbPCacheRemovePageFromHash(SPCache *pCache, SPage *pPage);
static void   tdbPCacheAddPageToHash(SPCache *pCache, SPage *pPage);
static void   tdbPCacheUnpinPage(SPCache *pCache, SPage *pPage);
H
Hongze Cheng 已提交
43 44 45 46 47 48
static int    tdbPCacheCloseImpl(SPCache *pCache);

static void tdbPCacheInitLock(SPCache *pCache) { tdbMutexInit(&(pCache->mutex), NULL); }
static void tdbPCacheDestroyLock(SPCache *pCache) { tdbMutexDestroy(&(pCache->mutex)); }
static void tdbPCacheLock(SPCache *pCache) { tdbMutexLock(&(pCache->mutex)); }
static void tdbPCacheUnlock(SPCache *pCache) { tdbMutexUnlock(&(pCache->mutex)); }
H
Hongze Cheng 已提交
49

H
Hongze Cheng 已提交
50
int tdbPCacheOpen(int pageSize, int cacheSize, SPCache **ppCache) {
H
more  
Hongze Cheng 已提交
51
  SPCache *pCache;
H
Hongze Cheng 已提交
52 53
  void    *pPtr;
  SPage   *pPgHdr;
H
Hongze Cheng 已提交
54

H
Hongze Cheng 已提交
55
  pCache = (SPCache *)tdbOsCalloc(1, sizeof(*pCache));
H
more  
Hongze Cheng 已提交
56
  if (pCache == NULL) {
H
Hongze Cheng 已提交
57 58 59
    return -1;
  }

H
more  
Hongze Cheng 已提交
60 61
  pCache->pageSize = pageSize;
  pCache->cacheSize = cacheSize;
H
Hongze Cheng 已提交
62

H
more  
Hongze Cheng 已提交
63
  if (tdbPCacheOpenImpl(pCache) < 0) {
H
Hongze Cheng 已提交
64
    tdbOsFree(pCache);
H
more  
Hongze Cheng 已提交
65
    return -1;
H
Hongze Cheng 已提交
66 67
  }

H
more  
Hongze Cheng 已提交
68
  *ppCache = pCache;
H
Hongze Cheng 已提交
69 70 71
  return 0;
}

H
Hongze Cheng 已提交
72
int tdbPCacheClose(SPCache *pCache) {
H
Hongze Cheng 已提交
73 74 75 76
  if (pCache) {
    tdbPCacheCloseImpl(pCache);
    tdbOsFree(pCache);
  }
H
Hongze Cheng 已提交
77
  return 0;
H
Hongze Cheng 已提交
78 79
}

H
Hongze Cheng 已提交
80
SPage *tdbPCacheFetch(SPCache *pCache, const SPgid *pPgid, TXN *pTxn) {
H
refact  
Hongze Cheng 已提交
81
  SPage *pPage;
H
more  
Hongze Cheng 已提交
82

H
Hongze Cheng 已提交
83
  tdbPCacheLock(pCache);
H
Hongze Cheng 已提交
84

H
Hongze Cheng 已提交
85
  pPage = tdbPCacheFetchImpl(pCache, pPgid, pTxn);
H
Hongze Cheng 已提交
86 87 88 89
  if (pPage) {
    TDB_REF_PAGE(pPage);
  }

H
Hongze Cheng 已提交
90
  tdbPCacheUnlock(pCache);
H
more  
Hongze Cheng 已提交
91 92

  return pPage;
H
Hongze Cheng 已提交
93 94
}

H
Hongze Cheng 已提交
95
void tdbPCacheRelease(SPCache *pCache, SPage *pPage, TXN *pTxn) {
H
Hongze Cheng 已提交
96 97
  i32 nRef;

H
Hongze Cheng 已提交
98 99
  ASSERT(pTxn);

H
Hongze Cheng 已提交
100 101 102 103
  nRef = TDB_UNREF_PAGE(pPage);
  ASSERT(nRef >= 0);

  if (nRef == 0) {
H
Hongze Cheng 已提交
104 105 106 107 108 109 110 111 112
    tdbPCacheLock(pCache);

    // test the nRef again to make sure
    // it is safe th handle the page
    nRef = TDB_GET_PAGE_REF(pPage);
    if (nRef == 0) {
      if (pPage->isLocal) {
        tdbPCacheUnpinPage(pCache, pPage);
      } else {
H
Hongze Cheng 已提交
113 114 115 116
        if (TDB_TXN_IS_WRITE(pTxn)) {
          // remove from hash
          tdbPCacheRemovePageFromHash(pCache, pPage);
        }
H
Hongze Cheng 已提交
117

H
Hongze Cheng 已提交
118
        tdbPageDestroy(pPage, pTxn->xFree, pTxn->xArg);
H
Hongze Cheng 已提交
119 120 121 122
      }
    }

    tdbPCacheUnlock(pCache);
H
more  
Hongze Cheng 已提交
123
  }
H
Hongze Cheng 已提交
124 125
}

H
Hongze Cheng 已提交
126
int tdbPCacheGetPageSize(SPCache *pCache) { return pCache->pageSize; }
H
more  
Hongze Cheng 已提交
127

H
Hongze Cheng 已提交
128
static SPage *tdbPCacheFetchImpl(SPCache *pCache, const SPgid *pPgid, TXN *pTxn) {
H
Hongze Cheng 已提交
129 130 131 132 133
  int    ret = 0;
  SPage *pPage = NULL;
  SPage *pPageH = NULL;

  ASSERT(pTxn);
H
more  
Hongze Cheng 已提交
134 135

  // 1. Search the hash table
wafwerar's avatar
wafwerar 已提交
136
  pPage = pCache->pgHash[tdbPCachePageHash(pPgid) % pCache->nHash];
H
more  
Hongze Cheng 已提交
137
  while (pPage) {
H
Hongze Cheng 已提交
138
    if (memcmp(pPage->pgid.fileid, pPgid->fileid, TDB_FILE_ID_LEN) == 0 && pPage->pgid.pgno == pPgid->pgno) break;
H
more  
Hongze Cheng 已提交
139 140 141
    pPage = pPage->pHashNext;
  }

H
refact  
Hongze Cheng 已提交
142
  if (pPage) {
H
Hongze Cheng 已提交
143 144 145 146
    if (pPage->isLocal || TDB_TXN_IS_WRITE(pTxn)) {
      tdbPCachePinPage(pCache, pPage);
      return pPage;
    }
H
more  
Hongze Cheng 已提交
147 148
  }

H
Hongze Cheng 已提交
149 150 151 152 153
  // 1. pPage == NULL
  // 2. pPage && pPage->isLocal == 0 && !TDB_TXN_IS_WRITE(pTxn)
  pPageH = pPage;
  pPage = NULL;

H
more  
Hongze Cheng 已提交
154 155 156 157 158 159 160 161 162 163 164
  // 2. Try to allocate a new page from the free list
  if (pCache->pFree) {
    pPage = pCache->pFree;
    pCache->pFree = pPage->pFreeNext;
    pCache->nFree--;
    pPage->pLruNext = NULL;
  }

  // 3. Try to Recycle a page
  if (!pPage && !pCache->lru.pLruPrev->isAnchor) {
    pPage = pCache->lru.pLruPrev;
H
Hongze Cheng 已提交
165 166
    tdbPCacheRemovePageFromHash(pCache, pPage);
    tdbPCachePinPage(pCache, pPage);
H
more  
Hongze Cheng 已提交
167 168
  }

H
Hongze Cheng 已提交
169
  // 4. Try a create new page
H
Hongze Cheng 已提交
170
  if (!pPage) {
H
Hongze Cheng 已提交
171 172 173 174 175 176 177 178 179 180 181 182
    ret = tdbPageCreate(pCache->pageSize, &pPage, pTxn->xMalloc, pTxn->xArg);
    if (ret < 0) {
      // TODO
      ASSERT(0);
      return NULL;
    }

    // init the page fields
    pPage->isAnchor = 0;
    pPage->isLocal = 0;
    TDB_INIT_PAGE_REF(pPage);
  }
H
more  
Hongze Cheng 已提交
183 184 185 186 187

  // 5. Page here are just created from a free list
  // or by recycling or allocated streesly,
  // need to initialize it
  if (pPage) {
H
Hongze Cheng 已提交
188 189 190 191 192 193 194
    if (pPageH) {
      // copy the page content
      memcpy(&(pPage->pgid), pPgid, sizeof(*pPgid));
      pPage->pLruNext = NULL;
      pPage->pPager = pPageH->pPager;

      memcpy(pPage->pData, pPageH->pData, pPage->pageSize);
H
Hongze Cheng 已提交
195
      tdbPageInit(pPage, pPageH->pPageHdr - pPageH->pData, pPageH->xCellSize);
H
Hongze Cheng 已提交
196 197 198 199
      pPage->kLen = pPageH->kLen;
      pPage->vLen = pPageH->vLen;
      pPage->maxLocal = pPageH->maxLocal;
      pPage->minLocal = pPageH->minLocal;
H
Hongze Cheng 已提交
200 201 202 203 204 205 206 207 208
    } else {
      memcpy(&(pPage->pgid), pPgid, sizeof(*pPgid));
      pPage->pLruNext = NULL;
      pPage->pPager = NULL;

      if (pPage->isLocal || TDB_TXN_IS_WRITE(pTxn)) {
        tdbPCacheAddPageToHash(pCache, pPage);
      }
    }
H
more  
Hongze Cheng 已提交
209 210
  }

H
more  
Hongze Cheng 已提交
211
  return pPage;
H
more  
Hongze Cheng 已提交
212 213
}

H
Hongze Cheng 已提交
214
static void tdbPCachePinPage(SPCache *pCache, SPage *pPage) {
H
more  
Hongze Cheng 已提交
215 216 217 218 219 220
  if (!PAGE_IS_PINNED(pPage)) {
    pPage->pLruPrev->pLruNext = pPage->pLruNext;
    pPage->pLruNext->pLruPrev = pPage->pLruPrev;
    pPage->pLruNext = NULL;

    pCache->nRecyclable--;
H
more  
Hongze Cheng 已提交
221
  }
H
more  
Hongze Cheng 已提交
222 223
}

H
Hongze Cheng 已提交
224 225
static void tdbPCacheUnpinPage(SPCache *pCache, SPage *pPage) {
  i32 nRef;
H
Hongze Cheng 已提交
226

H
Hongze Cheng 已提交
227
  ASSERT(!pPage->isDirty);
H
Hongze Cheng 已提交
228
  ASSERT(TDB_GET_PAGE_REF(pPage) == 0);
H
Hongze Cheng 已提交
229

H
Hongze Cheng 已提交
230
  ASSERT(pPage->pLruNext == NULL);
H
more  
Hongze Cheng 已提交
231

H
Hongze Cheng 已提交
232 233 234 235
  pPage->pLruPrev = &(pCache->lru);
  pPage->pLruNext = pCache->lru.pLruNext;
  pCache->lru.pLruNext->pLruPrev = pPage;
  pCache->lru.pLruNext = pPage;
H
more  
Hongze Cheng 已提交
236 237 238 239

  pCache->nRecyclable++;
}

H
Hongze Cheng 已提交
240 241 242
static void tdbPCacheRemovePageFromHash(SPCache *pCache, SPage *pPage) {
  SPage **ppPage;
  int     h;
H
more  
Hongze Cheng 已提交
243

wafwerar's avatar
wafwerar 已提交
244
  h = tdbPCachePageHash(&(pPage->pgid));
H
fix  
Hongze Cheng 已提交
245
  for (ppPage = &(pCache->pgHash[h % pCache->nHash]); (*ppPage) && *ppPage != pPage; ppPage = &((*ppPage)->pHashNext))
H
more  
Hongze Cheng 已提交
246 247 248 249 250 251 252
    ;
  ASSERT(*ppPage == pPage);
  *ppPage = pPage->pHashNext;

  pCache->nPage--;
}

H
Hongze Cheng 已提交
253 254
static void tdbPCacheAddPageToHash(SPCache *pCache, SPage *pPage) {
  int h;
H
more  
Hongze Cheng 已提交
255

wafwerar's avatar
wafwerar 已提交
256
  h = tdbPCachePageHash(&(pPage->pgid)) % pCache->nHash;
H
more  
Hongze Cheng 已提交
257 258 259 260 261

  pPage->pHashNext = pCache->pgHash[h];
  pCache->pgHash[h] = pPage;

  pCache->nPage++;
H
more  
Hongze Cheng 已提交
262 263 264
}

static int tdbPCacheOpenImpl(SPCache *pCache) {
H
refact  
Hongze Cheng 已提交
265
  SPage *pPage;
H
Hongze Cheng 已提交
266
  u8    *pPtr;
H
refact  
Hongze Cheng 已提交
267
  int    tsize;
H
Hongze Cheng 已提交
268
  int    ret;
H
more  
Hongze Cheng 已提交
269 270 271 272 273 274 275

  tdbPCacheInitLock(pCache);

  // Open the free list
  pCache->nFree = 0;
  pCache->pFree = NULL;
  for (int i = 0; i < pCache->cacheSize; i++) {
H
Hongze Cheng 已提交
276
    ret = tdbPageCreate(pCache->pageSize, &pPage, tdbDefaultMalloc, NULL);
H
Hongze Cheng 已提交
277 278
    if (ret < 0) {
      // TODO: handle error
H
more  
Hongze Cheng 已提交
279 280 281 282 283
      return -1;
    }

    // pPage->pgid = 0;
    pPage->isAnchor = 0;
H
Hongze Cheng 已提交
284
    pPage->isLocal = 1;
H
Hongze Cheng 已提交
285
    TDB_INIT_PAGE_REF(pPage);
H
more  
Hongze Cheng 已提交
286 287 288
    pPage->pHashNext = NULL;
    pPage->pLruNext = NULL;
    pPage->pLruPrev = NULL;
H
more  
Hongze Cheng 已提交
289
    pPage->pDirtyNext = NULL;
H
more  
Hongze Cheng 已提交
290

H
Hongze Cheng 已提交
291
    // add page to free list
H
more  
Hongze Cheng 已提交
292 293 294
    pPage->pFreeNext = pCache->pFree;
    pCache->pFree = pPage;
    pCache->nFree++;
H
Hongze Cheng 已提交
295 296 297 298

    // add to local list
    pPage->pCacheNext = pCache->pList;
    pCache->pList = pPage;
H
more  
Hongze Cheng 已提交
299 300 301 302
  }

  // Open the hash table
  pCache->nPage = 0;
H
Hongze Cheng 已提交
303
  pCache->nHash = pCache->cacheSize < 8 ? 8 : pCache->cacheSize;
H
Hongze Cheng 已提交
304
  pCache->pgHash = (SPage **)tdbOsCalloc(pCache->nHash, sizeof(SPage *));
H
more  
Hongze Cheng 已提交
305 306 307 308 309 310 311 312 313 314 315 316
  if (pCache->pgHash == NULL) {
    // TODO
    return -1;
  }

  // Open LRU list
  pCache->nRecyclable = 0;
  pCache->lru.isAnchor = 1;
  pCache->lru.pLruNext = &(pCache->lru);
  pCache->lru.pLruPrev = &(pCache->lru);

  return 0;
H
Hongze Cheng 已提交
317 318
}

H
Hongze Cheng 已提交
319 320 321 322 323
static int tdbPCacheCloseImpl(SPCache *pCache) {
  SPage *pPage;

  for (pPage = pCache->pList; pPage; pPage = pCache->pList) {
    pCache->pList = pPage->pCacheNext;
H
Hongze Cheng 已提交
324
    tdbPageDestroy(pPage, tdbDefaultFree, NULL);
H
Hongze Cheng 已提交
325 326
  }

H
Hongze Cheng 已提交
327
  tdbOsFree(pCache->pgHash);
H
Hongze Cheng 已提交
328
  tdbPCacheDestroyLock(pCache);
wmmhello's avatar
wmmhello 已提交
329
  return 0;
H
Hongze Cheng 已提交
330
}