1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 2009 Oracle. All rights reserved. 5 * 6 */ 7using System; 8using System.Collections.Generic; 9using System.Text; 10using BerkeleyDB.Internal; 11 12namespace BerkeleyDB { 13 /// <summary> 14 /// A class representing a RecnoDatabase. The Recno format supports fixed- 15 /// or variable-length records, accessed sequentially or by logical record 16 /// number, and optionally backed by a flat text file. 17 /// </summary> 18 public class RecnoDatabase : Database { 19 private BDB_AppendRecnoDelegate doAppendRef; 20 private AppendRecordDelegate appendHandler; 21 22 #region Constructors 23 private RecnoDatabase(DatabaseEnvironment env, uint flags) 24 : base(env, flags) { } 25 internal RecnoDatabase(BaseDatabase clone) : base(clone) { } 26 27 private void Config(RecnoDatabaseConfig cfg) { 28 base.Config(cfg); 29 /* 30 * Database.Config calls set_flags, but that doesn't get the Recno 31 * specific flags. No harm in calling it again. 32 */ 33 db.set_flags(cfg.flags); 34 35 if (cfg.delimiterIsSet) 36 RecordDelimiter = cfg.Delimiter; 37 if (cfg.lengthIsSet) 38 RecordLength = cfg.Length; 39 if (cfg.padIsSet) 40 RecordPad = cfg.PadByte; 41 if (cfg.BackingFile != null) 42 SourceFile = cfg.BackingFile; 43 } 44 45 /// <summary> 46 /// Instantiate a new RecnoDatabase object and open the database 47 /// represented by <paramref name="Filename"/>. 48 /// </summary> 49 /// <remarks> 50 /// <para> 51 /// If <paramref name="Filename"/> is null, the database is strictly 52 /// temporary and cannot be opened by any other thread of control, thus 53 /// the database can only be accessed by sharing the single database 54 /// object that created it, in circumstances where doing so is safe. 55 /// </para> 56 /// <para> 57 /// If <see cref="DatabaseConfig.AutoCommit"/> is set, the operation 58 /// will be implicitly transaction protected. Note that transactionally 59 /// protected operations on a datbase object requires the object itself 60 /// be transactionally protected during its open. 61 /// </para> 62 /// </remarks> 63 /// <param name="Filename"> 64 /// The name of an underlying file that will be used to back the 65 /// database. In-memory databases never intended to be preserved on disk 66 /// may be created by setting this parameter to null. 67 /// </param> 68 /// <param name="cfg">The database's configuration</param> 69 /// <returns>A new, open database object</returns> 70 public static RecnoDatabase Open( 71 string Filename, RecnoDatabaseConfig cfg) { 72 return Open(Filename, null, cfg, null); 73 } 74 /// <summary> 75 /// Instantiate a new RecnoDatabase object and open the database 76 /// represented by <paramref name="Filename"/> and 77 /// <paramref name="DatabaseName"/>. 78 /// </summary> 79 /// <remarks> 80 /// <para> 81 /// If both <paramref name="Filename"/> and 82 /// <paramref name="DatabaseName"/> are null, the database is strictly 83 /// temporary and cannot be opened by any other thread of control, thus 84 /// the database can only be accessed by sharing the single database 85 /// object that created it, in circumstances where doing so is safe. If 86 /// <paramref name="Filename"/> is null and 87 /// <paramref name="DatabaseName"/> is non-null, the database can be 88 /// opened by other threads of control and will be replicated to client 89 /// sites in any replication group. 90 /// </para> 91 /// <para> 92 /// If <see cref="DatabaseConfig.AutoCommit"/> is set, the operation 93 /// will be implicitly transaction protected. Note that transactionally 94 /// protected operations on a datbase object requires the object itself 95 /// be transactionally protected during its open. 96 /// </para> 97 /// </remarks> 98 /// <param name="Filename"> 99 /// The name of an underlying file that will be used to back the 100 /// database. In-memory databases never intended to be preserved on disk 101 /// may be created by setting this parameter to null. 102 /// </param> 103 /// <param name="DatabaseName"> 104 /// This parameter allows applications to have multiple databases in a 105 /// single file. Although no DatabaseName needs to be specified, it is 106 /// an error to attempt to open a second database in a file that was not 107 /// initially created using a database name. 108 /// </param> 109 /// <param name="cfg">The database's configuration</param> 110 /// <returns>A new, open database object</returns> 111 public static RecnoDatabase Open( 112 string Filename, string DatabaseName, RecnoDatabaseConfig cfg) { 113 return Open(Filename, DatabaseName, cfg, null); 114 } 115 /// <summary> 116 /// Instantiate a new RecnoDatabase object and open the database 117 /// represented by <paramref name="Filename"/>. 118 /// </summary> 119 /// <remarks> 120 /// <para> 121 /// If <paramref name="Filename"/> is null, the database is strictly 122 /// temporary and cannot be opened by any other thread of control, thus 123 /// the database can only be accessed by sharing the single database 124 /// object that created it, in circumstances where doing so is safe. 125 /// </para> 126 /// <para> 127 /// If <paramref name="txn"/> is null, but 128 /// <see cref="DatabaseConfig.AutoCommit"/> is set, the operation will 129 /// be implicitly transaction protected. Note that transactionally 130 /// protected operations on a datbase object requires the object itself 131 /// be transactionally protected during its open. Also note that the 132 /// transaction must be committed before the object is closed. 133 /// </para> 134 /// </remarks> 135 /// <param name="Filename"> 136 /// The name of an underlying file that will be used to back the 137 /// database. In-memory databases never intended to be preserved on disk 138 /// may be created by setting this parameter to null. 139 /// </param> 140 /// <param name="cfg">The database's configuration</param> 141 /// <param name="txn"> 142 /// If the operation is part of an application-specified transaction, 143 /// <paramref name="txn"/> is a Transaction object returned from 144 /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if 145 /// the operation is part of a Berkeley DB Concurrent Data Store group, 146 /// <paramref name="txn"/> is a handle returned from 147 /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null. 148 /// </param> 149 /// <returns>A new, open database object</returns> 150 public static RecnoDatabase Open( 151 string Filename, RecnoDatabaseConfig cfg, Transaction txn) { 152 return Open(Filename, null, cfg, txn); 153 } 154 /// <summary> 155 /// Instantiate a new RecnoDatabase object and open the database 156 /// represented by <paramref name="Filename"/> and 157 /// <paramref name="DatabaseName"/>. 158 /// </summary> 159 /// <remarks> 160 /// <para> 161 /// If both <paramref name="Filename"/> and 162 /// <paramref name="DatabaseName"/> are null, the database is strictly 163 /// temporary and cannot be opened by any other thread of control, thus 164 /// the database can only be accessed by sharing the single database 165 /// object that created it, in circumstances where doing so is safe. If 166 /// <paramref name="Filename"/> is null and 167 /// <paramref name="DatabaseName"/> is non-null, the database can be 168 /// opened by other threads of control and will be replicated to client 169 /// sites in any replication group. 170 /// </para> 171 /// <para> 172 /// If <paramref name="txn"/> is null, but 173 /// <see cref="DatabaseConfig.AutoCommit"/> is set, the operation will 174 /// be implicitly transaction protected. Note that transactionally 175 /// protected operations on a datbase object requires the object itself 176 /// be transactionally protected during its open. Also note that the 177 /// transaction must be committed before the object is closed. 178 /// </para> 179 /// </remarks> 180 /// <param name="Filename"> 181 /// The name of an underlying file that will be used to back the 182 /// database. In-memory databases never intended to be preserved on disk 183 /// may be created by setting this parameter to null. 184 /// </param> 185 /// <param name="DatabaseName"> 186 /// This parameter allows applications to have multiple databases in a 187 /// single file. Although no DatabaseName needs to be specified, it is 188 /// an error to attempt to open a second database in a file that was not 189 /// initially created using a database name. 190 /// </param> 191 /// <param name="cfg">The database's configuration</param> 192 /// <param name="txn"> 193 /// If the operation is part of an application-specified transaction, 194 /// <paramref name="txn"/> is a Transaction object returned from 195 /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if 196 /// the operation is part of a Berkeley DB Concurrent Data Store group, 197 /// <paramref name="txn"/> is a handle returned from 198 /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null. 199 /// </param> 200 /// <returns>A new, open database object</returns> 201 public static RecnoDatabase Open(string Filename, 202 string DatabaseName, RecnoDatabaseConfig cfg, Transaction txn) { 203 RecnoDatabase ret = new RecnoDatabase(cfg.Env, 0); 204 ret.Config(cfg); 205 ret.db.open(Transaction.getDB_TXN(txn), 206 Filename, DatabaseName, DBTYPE.DB_RECNO, cfg.openFlags, 0); 207 ret.isOpen = true; 208 return ret; 209 } 210 #endregion Constructors 211 212 #region Callbacks 213 private static void doAppend(IntPtr dbp, IntPtr dbtp1, uint recno) { 214 DB db = new DB(dbp, false); 215 DBT dbt1 = new DBT(dbtp1, false); 216 RecnoDatabase rdb = (RecnoDatabase)(db.api_internal); 217 218 rdb.AppendCallback(DatabaseEntry.fromDBT(dbt1), recno); 219 } 220 #endregion Callbacks 221 222 #region Properties 223 /// <summary> 224 /// A function to call after the record number has been selected but 225 /// before the data has been stored into the database. 226 /// </summary> 227 /// <remarks> 228 /// <para> 229 /// When using <see cref="QueueDatabase.Append"/>, it may be useful to 230 /// modify the stored data based on the generated key. If a delegate is 231 /// specified, it will be called after the record number has been 232 /// selected, but before the data has been stored. 233 /// </para> 234 /// </remarks> 235 public AppendRecordDelegate AppendCallback { 236 get { return appendHandler; } 237 set { 238 if (value == null) 239 db.set_append_recno(null); 240 else if (appendHandler == null) { 241 if (doAppendRef == null) 242 doAppendRef = new BDB_AppendRecnoDelegate(doAppend); 243 db.set_append_recno(doAppendRef); 244 } 245 appendHandler = value; 246 } 247 } 248 249 /// <summary> 250 /// The delimiting byte used to mark the end of a record in 251 /// <see cref="SourceFile"/>. 252 /// </summary> 253 public int RecordDelimiter { 254 get { 255 int ret = 0; 256 db.get_re_delim(ref ret); 257 return ret; 258 } 259 private set { 260 db.set_re_delim(value); 261 } 262 } 263 264 /// <summary> 265 /// If using fixed-length, not byte-delimited records, the length of the 266 /// records. 267 /// </summary> 268 public uint RecordLength { 269 get { 270 uint ret = 0; 271 db.get_re_len(ref ret); 272 return ret; 273 } 274 private set { 275 db.set_re_len(value); 276 } 277 } 278 279 /// <summary> 280 /// The padding character for short, fixed-length records. 281 /// </summary> 282 public int RecordPad { 283 get { 284 int ret = 0; 285 db.get_re_pad(ref ret); 286 return ret; 287 } 288 private set { 289 db.set_re_pad(value); 290 } 291 } 292 293 /// <summary> 294 /// If true, the logical record numbers are mutable, and change as 295 /// records are added to and deleted from the database. 296 /// </summary> 297 public bool Renumber { 298 get { 299 uint flags = 0; 300 db.get_flags(ref flags); 301 return (flags & DbConstants.DB_RENUMBER) != 0; 302 } 303 } 304 305 /// <summary> 306 /// If true, any <see cref="SourceFile"/> file will be read in its 307 /// entirety when <see cref="Open"/> is called. If false, 308 /// <see cref="SourceFile"/> may be read lazily. 309 /// </summary> 310 public bool Snapshot { 311 get { 312 uint flags = 0; 313 db.get_flags(ref flags); 314 return (flags & DbConstants.DB_SNAPSHOT) != 0; 315 } 316 } 317 318 /// <summary> 319 /// The underlying source file for the Recno access method. 320 /// </summary> 321 public string SourceFile { 322 get { 323 string ret = ""; 324 db.get_re_source(ref ret); 325 return ret; 326 } 327 private set { 328 db.set_re_source(value); 329 } 330 } 331 332 #endregion Properties 333 334 #region Methods 335 /// <summary> 336 /// Append the data item to the end of the database. 337 /// </summary> 338 /// <param name="data">The data item to store in the database</param> 339 /// <returns>The record number allocated to the record</returns> 340 public uint Append(DatabaseEntry data) { 341 return Append(data, null); 342 } 343 /// <summary> 344 /// Append the data item to the end of the database. 345 /// </summary> 346 /// <remarks> 347 /// There is a minor behavioral difference between 348 /// <see cref="RecnoDatabase.Append"/> and 349 /// <see cref="QueueDatabase.Append"/>. If a transaction enclosing an 350 /// Append operation aborts, the record number may be reallocated in a 351 /// subsequent <see cref="RecnoDatabase.Append"/> operation, but it will 352 /// not be reallocated in a subsequent 353 /// <see cref="QueueDatabase.Append"/> operation. 354 /// </remarks> 355 /// <param name="data">The data item to store in the database</param> 356 /// <param name="txn"> 357 /// If the operation is part of an application-specified transaction, 358 /// <paramref name="txn"/> is a Transaction object returned from 359 /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if 360 /// the operation is part of a Berkeley DB Concurrent Data Store group, 361 /// <paramref name="txn"/> is a handle returned from 362 /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null. 363 /// </param> 364 /// <returns>The record number allocated to the record</returns> 365 public uint Append(DatabaseEntry data, Transaction txn) { 366 DatabaseEntry key = new DatabaseEntry(); 367 Put(key, data, txn, DbConstants.DB_APPEND); 368 return BitConverter.ToUInt32(key.Data, 0); 369 } 370 371 /// <summary> 372 /// Compact the database, and optionally return unused database pages to 373 /// the underlying filesystem. 374 /// </summary> 375 /// <remarks> 376 /// If the operation occurs in a transactional database, the operation 377 /// will be implicitly transaction protected using multiple 378 /// transactions. These transactions will be periodically committed to 379 /// avoid locking large sections of the tree. Any deadlocks encountered 380 /// cause the compaction operation to be retried from the point of the 381 /// last transaction commit. 382 /// </remarks> 383 /// <param name="cdata">Compact configuration parameters</param> 384 /// <returns>Compact operation statistics</returns> 385 public CompactData Compact(CompactConfig cdata) { 386 return Compact(cdata, null); 387 } 388 /// <summary> 389 /// Compact the database, and optionally return unused database pages to 390 /// the underlying filesystem. 391 /// </summary> 392 /// <remarks> 393 /// <para> 394 /// If <paramref name="txn"/> is non-null, then the operation is 395 /// performed using that transaction. In this event, large sections of 396 /// the tree may be locked during the course of the transaction. 397 /// </para> 398 /// <para> 399 /// If <paramref name="txn"/> is null, but the operation occurs in a 400 /// transactional database, the operation will be implicitly transaction 401 /// protected using multiple transactions. These transactions will be 402 /// periodically committed to avoid locking large sections of the tree. 403 /// Any deadlocks encountered cause the compaction operation to be 404 /// retried from the point of the last transaction commit. 405 /// </para> 406 /// </remarks> 407 /// <param name="cdata">Compact configuration parameters</param> 408 /// <param name="txn"> 409 /// If the operation is part of an application-specified transaction, 410 /// <paramref name="txn"/> is a Transaction object returned from 411 /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if 412 /// the operation is part of a Berkeley DB Concurrent Data Store group, 413 /// <paramref name="txn"/> is a handle returned from 414 /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null. 415 /// </param> 416 /// <returns>Compact operation statistics</returns> 417 public CompactData Compact(CompactConfig cdata, Transaction txn) { 418 DatabaseEntry end = null; 419 if (cdata.returnEnd) 420 end = new DatabaseEntry(); 421 422 db.compact(Transaction.getDB_TXN(txn), 423 cdata.start, 424 cdata.stop, 425 CompactConfig.getDB_COMPACT(cdata), 426 cdata.flags, end); 427 return new CompactData(CompactConfig.getDB_COMPACT(cdata), end); 428 } 429 430 /// <summary> 431 /// Create a database cursor. 432 /// </summary> 433 /// <returns>A newly created cursor</returns> 434 public new RecnoCursor Cursor() { 435 return Cursor(new CursorConfig(), null); 436 } 437 /// <summary> 438 /// Create a database cursor with the given configuration. 439 /// </summary> 440 /// <param name="cfg"> 441 /// The configuration properties for the cursor. 442 /// </param> 443 /// <returns>A newly created cursor</returns> 444 public new RecnoCursor Cursor(CursorConfig cfg) { 445 return Cursor(cfg, null); 446 } 447 /// <summary> 448 /// Create a transactionally protected database cursor. 449 /// </summary> 450 /// <param name="txn"> 451 /// The transaction context in which the cursor may be used. 452 /// </param> 453 /// <returns>A newly created cursor</returns> 454 public new RecnoCursor Cursor(Transaction txn) { 455 return Cursor(new CursorConfig(), txn); 456 } 457 /// <summary> 458 /// Create a transactionally protected database cursor with the given 459 /// configuration. 460 /// </summary> 461 /// <param name="cfg"> 462 /// The configuration properties for the cursor. 463 /// </param> 464 /// <param name="txn"> 465 /// The transaction context in which the cursor may be used. 466 /// </param> 467 /// <returns>A newly created cursor</returns> 468 public new RecnoCursor Cursor(CursorConfig cfg, Transaction txn) { 469 return new RecnoCursor( 470 db.cursor(Transaction.getDB_TXN(txn), cfg.flags), Pagesize); 471 } 472 473 /// <summary> 474 /// Return the database statistical information which does not require 475 /// traversal of the database. 476 /// </summary> 477 /// <returns> 478 /// The database statistical information which does not require 479 /// traversal of the database. 480 /// </returns> 481 public RecnoStats FastStats() { 482 return Stats(null, true, Isolation.DEGREE_THREE); 483 } 484 /// <summary> 485 /// Return the database statistical information which does not require 486 /// traversal of the database. 487 /// </summary> 488 /// <param name="txn"> 489 /// If the operation is part of an application-specified transaction, 490 /// <paramref name="txn"/> is a Transaction object returned from 491 /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if 492 /// the operation is part of a Berkeley DB Concurrent Data Store group, 493 /// <paramref name="txn"/> is a handle returned from 494 /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null. 495 /// </param> 496 /// <returns> 497 /// The database statistical information which does not require 498 /// traversal of the database. 499 /// </returns> 500 public RecnoStats FastStats(Transaction txn) { 501 return Stats(txn, true, Isolation.DEGREE_THREE); 502 } 503 /// <summary> 504 /// Return the database statistical information which does not require 505 /// traversal of the database. 506 /// </summary> 507 /// <overloads> 508 /// <para> 509 /// Among other things, this method makes it possible for applications 510 /// to request key and record counts without incurring the performance 511 /// penalty of traversing the entire database. 512 /// </para> 513 /// <para> 514 /// The statistical information is described by the 515 /// <see cref="BTreeStats"/>, <see cref="HashStats"/>, 516 /// <see cref="QueueStats"/>, and <see cref="RecnoStats"/> classes. 517 /// </para> 518 /// </overloads> 519 /// <param name="txn"> 520 /// If the operation is part of an application-specified transaction, 521 /// <paramref name="txn"/> is a Transaction object returned from 522 /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if 523 /// the operation is part of a Berkeley DB Concurrent Data Store group, 524 /// <paramref name="txn"/> is a handle returned from 525 /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null. 526 /// </param> 527 /// <param name="isoDegree"> 528 /// The level of isolation for database reads. 529 /// <see cref="Isolation.DEGREE_ONE"/> will be silently ignored for 530 /// databases which did not specify 531 /// <see cref="DatabaseConfig.ReadUncommitted"/>. 532 /// </param> 533 /// <returns> 534 /// The database statistical information which does not require 535 /// traversal of the database. 536 /// </returns> 537 public RecnoStats FastStats(Transaction txn, Isolation isoDegree) { 538 return Stats(txn, true, isoDegree); 539 } 540 541 /// <summary> 542 /// Return the database statistical information for this database. 543 /// </summary> 544 /// <returns>Database statistical information.</returns> 545 public RecnoStats Stats() { 546 return Stats(null, false, Isolation.DEGREE_THREE); 547 } 548 /// <summary> 549 /// Return the database statistical information for this database. 550 /// </summary> 551 /// <param name="txn"> 552 /// If the operation is part of an application-specified transaction, 553 /// <paramref name="txn"/> is a Transaction object returned from 554 /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if 555 /// the operation is part of a Berkeley DB Concurrent Data Store group, 556 /// <paramref name="txn"/> is a handle returned from 557 /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null. 558 /// </param> 559 /// <returns>Database statistical information.</returns> 560 public RecnoStats Stats(Transaction txn) { 561 return Stats(txn, false, Isolation.DEGREE_THREE); 562 } 563 /// <summary> 564 /// Return the database statistical information for this database. 565 /// </summary> 566 /// <overloads> 567 /// The statistical information is described by 568 /// <see cref="BTreeStats"/>. 569 /// </overloads> 570 /// <param name="txn"> 571 /// If the operation is part of an application-specified transaction, 572 /// <paramref name="txn"/> is a Transaction object returned from 573 /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if 574 /// the operation is part of a Berkeley DB Concurrent Data Store group, 575 /// <paramref name="txn"/> is a handle returned from 576 /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null. 577 /// </param> 578 /// <param name="isoDegree"> 579 /// The level of isolation for database reads. 580 /// <see cref="Isolation.DEGREE_ONE"/> will be silently ignored for 581 /// databases which did not specify 582 /// <see cref="DatabaseConfig.ReadUncommitted"/>. 583 /// </param> 584 /// <returns>Database statistical information.</returns> 585 public RecnoStats Stats(Transaction txn, Isolation isoDegree) { 586 return Stats(txn, false, isoDegree); 587 } 588 private RecnoStats Stats( 589 Transaction txn, bool fast, Isolation isoDegree) { 590 uint flags = 0; 591 flags |= fast ? DbConstants.DB_FAST_STAT : 0; 592 switch (isoDegree) { 593 case Isolation.DEGREE_ONE: 594 flags |= DbConstants.DB_READ_UNCOMMITTED; 595 break; 596 case Isolation.DEGREE_TWO: 597 flags |= DbConstants.DB_READ_COMMITTED; 598 break; 599 } 600 BTreeStatStruct st = db.stat_bt(Transaction.getDB_TXN(txn), flags); 601 return new RecnoStats(st); 602 } 603 604 /// <summary> 605 /// Return pages to the filesystem that are already free and at the end 606 /// of the file. 607 /// </summary> 608 /// <returns> 609 /// The number of database pages returned to the filesystem 610 /// </returns> 611 public uint TruncateUnusedPages() { 612 return TruncateUnusedPages(null); 613 } 614 /// <summary> 615 /// Return pages to the filesystem that are already free and at the end 616 /// of the file. 617 /// </summary> 618 /// <param name="txn"> 619 /// If the operation is part of an application-specified transaction, 620 /// <paramref name="txn"/> is a Transaction object returned from 621 /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if 622 /// the operation is part of a Berkeley DB Concurrent Data Store group, 623 /// <paramref name="txn"/> is a handle returned from 624 /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null. 625 /// </param> 626 /// <returns> 627 /// The number of database pages returned to the filesystem 628 /// </returns> 629 public uint TruncateUnusedPages(Transaction txn) { 630 DB_COMPACT cdata = new DB_COMPACT(); 631 db.compact(Transaction.getDB_TXN(txn), 632 null, null, cdata, DbConstants.DB_FREELIST_ONLY, null); 633 return cdata.compact_pages_truncated; 634 } 635 #endregion Methods 636 } 637}